Appearance
API reference
Before you start
This page is the reference for the Payloads API that a payload or an operator calls in MC. A payload on the device API path does not call it: the bus does.
For the self-announce path, obtain the connection details from Urban Sky. This reference covers Payloads API version 1.
Device API (port 8090)
Served by your payload, read by the bus on the payload LAN. Guide and examples: Serve the device API.
| Method and path | Purpose |
|---|---|
GET /api/v1/capabilities | schema_version: "urbansky.payload_api.v1", modules, identity, telemetry_fields, commands, and optional streams, services, metrics. |
GET /api/v1/telemetry | schema_version, hostname, generated_at, values. |
POST /api/v1/command | {command, parameters, request_id}. Answers 200, 400, 409 in_progress or 503. |
The bus forwards a command only when its module is in modules, is not reserved (gimbal, rotor, gps, camera, jetson, bus, api), and is named in the bus's PAYLOAD_LAN_MODULES.
Endpoint summary
serial identifies the device; :id is its registration UUID. Device requests use x-device-api-token; operator requests use a signed-in operator’s access JWT for the same organization. SDK/API tokens do not grant access to these operator endpoints.
| Method and path | Caller | Purpose |
|---|---|---|
POST /payloads/announce | Device | Register or refresh identity, reachability, and inline manifests. |
POST /payloads/heartbeat | Device | Refresh the address and liveness. |
POST /payloads/telemetry | Device | Submit a JSON or protobuf telemetry batch. |
GET /payloads | Operator, payload read | List the organization's registrations. |
GET /payloads/:id | Operator, payload read | Inspect a registration. |
GET /payloads/:id/telemetry | Operator, payload read | Read up to 50 samples from the last seven days, newest sample time first. limit up to 500. |
GET /payloads/:id/ingest-rejections | Operator, payload read | Read telemetry rejections from the last seven days. Optional limit and since. |
GET /payloads/:id/command-audit | Operator, payload read | Read sent commands, newest first. limit 1–200, requestId, and cursor from X-Next-Cursor. |
POST /payloads | Operator, payload write | Create an operator-authored registration, adopted immediately. |
PUT /payloads/:id | Operator, payload write | Change settings, manifest sources, or command enablement. |
POST /payloads/:id/adopt | Operator, payload write | Adopt a discovered device. |
POST /payloads/:id/restore | Operator, payload write | Return a retired registration to discovered, with commands disabled. |
POST /payloads/:id/commands | Operator, payload write | Validate and dispatch a declared command; registry commands can need higher roles. |
GET /payloads/:id/video-streams | Operator, payload read | Obtain playback metadata when video is configured. |
POST /payloads/:id/shares | Operator, payload write | Mint a time-limited SRT address for the camera stream. The address is shown once. See Share the stream. |
GET /payloads/:id/shares | Operator, payload write | List live shares of the camera stream, without credentials. |
DELETE /payloads/:id/shares/:user | Operator, payload write | Revoke one share now. |
DELETE /payloads/:id | Operator, payload write | Retire a registration. MC keeps its history. Device traffic cannot restore it. |
POST /commands on the device | MC, using mTLS in this guide | Deliver the command to your hardware adapter. |
Payload read means mission-control:payload:read; payload write means mission-control:payload:write.
On a Husky bus, the payload also sends logs and metrics to the bus itself, not to MC. These routes are on the bus's payload-LAN address, port 4318, with no credentials:
| Method and path | Caller | Purpose |
|---|---|---|
POST /api/v1/payload/logs | Device | Log lines as JSON lines. |
POST /api/v1/payload/metrics | Device | Declared gauge and counter values as JSON. |
POST /v1/logs, /v1/metrics | Device | The same as OTLP/HTTP, for an OpenTelemetry SDK. |
GET /api/v1/payload/status | Device | What the bus received from your payload, and what it dropped. |
PayloadTelemetry in the Python and JavaScript SDKs uses these routes. Limits and rules: Run on a Husky bus.
Message shapes
| Message | Main fields | Example |
|---|---|---|
| Announcement | schemaVersion, identity, reachability, codec, security, manifests, optional streams and services | First announcement |
| Telemetry manifest | schemaVersion, fields, staleAfterS, optional minMessageIntervalMs | Telemetry fields |
| Telemetry batch | serial, schemaVersion, samples containing timestamp, seq, values | Send a measurement |
| Heartbeat | serial, address, optional timestamp | Send a heartbeat |
| Command manifest | schemaVersion, commands containing name, description, confirm, params | Define a command |
| Operator command | name, params, optional relay via or retry requestId | Send a command |
| Device command | name, requestId, params, optional targetSerial | Implement the handler |
| Device acknowledgment | Matching requestId, state, optional reason and result | Acknowledgment states |
| Operator command result | requestId, nested ack, optional deduplicated and contention advisory | Verify the result |
Announcements and heartbeats use JSON. Telemetry accepts JSON or raw protobuf with application/x-protobuf. MC sends device commands as JSON regardless of the telemetry codec.
Complete announcement
ENV-001 with telemetry and command support
json
{
"schemaVersion": 1,
"identity": {
"serial": "ENV-001",
"name": "Environmental sensor",
"vendor": "Example Instruments"
},
"reachability": {
"address": "100.64.0.42",
"port": 8091,
"protocol": "https",
"networkMode": "NETWORK_MODE_SHARED_VPN"
},
"codec": "CODEC_JSON",
"security": "SECURITY_TRANSPORT_MTLS",
"telemetryManifest": {
"schemaVersion": 1,
"staleAfterS": 30,
"fields": [
{
"key": "sensor.temperature_c",
"label": "Temperature",
"type": "FIELD_TYPE_NUMBER",
"unit": "°C",
"min": -80,
"max": 125
},
{
"key": "sensor.sample_period_s",
"label": "Applied sample period",
"type": "FIELD_TYPE_NUMBER",
"unit": "s",
"min": 1,
"max": 60
},
{
"key": "sensor.state",
"label": "Sensor state",
"type": "FIELD_TYPE_ENUM",
"values": ["idle", "sampling", "fault"]
}
]
},
"commandManifest": {
"schemaVersion": 1,
"commands": [
{
"name": "sensor.set_sample_period",
"description": "Set the measurement interval in seconds. Read back the applied interval in telemetry.",
"confirm": true,
"params": [
{
"key": "seconds",
"label": "Sample period",
"type": "FIELD_TYPE_NUMBER",
"unit": "s",
"min": 1,
"max": 60,
"required": true
}
]
}
]
}
}Manifest rules
- Use camelCase property names and full enum strings.
- Types:
FIELD_TYPE_NUMBER,FIELD_TYPE_STRING,FIELD_TYPE_BOOLEAN,FIELD_TYPE_ENUM. Enums requirevalues. - Keep telemetry keys and command names unique; parameter keys must be unique within a command.
- Declare at least one field or command. Either list may otherwise be empty. On re-announcement, omitting a manifest preserves it; send an empty
fieldsorcommandslist to remove that capability set. The same announcement must still include a nonempty list for the other manifest, because the check counts only entries in the current request and a stored manifest does not satisfy it. - Match hardware units and bounds. Only
required: falsemakes a parameter optional; enforce integer-only rules in the device. confirmrequests UI confirmation; it is not authorization or an interlock.- Set
audience: "AUDIENCE_ENGINEERING"on a command or telemetry field for tuning, diagnostics, and bench use. MC does not show it to operators. Omitaudiencefor everything that operators use. Engineering is not a safety lock: leave a command out of the manifest until it is safe to send remotely. - Set
sensitive: trueon a parameter whose value MC must not store in a mission plan. The operator supplies the value when the command is sent. staleAfterSmust exceed normal reporting delay. OptionalminMessageIntervalMscontrols persistence thinning, not sampling.- Generate manifests and validation from one registry. Omit unavailable measurements rather than invent values.
Limits and timing
| Item | Limit or behavior |
|---|---|
| Payload serial | Up to 64 letters, digits, _, ., :, or -. |
| Each manifest | 64 KiB. |
| Telemetry fields | 200 per manifest. |
| Commands | 100 per manifest. |
| Samples | 100 per batch. |
| Values | 300 per sample. |
| String value | 1,024 characters. |
| Sequence number | Exact integer range 0 through 9007199254740991. |
| Future sample timestamp | More than five minutes ahead of MC is rejected. |
| Direct command request | 10-second timeout. |
| Manifest fetch | Five-second timeout and 64 KiB cap; cached for five minutes. |
| Example loop intervals | Reporting every 2 seconds, heartbeat and capability refresh every 15 seconds; implementation defaults, not protocol requirements. |
Network modes
| Mode | Routing |
|---|---|
NETWORK_MODE_SHARED_VPN | Behind a bus. With identity.parentSerial set to the bus, MC sends commands through the bus link to your payload-LAN lease. The name is older than the bus link. |
NETWORK_MODE_SHARED_LAN | Direct connection; MC needs a route to the LAN. |
NETWORK_MODE_STATIC_IP | Direct connection to the announced address. |
NETWORK_MODE_PAYLOAD_VPN | Reserved; command routing is unavailable. |
Protobuf
Obtain the matching .proto bundle from Urban Sky, generate a client, and encode TelemetryBatch. Send raw bytes as application/x-protobuf. Announcements, heartbeats, and device commands remain JSON.
Optional integrations
Serve manifests by URL
Set telemetrySchemaUrl or commandsUrl through PUT /payloads/:id. The URL must match the registered host and protocol. A nonempty URL clears its stored inline manifest; re-announcing an inline manifest makes that source take precedence again.
Serve a contract TelemetryManifest or CommandManifest. MC applies the same limits, with a five-second fetch timeout and five-minute cache. An unreachable telemetry schema fails ingestion with 503.
Gateway children and relays
Announce each child with its own serial, identity.parentSerial, and the gateway's address/port. Set reachability.dispatch: "parent" to send the child's commands through its gateway. A gateway that MC cannot reach directly announces no address. One enrolled credential may own multiple serials. Adopt and enable each child separately; route commands by targetSerial and reject unknown targets.
reachability.relays declares alternate routes; stratcom is the supported last leg. Operators select a relay with via. Direct failures never silently fall back, and relay acceptance does not confirm delivery.
For positional RF commands, preserve manifest parameter order, omit only trailing optional arguments, and reject argument values containing whitespace.
Video
Do not send video bytes as telemetry. Declare each video source in streams:
json
"streams": [{ "name": "eo", "protocol": "srt", "port": 9595 }]| Field | Rule |
|---|---|
protocol | Must be srt (any letter case). MC ignores other declarations. |
url | Optional srt:// or srts:// URL, 2,048 characters maximum. Use it when the video is served from another host. |
port | Used when url is empty. MC pulls from srt://<reachability.address>:<port>. Default 9595. |
name | Your label for the stream. |
MC plays one camera source for each payload. It uses the first SRT declaration with a url. If no SRT declaration has a url, MC uses the first SRT declaration with the announced address. Use 8 streams or fewer, 8 KiB of JSON or less in total.
Send MPEG-TS over SRT. H.264 and H.265 are accepted. MC transcodes the video to H.264 for browsers. Confirm the codec, resolution, and network route with Urban Sky before flight.
Camera metadata (KLV)
If the camera knows where it points, put MISB ST 0601 KLV metadata in the MPEG-TS stream. MC keeps the KLV track on the raw stream. MC can use the following tags:
| Tags | Content |
|---|---|
| 1 | Checksum. Required: MC ignores a packet with a bad checksum. |
| 2 | UTC time, microseconds. Match it to the frame time. |
| 5–7 | Platform heading, pitch, and roll. |
| 13–15 | Sensor latitude, longitude, and altitude (MSL). |
| 16–17 | Horizontal and vertical field of view. |
| 18–20 | Sensor azimuth, elevation, and roll, relative to the platform. |
| 21 | Slant range. |
| 23–25 | Frame center. |
| 26–33, 82–89 | Frame corners (offset or full). |
MC adds tag 5 and tag 18 to get the camera compass bearing. Elevation is negative below the horizon. MC marks a footprint as suspect when its computed slant range differs from tag 21 by more than 20%. GET /payloads/:id/camera-pose returns the poses of the last 30 seconds. Confirm with Urban Sky that KLV overlays are enabled for your payload.
Share the stream
POST /payloads/:id/shares returns an SRT read address that expires. MC shows the address one time only.
| Field | Rule |
|---|---|
kind | picture (default): the transcoded stream. raw: the camera stream with KLV. raw is not available to operators. |
ttlSeconds | Default 3600. MC limits it to 60–28800. |
Public sharing can be off in an environment. Ask Urban Sky.
Pointing conventions
Use these names if your payload points a camera. MC's existing camera and gimbal controls read them:
| Name | Meaning |
|---|---|
gimbal.az_deg, gimbal.el_deg | Actual camera azimuth as a compass heading, and elevation. |
gimbal.target_az_deg, gimbal.target_el_deg | The target the device holds. |
gimbal.connected | Whether the gimbal is up. |
gimbal.set_az, gimbal.set_el, gimbal.set_azel | Commands with az_deg and el_deg parameters. |
MC shows an axis as arrived when it is within 1° of its target. The test for arrival works across 0°/360°. Other names work, but they appear as generic fields and commands.
Display hints
All display hints are optional. They change only how MC shows a value or command. Permissions, validation, and confirmation never depend on them.
| Where | Fields |
|---|---|
| Either manifest | groups: id, label, description, kind (DISPLAY_GROUP_KIND_PRIMARY, _STATUS, _SETTINGS, _ADVANCED, _DIAGNOSTICS, _DANGER), collapsedByDefault. Up to 32. |
| Telemetry field | description, valueLabels (for enum values or "true"/"false"), warnAbove, critAbove, warnBelow, critBelow, per-field staleAfterS. |
Field presentation | groupId, precision (0–12), normalMin, normalMax, primary, trend, format (VALUE_FORMAT_DURATION, VALUE_FORMAT_BYTES), connectedOf. |
Command presentation | label, groupId, style (COMMAND_DISPLAY_STYLE_ACTION, _INLINE, _FORM), settleMs, risk (COMMAND_RISK_SAFE, _CAUTION, _DANGER), confirmTitle, consequences (up to 4), endsModes. |
Parameter presentation | widget (INPUT_WIDGET_TOGGLE, _SLIDER, _NUMBER, _SELECT, _SEGMENTED, _TEXT), scale (VALUE_SCALE_LINEAR, VALUE_SCALE_LOG10), step, readbackKey. |
normalMinandnormalMaxmark the healthy range insidemin/max. Warnings still come from thewarn*andcrit*thresholds.connectedOfgoes on a boolean field.falsemeans that the named part is down.readbackKeynames the telemetry field that reports the applied value. MC shows that reading as the actual state.riskchanges the display only. Without it,confirm: trueshows as caution.VALUE_SCALE_LOG10requires a positivemin.
Ask Urban Sky before you depend on a custom widget or a semanticRole.