Exchange a code, or refresh, for tokens
POST/oauth/token
RFC 6749 §4.1.3 and §6, form-encoded (application/x-www-form-urlencoded, as the RFC says) or
JSON. Parameters are read from the body only.
Client authentication first: HTTP Basic (client_id:client_secret, each form-urlencoded
before Base64) or client_id + client_secret in the body — never both (invalid_request),
never in the query string (invalid_request). A wrong or missing secret is 401 invalid_client
with WWW-Authenticate: Basic realm="KudosCRM"; during a client-secret rotation grace the
previous secret still works. A suspended app or publisher is unauthorized_client.
grant_type=authorization_code: the code, the same redirect_uri the code was issued for,
and the PKCE code_verifier (43–128 of [A-Za-z0-9-._~]). A code is single use: presenting it a
second time is refused and revokes everything it minted. When that was the grant the install
runs on, the install must be reconnected (reauth_required) and its webhook hears
integration.disconnected with reason: reauth_required; an install the admin has reconnected
since, under a newer grant, is left as it is. The first exchange activates the install and
delivers integration.installed to its webhook.
grant_type=refresh_token: the refresh_token. Refresh tokens rotate — every refresh
returns a new one and the old one stops working. Two refreshes of one token within 30 seconds:
the second is invalid_grant (refresh_token_already_rotated) and nothing is revoked. A rotated
token presented later is reuse: its whole family is revoked and, by the same rule as a reused
code, the install must be reconnected unless it holds a newer grant. Every reuse is audited at high
severity with the address and client that presented it. Refresh works while an admin has the
install paused.
Optional scope narrows what this token carries (catalog keys, space-separated); it can never
widen past the install's grant. The access token (kat_…) lives one hour; the refresh token
(krt_…) 90 days, renewed on every rotation.
Throttles: oauth/token/client (60 a minute per client and IP) and oauth/token/ip
(120 a minute per IP).
Request
Responses
- 200
- 400
- 401
- 429
Tokens for the install, and where it lives.
Response Headers
Every OAuth answer — a token response cached by a proxy is a leaked token (RFC 6749 §5.1).
RFC 6749 §5.2: invalid_request (a parameter missing or sent twice ways, credentials in the
query), invalid_grant (code or refresh token unknown, used, expired or revoked; a
redirect_uri or PKCE mismatch; the app no longer installed or needing a reconnect),
invalid_scope (nothing asked for is granted), unauthorized_client (the app or its
publisher is suspended), unsupported_grant_type.
Response Headers
Every OAuth answer — a token response cached by a proxy is a leaked token (RFC 6749 §5.1).
invalid_client — client authentication failed.
Response Headers
Every OAuth answer — a token response cached by a proxy is a leaked token (RFC 6749 §5.1).
A throttle refused the request. Wait Retry-After seconds — the time left in the refusing window
plus 0–3 s of jitter. The X-RateLimit-* headers describe the bucket that refused it.
Response Headers
Seconds until the window rolls.