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 |