Skip to content

Notifications API

The Notifications API manages the full lifecycle of push notifications: registering browser push subscriptions via the Web Push (VAPID) protocol, configuring per-category delivery preferences, and querying notification history. Categories are split into global (location-independent) and location-specific groups, each with granular controls for lead times, quiet hours, and scheduling.

All endpoints that accept a category parameter validate against the following set:

These apply regardless of observer location.

CategoryDescription
launchUpcoming rocket launches
reentryTracked reentry events
space_weatherGeneral space weather alerts
solar_flareSolar flare detections
noaa_scalesNOAA space weather scale changes (R/S/G)
neo_approachNear-Earth object close approaches
conjunctionSatellite conjunction warnings
hf_conditionsHF radio propagation condition changes
daily_digestScheduled daily summary of upcoming events

These require a location_id and deliver notifications relevant to that observer position.

CategoryDescription
satellite_passVisible satellite passes overhead
auroraAurora visibility forecasts for the location
observingFavorable observing conditions (clear skies, low wind)
sonde_nearbyRadiosonde landings predicted near the location
whats_upNotable objects currently above the horizon

Returns the server’s VAPID public key, which the browser needs to create a push subscription. This key is configured server-side via the VAPID_PUBLIC_KEY environment variable.

GET /api/notifications/vapid-key
{
"public_key": "BNz..."
}

Returns 503 if VAPID keys have not been configured on the server.


Registers a push subscription endpoint. If the endpoint URL already exists in the database, the subscription is reactivated and its keys are updated (upsert behavior).

POST /api/notifications/subscribe
{
"endpoint": "https://fcm.googleapis.com/fcm/send/...",
"keys": {
"p256dh": "BNz...",
"auth": "abc..."
},
"user_agent": "Mozilla/5.0 ..."
}
FieldTypeRequiredDescription
endpointstringYesThe push service URL from the browser subscription
keys.p256dhstringYesClient public key for message encryption
keys.authstringYesAuthentication secret
user_agentstringNoBrowser user agent string for diagnostics
{
"id": 1,
"endpoint": "https://fcm.googleapis.com/fcm/send/...",
"is_active": true,
"created_at": "2026-02-14T18:00:00Z"
}

Deactivates a push subscription by its database ID. The subscription record is retained but marked inactive, so it will not receive further push messages.

DELETE /api/notifications/subscribe/{sub_id}
ParameterTypeDescription
sub_idinteger (path)The subscription ID returned from the subscribe endpoint
{
"ok": true
}

Returns 404 if the subscription ID does not exist.


Preferences control which notification categories are enabled and how they are delivered. Global preferences have no location_id; location-specific preferences are scoped to a saved observer location.

Returns all configured notification preferences, ordered by location (global first, then per-location) and category.

GET /api/notifications/preferences
[
{
"id": 1,
"location_id": null,
"category": "daily_digest",
"is_enabled": true,
"lead_times": null,
"schedule_cron": "0 19 * * *",
"min_altitude": 10.0,
"timezone": "America/Denver",
"config": null,
"quiet_start": "22:00",
"quiet_end": "07:00"
},
{
"id": 2,
"location_id": 5,
"category": "satellite_pass",
"is_enabled": true,
"lead_times": [1440, 60, 15],
"schedule_cron": null,
"min_altitude": 25.0,
"timezone": "America/Denver",
"config": null,
"quiet_start": "23:00",
"quiet_end": "06:00"
}
]

Creates or updates a preference for a global (location-independent) category. Only categories from the global set are accepted here; location-specific categories will be rejected with a 400 error.

PUT /api/notifications/preferences/global/{category}
ParameterTypeDescription
categorystring (path)One of the global notification categories
{
"is_enabled": true,
"lead_times": [1440, 60, 15],
"schedule_cron": "0 19 * * *",
"min_altitude": 10.0,
"timezone": "America/Denver",
"config": null,
"quiet_start": "22:00",
"quiet_end": "07:00"
}
FieldTypeDefaultDescription
is_enabledbooleantrueWhether this category is active
lead_timeslist of int or nullnullAdvance notice in minutes (e.g. [1440, 60, 15] for 1 day, 1 hour, 15 min). Max 10 entries, each 1—10080.
schedule_cronstring or nullnullCron expression for scheduled delivery (e.g. "0 19 * * *" for 7 PM daily)
min_altitudefloat10.0Minimum altitude in degrees (0—90) for pass-type notifications
timezonestring"UTC"IANA timezone name used for scheduling and quiet hours
configobject or nullnullCategory-specific settings (max 20 keys)
quiet_startstring or nullnullStart of quiet hours in HH:MM format (e.g. "22:00")
quiet_endstring or nullnullEnd of quiet hours in HH:MM format (e.g. "07:00")

Returns the saved PreferenceOut object (same shape as the list response items).


Creates or updates a preference for any category scoped to a specific observer location. Both global and location-specific categories are accepted here, but location-specific categories (like satellite_pass) must use this endpoint rather than the global one.

PUT /api/notifications/preferences/{location_id}/{category}
ParameterTypeDescription
location_idinteger (path)The saved location ID
categorystring (path)Any valid notification category

The request body and response follow the same shape as the global preference endpoint above.


Removes a global preference for the given category.

DELETE /api/notifications/preferences/global/{category}
ParameterTypeDescription
categorystring (path)The global category to delete
{
"ok": true
}

Returns 404 if no global preference exists for that category.


Removes a preference for a specific location and category.

DELETE /api/notifications/preferences/{location_id}/{category}
ParameterTypeDescription
location_idinteger (path)The saved location ID
categorystring (path)The category to delete
{
"ok": true
}

Returns 404 if no matching preference exists.


Returns a paginated list of all notification log entries, newest first.

GET /api/notifications
ParameterTypeDefaultDescription
limitinteger (query)50Number of results to return (max 200)
offsetinteger (query)0Number of results to skip
[
{
"id": 42,
"category": "satellite_pass",
"title": "ISS Pass in 15 minutes",
"body": "Max elevation 72 deg, magnitude -3.8",
"data_json": "{\"type\": \"satellite_pass\", \"url\": \"/passes/25544\"}",
"location_id": 5,
"sent_at": "2026-02-14T02:45:00Z",
"read_at": null,
"push_sent": true
}
]

Returns the number of notifications that have not yet been marked as read.

GET /api/notifications/unread-count
{
"count": 7
}

Marks a single notification as read by setting its read_at timestamp.

POST /api/notifications/{notification_id}/read
ParameterTypeDescription
notification_idinteger (path)The notification log entry ID
{
"ok": true
}

Returns 404 if the notification ID does not exist.


Marks every unread notification as read in a single operation.

POST /api/notifications/read-all
{
"ok": true
}

Sends a test push notification to all active subscriptions. This is useful for verifying that the VAPID configuration and browser push subscription are working end to end. The test notification is also logged in notification history and broadcast over the live WebSocket feed.

POST /api/notifications/test
{
"ok": true,
"sent_count": 2
}

The sent_count reflects how many active push subscriptions received the message.