Auth
API keys
API keys are project-scoped — one project = one or more keys. Format:
ucrm_pk_<env>_<id8>_<secret44>
ucrm_pk_prod_TJxd_AbCd1234EfGh5678IjKl9012MnOp3456QrSt7890UvWx
env ∈ {dev, stag, prod}. id8 is a public prefix (logged + visible in admin). secret44 is base64 — only the bcrypt hash is stored server-side.
Generate
POST /v1/projects/:projectId/api-keys
Auth: Clerk session.
Request:
{ "name": "production-prod-key" }
Response 201:
{
"data": {
"id": "...",
"name": "production-prod-key",
"prefix": "ucrm_pk_prod_TJxd",
"key": "ucrm_pk_prod_TJxd_AbCd...", // ONLY returned at creation
"created_at": "..."
}
}
The full key is only returned once at creation. UCRM stores only the bcrypt hash + prefix. If you lose it, generate a new key + revoke the old.
Revoke
DELETE /v1/projects/:projectId/api-keys/:id → soft-deletes (existing in-flight requests succeed; new ones fail).
Verify (server side, for SDK testing)
GET /v1/me with Authorization: Bearer <key> → returns {tenant_id, project_id, environment} if the key is valid.
Clerk session (admin)
Admin endpoints (every /v1/* not in the API-key list) require a Clerk JWT:
Authorization: Bearer eyJhbGc...
Clerk handles all the auth flows (sign in / sign up / org switching) on app.casinocrm.io. The middleware resolves (user_id, tenant_id, role) from the tenant_memberships row.
Internal secret (server-to-server)
/v1/internal/* endpoints use a shared secret:
X-Internal-Secret: <env-set-secret>
Used by:
services/stream-processorcalling/v1/internal/recompute-tier+/v1/internal/recompute-player-segmentsservices/messaging-workercalling/v1/internal/bonus-progress- Bonus campaign worker calling
/v1/internal/bonus-grant
Never expose to end users.