Skip to content

Errors & request_id ​

Every API error uses one consistent JSON shape, so you can handle them all the same way:

json
{
  "error": { "code": "NOT_FOUND", "message": "App not found" },
  "request_id": "req_..."
}
  • error.code — a stable, uppercase machine code. Branch on this, not on the HTTP status or the message text.
  • error.message — a short human-readable explanation. Safe to log; don't parse.
  • error.details — optional, present only when there is something machine-readable to add: retry_after (seconds) on a 429, required (the call's cost in credits) on a 402. New keys may appear; ignore the ones you don't use.
  • request_id — the id of this request. Include it whenever you report a problem.

Request ids ​

Every response — success or error — carries an X-Request-Id header with our id for that request. Log it. You can also send your own X-Request-Id (up to 80 letters, digits, ., _, : or -): we record it next to ours, so a request can be traced by either. It has no effect on metering — every call is charged on its own.

Status codes ​

StatuscodeMeaning
400BAD_REQUESTMissing or invalid parameters.
401UNAUTHORIZEDMissing, malformed, or revoked API key.
402INSUFFICIENT_CREDITSYour balance can't cover the call's cost.
403FORBIDDENThe key isn't allowed to do this.
403ACCOUNT_SUSPENDEDThe account is suspended, so API and MCP access are paused. Contact support.
404NOT_FOUNDNo such resource, or no data for these parameters.
410PAGE_EXPIREDA reviews page was requested out of order, more than about an hour after the previous page, or with a different sort_type. Not charged; read again from page 1. The App Store has only page 1.
422INVALID_PARAMETERSA parameter is outside what the endpoint accepts — its type, allowed values or limits in the API reference — or the data engine rejected it. The message names the parameter.
429RATE_LIMIT_EXCEEDEDToo many requests — see rate limits.
500INTERNAL_ERRORSomething broke on our side. Retry, then report with the request_id.
502UPSTREAM_ERRORThe data engine returned an error.
503UPSTREAM_UNAVAILABLEThe data engine is temporarily unavailable. Retry with backoff.
503MAINTENANCEScheduled maintenance. Nothing is charged; Retry-After and details.ends_at say when it ends.
504UPSTREAM_TIMEOUTThe data engine took too long. Retry with backoff.

400, 404, 410 and 422 are about your request and will fail identically on every retry — fix the parameters instead. 502, 503 and 504 are about us; those are the ones worth retrying with backoff. A 503 also answers a live check (cache=false / force_update=true) the store could not complete — retry it, or drop the flag to get the stored answer. A 503 with MAINTENANCE is planned downtime: wait out Retry-After instead of backing off. 401, 402 and 403 will not change on retry either: they need a key, credits or support.

Repeatable parameters ​

Parameters documented as repeatable (packages, keywords) are lists even when you send one value — ?packages=com.foo and ?packages=com.foo&packages=com.bar are both valid, and a single value is not a special case.

Insufficient credits ​

When your balance can't cover a call, the request is rejected before any work is done — you're never charged for a 402:

json
{
  "error": {
    "code": "INSUFFICIENT_CREDITS",
    "message": "Out of credits. Buy a credit pack at https://appmanai.com/app/billing#packs or wait for your monthly refill of 5,000 on 2026-10-19.",
    "details": { "required": 3 }
  },
  "request_id": "req_..."
}

The message names the way out, links to the page that resolves it, and says when your credits next refresh. All three differ by plan — Free is pointed at the Base upgrade, Base at the credit packs, because a subscriber cannot upgrade any further. There is no overdraft: calls stop rather than running up a bill. An agent seeing a 402 should stop and surface it rather than retrying; retries won't succeed until credits are added.