База знань GetMyBot

API Errors

Unified GetMyBot API error format, HTTP status code meanings, and safe retries of money operations through Idempotency-Key.

На цій сторінці

The API communicates errors using standard HTTP status codes and a consistent response body. Successful responses return data directly, without an envelope wrapper.

Error format

On error, the response body is a JSON object with a single error field containing a human-readable message:

{"error":"reaction not found"}

Treat the HTTP status code as the primary signal; use the error text for logs and user-facing hints.

Status codes

  • 200 OK: request succeeded, data in the body.
  • 201 Created: a new resource was created (some POST endpoints).
  • 204 No Content: success with no body (some deletions).
  • 400 Bad Request: invalid request body or parameters.
  • 401 Unauthorized: token is absent, invalid, or expired; or the route is not accessible via a personal token.
  • 402 Payment Required: the action is blocked by a plan or quota (for example, custom media storage requires a premium plan).
  • 403 Forbidden: the token lacks the required scope for this route, or the token holder lacks the required account right (missing cabinet right, see The token's account).
  • 404 Not Found: the resource was not found or does not belong to you.
  • 409 Conflict: state conflict (for example, a duplicate unique value). Second meaning: a request with this Idempotency-Key is still in flight: see below.
  • 413 Payload Too Large: the body exceeds the limit (see rate limits). Requests carrying an Idempotency-Key have their own, lower threshold of 64 KiB.
  • 422 Unprocessable Entity: the body is syntactically valid but fails domain validation. Second meaning: the same Idempotency-Key was already used with a different body: see below.
  • 429 Too Many Requests: rate limit exceeded (see rate limits).
  • 500 Internal Server Error: internal server error; retry later.

How to handle errors

Treat 2xx codes as success. On 401/403, check your token, its scopes, and your account rights. On 429 and 5xx, retry with exponential backoff.

On 4xx (except 429) retrying the request unchanged is pointless: fix the request. With one exception: a 409 on a request carrying an Idempotency-Key does not mean "fix the request", it means "the same operation is running right now". Abandoning the operation here is exactly the wrong move: you would record as failed a payment or a broadcast that is going through. Retry with the same key, honouring the Retry-After in the response.

Retrying money operations: Idempotency-Key

An ordinary retry is safe for reads and dangerous for operations that cost something: a dropped connection does not tell you whether the request arrived. The Idempotency-Key header exists for exactly that: it makes a retry safe.

The key is a canonical UUID (lowercase, hyphenated), for example 9b1f0d4c-2f6a-4a5f-9a3f-1f2f3a4b5c6d. Any other encoding of the same value is refused with 400.

Where it applies

The header is optional but honoured on operations whose repetition costs money or starts a mass send:

  • POST /api/billing/topup: topping up the balance;
  • POST /api/billing/subscribe: taking out a subscription;
  • POST /api/bots/{botID}/reactions/{reactionID}/broadcast: starting a broadcast.

On two operator sends it is, on the contrary, mandatory: without it the request is refused with 400:

  • POST /api/bots/{botID}/users/{userID}/dialog/messages;
  • POST /api/bots/{botID}/support/dialogs/{subscriberID}/templates.

On every other route the header is ignored. Do not treat it as universal duplicate protection: where it is not in the list above, a retry is simply a second request.

What the server answers

  • Same key, same body, operation finished: the server returns the recorded answer of the first attempt: same status code, same body, plus an Idempotent-Replay: true header. The operation happens once. The record is kept for a week.
  • Same key, operation still running: 409 with Retry-After. Retry with the same key after that pause; a fresh key here is precisely what would create a second charge.
  • Same key, different body: 422. This guards against reusing a key for something else: the server cannot know which of the two bodies you meant. Take a new key.
  • Body over 64 KiB: 413. These operations send small bodies; that size means a client-side mistake.

Some answers are deliberately not recorded against the key: 5xx, 408, 425 and 429. They mean "the request was not acted on", so a retry with the same key does the work: as it should. Were they recorded, you would get your own refusal back on every later attempt for a week, and the operation could never be performed under that key.

How to use it

  1. Generate the UUID before the first attempt and store it with the task.
  2. Send the request with that key.
  3. On a dropped connection, timeout, 5xx or 429, retry with the same key, not a new one.
  4. On 409, wait out the Retry-After and retry with the same key.
  5. Take a new key only for a genuinely different operation.

The classic mistake is generating a fresh key on every attempt. The header then looks configured while protecting against nothing: every attempt is a separate operation as far as the server is concerned.

Managed AI and workflow errors

Managed AI uses stable codes such as not_available, not_entitled, budget_exceeded, rate_limited, provider_unavailable, and schema_validation_failed. Retry only errors marked retryable and preserve the idempotency key. Never retry a 4xx or schema error as another provider request.

Copilot can return stale_base; recreate the proposal against the current graph. Policy updates can return 409 on an optimistic version conflict. Reaggregation and replay runs are bounded jobs: poll their status instead of starting duplicates. Meta asset checks return actionable reason codes; the API never includes upstream response bodies or access tokens in an error.

What's next