Every LithosPOS API failure carries a stable machine-readable code alongside a
human-readable message. Branch on code. Messages are translated server-side into the
locale you send in Accept-Language and their wording changes without notice; codes do not.
The developer API and the partner API are different services and return different shapes.
" code " : " developer.grant_missing " ,
" message " : " This app is not authorised for merchant 104271. " ,
" params " : { " companyId " : 104271 }
Field Type Notes error.codestring Stable identifier. Always present error.messagestring Localised, display-ready error.detailsobject | array Field-level validation detail when applicable error.paramsobject Interpolation values used to build the message
" timestamp " : " 2026-07-29T09:14:22.481Z " ,
" message " : " Your app does not have the items.write scope. " ,
" code " : " partner.scope_denied " ,
" params " : { " scope " : " items.write " },
" correlationId " : " f2b1c8a4-9d13-4f77-8c0e-2a5b6e0d3417 "
Field Type Notes statusstring Always the literal "error" statusCodenumber Mirrors the HTTP status timestampstring ISO 8601, server clock pathstring Request path messagestring Localised. 5xx messages are deliberately generic codestring Present for all documented failures; absent for unclassified errors paramsobject Interpolation values correlationIdstring UUID. Log it — support lookups start here
Code Status Meaning developer.email_not_verified403 Sign-in attempted before the verification link was opened developer.too_many_attempts429 Repeated failed sign-ins — the account is locked for a short window developer.account_suspended403 The developer account is suspended; contact the program team developer.refresh_reuse_detected401 A refresh token was presented twice — the whole session family is revoked; sign in again developer.nda_required403 Account has not submitted a program application developer.nda_already_submitted409 A pending application already exists developer.nda_not_approved403 Program application is still pending or was declined developer.agreement_required403 Developer agreement not signed developer.agreement_version_stale409 Signature targets an agreement version that is no longer active — reload and sign the current one
Code Status Meaning developer.not_org_member403 The account is not a member of that organization developer.insufficient_org_role403 Your role in the organization cannot perform this action developer.owner_immutable409 The organization owner cannot be removed or downgraded developer.invite_invalid400 The invitation link is malformed or was already used developer.invite_expired400 The invitation link expired — ask for a new invite
Code Status Meaning developer.product_immutable409 An app’s product cannot change after creation developer.app_archived403 The app is archived; credentials no longer mint tokens developer.app_not_approved403 Production access attempted before review approval developer.review_not_in_review409 Review action attempted from the wrong state developer.sandbox_limit409 The organization already has three active sandbox merchants developer.sandbox_country_unknown400 The country code is not a supported ISO 3166-1 alpha-2 value
Code Status Meaning developer.invalid_client401 Unknown client id, wrong secret or revoked credential — one code for all three, by design developer.merchant_required400 merchant_id omitted and not inferabledeveloper.merchant_not_found404 merchant_id does not existdeveloper.merchant_inactive403 The merchant exists but is not active developer.grant_missing403 No active grant links this app to that merchant developer.env_mismatch403 Sandbox credential against a live merchant, or a production credential against a demo one developer.region_unconfigured503 The merchant’s region has no API base URL configured — contact support
These tables cover the codes an integration will realistically encounter; console-only flows
(email verification, password reset, profile) carry additional developer.* codes that follow
the same envelope.
Code Status Meaning Fix partner.scope_denied403 The route needs a scope your product bundle does not include Use an app with the right product partner.env_mismatch403 Token environment does not match the merchant’s demo flag Use the matching credential partner.ip_denied403 Source address is not on the credential’s allowlist Update the allowlist, or call from the declared egress partner.grant_missing403 The grant was revoked after the token was minted Re-mint; if it still fails, the merchant link is gone partner.rate_limited429 More than 300 requests in the current minute Back off — see rate limits partner.window_too_large400 A report window exceeds 31 days Split the range partner.invalid_window400 from/to is missing, malformed, or to precedes fromSend both as YYYY-MM-DD partner.order_not_found404 The online-order id does not exist in this merchant Check the id returned at creation partner.acting_user_unavailable409 The merchant has no employee record to attribute writes to Contact the merchant — their account is not fully set up
These come from the shared data layer and can surface on any partner route.
Code Status Meaning db.duplicate409 A unique constraint rejected the write — usually a repeated barcode, code or name db.not_found404 The referenced row does not exist in this merchant company.not_provisioned503 The merchant’s database is not ready yet. Retry shortly
Request bodies are validated strictly. Unknown properties are rejected , not ignored, so
a typo in a field name fails loudly instead of silently dropping data.
" timestamp " : " 2026-07-29T09:20:03.117Z " ,
" message " : " groupId must be a number; property 'grupId' should not exist " ,
" correlationId " : " 0b7a5c11-84c2-4f0a-9f2f-7c1e40d6b8aa "
Validation failures have no code — the message names the offending fields.
Situation Action 429Wait until X-RateLimit-Reset, then retry. Do not retry immediately 503 company.not_provisionedRetry with exponential backoff, up to about a minute Other 5xx Retry up to three times with jittered backoff 401 on a partner callMint a fresh token once, then retry. If it fails again, stop Any other 4xx Do not retry — fix the request
Writes are not idempotent
There are no idempotency keys in this version of the API. A retried POST that actually
succeeded the first time creates a second record. Retry writes only on network errors where
you never saw a response, and reconcile with a read before retrying anything else.