Authentication
OAuth 2.0 client credentials flow for Carrot API access.
Last updated on
Carrot API uses OAuth 2.0 client credentials with bearer tokens.
There is no user login step. Integrations authenticate with a clientId and clientSecret.
Authentication flow
- Receive
clientIdandclientSecretfrom the Carrot API team. - Request an access token from the auth endpoint using Basic Authentication.
- Use the returned bearer token in the
Authorizationheader on API requests.
curl --request POST \
--url https://auth.api.carrot.eco/oauth2/token \
--header 'Authorization: Basic <clientId:clientSecret in base64>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'scope=api.carrot.eco/main-scope'Token lifecycle
access_tokenmaximum duration is currently 1 hour.expires_inis returned by the token endpoint response and must be treated as API-provided runtime data (not hard-coded in your integration).- Refresh tokens are not used in this flow.
- Request a new token before expiry to avoid request failures.
Token response format
Typical successful response:
{
"access_token": "<jwt-or-opaque-token>",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "api.carrot.eco/main-scope"
}Applying bearer tokens
Send your token on each request:
Authorization: Bearer <access_token>Environment behavior
Environment is controlled by credentials, not by URL.
- Test credentials operate only on test data.
- Production credentials operate only on production data.
- A test token cannot modify production documents, and the reverse is also true.
See Environments for operational guidance.
Common auth errors
401— the token could not be parsed: noAuthorizationheader, or a bearer value that is not a decodable JWT. The body is{"message":"Unauthorized"}, with nocodefield.403(edge authorizer) — the token parsed but was rejected: expired, invalid signature, non-Bearerscheme, scope not allowed, or issuer mismatch. The body is{"message":"<reason>"}, for example{"message":"Authorization token expired"}. There is noerrors[]envelope.403(RESTRICTED_RESOURCE_ERROR) — a valid token without permission for the target resource, including a test credential touching production data or the reverse. The body is the standarderrors[]envelope described in Errors.
Refresh on 403, not 401
An expired token never produces a 401 — it is rejected at the edge as a 403, so token-refresh
logic keyed on 401 will never fire. Refresh only when the gateway body identifies expiry
({"message":"Authorization token expired"}). The other 403 causes — bad signature, wrong scope
or issuer, RESTRICTED_RESOURCE_ERROR — are not fixed by a new token, and retrying them after a
refresh only loops.