OrbitAlert
Sign in →
Live

OrbitAlert API

REST · JSON · HTTPS · Get started in 5 minutes

Satellite pass predictions and proactive webhook alerts — delivered to any HTTPS endpoint minutes before a satellite rises above your horizon. One API key, three endpoints.

All systems operationalBase URL: https://api.orbitalert.net

Authentication

Every request must include your API key in the X-API-Key header. Manage your keys from the API Keys page.

bash
curl https://api.orbitalert.net/health \
  -H "X-API-Key: sat_xk29mQpLvN3rT8wZ"

Keep your key secret. Never commit it to version control or expose it in client-side code. Rotate it immediately from the dashboard if it is ever compromised.

GET /passes

Returns all predicted passes above the elevation threshold for the given observer and prediction window, sorted chronologically by AOS. Timing precision is ±10 seconds (10 s propagation steps, SGP4).

Query parameters

ParameterTypeDefaultDescription
satelliterequiredstringSatellite name from the Celestrak catalog, e.g. "NOAA-20", "ISS (ZARYA)", "METOP-B", "TERRA"
latrequiredfloatObserver geodetic latitude in degrees, −90 to 90
lonrequiredfloatObserver longitude in degrees, −180 to 180
hoursfloat24Prediction window in hours. Clamped to 0.1 – 72.
min_elevationfloat10Minimum peak elevation in degrees. Passes that never reach this angle are omitted.

Request

curl "https://api.orbitalert.net/passes?satellite=NOAA-20&lat=37.92&lon=23.73&hours=24" \
  -H "X-API-Key: sat_xk29mQpLvN3rT8wZ"

Response 200 OK

json
[
  {
    "satellite": "NOAA-20",
    "aos_utc": "2026-06-01T06:14:32Z",
    "los_utc": "2026-06-01T06:23:17Z",
    "tca_utc": "2026-06-01T06:18:54Z",
    "max_elevation_deg": 67.3,
    "duration_seconds": 525,
    "azimuth_at_aos": 342.1,
    "azimuth_at_los": 158.7
  },
  {
    "satellite": "NOAA-20",
    "aos_utc": "2026-06-01T14:53:08Z",
    "los_utc": "2026-06-01T15:01:44Z",
    "tca_utc": "2026-06-01T14:57:26Z",
    "max_elevation_deg": 22.8,
    "duration_seconds": 516,
    "azimuth_at_aos": 315.4,
    "azimuth_at_los": 197.2
  }
]
FieldDescription
aos_utcAcquisition of Signal — satellite rises above horizon (ISO 8601 UTC)
los_utcLoss of Signal — satellite drops below horizon (ISO 8601 UTC)
tca_utcTime of Closest Approach — moment of maximum elevation (ISO 8601 UTC)
max_elevation_degPeak elevation angle in degrees (0–90). Higher = stronger signal.
duration_secondsTotal pass duration in whole seconds (LOS − AOS)
azimuth_at_aosSatellite compass bearing at rise — 0° = North, clockwise
azimuth_at_losSatellite compass bearing at set — 0° = North, clockwise

POST /alerts

Creates a persistent alert. OrbitAlert checks for upcoming passes every 5 minutes and fires a POST to your webhook the specified number of minutes before each qualifying pass. Alerts remain active until deleted.

Request body

ParameterTypeDefaultDescription
satellite_namerequiredstringSatellite name matching the Celestrak catalog, e.g. "NOAA-20", "METOP-C"
observer_latrequiredfloatObserver geodetic latitude, −90 to 90
observer_lonrequiredfloatObserver longitude, −180 to 180
webhook_urlrequiredstring (HTTPS)Destination for webhook POSTs. Must use HTTPS — HTTP URLs are rejected.
minutes_beforeinteger10How many minutes before AOS to fire the webhook. Range: 1–60.
min_elevationfloat10.0Skip passes with a peak elevation below this threshold (degrees).

Request

curl -X POST https://api.orbitalert.net/alerts \
  -H "X-API-Key: sat_xk29mQpLvN3rT8wZ" \
  -H "Content-Type: application/json" \
  -d '{
    "satellite_name": "NOAA-20",
    "observer_lat": 37.9195,
    "observer_lon": 23.7310,
    "webhook_url": "https://your-server.com/hook",
    "minutes_before": 10,
    "min_elevation": 15.0
  }'

Response 201 Created

json
{
  "id": "alert_8f3a12bc",
  "satellite_name": "NOAA-20",
  "observer_lat": 37.9195,
  "observer_lon": 23.7310,
  "webhook_url": "https://your-server.com/hook",
  "minutes_before": 10,
  "min_elevation": 15.0,
  "created_at": "2026-05-31T14:22:07Z"
}

Delivery & retry policy

If your endpoint returns a non-2xx status, OrbitAlert retries up to 3 times with exponential back-off: 30 s → 2 min → 8 min. Your endpoint must respond within 10 seconds or the attempt is counted as failed. All delivery attempts and their HTTP status codes are visible in the dashboard webhook log.

GET /space-weather

Returns the current NOAA planetary K-index (Kp), a 0–9 scale measuring geomagnetic disturbance. Useful for scheduling high-priority passes or adjusting receive parameters. Data is refreshed every 15 minutes from NOAA SWPC.

Request

curl https://api.orbitalert.net/space-weather \
  -H "X-API-Key: sat_xk29mQpLvN3rT8wZ"

Response 200 OK

json
{
  "kp_index": 3.2,
  "severity": "unsettled",
  "description": "Minor geomagnetic disturbance. Enhanced auroral activity above 60°N/S. No impact on VHF/UHF satellite links.",
  "updated_at": "2026-05-31T14:00:00Z"
}
severityKp rangeWhat it means
quiet0–2Nominal conditions. No impact on satellite operations or polar routes.
unsettled3–4Minor disturbance. Enhanced auroral activity above 60°N/S.
storm5–6Geomagnetic storm. HF radio degraded at polar latitudes.
severe7–9Severe storm. Possible satellite drag increase and orientation effects.

Webhook payload

When a pass is imminent, OrbitAlert POSTs the following JSON to your registered webhook_url. Respond with any 2xx status within 10 seconds to acknowledge delivery.

json
{
  "event": "pass.upcoming",
  "alert_id": "alert_8f3a12bc",
  "satellite": "NOAA-20",
  "aos_utc": "2026-06-01T06:14:32Z",
  "los_utc": "2026-06-01T06:23:17Z",
  "tca_utc": "2026-06-01T06:18:54Z",
  "max_elevation_deg": 67.3,
  "duration_seconds": 525,
  "azimuth_at_aos": 342.1,
  "azimuth_at_los": 158.7,
  "kp_index": 3.2,
  "minutes_until_aos": 9,
  "observer": {
    "lat": 37.9195,
    "lon": 23.7310
  },
  "delivered_at": "2026-06-01T06:05:33Z"
}
FieldDescription
eventAlways "pass.upcoming" in this version of the API
alert_idID of the alert that triggered this delivery
satelliteSatellite name from the Celestrak catalog
aos_utc / los_utc / tca_utcPass window timestamps in ISO 8601 UTC
max_elevation_degPredicted peak elevation above the horizon (degrees)
duration_secondsTotal pass duration in seconds (LOS − AOS)
azimuth_at_aos / azimuth_at_losCompass bearing at rise and set — 0° = North, clockwise
kp_indexCurrent NOAA Kp at the moment of delivery
minutes_until_aosMinutes remaining until the satellite clears the horizon
observerThe lat/lon registered for this alert
delivered_atServer timestamp when this POST was dispatched (ISO 8601 UTC)

Error codes

All errors return JSON with error (human-readable) and code (machine-readable) fields.

json
{
  "error": "Invalid or missing API key.",
  "code": "unauthorized"
}
StatuscodeWhen it happens
401unauthorizedMissing X-API-Key header, or the key has been revoked
403forbiddenYour plan does not include this endpoint
404not_foundAlert ID does not exist, or belongs to another account
422validation_errorRequest body failed schema validation — check field types and required fields
422invalid_webhook_urlwebhook_url must use HTTPS — http:// URLs are rejected
429rate_limitedToo many requests. Free: 60 req/min · Starter: 300 req/min · Pro: unlimited
500internal_errorUnexpected server error. Persistent occurrences should be reported.

Complete quickstart

A self-contained Python script that starts a local webhook receiver, registers a NOAA-20 alert over Athens, and prints the full payload when the satellite is 10 minutes out. Zero dependencies beyond requests.

python
#!/usr/bin/env python3
"""
OrbitAlert quickstart — register an alert and print the webhook payload.
Run:  pip install requests && python quickstart.py
"""
import time, threading, requests
from http.server import HTTPServer, BaseHTTPRequestHandler

API_KEY = "sat_xk29mQpLvN3rT8wZ"          # replace with your key
WEBHOOK = "https://YOUR_NGROK_ID.ngrok.io/hook"  # expose :9000 via ngrok
BASE    = "https://api.orbitalert.net"

# 1. Local receiver — prints every incoming POST body
class Hook(BaseHTTPRequestHandler):
    def do_POST(self):
        n    = int(self.headers["Content-Length"])
        body = self.rfile.read(n).decode()
        print(f"\n>>> Webhook received:\n{body}\n")
        self.send_response(200)
        self.end_headers()
    def log_message(self, *_): pass

threading.Thread(
    target=HTTPServer(("", 9000), Hook).serve_forever,
    daemon=True,
).start()
print("Webhook receiver listening on :9000")

# 2. Register an alert — NOAA-20 over Athens, 10 min notice, ≥ 15° elevation
r = requests.post(f"{BASE}/alerts",
    headers={"X-API-Key": API_KEY},
    json={"satellite_name": "NOAA-20",
          "observer_lat": 37.9195, "observer_lon": 23.7310,
          "webhook_url": WEBHOOK,
          "minutes_before": 10, "min_elevation": 15.0})
r.raise_for_status()
print(f"Alert registered: {r.json()['id']}")
print("Waiting for the next NOAA-20 pass…  (Ctrl-C to quit)")
time.sleep(86400)

For local development, expose port 9000 with ngrok (ngrok http 9000) and replace YOUR_NGROK_ID with the subdomain it assigns. The first qualifying pass typically fires within a few hours, depending on your location.

OrbitAlert API · Dashboard

Get an API key →