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. Config endpoints require an admin JWT (app admin or above).

PATCH /push/config/{app_id}

Enable or update push notification settings for an app.

Auth: Admin JWT (app admin, tenant admin, or platform admin)

Request:

{
  "enabled": true,
  "webhook_url": "https://yourapp.com/hooks/push-receipts",
  "daily_quota": 10000
}

All fields are optional. Only provided fields are updated.

Response (200):

{
  "enabled": true,
  "webhook_url": "https://yourapp.com/hooks/push-receipts",
  "webhook_secret": "whsec_abc123...",
  "daily_quota": 10000
}

On first enable, a webhook_secret is auto-generated and returned. Subsequent updates preserve the existing secret unless explicitly regenerated.


GET /push/config/{app_id}

Get push notification configuration and current status for an app.

Auth: Admin JWT (app admin, tenant admin, or platform admin)

Response (200):

{
  "enabled": true,
  "webhook_url": "https://yourapp.com/hooks/push-receipts",
  "webhook_secret": "whsec_abc123...",
  "daily_quota": 10000,
  "device_count": 42,
  "notifications_today": 128
}

GET /push/devices/{app_id}

List all registered push devices for an app.

Auth: Admin JWT (app admin, tenant admin, or platform admin)

Response (200):

{
  "devices": [
    {
      "device_id": "uuid",
      "user_id": "uuid",
      "platform": "ios",
      "last_seen_at": "2026-03-19T08:00:00Z"
    }
  ],
  "total": 42
}

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 JWT
403 Missing required scope JWT doesn't have push:send
403 Push not enabled App does not have push notifications enabled (device registration)
403 Insufficient permissions JWT does not have admin access for config endpoints
404 App not found App ID does not exist
404 Device not found Device ID doesn't exist or belongs to another app
429 Daily quota exceeded App has hit its notification limit