API Reference
The Hub API is a Fastify HTTP server. All endpoints are under /api/.
Authentication
| Method | Description |
|---|---|
| JWT Cookie | Set by POST /api/auth/login, sent automatically by browsers |
| Bearer Token | Authorization: Bearer <token> for mobile apps and API clients |
Both resolve to a user identity with tenant role. Platform admins have cross-tenant access.
Login security:
- Rate limiting: max 20 attempts per IP per 15 minutes (429)
- Account lockout: 5 failed attempts locks for 15 minutes (423)
- Last login timestamp + IP recorded on success
- Platform admin status resolved from DB on every request (not from stale JWT)
Auth
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /auth/register |
Public* | Register user (with optional invite token) |
| POST | /auth/login |
Public | Login, returns JWT cookie (+ token if ?returnToken=true) |
| POST | /auth/logout |
Authenticated | Clear session |
| GET | /auth/me |
Authenticated | Current user, tenants, preferences |
| PUT | /auth/me/preferences |
Authenticated | Update language + date format preferences |
| PUT | /auth/me/profile |
Authenticated | Update name and/or email |
| PUT | /auth/me/password |
Authenticated | Change password (requires current) |
| DELETE | /auth/me |
Authenticated | Delete own account |
| POST | /auth/invites |
Admin+ | Generate invite link (tenant + role) |
| GET | /auth/invites |
Admin+ | List pending invites |
| DELETE | /auth/invites/:id |
Admin+ | Revoke invite |
| GET | /auth/members |
Admin+ | List tenant members (excludes platform admins) |
| POST | /auth/create-tenant |
Logged in* | Create new tenant |
*Gated by platform settings (allow_self_registration, allow_tenant_creation)
Detections
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /detections |
Viewer+ | List detections (filterable) |
| GET | /detections/:id |
Viewer+ | Detection detail with storage key |
| GET | /detections/votes |
Viewer+ | Get user's votes for detection IDs |
| POST | /detections/:id/verify |
Member+ | Submit verification vote |
Query params for GET /detections:
tenantId— filter by tenantsatelliteId— filter by satellitespecies— filter by species codeminConfidence— minimum confidence thresholdverificationStatus—pending_review,confirmed,rejected,unverifiedlimit,offset— pagination
Satellites
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /satellites |
Viewer+ | List satellites with latest telemetry |
| GET | /satellites/:id |
Viewer+ | Satellite detail |
| POST | /satellites |
Admin+ | Register satellite (returns MQTT credentials) |
| PATCH | /satellites/:id |
Member+ | Update satellite (rename) |
| POST | /satellites/:id/profile |
Admin+ | Push recording profile via MQTT |
| GET | /satellites/:id/schedule |
Viewer+ | Resolved recording schedule with sun times |
| DELETE | /satellites/:id |
Admin+ | Delete satellite (revokes MQTT) |
Audio
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /audio/:chunkId |
Viewer+ | Stream audio WAV from MinIO |
Alerts
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /alerts |
Viewer+ | List alerts (?acknowledged=true/false) |
| POST | /alerts/:id/acknowledge |
Viewer+ | Dismiss alert |
Export
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /export/detections |
Member+ | Export CSV or JSON (?format=csv/json) |
| GET | /export/ebird |
Member+ | eBird checklist format |
| GET | /export/inaturalist |
Member+ | iNaturalist observation format |
| GET | /export/xenocanto |
Member+ | xeno-canto submission format |
Stats
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /stats/dashboard |
Viewer+ | Species count, detection count, chunk count |
| GET | /stats/trends |
Viewer+ | Daily detection trends (?days=30) |
| GET | /stats/top-species |
Viewer+ | Top species ranking |
| GET | /stats/activity |
Viewer+ | Hourly detection activity |
| GET | /stats/verification |
Viewer+ | Verification progress counts |
| GET | /stats/leaderboard |
Viewer+ | Verification contributor ranking |
| GET | /stats/species |
Viewer+ | Species catalog with rich per-species stats |
| GET | /stats/map |
Viewer+ | Satellite positions with detection summaries |
Species
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /species/languages |
Public | Available translation languages |
| GET | /species/translate |
Viewer+ | Translate single species |
| POST | /species/translate |
Viewer+ | Bulk translate species names |
| POST | /species/images |
Viewer+ | Get image statuses (queues missing) |
| GET | /species/image/proxy |
Viewer+ | Serve species image from MinIO |
| GET | /species/image-cache/stats |
Platform Admin | Image cache statistics |
| POST | /species/image-cache/clear |
Platform Admin | Clear entire image cache |
| POST | /species/image-cache/retry |
Platform Admin | Re-queue failed downloads |
Webhooks
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /webhooks |
Admin+ | List webhooks for tenant |
| POST | /webhooks |
Admin+ | Create webhook |
| DELETE | /webhooks/:id |
Admin+ | Delete webhook |
| POST | /webhooks/:id/test |
Admin+ | Send test payload |
Webhook payload: Detection details with HMAC signature in X-Webhook-Signature header.
Event types: detection.new, detection.rare, satellite.offline
Workers
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /workers |
Admin+ | Queue stats + connected workers (IP-based dedup) |
| GET | /workers/jobs |
Admin+ | Recent completed jobs |
Settings
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /settings/tenant |
Viewer+ | Tenant settings |
| PUT | /settings/tenant |
Admin+ | Update tenant settings |
| GET | /settings/platform |
Platform Admin | Platform settings |
| PUT | /settings/platform |
Platform Admin | Update platform settings |
Tenants
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /tenants |
Authenticated | List tenants |
Admin (Platform Admin only)
| Method | Path | Description |
|---|---|---|
| GET | /admin/users |
List all users (search, status, tenant filters) |
| GET | /admin/users/:id |
User detail |
| PUT | /admin/users/:id |
Update user (name, email, admin flag) |
| POST | /admin/users/:id/block |
Block/unblock user |
| POST | /admin/users/:id/reset-password |
Reset password |
| DELETE | /admin/users/:id |
Delete user |
| POST | /admin/users/:id/tenants |
Add user to tenant (409 if already member) |
| DELETE | /admin/users/:id/tenants/:tid |
Remove from tenant |
| PUT | /admin/members/:id/role |
Change member role |
| DELETE | /admin/members/:id |
Remove member from tenant |
| POST | /admin/members/:id/transfer-ownership |
Transfer tenant ownership |
| GET | /admin/audit-log |
Audit log (paginated) |
User list query params: ?search=, ?status=active|blocked, ?tenantId=
Audit Log
All audit log entries include the real client IP address (via X-Forwarded-For, with trustProxy enabled on Fastify).
User actions:
user.register— new account createduser.login— successful loginuser.login_failed— failed login attempt (reason:rate_limited,locked,invalid_credentials,blocked)user.logout— session endeduser.profile_updated— name or email changeduser.password_changed— password updateduser.preferences_updated— language or date format preferences changeduser.account_deleted— user deleted their own account
Admin actions:
admin.user_edited— admin updated user detailsadmin.user_blocked— admin blocked a useradmin.user_unblocked— admin unblocked a useradmin.user_deleted— admin deleted a useradmin.password_reset— admin reset a user's passwordadmin.user_added_to_tenant— admin added a user to a tenantadmin.user_removed_from_tenant— admin removed a user from a tenantadmin.member_role_changed— admin changed a member's roleadmin.member_removed— admin removed a memberadmin.invite_created— admin generated an invite linkadmin.invite_revoked— admin revoked an inviteadmin.tenant_created— new tenant createdadmin.tenant_settings_updated— tenant settings changedadmin.platform_settings_updated— platform settings changedadmin.ownership_transferred— tenant ownership transferred to another useradmin.satellite_deleted— satellite removedadmin.satellite_renamed— satellite renamedadmin.satellite_profile_changed— satellite recording profile changedadmin.webhook_created— webhook createdadmin.webhook_deleted— webhook deletedadmin.image_cache_cleared— species image cache cleared
Detection actions:
detection.voted— user submitted a verification vote
WebSocket
Connect to /ws/events?tenantId=<id> for real-time events.
Event types:
detection— new bird detected (species, confidence, satellite, rare flag)alert— system alert (rare species, satellite offline, etc.)
Toast format: Rare species notifications show translated names (primary + secondary languages).
System
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /system/status |
Platform Admin | Full platform status: all service instances, infrastructure, data summary |
Response includes:
- Services: each registered instance (API, dispatcher, web, workers, satellites) with status, version, uptime, memory usage, IP address, and service-specific details (e.g., per-worker job stats: processed, succeeded, failed, avg duration)
- Infrastructure: PostgreSQL, Redis, MQTT, MinIO connectivity and status
- Data summary: detection counts, inference queue stats, species image totals, tenant and user counts
Service instances are discovered via Redis service registry (birdnet:registry:{service}:{instanceId}, 30s TTL).
Health
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /health |
Public | Returns { status, version, timestamp } |