Push Notification Endpoints

All send endpoints require a service JWT with scope=push:send (from client credentials grant). Device registration uses the user's access JWT.

POST /push/devices/register

Register a device for push notifications.

Auth: User JWT

Request:

{
  "app_id": "uuid",
  "platform": "web" | "ios" | "android",
  "push_token": "fcm-token-or-web-push-subscription"
}

Response (201):

{ "device_id": "uuid" }

Deduplicates on (app_id, token_hash). Re-registering updates last_seen_at.

Rate limit: 10 per user per hour.


DELETE /push/devices/{device_id}

Unregister a device.

Auth: User JWT (own devices) OR service JWT with push:send scope (app's devices)

Response (200):

{ "status": "ok" }

POST /push/send

Send a notification to a single user (all their registered devices for this app).

Auth: Service JWT with push:send scope

Request:

{
  "user_id": "uuid",
  "title": "Your shift starts in 30 min",
  "body": "Open GymOps to view details.",
  "data": { "route": "/schedule" },
  "ttl": 3600
}

Response (200):

{ "notification_id": "uuid" }

Validation: - user_id must be enrolled in the calling app - data max 4KB - title max 256 chars - body max 4096 chars


POST /push/send/bulk

Send the same notification to multiple users.

Auth: Service JWT with push:send scope

Request:

{
  "user_ids": ["uuid1", "uuid2", "uuid3"],
  "title": "Gym closes early today",
  "body": "Closing at 6pm.",
  "data": {}
}

Response (200):

{ "notification_ids": ["uuid1", "uuid2", "uuid3"] }

Max user_ids: 500.


POST /push/send/batch

Send different notifications in one call.

Auth: Service JWT with push:send scope

Request:

{
  "notifications": [
    { "user_id": "uuid1", "title": "Shift approved", "body": "Your request was approved." },
    { "user_id": "uuid2", "title": "Time off denied", "body": "Please contact your manager." }
  ]
}

Max notifications: 500.


Errors

Status Detail Meaning
400 User not enrolled Target user_id not in the calling app
400 Data payload too large data field exceeds 4KB
401 Invalid token Missing or invalid service JWT
403 Missing required scope JWT doesn't have push:send
404 Device not found Device ID doesn't exist or belongs to another app
429 Daily quota exceeded App has hit its notification limit