Decentralized Space Network API

Overview

The Decentralized Space Network API provides programmatic access to satellite pass prediction, reservation management, mission profile management, and file-transfer metadata for ground-station operations.

The API is intended for server-to-server integrations. File payloads are exchanged through S3 buckets; the API stores and reports metadata, ownership, reservation status, and delivery state.

Base path:

/orbapi

Organizations and Administrative UI

API tokens and operational resources belong to organizations. Registration creates a personal organization, and users may join company organizations. The active organization supplies the ownership context for tokens, reservations, storage paths, TLE selection, and transmitter selection.

Roles are owner, admin, operator, and viewer. Profile -> Organizations manages organizations, active selection, and registered-user memberships. Mission Administration lets platform administrators view reservations grouped by organization, edit non-terminal reservation types, and cancel eligible reservations. Owned Manual Catalog is available to platform administrators and organization owners/admins.

The catalog editor exposes only rows where source = manual, pinned = true, and the row belongs to the selected organization. The same owned manual satellite, TLE, and transmitter records can be listed and edited with a dsn_live_... token carrying catalog:write. Platform-admin booking-edit routes remain internal. Pass windows require cancel-and-recreate.

Authentication

Client operational endpoints use API-token authentication.

Authorization: Bearer dsn_live_...

API tokens are scoped. A request is rejected if the token does not include the scope required by the endpoint.

Station agents use station-scoped bearer tokens:

Authorization: Bearer dsn_station_<stationId>_<secret>

Station tokens are bound to one ground station. A token for station 1234 cannot poll, refresh upload URLs, or report telemetry for station 3886.

Satellite Identity

Satellite-specific operational requests require satelliteId.

noradId / norad_cat_id is search metadata, not the booking/pass identity. A NORAD lookup can return multiple satellites.

Client flow:

1. Search/list satellites by NORAD or name. 2. Select the intended satellite. 3. Use its satelliteId for pass search, booking, TLE, transmitter, and mission-profile calls.

Normal client tokens cannot override ownerId. Admin/service calls may pass ownerId when acting on behalf of a client.

Satellite ownership is enforced by default through SatelliteOwner.satelliteId + ownerId.

Common scopes:

ScopePurpose
passes:readSearch satellite passes
bookings:createCreate bookings and attach uplink files
bookings:cancelCancel bookings
mission-profile:createCreate, read, and delete mission profiles
catalog:writeList and edit the organization's owned manual catalog
payloads:writeUpload and manage mission payload files
payloads:writeCreate uplink payload records and receive presigned upload URLs

Conventions

All request and response bodies are JSON unless otherwise stated.

Timestamps use ISO 8601 UTC format:

2026-05-06T10:00:00Z

Errors use the following general shape:

{
  "error": "Human-readable error message"
}

Common status codes:

StatusMeaning
200Request completed successfully
201Resource created successfully
400Invalid request
401Missing or invalid API token
403API token does not have the required scope
404Resource not found or not visible to the caller
500Internal server error

Satellite Pass Search

Searches predicted visibility passes for one satellite across one or more ground stations.

POST /orbapi/passes/search
Authorization: Bearer dsn_live_...

Purpose: Calculate upcoming visibility windows for a satellite from one or more ground stations.

Required scope:

passes:read

The request is per satellite and requires the stable DSN satelliteId. A raw TLE may be supplied for a satellite owned by the token's organization. It must contain two correctly aligned 69-character lines with valid checksums. A valid newer TLE updates the organization's selected manual TLE row, so subsequent frontend, scheduler, and API reads use it too.

Search by satellite ID:

{
  "satelliteId": "sat_123",
  "days": 7,
  "groundStationIds": ["1", "2"],
  "minElevationDeg": 10
}

Search by TLE:

{
  "satelliteId": "sat_123",
  "tle": {
    "name": "SATELLITE NAME",
    "line1": "1 ...",
    "line2": "2 ..."
  },
  "days": 7,
  "groundStationIds": ["1"],
  "minElevationDeg": 10
}

Request fields:

FieldRequiredDescription
satelliteIdYesStable DSN satellite identity returned by satellite search/list endpoints.
tleNoOptional raw TLE override for the selected satellite.
daysNoNumber of days to search. Defaults to 7, maximum 14.
startNoSearch start timestamp. Defaults to current time.
endNoSearch end timestamp. Capped to start + 14 days.
groundStationIdsNoGround stations to include. If omitted, all configured stations with coordinates are used.
minElevationDegNoMinimum pass elevation in degrees. Defaults to 10.
stepSecondsNoCalculation step size. Allowed range is 15-300 seconds. Defaults to 60.

When tle is supplied, the response includes tleUpdate with refreshed, unchanged, or stale. Malformed TLEs are rejected with 400 before pass calculation.

Response:

{
  "satellite": {
    "satelliteId": "sat_123",
    "noradId": 25544,
    "name": "ISS",
    "tle": {
      "name": "ISS",
      "line1": "1 ...",
      "line2": "2 ..."
    }
  },
  "groundStations": [
    {
      "id": "1",
      "description": "Ground Station",
      "latitude": 42.0,
      "longitude": 23.0,
      "altitude": 500
    }
  ],
  "passes": [
    {
      "groundStationId": "1",
      "rise_time": "2026-05-06T10:00:00.000Z",
      "set_time": "2026-05-06T10:10:00.000Z",
      "aos": "2026-05-06T10:00:00.000Z",
      "los": "2026-05-06T10:10:00.000Z",
      "aos_azimuth": 183.1,
      "los_azimuth": 31.8,
      "max_elevation": 42.3,
      "max_elevation_time": "2026-05-06T10:05:00.000Z",
      "slant_range_km": 1250.4,
      "polar_track": [
        {
          "azimuth": 183.1,
          "elevation": 0,
          "time": "2026-05-06T10:00:00.000Z"
        }
      ]
    }
  ],
  "total": 1,
  "generated_at": "2026-05-05T12:00:00.000Z"
}

Bookings

Bookings reserve one or more pass windows for a satellite and mission type.

Create Booking

POST /orbapi/bookings
Authorization: Bearer dsn_live_...

Purpose: Reserve one or more ground-station pass windows for a satellite mission.

Required scope:

bookings:create

Request:

{
  "satelliteId": "sat_123",
  "type": "data",
  "clientRequestId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "slots": [
    {
      "start": "2026-05-06T10:00:00Z",
      "end": "2026-05-06T10:10:00Z",
      "gs_id": "1"
    }
  ],
  "uplinkFile": {
    "key": "clients/client-storage-slug/uplink/42-uplink-command.bin",
    "sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
  }
}

Request fields:

FieldRequiredDescription
satelliteIdYesStable DSN satellite identity returned by satellite search/list endpoints.
typeYesMission type: data or test. lora is still accepted for legacy API compatibility.
slotsYesRequested reservation windows.
slots[].startYesSlot start timestamp.
slots[].endYesSlot end timestamp.
slots[].gs_idYesGround station ID.
clientRequestIdNoIdempotency key (up to 128 characters, e.g. a UUID). Retrying a request with the same clientRequestId returns the original booking with "idempotentReplay": true instead of creating a duplicate.
uplinkPayloadIdNoID of a pre-uploaded uplink payload (see Uplink Payloads). The payload must belong to the caller and be in status READY; otherwise the booking is rejected with 400.
uplinkFileNoOptional uplink object metadata to attach during booking creation.
uplinkFile.keyYes, if uplinkFile is presentObject key in the DSN S3 bucket.
uplinkFile.sha256NoOptional SHA-256 checksum as 64 hexadecimal characters.

A test mission is a simulated bidirectional pass and REQUIRES a command file: either uplinkPayloadId or uplinkFile must be supplied, otherwise the request is rejected with 400.

Response:

{
  "status": "success",
  "bookingId": 42,
  "missionId": 42,
  "satelliteId": "sat_123",
  "noradId": "25544",
  "uplinkFile": {
    "id": 1,
    "missionId": 42,
    "direction": "uplink",
    "key": "clients/client-storage-slug/uplink/42-uplink-command.bin",
    "sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
    "status": "pending",
    "createdAt": "2026-05-05T12:00:00.000Z",
    "updatedAt": "2026-05-05T12:00:00.000Z"
  }
}

If no uplink file is supplied, uplinkFile is null.

List Bookings

GET /orbapi/bookings
Authorization: Bearer dsn_live_...

Purpose: Return the caller's current and historical bookings, including reserved slots.

Optional cursor pagination (additive — omitting limit returns the full list):

Query parameterDescription
limitMaximum number of bookings to return (1-200). Enables pagination.
cursorThe nextCursor value from the previous page. Bookings with an ID greater than the cursor are returned.

Example:

GET /orbapi/bookings?limit=50&cursor=42

The response includes a nextCursor field: the booking ID to pass as cursor for the next page, or null when there are no further pages (always null when limit is omitted).

Response:

{
  "bookings": [
    {
      "id": 42,
      "bookingId": 42,
      "missionId": 42,
      "ownerId": "client_123",
      "ownerType": "api_token",
      "satelliteId": "sat_123",
      "noradId": "25544",
      "type": "data",
      "status": "Pending",
      "requestedAt": "2026-05-05T12:00:00.000Z",
      "slots": [
        {
          "id": 100,
          "missionId": 42,
          "gsId": "1",
          "start": "2026-05-06T10:00:00.000Z",
          "end": "2026-05-06T10:10:00.000Z",
          "status": "Pending"
        }
      ]
    }
  ],
  "nextCursor": null
}

Cancel Booking

DELETE /orbapi/bookings/:bookingId
Authorization: Bearer dsn_live_...

Purpose: Cancel a booking. A booking can be cancelled up until its pass starts — a booking that has already been dispatched to the station but whose pass is still in the future is freely cancellable (the backend relays a cancel to the station). Once a pass is in progress or has finished, cancellation returns 409 CONFLICT. A booking that does not exist (or that the caller is not permitted to manage) returns 404.

Required scope:

bookings:cancel

Response:

{
  "status": "success",
  "message": "Booking cancelled successfully",
  "bookingId": 42,
  "missionId": 42,
  "satelliteId": "sat_123",
  "noradId": "25544"
}

> DELETE /orbapi/mission (with { "missionId": 42 } in the body) is an equivalent alias — it runs > the identical handler and returns the same result.

Satellite Ownership (authorization)

Satellites can be owned by specific customers. Ownership enforcement is always enabled: only an owner of a satellite (or an operator/admin) may:

  • update its stored TLE (by supplying a tle on POST /orbapi/passes/search), and
  • create, cancel, and manage bookings for it.

Key points:

  • Multiple owners per satellite are supported — co-owners share full control and may cancel or

manage any booking on that satellite, regardless of which owner created it.

  • Ownership grants are keyed by satelliteId + ownerId.
  • Protected satellites: a satellite with explicit owners is owner/admin-only for booking management and TLE changes. A satellite with no owner grant and no ownerId is treated as a generic public catalog satellite and can be reserved by authenticated clients.
  • A non-owner who calls a gated operation receives 403 (booking create / TLE update) or 404

(cancel / manage of a specific booking). Read-only pass search (without a tle) and the public satellite catalog remain open.

Mission Profiles

Mission profiles store arbitrary JSON configuration for a satellite. Use satelliteId for profile APIs.

Create Mission Profile

POST /orbapi/satellites/:satelliteId/profiles
Authorization: Bearer dsn_live_...

Purpose: Store a caller-owned mission configuration profile for a satellite.

Required scope:

mission-profile:create

Request:

{
  "name": "Primary data profile",
  "profile": {
    "radio": {
      "frequencyHz": 437000000,
      "modulation": "GMSK",
      "baud": 9600
    }
  }
}

The profile wrapper is optional. If omitted, the full request body is stored as profile JSON.

Response:

{
  "status": "success",
  "profile": {
    "id": 12,
    "satelliteId": "sat_123",
    "satelliteNoradId": 25544,
    "name": "Primary data profile",
    "profile": {
      "radio": {
        "frequencyHz": 437000000,
        "modulation": "GMSK",
        "baud": 9600
      }
    },
    "createdBy": "client_123",
    "createdByType": "api_client",
    "createdAt": "2026-05-05T12:00:00.000Z",
    "updatedAt": "2026-05-05T12:00:00.000Z"
  }
}

List Mission Profiles For Satellite

GET /orbapi/satellites/:satelliteId/profiles
Authorization: Bearer dsn_live_...

Purpose: List mission profiles for the requested satellite that are visible to the caller.

Response:

{
  "satelliteId": "sat_123",
  "noradId": 25544,
  "profiles": [
    {
      "id": 12,
      "satelliteId": "sat_123",
      "satelliteNoradId": 25544,
      "name": "Primary data profile",
      "profile": {},
      "createdAt": "2026-05-05T12:00:00.000Z",
      "updatedAt": "2026-05-05T12:00:00.000Z"
    }
  ]
}

Get Mission Profile

GET /orbapi/satellites/profiles/:profileId
Authorization: Bearer dsn_live_...

Purpose: Fetch one mission profile by its profile ID.

Response:

{
  "profile": {
    "id": 12,
    "satelliteId": "sat_123",
    "satelliteNoradId": 25544,
    "name": "Primary data profile",
    "profile": {}
  }
}

Delete Mission Profile

DELETE /orbapi/satellites/profiles/:profileId
Authorization: Bearer dsn_live_...

Purpose: Delete a mission profile owned by the caller, or any profile when using a service token.

Response:

{
  "status": "success",
  "message": "Mission profile deleted successfully",
  "profileId": 12
}

Uplink Payloads

Uplink payloads are pre-uploaded, server-verified command files. Unlike raw uplink file metadata, the payload flow gives the client a presigned upload URL and the backend verifies the object (size and SHA-256) before it can be attached to a booking:

1. POST /orbapi/uplink-payloads — create the payload record and receive a presigned uploadUrl. 2. PUT the file content to uploadUrl (direct to object storage, not through the API). 3. Poll GET /orbapi/uplink-payloads/:id until the status settles to READY (or REJECTED). 4. Create a booking with uplinkPayloadId — only READY payloads can be attached.

Files are limited to 67,108,864 bytes (64 MB); larger objects are REJECTED during verification.

Create Uplink Payload

POST /orbapi/uplink-payloads
Authorization: Bearer dsn_live_...

Purpose: Register an uplink command file and obtain a presigned upload URL.

Required scope:

payloads:write

Request:

{
  "satelliteId": "sat_123",
  "filename": "command-sequence.bin",
  "contentType": "application/octet-stream",
  "sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
}

Request fields:

FieldRequiredDescription
satelliteIdYesStable DSN identity of the satellite for which the command file is intended.
filenameYesOriginal filename (max 255 characters). Sanitized into the object key.
contentTypeNoMIME type. Defaults to application/octet-stream.
sha256NoExpected SHA-256 checksum as 64 hexadecimal characters. If provided, verification rejects the upload on mismatch.

Response (201):

{
  "uplinkPayloadId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "uploadUrl": "https://...",
  "uploadUrlExpiresIn": 900,
  "status": "AWAITING_UPLOAD",
  "satelliteId": "sat_123",
  "noradId": "25544",
  "filename": "command-sequence.bin",
  "createdAt": "2026-05-05T12:00:00.000Z"
}

The uploadUrl is valid for 15 minutes. Upload the file with an HTTP PUT using the same Content-Type supplied at creation.

Get Uplink Payload Status

GET /orbapi/uplink-payloads/:id
Authorization: Bearer dsn_live_...

Purpose: Fetch the payload status. Verification is lazy — polling this endpoint while the payload is AWAITING_UPLOAD triggers the server-side check once the object is present, settling the status to READY or REJECTED.

Only the owner of the payload can read it; other callers receive 404.

Response:

{
  "uplinkPayloadId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "status": "READY",
  "filename": "command-sequence.bin",
  "contentType": "application/octet-stream",
  "sizeBytes": 4096,
  "sha256Expected": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
  "sha256Actual": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
  "rejectReason": null,
  "forwardError": null,
  "satelliteId": "sat_123",
  "noradId": "25544",
  "createdAt": "2026-05-05T12:00:00.000Z",
  "updatedAt": "2026-05-05T12:05:00.000Z"
}

Payload status values:

StatusMeaning
AWAITING_UPLOADRecord created; the object has not been uploaded or verified yet.
READYObject verified (size and checksum); the payload can be attached to a booking.
REJECTEDVerification failed (rejectReason explains: size over 64 MB, or SHA-256 mismatch).
FORWARDEDThe payload was delivered to the ground station by the mission workflow.
FORWARD_FAILEDStation transfer failed (forwardError explains).

Uplink File Metadata

The API does not accept file uploads directly. Uplink payloads are delivered to the DSN S3 bucket by the client-side transfer process. The API records the S3 object key and marks the file as pending. The client chooses the uplink object name; the backend only rejects unsafe keys such as empty keys, leading /, .., or keys over 1024 characters.

Attach Uplink File After Booking

POST /orbapi/bookings/:bookingId/uplink-files
Authorization: Bearer dsn_live_...

Purpose: Attach uplink S3 object metadata to an existing booking.

Required scope:

bookings:create

Request:

{
  "key": "clients/client-storage-slug/uplink/42-uplink-command.bin",
  "sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
}

Response:

{
  "status": "success",
  "bookingId": 42,
  "missionId": 42,
  "uplinkFile": {
    "id": 1,
    "missionId": 42,
    "direction": "uplink",
    "key": "clients/client-storage-slug/uplink/42-uplink-command.bin",
    "sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
    "status": "pending",
    "createdAt": "2026-05-05T12:00:00.000Z",
    "updatedAt": "2026-05-05T12:00:00.000Z"
  }
}

File status values:

StatusMeaning
pendingMetadata has been accepted; object verification has not completed.
availableObject is available for ground-station use.
consumedObject has been used by the ground-station workflow.
failedObject verification or use failed.
deliveredDownlink object has been delivered to the client bucket.

List Uplink Files

GET /orbapi/bookings/:bookingId/uplink-files
Authorization: Bearer dsn_live_...

Purpose: List uplink file metadata attached to a booking.

Response:

{
  "bookingId": 42,
  "missionId": 42,
  "files": [
    {
      "id": 1,
      "missionId": 42,
      "direction": "uplink",
      "key": "clients/client-storage-slug/uplink/42-uplink-command.bin",
      "sha256": null,
      "status": "pending",
      "createdAt": "2026-05-05T12:00:00.000Z",
      "updatedAt": "2026-05-05T12:00:00.000Z"
    }
  ]
}

Downlink File Metadata

Downlink file contents are delivered to the client S3 bucket by the DSN delivery process. The API is used for status and metadata only.

List Downlink Files

GET /orbapi/bookings/:bookingId/downlink-files
Authorization: Bearer dsn_live_...

Purpose: List downlink file metadata produced for a booking.

Response:

{
  "bookingId": 42,
  "missionId": 42,
  "files": [
    {
      "id": 2,
      "missionId": 42,
      "direction": "downlink",
      "key": "clients/client-storage-slug/downlink/42-downlink-20260604T151102Z-a1b2c3d4-data.bin",
      "sha256": null,
      "status": "delivered",
      "createdAt": "2026-05-06T10:20:00.000Z",
      "updatedAt": "2026-05-06T10:21:00.000Z"
    }
  ]
}

Reference Data

Station Agent API

Station agents use station-scoped bearer tokens. These endpoints reject requests when the token does not match the :stationId path parameter.

Poll Commands

GET /orbapi/stations/:stationId/commands
Authorization: Bearer dsn_station_<stationId>_<secret>

Example:

GET /orbapi/stations/1234/commands
Authorization: Bearer dsn_station_1234_<secret>

Result:

{
  "stationId": "1234",
  "commands": [
    {
      "id": "cmd_42_7",
      "type": "MISSION_SLOT",
      "commandStatus": "acknowledged",
      "direction": "rx_tx",
      "rfLink": {
        "satelliteTransmitterUuid": "sat-transmitter-uuid",
        "stationTransmitterUuid": "ground-station-transmitter-uuid",
        "downlinkHz": 437000000,
        "uplinkHz": 145900000,
        "mode": "LoRa",
        "modeId": 89,
        "uplinkMode": "LoRa",
        "baud": 9600,
        "invert": false,
        "bandwidthHz": 125000,
        "txPowerMaxDbm": 20,
        "eirpMaxDbm": 30
      },
      "bookingId": 42,
      "missionId": 42,
      "slotId": 7,
      "groundStationId": "1234",
      "uplinkFiles": [
        {
          "fileId": 12,
          "key": "clients/client-storage-slug/uplink/42-uplink-command.bin",
          "downloadUrl": "https://...",
          "transferStatus": "ready",
          "transferError": null
        }
      ],
      "downlinkUpload": {
        "fileId": 13,
        "key": "clients/client-storage-slug/downlink/42-downlink-20260604T151102Z-a1b2c3d4-data.bin",
        "uploadUrl": "https://...",
        "transferStatus": "ready",
        "transferError": null,
        "refreshUrl": "/orbapi/stations/1234/bookings/42/downlink-files/13/upload-url"
      }
    }
  ]
}

direction is rx for receive-only slots and rx_tx when uplinkFiles is non-empty. Commands are persisted in the database; polling marks a queued command acknowledged, and terminal statuses stop redelivery.

The downlink upload key is generated from the booking owner's configured storage slug. If no owner mapping exists yet, the backend falls back to clients/generic/downlink/... so command creation is not blocked.

downloadUrl and downlinkUpload.uploadUrl are nullable. If presigned URL generation is unavailable when the command is queued, the command is still delivered with transferStatus: "pending_presign" and the station should retry the downlink upload URL through downlinkUpload.refreshUrl.

Report Command Status

POST /orbapi/stations/:stationId/commands/:commandId/status
Authorization: Bearer dsn_station_<stationId>_<secret>
Content-Type: application/json
{
  "status": "completed",
  "bookingId": 42,
  "slotId": 7,
  "completedAt": "2026-06-03T20:18:10Z",
  "message": "Pass completed"
}

Accepted command statuses:

StatusMeaning
acknowledgedStation has received the command.
in_progressStation has started executing the pass command.
completedCommand finished successfully; it will not be delivered again.
failedCommand failed during execution; it will not be delivered again.
rejectedStation refused the command before execution; it will not be delivered again.
cancelledCommand was cancelled; it will not be delivered again.

Refresh Downlink Upload URL

POST /orbapi/stations/:stationId/bookings/:bookingId/downlink-files/:fileId/upload-url
Authorization: Bearer dsn_station_<stationId>_<secret>
Content-Type: application/json
{ "expires": 900 }

Report Station Telemetry

POST /orbapi/stations/:stationId/telemetry
Authorization: Bearer dsn_station_<stationId>_<secret>
Content-Type: application/json
{
  "bookingId": 42,
  "records": [
    {
      "timestamp": "2026-06-03T20:12:00Z",
      "data": {
        "snr": 12.4,
        "rssi": -91,
        "frequency": 437500000
      }
    }
  ]
}

Limits: maximum 100 telemetry records per request, and each data object must serialize to 16 KB or less. The recommended station reporting rate is up to 1 request per second unless agreed otherwise.

Satellites

GET /orbapi/satellites

Purpose: List satellites available in the catalog.

Example:

GET /orbapi/satellites?start=0&limit=20

Result:

{
  "data": [
    {
      "satelliteId": "sat_123",
      "norad_cat_id": 25544,
      "name": "ISS",
      "names": "ISS (ZARYA)",
      "status": "alive"
    }
  ],
  "total": 1
}
GET /orbapi/satellites/norad/:noradId

Purpose: List every satellite matching a NORAD catalog ID. This route never selects one satellite.

For an unambiguous lookup by stable identity, use GET /orbapi/satellites/:satelliteId.

Example:

GET /orbapi/satellites/norad/25544

Result:

{
  "data": [
    {
      "satelliteId": "sat_123",
      "norad_cat_id": 25544,
      "name": "ISS",
      "names": "ISS (ZARYA)",
      "status": "alive"
    }
  ],
  "total": 1
}
GET /orbapi/satellites/name/:name

Purpose: Search satellites by name.

Example:

GET /orbapi/satellites/name/ISS

Result:

{
  "data": [
    {
      "satelliteId": "sat_123",
      "norad_cat_id": 25544,
      "name": "ISS",
      "names": "ISS (ZARYA)",
      "status": "alive"
    }
  ],
  "total": 1
}

Owned Manual Catalog

GET /orbapi/catalog-management
Authorization: Bearer dsn_live_...

Required scope: catalog:write.

Lists the calling token organization's editable pinned manual satellites, TLEs, and transmitters. The organization is taken from the token; a caller cannot select another organization with query or body fields.

The canonical TLE update uses the stable satellite ID:

PATCH /orbapi/tles/sat_1887805
Authorization: Bearer dsn_live_...
Content-Type: application/json

{
  "line1": "1 88246U          26194.85245136 +.00000606 +00000+0 +67191-4 0 00185",
  "line2": "2 88246  97.7567  95.1926 0004040 106.5039 253.6623 14.90796340000971"
}

The older PATCH /orbapi/catalog-management/tle/:databaseId form remains available for compatibility with the web catalog editor.

The supported kinds and identifiers are:

KindIdentifierEditable fields
satelliteNumeric database id returned by the catalog listname, names, image
tleStable satelliteId with PATCH /orbapi/tles/:satelliteId; numeric database id on the compatibility catalog routename, line1, line2
transmitteruuid returned by the catalog listdescription, mode, uplinkMode, service, status, alive, invert, baud, bandwidthHz, uplinkLow, uplinkHigh, downlinkLow, downlinkHigh

For example, edit a satellite or transmitter with PATCH /orbapi/catalog-management/satellite/:id or PATCH /orbapi/catalog-management/transmitter/:uuid.

TLEs

GET /orbapi/tles

Purpose: List current TLE records.

Example:

GET /orbapi/tles?start=0&limit=20

Result:

{
  "data": [
    {
      "id": 25544,
      "name": "ISS",
      "tle0": "ISS (ZARYA)",
      "tle1": "1 ...",
      "tle2": "2 ..."
    }
  ],
  "total": 1
}
GET /orbapi/tles/norad/:noradId

Purpose: List TLE records for every satellite matching a NORAD catalog ID.

For operational use, fetch it by stable identity with GET /orbapi/tles/:satelliteId.

Example:

GET /orbapi/tles/norad/25544

Result:

{
  "data": [
    {
      "id": 25544,
      "name": "ISS",
      "tle0": "ISS (ZARYA)",
      "tle1": "1 ...",
      "tle2": "2 ..."
    }
  ],
  "total": 1
}
GET /orbapi/tles/name/:name

Purpose: Search TLE records by satellite name.

Example:

GET /orbapi/tles/name/ISS

Result:

{
  "data": [
    {
      "id": 25544,
      "name": "ISS",
      "tle0": "ISS (ZARYA)",
      "tle1": "1 ...",
      "tle2": "2 ..."
    }
  ],
  "total": 1
}

Ground Stations

GET /orbapi/gs

Purpose: List ground stations in the network.

Example:

GET /orbapi/gs?start=0&limit=20

Result:

{
  "data": [
    {
      "id": "3886",
      "description": "DSN Stob W1AW 2m dish and 70GHz V-band",
      "latitude": 42.09963,
      "longitude": 23.106661,
      "altitude": 472
    }
  ],
  "total": 1
}
GET /orbapi/gs/id/:id

Purpose: Fetch one ground station by ID.

Example:

GET /orbapi/gs/id/1

Result:

{
  "data": [
    {
      "id": "1",
      "description": "Ground Station",
      "latitude": 42.0,
      "longitude": 23.0,
      "altitude": 500
    }
  ],
  "total": 1
}
GET /orbapi/gs/id/:id/status

Purpose: Report command-broker heartbeat status for a ground station.

Example:

GET /orbapi/gs/id/1/status

Result:

{
  "groundStation": {
    "id": "1",
    "description": "Ground Station"
  },
  "host": "1",
  "online": true,
  "status": "online",
  "lastSeenAt": "2026-05-05T12:00:00.000Z",
  "lastSeenAgeMs": 1200,
  "queueDepth": 0
}
GET /orbapi/gs/description/:description

Purpose: Search ground stations by description.

Example:

GET /orbapi/gs/description/Sofia

Result:

{
  "data": [
    {
      "id": "4567",
      "description": "DSN Sofia Tech Park LoRa and X-band/V-band reflector",
      "latitude": 42.667693,
      "longitude": 23.373397,
      "altitude": 630
    }
  ],
  "total": 1
}

Ground-station status is based on the command-broker heartbeat. Each time a station polls the broker for pending commands, the station lastSeenAt timestamp is updated.

{
  "groundStation": {
    "id": "1",
    "description": "Ground Station"
  },
  "host": "1",
  "online": true,
  "status": "online",
  "lastSeenAt": "2026-05-05T12:00:00.000Z",
  "lastSeenAgeMs": 1200,
  "queueDepth": 0
}

Transmitters

GET /orbapi/transmitters

Purpose: List transmitter records.

Example:

GET /orbapi/transmitters?start=0&limit=20

Result:

{
  "data": [
    {
      "uuid": "ZzPz4gcsNBPKPKAFPmer7g",
      "description": "DSN Stob LoRa(868MHz) band",
      "mode": "LoRa",
      "mode_id": 89,
      "gs_id": "3886",
      "status": "active"
    }
  ],
  "total": 1
}
GET /orbapi/transmitters/norad/:noradId

Purpose: List transmitters for every satellite matching a NORAD catalog ID.

For operational use, list them by stable identity with GET /orbapi/transmitters/satellite/:satelliteId.

Example:

GET /orbapi/transmitters/norad/25544

Result:

{
  "data": [
    {
      "uuid": "sat-transmitter-uuid",
      "satelliteId": "sat_123",
      "norad_cat_id": 25544,
      "description": "Satellite downlink",
      "mode": "LoRa",
      "mode_id": 89,
      "gs_id": null
    }
  ],
  "total": 1
}
GET /orbapi/transmitters/uuid/:uuid

Purpose: Fetch one transmitter by UUID.

Example:

GET /orbapi/transmitters/uuid/550e8400-e29b-41d4-a716-446655440000

Result:

{
  "data": [
    {
      "uuid": "550e8400-e29b-41d4-a716-446655440000",
      "description": "Transmitter",
      "mode": "LoRa",
      "mode_id": 89,
      "gs_id": "1"
    }
  ],
  "total": 1
}
GET /orbapi/transmitters/mode/:modeId

Purpose: List transmitters that support a mode such as lora or a numeric mode ID.

Example:

GET /orbapi/transmitters/mode/lora

Result:

{
  "data": [
    {
      "uuid": "ZzPz4gcsNBPKPKAFPmer7g",
      "description": "DSN Stob LoRa(868MHz) band",
      "mode": "LoRa",
      "mode_id": 89,
      "gs_id": "3886"
    }
  ],
  "total": 1
}
GET /orbapi/transmitters/norad/:noradId/mode/:modeId

Purpose: List transmitters for one satellite filtered by mode.

Example:

GET /orbapi/transmitters/norad/25544/mode/lora

Result:

{
  "data": [
    {
      "uuid": "sat-transmitter-uuid",
      "satelliteId": "sat_123",
      "norad_cat_id": 25544,
      "description": "Satellite LoRa downlink",
      "mode": "LoRa",
      "mode_id": 89
    }
  ],
  "total": 1
}
GET /orbapi/transmitters/gs/:gsId

Purpose: List transmitters associated with a ground station.

Example:

GET /orbapi/transmitters/gs/1

Result:

{
  "data": [
    {
      "uuid": "ground-station-transmitter-uuid",
      "description": "Ground station transmitter",
      "mode": "LoRa",
      "mode_id": 89,
      "gs_id": "1"
    }
  ],
  "total": 1
}
GET /orbapi/transmitters/gs/:gsId/mode/:modeId

Purpose: List ground-station transmitters filtered by mode.

Example:

GET /orbapi/transmitters/gs/1/mode/lora

Result:

{
  "data": [
    {
      "uuid": "ground-station-transmitter-uuid",
      "description": "Ground station LoRa transmitter",
      "mode": "LoRa",
      "mode_id": 89,
      "gs_id": "1"
    }
  ],
  "total": 1
}