Get started

Authentication

Non-public endpoints require authentication. Most integrations use app credentials sent in a Bearer header; user tokens cover requests made on behalf of a signed-in user.

Which method should I use?

App authentication

App credentials are scoped to a tenant. Send them in the Authorization header - this keeps secrets out of URLs, logs, and caches:

curl -s "https://api.readycms.io/orders/?namespace=<tenant>" \
  -H "Authorization: Bearer <app_id>:<app_secret>"

The Bearer token is the two values joined by a colon: <app_id>:<app_secret>. The scheme is parsed case-insensitively and the colon separator is required.

Credentials may also be passed as query or body parameters (app_id, app_secret, namespace), but the header form is strongly preferred.

Note
App credentials live in Settings → API Access in the admin. A tenant can hold multiple keys - rotate by issuing a new one and retiring the old.

Domain enforcement

A key can optionally restrict which origins may use it. When domain enforcement is enabled for a key, the request's Origin host must match the key's allowlist (exact, or a wildcard such as *.example.com). Requests with no Origin are allowed only if the key permits it. This matters most for browser-based usage, including the try-it console.

Token authentication

Use a user token to act as a specific signed-in user. Send user_id and token with tenant context:

curl -s "https://api.readycms.io/users/?namespace=<tenant>&user_id=<user_id>&token=<token>"

Expired or revoked tokens fail with error 5207 - refresh the token and retry.

Obtaining a user token

External clients (for example a mobile app backend) obtain a v2 user token by calling POST /auth/login/ with the user's email and password in the JSON body. This call needs no app credentials: the store name in namespace plus the email and password are the whole sign-in, so a client can connect to a store whose key pair it has never seen. The token is random, stored hashed, expires after 30 days by default, and can be rotated or revoked.

curl -s -X POST "https://api.readycms.io/auth/login/?namespace=<tenant>" \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"••••••"}'

The response carries data.user_id, data.token (v2.…) and data.expires_at. Send user_id + token on later requests. If the user has two-factor enabled the call fails with 5211; repeat it with the 6-digit code in otp. Use POST /auth/refresh/ to rotate the token before it expires and POST /auth/logout/ to revoke it. One token is active per user; a new login replaces the previous one.

data.store comes back with the session (namespace, title, domain, url, currency, currency_sign, logo) so a client can show which store it just connected to. An unknown or unreachable store name fails with 5215 before the password is ever checked. Login is throttled per email (3 failures / 20 minutes) and per IP (30 attempts / 20 minutes per store); it and the two password reset routes are the only ones that accept no credentials, and it is POST only so the password never lands in a URL.

Resetting a forgotten password

A back-office user who cannot sign in resets the password in two calls, without a browser and without credentials. POST /auth/password/forgot/ with the email sends a 6-digit code to that inbox. The reply is the same whether or not the email belongs to a user, so the endpoint cannot be used to find accounts.

curl -s -X POST "https://api.readycms.io/auth/password/forgot/?namespace=<tenant>" \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","language":"en"}'

Then POST /auth/password/reset/ with email, code (as a string, to keep leading zeros) and the new password. The code works once, expires after 15 minutes and stops working after 5 wrong tries (5213; request a new code). The password must be at least 16 characters with a lowercase letter, an uppercase letter, a digit and a special character (5217). A successful reset revokes the user's API token, so every session signs in again, and it does not sign the user in: call /auth/login/ next, which still asks for the two-factor code when the user has one.

curl -s -X POST "https://api.readycms.io/auth/password/reset/?namespace=<tenant>" \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","code":"048213","password":"••••••••••••••••"}'

Authentication error codes

CodeMeaningWhat to do
5202Invalid app credential paramsEnsure app_id, app_secret, and namespace are all present and valid.
5203App auth failed (no match)Wrong secret, or the key is not active/published.
5204Invalid token paramsEnsure token, user_id, and tenant are present.
5205Token not found / mismatchRe-issue the user token.
5206General auth failedNo method succeeded - check which one you intended to use.
5207Token expired / revokedRefresh the user token.
5209Rate limit exceededToo many auth attempts - back off (10 attempts/min per IP).
5211Two-factor code requiredRepeat /auth/login/ with the user's 6-digit otp.
5212Invalid credentialsWrong email, password or one-time code.
5213Too many sign-in attemptsWait a few minutes; 3 failures per 20 minutes are allowed per email.
5214User token invalid, expired or revokedReturned by /auth/refresh/ and /auth/logout/. Log in again.
5215Store not foundThe namespace sent to /auth/login/ or /auth/password/* has no reachable store. Check the store name.
5216Reset code invalid or expiredWrong, used or expired code for /auth/password/reset/. Request a new code.
5217Password too weakUse at least 16 characters with a lowercase letter, an uppercase letter, a digit and a special character.

See the full error code index for every code.

Danger
If a secret is ever exposed - committed to a repo, pasted in a ticket - treat it as compromised and rotate it immediately.