Skip to content

Credentials & tokens

POST https://{store domain}/apps/token — the OAuth 2.0 client credentials grant, the one a private app uses: it is installed on one store and presents its own credentials, so there is no user to redirect. The same endpoint also serves the authorization_code (with PKCE) and refresh_token grants for an app a merchant installed by consent; the table and examples below are the client credentials grant.

Form field Value
grant_type exactly client_credentials
client_id your ciqra_ci_… id
client_secret your ciqra_cs_… secret

The body must be application/x-www-form-urlencoded. Send the client credentials either as the client_id / client_secret form fields or in an HTTP Basic header (Authorization: Basic base64(client_id:client_secret), RFC 6749 §2.3.1) — what most OAuth libraries do by default. Sending both is refused with 400 invalid_request. The response carries Cache-Control: no-store.

{
"access_token": "ciqra_at_…",
"token_type": "Bearer",
"expires_in": 3600,
"accessToken": "ciqra_at_…",
"tokenType": "Bearer",
"expiresIn": 3600,
"scope": "read_products write_products",
"scopeNotYetEnforced": ""
}
Field Meaning
access_token Send as Authorization: Bearer <access_token>.
token_type Always Bearer.
expires_in Seconds until it expires — one hour by default.
accessToken, tokenType, expiresIn The same three values in camelCase, kept so existing apps keep working. New code should use the snake_case fields (RFC 6749 §5.1), which standard OAuth client libraries read without help.
scope Space-separated effective scopes: what was granted, plus the read_ scope each write_ scope implies. Order is not significant.
scopeNotYetEnforced The subset of scope that no endpoint honours yet (empty string when none) — only a reserved scope can appear here, implied by a write_ scope or granted before it was reserved. See scopes.

There is no refresh token. Request a new token shortly before expiresIn runs out — the reference app does so one minute early.

Status Body Cause
400 {"error":"invalid_request","error_description":"…"} Body is not form-encoded, or credentials were sent both in the Basic header and in the form.
400 {"error":"unsupported_grant_type","error_description":"…"} grant_type is anything but client_credentials.
401 {"error":"invalid_client","error_description":"Client authentication failed."} Unknown client id, wrong secret, app not active, or no active installation on this domain’s store. The cases are deliberately indistinguishable.
429 — More than 20 token requests per minute from your IP address. Do not parse the body.

Token-endpoint errors follow RFC 6749 §5.2 (error plus error_description). Every other app route uses the error envelope instead.

The installation is looked up as the store the request’s domain resolves to. The same credentials used on another store’s domain receive 401, even if the app is installed there too — each store’s installation must be addressed on that store’s domain.

A merchant can issue a long-lived token for an installation from the admin (Settings → Apps → the app → Tokens): a label and a lifetime of 30, 90, 180 or 365 days. It is shown once, carries the installation’s current scopes, and can be revoked individually. The admin shows when each token was last used (updated at most every five minutes).

Use one only for a tool that cannot perform the token exchange. A leaked standing token is valid for months; a leaked exchanged token for under an hour.

  • Client secret. Rotated by CIQRA on request. The previous secret keeps working for an overlap window (24 hours by default) so you can deploy the new one without downtime.
  • Revocation is immediate. Tokens are checked against the installation and the app on every request; nothing is cached. Uninstalling the app, revoking a standing token, or suspending the app takes effect on the very next call.
  • Signing secret. Issued once at installation. There is currently no route for you to rotate it — see limitations. If it is compromised, CIQRA retires it at once (no overlap) and the new secret is not shown on our side; deliveries fail verification until you are given it. During an ordinary rotation both secrets sign every delivery — see verifying signatures.