// hub api

SignalForge Hub API

Every SignalForge Hub exposes the same API surface. The web console, recorder clients, public radio-set players, and trusted peer hubs all talk to this hub API.

Use this as the public operator reference. The source repository contains the deeper developer copy at docs/API.md.

Base URL

Use the public hub URL as the base URL. API routes are under /api/v1 unless noted.

https://p7hub.projectseven.us/api/v1/health

Authentication Model

ScopeAccess
PublicHealth, version, update check, recorder ingest, public player routes.
User sessionCall browsing, radio sets, talkgroup preferences, readable sources.
Admin sessionUsers, audit logs, hub identity, federation peers, source management, call retention and archive, directory refresh.
Source keyRecorder upload through POST /api/call-upload.

Authentication

Hubs advertise available sign-in methods through GET /api/v1/auth/capabilities. Online hubs with Mailjet configured offer magic-link email codes; off-grid cells typically enable password login and leave email delivery disabled.

MethodPathPurpose
GET/api/v1/auth/capabilitiesPassword login, magic link, and email-delivery flags.
POST/api/v1/auth/loginEmail + password session (when AUTH_PASSWORD_LOGIN_ENABLED).
POST/api/v1/auth/magic-linkRequest a sign-in code by email (when Mailjet is configured).
POST/api/v1/auth/verify-codeComplete magic-link sign-in with a 6-digit code.
GET/api/v1/auth/meCurrent session user.
POST/api/v1/auth/logoutRevoke the session cookie or bearer token.

Bootstrap admin credentials are set with AUTH_BOOTSTRAP_EMAIL and AUTH_BOOTSTRAP_PASSWORD in the API environment. See Off-Grid Hub Cells on the main site.

System Endpoints

MethodPathPurpose
GET/api/v1/healthBasic hub health.
GET/api/v1/versionServer build metadata.
GET/api/v1/update-checkCompare deployed tag to the public image manifest.

Hub Identity And Directory

MethodPathPurpose
GET/api/v1/hub/identityRead local hub identity. Requires a user session.
PUT/api/v1/hub/identityUpdate hub name, URL, region, contact, and federation toggle.
POST/api/v1/hub/identity/keypairGenerate the local Ed25519 hub keypair if missing. Returns only the public key.
POST/api/v1/hub/directory/refreshFetch the configured directory feed and update local trust fields.
GET/api/v1/hub/federation/statusAdmin federation, trust, sharing, and peer status view.

Federation

MethodPathPurpose
GET/api/v1/hub/invitesList hub invite tokens.
POST/api/v1/hub/invitesCreate a peer invite token.
POST/api/v1/hub/invites/acceptAccept a remote hub invite.
GET/api/v1/hub/peersList known peer hubs.
POST/api/v1/hub/peersConnect to a remote hub with URL and invite token.
GET/api/v1/federation/sourcesPeer-readable shared local sources.
GET/api/v1/federation/callsPeer-readable shared local calls. Imported remote calls are not re-exported.

Calls, Sources, And Radio Sets

MethodPathPurpose
GET/api/v1/callsList readable calls with pagination, search, talkgroup, group, source, and radio-set filters.
GET/api/v1/calls/{id}/audioDownload or play readable call audio.
GET/api/v1/sourcesList visible ingestion sources.
PUT/api/v1/sourcesCreate or update a source profile.
POST/api/v1/sources/{id}/keysGenerate a source upload key.
GET/api/v1/radio-setsList saved radio sets.
POST/api/v1/radio-setsCreate a set by talkgroup IDs or by talkgroup_group names (selectionMode: "groups").
POST/api/v1/radio-sets/{id}/shareGenerate a public player share token.

Call Retention And Archive (Admin)

Call audio is stored in PostgreSQL. Operators configure a retention window so older calls are exported to disk (and optionally S3-compatible object storage) before deletion. Sweeps run automatically every six hours, or on demand from the web console Account tab. A single Archive Now action batches through the full backlog until remainingOld reaches zero.

MethodPathPurpose
GET/api/v1/admin/calls/storageCall count, total audio bytes, oldest/newest timestamps, retention and archive config.
POST/api/v1/admin/calls/archiveExport then delete calls older than N days. dryRun: true reports the backlog without changes. Real runs batch up to 500 calls at a time and continue until empty by default (untilEmpty: true).

Key environment variables on the api service:

VariableMeaning
CALL_RETENTION_DAYSDelete calls older than this many days when archiving (also drives the six-hour scheduler).
CALL_ARCHIVE_DIRHost path for exported day folders (mount a volume here).
CALL_ARCHIVE_S3_URIOptional s3://space-name/prefix destination for object storage sync.
SPACES_ACCESS_KEY / SPACES_SECRET_KEY / SPACES_ENDPOINTDigitalOcean Spaces credentials; entrypoint writes s3cmd config at container start.
CALL_ARCHIVE_DELETE_LOCAL_AFTER_S3Remove local day folders after a successful upload.
CALL_ARCHIVE_VACUUM_FULLWhen true (default), run VACUUM FULL on calls after a sweep clears the backlog.

Archive export layout:

/data/call-archive/
  2026-06-01/
    call-12345.json
    call-12345.mp3

Example archive request:

POST /api/v1/admin/calls/archive
{
  "olderThanDays": 14,
  "dryRun": true
}

See Call Retention & Archive on the main site for operator setup notes.

Recorder Upload

Recorder clients upload calls with multipart form data to POST /api/call-upload. Required fields are key, talkgroup, and an audio file part.

curl -F key=sk_live_REPLACE_WITH_SOURCE_KEY -F test=1 https://p7hub.projectseven.us/api/call-upload

A valid key probe returns HTTP 417 with incomplete call data: no talkgroup. That is expected and means the key was accepted.

sf recorder check --source-key sk_live_REPLACE_WITH_SOURCE_KEY
  sf recorder watch --input ./calls --source-key sk_live_REPLACE_WITH_SOURCE_KEY
  sf update check

Public Player

MethodPathPurpose
GET/public/player/{token}Self-contained public player page.
GET/public/ws/{token}Public WebSocket with metadata and base64 audio in one message.
GET/public/last-call/{token}Most recent call audio for a share token.

Custom Consoles

Authenticated operator consoles can connect to GET /ws for live hub events. Most integrations should use the documented HTTP routes first.

Do not publish source API keys, invite tokens, magic-link tokens, session cookies, or private hub keys.