Skip to main content

Bearer keys

The Bearer SyncApiKey is the only credential that crosses the boundary aside from the HMAC signing secret. Two channels use it:

  1. Pull channel. Kudos CRM walks your GET /v1/sync/manifest, GET /v1/sync/tenants, GET /v1/sync/events endpoints nightly and on operator demand to reconcile drift. Authenticated with Authorization: Bearer <sak_…>.
  2. 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:

FieldNotes
ScopesMulti-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.
ExpiresOptional. We recommend 90 days in production, 30 days in staging. Leave blank only for short-lived test windows.
Rate limit per minuteProducer-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​

ScopeWhat it authorises
sync:tenants:readGET /v1/sync/tenants (paginated current-state list)
sync:events:readGET /v1/sync/events (event ledger walk, since-cursor)
sync:subscriptions:readGET /v1/sync/subscriptions/:id (single-subscription lookup)
sync:payments:readGET /v1/sync/payments (payment ledger walk)
crm.overrides:writePOST /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:

  1. Verify the Bearer matches an active, non-revoked key with the right scope.
  2. Verify the HMAC (reverse-channel signing secret).
  3. Look up X-Kudos-Idempotency-Key in your 24-hour idempotency cache. If hit, return the cached response.
  4. 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 p95
  • GET /v1/sync/tenants?cursor=…: < 2 s p95 for a 100-row page
  • GET /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:

  1. Operator mints a fresh key with the same scopes.
  2. CRM operator pastes it into the source config in the CRM operator console.
  3. 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​

SymptomCauseFix
401 invalid_bearer on every pull-channel callKey revoked, expired, or mistyped.Mint fresh, paste into CRM source.
403 scope_missing on /v1/sync/paymentsKey minted without sync:payments:read.Mint a new key with all four read scopes selected.
429 rate_limited with no Retry-AfterProducer 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.