OAuth 2.1

Token Endpoint

Exchange codes for tokens and renew access tokens using refresh tokens.

The token endpoint issues access_token and refresh_token. It supports three grant types: authorization_code, refresh_token, and urn:ietf:params:oauth:grant-type:token-exchange. This page covers the first two; see Token Exchange for the third.

Endpoint

POST https://app.whatalo.com/oauth/token
Content-Type: application/x-www-form-urlencoded

Token endpoint rate limits:

  • 60 requests per minute per IP
  • 30 requests per minute per client_id

Exceeding either limit returns HTTP 429 with a Retry-After header. Implement exponential backoff.

Client authentication

Confidential clients (those with a client_secret) must authenticate. Public clients (token_endpoint_auth_method: "none") send no credentials.

Authorization: Basic BASE64(client_id:client_secret)

Body params (alternative)

client_id=abc123def456&client_secret=s3cr3t_v4lu3_xyz987wvu654

Both methods are equivalent. Do not use both simultaneously.

Grant type: authorization_code

Exchange the authorization code received from the authorization flow.

POST /oauth/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic YWJjMTIzZGVmNDU2OihzM2NyM3RfdmFsdWU=

grant_type=authorization_code
&code=SINGLE_USE_AUTH_CODE
&redirect_uri=https%3A%2F%2Fmy-app.com%2Foauth%2Fcallback
&client_id=abc123def456ghi789jkl012
&code_verifier=THE_PKCE_CODE_VERIFIER

Parameters

ParameterRequiredDescription
grant_typeYesauthorization_code
codeYesCode received in the callback
redirect_uriYesMust match exactly the URI used in the authorize request
client_idYes (if not in Basic)Your client_id
code_verifierYesThe original PKCE verifier (before hashing)

Response

{
  "access_token": "DlcGJFC7UmSx2fYKj7Bg3jhT9QgpyIzNcx7OGAoFu8U",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "LKr5XU5xyiD0XscBPSO9tm0DsSK2AKsWL2fOe9an6v8",
  "scope": "read:products read:orders"
}

Grant type: refresh_token

When the access_token expires (every hour), use the refresh_token to obtain a new one.

POST /oauth/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic YWJjMTIzZGVmNDU2OihzM2NyM3RfdmFsdWU=

grant_type=refresh_token
&refresh_token=LKr5XU5xyiD0XscBPSO9tm0DsSK2AKsWL2fOe9an6v8
&client_id=abc123def456ghi789jkl012

Response

{
  "access_token": "00e1NyN_TYwjunXFjnNpMcs6PdJgXqoVMfeTfJgkhP0",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "n-zDToBmLXUEOrPtOH4usLAYOxZkmyU1WKwqOYJRaZ8",
  "scope": "read:products read:orders"
}

Refresh token rotation is strict. The previous refresh token is revoked immediately. If you present an already-revoked token, Whatalo revokes the entire token family — the user will need to re-authorize from scratch. Avoid race conditions: serialize refreshes in your infrastructure.

Optional downscoping

You can request a subset of the originally granted scopes:

&scope=read:products

Requesting broader scopes than those granted returns invalid_scope.

Token durations

TokenDurationNotes
access_token1 hourSend as Authorization: Bearer <token>
refresh_token30 daysRotates on each use — always store the new one
authorization_code10 minutesSingle-use, bound to the PKCE verifier

Using the access token

GET https://api.whatalo.com/v1/products
Authorization: Bearer DlcGJFC7UmSx2fYKj7Bg3jhT9QgpyIzNcx7OGAoFu8U

Error handling

ErrorHTTPCause
invalid_grant400Code expired, already used, or incorrect code_verifier
invalid_client401Invalid or missing client credentials
invalid_request400Missing or malformed parameter
invalid_scope400Requested scope exceeds those granted
rate_limit_exceeded429Rate limit exceeded — see Retry-After

See the complete reference in OAuth errors.

On this page