/drone/action/* call documented in Drone Management & Control Actions. Think of this page as “the database side of the map editor.”
src/routes/mission_routes.py— mission + mission-point CRUD (9 endpoints), backed byMissionService(src/service/mission_service.py) andPointService(src/service/point_service.py).src/routes/geofence_routes.py— geofence + geofence-point CRUD/toggle/batch (11 endpoints), backed byGeofenceService(src/service/geofence_service.py).
Every endpoint on this page is
@jwt_required() (JWT Bearer, the UI auth model in HTTP API Overview). Unlike Socket.IO telemetry rooms, these routes are genuinely user-scoped: every service query filters user_id == get_jwt_identity(), so a token can only see and mutate its own missions and geofences.Lifecycle at a glance
The stored rows are MAVLink-shaped so the upload path (push_mission, push_geofence, sync_geofences in src/service/drone_control_service.py) can convert each row to a rosbridge waypoint with almost no transformation. The exact conversion and the on-drone protocol live in Mission & Geofence MAVLink Format.
Missions API
All routes are under the/api/v1 base path.
¹ The
GET /missions error branch returns jsonify(error=...) with no status code, so a failure serializes the error body with an HTTP 200 (src/routes/mission_routes.py:323) — a latent bug to preserve/fix deliberately. ² 400 only when the DB raises a foreign-key violation (drone_mission_id_fkey).
Mission point mutations return
201 for create and update and delete and batch. That is not a typo in this doc — it is what the handlers actually return. On the geofence side only point create returns 201 (same as mission); point update, delete, and batch return 200. Any client (and any refactor) must treat both as success; do not “normalize” these codes without updating the Dashboard.Create a mission, then add points
1
Create the mission shell
POST /mission takes just a name and returns the new id. MissionService.create_mission enforces a UNIQUE(user_id, name) constraint (src/models/mission.py:19).2
Add points one at a time
POST /mission/point expects a JSON array, but the handler only reads element [0] (src/routes/mission_routes.py:138). Sending several points in one call silently persists only the first.mission_points array), not just the created point.Mission point fields
create_mission_point (src/service/mission_service.py:106) reads the keys below. The underlying mission_point table columns and their nullability come from src/models/mission_point.py.
Batch update (reorder / drag-to-edit)
PATCH /mission/<mission_id>/points is what the editor calls after a drag-reorder. The body is an array of {id, ...} objects and PointService.batch_update (src/service/point_service.py:47) passes each raw dict straight into MissionPoint.query...update(point_data).
Deleting
DELETE /mission/<mission_id> (MissionService.delete, src/service/mission_service.py:83) does three things in order: sets Drone.mission_id = NULL on any drone pointing at this mission, deletes the mission’s points, then deletes the mission. The route still wraps a foreign-key violation into a friendly 400 (“unassign it first”) in case a drone reference survives.
Geofences API
Geofences model MAVLink fence zones — polygons and circles, either inclusion (stay inside) or exclusion (stay outside).Geofence metadata fields
Set onPOST /geofence and PATCH /geofence/<id> (src/service/geofence_service.py:78; columns in src/models/geofence.py):
Geofence point fields
create_geofence_point (src/service/geofence_service.py:94) reads:
Batch update
PATCH /geofence/<id>/points mirrors the mission batch endpoint — GeofenceService.batch_update_points (src/service/geofence_service.py:192) passes each raw dict into .update(), so keys must be real geofence_point columns (id, lat, lng, sequence, frame, command, param1–param4) and rows are re-scoped by user_id.
MAVLink command reference
These are the values the fields above map onto. The upload layer converts each row viato_mavlink_waypoint() / to_mavlink_fence_item(), renaming lat → x_lat, lng → y_long, altitude → z_alt (fence points force z_alt = 0.0, they are 2D).
Mission commands (command)
- 16 —
NAV_WAYPOINT - 22 —
NAV_TAKEOFF(auto-prepended if missing) - 21 —
NAV_LAND - 20 —
NAV_RETURN_TO_LAUNCH
Fence commands (command)
- 5001 —
POLYGON_VERTEX_INCLUSION - 5002 —
POLYGON_VERTEX_EXCLUSION - 5003 —
CIRCLE_INCLUSION(param1= radius) - 5004 —
CIRCLE_EXCLUSION(param1= radius)
get_fence_command() in src/models/geofence_point.py.Gotchas worth preserving
Array-body [0] quirk on both point-create endpoints
Array-body [0] quirk on both point-create endpoints
POST /mission/point and POST /geofence/point both accept a JSON array but process only data[0] (mission_routes.py:138, geofence_routes.py:154). The batch PATCH .../points endpoints are the real multi-point path. If a future editor wants to add many points in one request, it must loop the single-create endpoint or extend the handler — the array shape is a historical leftover, not multi-insert support.Point-create/update responses return the whole parent
Point-create/update responses return the whole parent
Adding, updating, or deleting a single point returns the entire mission/geofence object with its refreshed
*_points array — not the point you touched. This lets the editor replace its local state in one shot, but means the response can be large for big plans.Raw jsonify envelope — no success wrapper here
Raw jsonify envelope — no success wrapper here
Unlike the newer blueprints (auth, executions, billing), mission/geofence routes return bare
jsonify payloads (the object itself, or {"error": "..."} / {"message": "..."}), not the {"success": true, "data": ...} envelope from src/utils/common_helper.py. Clients must not assume a uniform envelope across the gateway. See HTTP API Overview.Status-code inconsistency (201 vs 200)
Status-code inconsistency (201 vs 200)
Mission point create/update/delete/batch all return 201. On the geofence side only point create returns 201 (same as mission); point update/delete/batch return 200.
GET /missions even returns 200 on error. These are load-bearing for the current Dashboard — treat any code < 400 as success and change codes only alongside the frontend.Related pages
Drone Management & Control Actions
push_mission, push_geofence, clear_fence, sync_geofences, start_mission — the endpoints that actually send a stored plan to a vehicle.Mission & Geofence MAVLink Format
Full DB → MAVLink conversion, the TAKEOFF auto-prepend, and the on-drone fence/mission protocol.
HTTP API Overview & Auth Models
Base path, the three auth models, and the response-envelope conventions.
Mission & Waypoint Planning (Dashboard)
How the Angular editor builds these payloads and drives the batch-reorder calls.

