Umoja Portal API
Public REST API for the Umoja satellite operations portal. All endpoints live under /api/v1; authenticate with an OAuth2 client_credentials token and pass it as Authorization: Bearer <token>.
Getting a token — ask Remos to provision an API client (client_id / client_secret) for your group, then exchange them directly with Keycloak:
curl -X POST https://umoja.remosspace.com:8443/realms/expedite/protocol/openid-connect/token \
-d grant_type=client_credentials \
-d client_id=<your-client-id> \
-d client_secret=<your-client-secret>
The response's access_token is your bearer for every call below. If your group already has portal access, you can also mint a short-lived test token yourself from Profile → API access without ever handling the secret.
Realtime & Data Integration
Three ways to get pass data out of Umoja programmatically:
-
portal-link: a small client that exposes the live pass as local TCP ports for a Mission Control System (Yamcs, COSMOS/OpenC3, Gpredict, scripts). -
The realtime WebSocket:
/ws/realtime, the same live feed the portal itself consumes. - The mission-data API: list and download recordings after a pass.
All three authenticate with your Keycloak token and respect the same group and booking-window rules as the portal.
portal-link (TCP bridge)
portal-link opens local TCP ports on your machine so an MCS can exchange
telemetry and telecommands with the hub during a pass. It speaks the hub's TCP
bridge protocol and handles sign-in for you.
Quick start
./portal-link \
--hub bridge.umoja.remosspace.com:10100 \
--station <your-station-id> \
--booking <booking-uuid> \
--kc-url https://umoja.remosspace.com:8443/realms/expedite
On first run it prints a URL to open in your browser to sign in. After sign-in:
- The client connects to the hub over TLS.
- A local TM server starts on
localhost:10025. - A local TC server starts on
localhost:10026.
Omit --booking to get an interactive picker of your active/upcoming passes.
Point your MCS at the local ports
- TM data source:
localhost:10025(TCP) - TC data sink:
localhost:10026(TCP)
CLI reference
Usage: portal-link [flags]
Required:
--hub Hub TCP bridge address (e.g. bridge.umoja.remosspace.com:10100)
--kc-url Keycloak realm URL
Optional:
--api-url Hub HTTP API URL (auto-derived from --hub if unset)
--station Ground station client ID (e.g. umoja)
--booking Booking UUID (interactive picker if omitted)
--streams Comma-separated streams (default: tm,tc)
Valid: tm,tc,antenna,doppler,ephemeris,command
--tm-port Local TM port (default: 10025)
--tc-port Local TC port (default: 10026)
--doppler-port Local doppler port (default: 10027)
--ephemeris-port Local ephemeris port (default: 10028)
--antenna-port Local antenna port (default: 10029)
--command-port Local command-echo port (default: 10030)
--client-id Keycloak client ID (default: portal-link)
--tls Enable TLS to hub (default: true)
--insecure Skip TLS certificate verification (testing only)
--verbose Enable debug logging
--version Show version
Streams and ports
Each requested stream is exposed on its own local TCP port. Multiple tools may connect to the same port at once. Every connection gets a copy of the stream.
| Stream | Default port | Direction | Purpose |
|---|---|---|---|
tm |
10025 | hub → MCS | Telemetry frames from the satellite. |
tc |
10026 | MCS → hub | Telecommand frames to the satellite. |
doppler |
10027 | hub → MCS | Doppler shift updates during the pass. |
ephemeris |
10028 | hub → MCS | Predicted trajectory for the pass. |
antenna |
10029 | hub → MCS | Antenna pointing telemetry (az/el). |
command |
10030 | hub → MCS | Echo of telecommands as they leave the radio. |
Request more than the default tm,tc by listing them:
./portal-link \
--hub bridge.umoja.remosspace.com:10100 \
--station <your-station-id> --booking <booking-uuid> \
--kc-url https://umoja.remosspace.com:8443/realms/expedite \
--streams tm,tc,antenna,doppler,ephemeris,command
MCS configuration examples
Yamcs
dataLinks:
- name: remos-tm
class: org.yamcs.tctm.TcpTmDataLink
host: localhost
port: 10025
stream: tm_realtime
- name: remos-tc
class: org.yamcs.tctm.TcpTcDataLink
host: localhost
port: 10026
stream: tc_realtime
COSMOS (OpenC3)
INTERFACE REMOS_TM_INT tcpip_client_interface.rb localhost 10025 10025 10.0 nil
INTERFACE REMOS_TC_INT tcpip_client_interface.rb localhost 10026 10026 10.0 nil
Custom script (Python)
import socket
# Receive TM
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("localhost", 10025))
while True:
data = sock.recv(4096)
if not data:
break
process_telemetry(data)
# Send TC
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("localhost", 10026))
sock.sendall(bytes.fromhex("A1B2C3D4"))
Realtime WebSocket
If you'd rather consume the feed directly (the same one the portal uses), open a WebSocket per stream:
wss://<host>/ws/realtime?station_id=<client_id>&stream=<stream>[&booking_id=<uuid>]
Authenticate by sending your Keycloak bearer token as a WebSocket subprotocol:
new WebSocket(url, ["bearer", "<your-jwt>"])
Available streams: spectrum, constellation, doppler, ephemeris,
antenna, telemetry, command.
Frames are binary, prefixed with a small header: a 2-byte magic (EX), a
1-byte stream tag, and the 16-byte station client ID (NUL-padded), followed by
the stream payload (e.g. spectrum is 1024 × [freq, power] float32 pairs). The
hub refreshes nothing for you: keep your token fresh and reconnect on drop.
Mission-data API
After a pass, list and download its recordings over REST. Send your Keycloak
token as Authorization: Bearer <jwt>.
| Endpoint | Method | Purpose |
|---|---|---|
/api/data/files |
GET | List files (filter by station_id, booking_id, status, from_ts/to_ts, search; group_by_pass). |
/api/data/files/summary |
GET | Aggregate counts and bytes. |
/api/data/files/{file_id}/link |
POST | Mint a short-lived signed download URL for one file. |
/api/data/bookings/{booking_id}/link |
POST | Mint a signed URL for the whole pass as a ZIP bundle. |
Minting a link, then downloading, keeps the long-lived token off the wire:
# 1. mint a signed URL (bearer token)
curl -X POST https://umoja.remosspace.com/api/data/files/$FILE_ID/link \
-H "Authorization: Bearer $TOKEN"
# -> { "download_url": "...", "expires_in": 900 }
# 2. download (the signed URL carries its own token)
curl -L -o capture.iq "<download_url>"
See the REST API tab for the full, interactive reference.
Session window
A live session (portal-link or WebSocket) is tied to a booking and only flows during its window:
- Earliest: AOS − 5 minutes. Latest: LOS + 5 minutes.
- Connect before the window opens and the hub rejects the session until the booking becomes active.
- The session disconnects automatically once the window closes.
portal-adminaccounts bypass the window for live diagnostics.
Troubleshooting
| Symptom | Cause | What to do |
|---|---|---|
AUTH_FAIL:invalid_token |
Token expired or malformed. | Re-run portal-link / refresh your token. |
AUTH_FAIL:no_active_booking |
No valid booking in the current window. | Check the window under Bookings; wait for AOS − 5 min. |
AUTH_FAIL:station_not_found |
Wrong --station. |
Use the client ID shown on the Stations page. |
AUTH_FAIL:server_full |
Too many concurrent sessions. | Retry shortly, or contact support. |
| TM stops mid-pass | Network drop or pass ended. | portal-link auto-reconnects until LOS + 5 min. |
| TC not delivered | Station offline. | Check the station's live state on Stations. |