Bearer keys
The Bearer SyncApiKey is the only credential that crosses the boundary aside from the HMAC signing secret. Two channels use it:
- Pull channel. Kudos CRM walks your
GET /v1/sync/manifest,GET /v1/sync/tenants,GET /v1/sync/eventsendpoints nightly and on operator demand to reconcile drift. Authenticated withAuthorization: Bearer <sak_…>. - Reverse channel inbox. Kudos CRM POSTs sales-led overrides to your
POST /v1/integrations/crm/...endpoints. Same Bearer header, additionally HMAC-signed with the reverse-channel signing secret (see reverse channel).
The producer mints the SAK; the CRM operator pastes the cleartext into the source's sync_api_key field in the operator console.
Minting a key
In the producer's operator console, find the relevant consumer subscription and click Mint Bearer key. You will be prompted for:
| Field | Notes |
|---|---|
| Scopes | Multi-select from the closed scope list below. Default selection is all four read scopes; tick crm.overrides:write only when granting reverse-channel write access. |
| Expires | Optional. We recommend 90 days in production, 30 days in staging. Leave blank only for short-lived test windows. |
| Rate limit per minute | Producer-side throttle on this key. Default 600. |
The cleartext token is returned once in the response. After the modal closes the producer cannot recover it.
The closed scope list
| Scope | What it authorises |
|---|---|
sync:tenants:read | GET /v1/sync/tenants (paginated current-state list) |
sync:events:read | GET /v1/sync/events (event ledger walk, since-cursor) |
sync:subscriptions:read | GET /v1/sync/subscriptions/:id (single-subscription lookup) |
sync:payments:read | GET /v1/sync/payments (payment ledger walk) |
crm.overrides:write | POST /v1/integrations/crm/tenants/:ref/{assignment,notes,discount_intents} |
Kudos CRM presents only the four sync:*:read scopes by default. crm.overrides:write is opt-in.
How Kudos CRM uses the Bearer
Every request carries the standard header:
Authorization: Bearer sak_<32+ chars>
Accept: application/json
User-Agent: Kudos-Sync/1.0 (+https://app.kudoscrm.com)
For reverse-channel POSTs, three additional headers are added:
X-Kudos-Signature: t=<unix>,v1=<hex> # HMAC over body using the reverse-channel secret
X-Kudos-Idempotency-Key: idk_<ulid> # Dedupe key, 24 h memory
Content-Type: application/json; charset=utf-8
Your endpoint should:
- Verify the Bearer matches an active, non-revoked key with the right scope.
- Verify the HMAC (reverse-channel signing secret).
- Look up
X-Kudos-Idempotency-Keyin your 24-hour idempotency cache. If hit, return the cached response. - Otherwise run your handler, cache the response keyed by
X-Kudos-Idempotency-Key, return.
Rate limit and timeout expectations
Kudos CRM honours your producer-set rate limit. We back off when you return 429 Too Many Requests with Retry-After. Our pull-channel scan caps at 100 req/s burst from the CRM side regardless of your producer setting.
Recommended endpoint SLO:
GET /v1/sync/manifest: < 200 ms p95GET /v1/sync/tenants?cursor=…: < 2 s p95 for a 100-row pageGET /v1/sync/events?since_event_id=…: < 2 s p95 for a 100-row page- Reverse-channel POST: < 1 s p95
Rotation
There is no shared rotation window like signing secrets — each key is independent. To rotate:
- Operator mints a fresh key with the same scopes.
- CRM operator pastes it into the source config in the CRM operator console.
- Once you confirm the CRM is using the new key (watch your access logs), revoke the old one in the producer console.
Recommended cadence: 90 days in production.
Revocation
DELETE /v1/super_admin/subscriptions/:id/api_keys/:key_id revokes immediately. Subsequent requests using the revoked Bearer return 401 Unauthorized. The CRM operator sees the failure on the source health dashboard and either pastes a fresh key or contacts you.
Failure modes
| Symptom | Cause | Fix |
|---|---|---|
401 invalid_bearer on every pull-channel call | Key revoked, expired, or mistyped. | Mint fresh, paste into CRM source. |
403 scope_missing on /v1/sync/payments | Key minted without sync:payments:read. | Mint a new key with all four read scopes selected. |
429 rate_limited with no Retry-After | Producer set the rate limit too low. | Raise the rate limit on the key (must mint a new one — it is immutable post-mint). |
Move on to reverse channel for the CRM → producer write path.