Enterprise — Authentication
Every call to the Enterprise API carries an OAuth 2.0 bearer token. This page covers getting one, the scopes that gate the enterprise surface, and revoking a token.
Credentials
You need a client ID and client secret issued for your enterprise account. These are machine credentials — there is no browser redirect and no user login.
The client secret authenticates your whole organisation. Keep it server-side. Never ship it in a mobile app or browser bundle.
Getting a token
Kesk supports exactly one grant: client_credentials. Authenticate with HTTP
Basic — client ID as username, secret as password — and send the grant type as
JSON.
A successful response:
Enterprise credentials authenticate against enterprise.apis.kesk.app. The same
endpoint answers on the vendor host, but a token minted there carries no
enterprise_id claim and reaches nothing on this surface.
Read scope and expires_in from the response rather than assuming either.
The values above are illustrative — the granted scope can be narrower than
what you asked for, and the token lifetime is set server-side. Never hardcode
a lifetime.
Using the token
Cache the token for its expires_in and refresh on a margin.
Enterprise scopes
| Scope | Grants |
|---|---|
enterprise:core:read | Read the enterprise record and dashboard stats |
enterprise:core:write | Update the enterprise record |
enterprise:users:read | List and fetch members |
enterprise:users:write | Invite, update, suspend, activate, remove, reset passwords |
enterprise:settings:read | Read the settings record |
enterprise:settings:write | Create, update, delete and bulk-update settings |
enterprise:billing:read | Read billing info, usage summaries and invoices |
enterprise:vouchers:read | Read vouchers, templates and analytics |
enterprise:vouchers:write | Create, update and delete vouchers and templates |
enterprise:scim:read | Read the directory over SCIM |
enterprise:scim:write | Provision and deprovision members over SCIM |
Scopes match exactly, or by an enterprise:* wildcard on the : boundary.
enterprise:* is not a synonym for the coarse grant enterprise — the
wildcard grants the whole surface including the sensitive scopes the coarse
grant withholds.
The coarse grant enterprise does not cover everything in the table above.
The registry withholds eight scopes from coarse grants, and three of them are on
this surface: enterprise:users:write, enterprise:scim:read and
enterprise:scim:write. Each administers the membership of your organisation,
which a consent granted for spending data must not silently carry.
So a coarse enterprise grant cannot invite, suspend or remove a member, and
reaches no SCIM endpoint. Request those three by name, or use enterprise:*.
See OAuth 2.0 for the full withheld list.
Read the granted scope back from the token response regardless; it is the
record of what you were actually given.
The complete scope registry is published as scopes_supported at
accounts.kesk.app/.well-known/oauth-authorization-server.
Note the host: that is the authorization server, not the API host, so the
path does not resolve on enterprise.apis.kesk.app. The table above is the subset
that gates the enterprise surface; the registry also lists the scopes of every other
surface. The scope in your token response remains the record of what you were
actually granted.
Errors
| Situation | Status | Body |
|---|---|---|
Missing Authorization header | 401 | {"title":"Unauthorized","message":"Authentication required.","status":401,"type":"unauthorized"} |
Wrong client ID or secret | 401 | {"error":"invalid_client","error_description":"Client authentication failed."} |
Unsupported grant_type | 400 | {"error":"unsupported_grant_type","error_description":"Only 'client_credentials' grant type is supported."} |
Scope not on your registration | 400 | {"error":"invalid_scope","error_description":"Scope exceeds the client's registered grant: ..."} |
Form-encoded body on /token | 400 | {"error":"Bad Request","message":"invalid content type ..., expect: application/json"} |
Validation order is grant_type → client → scope.
The missing-header and wrong-content-type cases return plain text — parsing either as JSON will throw.
Revoking a token
The token endpoint takes JSON; the revoke endpoint takes
application/x-www-form-urlencoded. Sending JSON here returns 415.
token_type_hint is optional and ignored, and access_token is the only value
the endpoint will parse — any other string is a 400. Revocation applies to
access tokens: passing a refresh token returns 200 and revokes nothing.
Revocation kills the entire token family, not just the string you passed.
Per RFC 7009 the endpoint returns 200 even for an unknown token, so a 200
means "not valid any more" rather than "existed and was revoked". Treat it as
idempotent and safe to retry.
Reference
Generated reference — every type, field and argument, built from the live schema.