API errors and rate limits

Every error code the API can return, what each one means, and the rate limits and plan limits that apply to a key.

By Peder HellandUpdated September 16, 2026

The error shape

Every failure comes back in the same envelope, with the HTTP status telling you the broad category and code telling you exactly what happened:

{
  "error": {
    "code": "invalid_card",
    "message": "cards[3].target must be at most 2000 characters.",
    "param": "cards[3].target",
    "request_id": "req_8fKd2mXp4LvNc7Bh"
  }
}
  • code is stable and safe to branch on in your script.
  • message is written for a human and may be reworded over time, so do not match on it.
  • param names the exact field, including its index in a batch.
  • request_id also appears in our logs. Quote it if you contact support and we can find the exact request.

Error codes

Authentication - 401

CodeMeaning
invalid_api_keyThe key is missing, malformed, or not one we issued
revoked_api_keyThe key was revoked. Create a new one in settings
expired_api_keyThe key passed its expiry date

These are kept distinct on purpose. You already hold the key, so telling you why it failed turns a confusing dead end into something you can fix yourself.

Permissions - 403

CodeMeaning
insufficient_scopeThe key lacks the scope this endpoint needs. The message names it
deck_not_ownedThe deck exists but belongs to another account
account_pending_deletionThe account is scheduled for deletion

Not found - 404

CodeMeaning
deck_not_foundNo deck with that doc_id
not_foundNo such endpoint
unknown_api_versionThe version in the URL does not exist. The message lists the ones that do

Bad request - 400

CodeMeaning
invalid_requestA required field is missing, or a value is the wrong type or too long
invalid_cardOne card in the batch is invalid. param names which
invalid_custom_fieldA custom field key is not defined on the deck, or its value is invalid
invalid_languageA language code is not in a recognised form
batch_too_largeMore than 100 cards in one request
field_not_patchableYou tried to change a field the API does not let you change
deck_not_emptyA language change was attempted on a deck that already has cards
invalid_cursorThe pagination cursor is not one we issued
unknown_field / unknown_parameterA field or query parameter we do not recognise
invalid_jsonThe body is not valid JSON
idempotency_key_reuseThe same Idempotency-Key was used for a different request

Unknown fields are refused rather than ignored, which means a typo tells you immediately instead of quietly doing nothing.

Limits - 402, 413, 429

CodeStatusMeaning
quota_exceeded402You reached your plan's deck or card limit
payload_too_large413The request body is over 256 KB
rate_limited429Too many requests. See the rate limits below

Everything else - 415, 503, 500

CodeStatusMeaning
unsupported_media_type415The body was not sent as application/json
method_not_allowed405Wrong HTTP method for that path
temporarily_unavailable503The API is paused for maintenance. Retry after the interval in Retry-After
internal500Something broke on our side. Quote the request_id

A 503 means paused, not lost - nothing was written, and the request is safe to retry.

Rate limits

Limits are counted per key, not per account, so one misbehaving script cannot starve the others.

  • 60 requests per minute
  • 5000 requests per day

Creating a deck counts for more than a read, because it is the most expensive thing a runaway loop can do.

Every response - not just a 429 - carries the current state:

HeaderMeaning
X-RateLimit-LimitRequests allowed in the current window
X-RateLimit-RemainingHow many you have left
X-RateLimit-ResetWhen the window resets, as a Unix timestamp in seconds

Headers that only appear once you have already been throttled are no use for avoiding it, which is why they are always there. On a 429 you also get Retry-After, in seconds.

Backing off

Wait for the interval in Retry-After and try again. For everything else, exponential backoff with a few retries is the right pattern - and pair it with an Idempotency-Key on writes so a retry after a timeout cannot duplicate anything.

Do not retry a 4xx other than 429: the request will fail the same way until you change it.

Plan limits

Rate limits cap how fast you can go. Plan limits cap how much you can store, and they are the same limits the web app enforces:

FreePremium
Decks100Unlimited
Cards10,000Unlimited

Crossing one returns 402 quota_exceeded, with a message saying how many you have and how many you can still add. Nothing is written when a request is rejected for quota, so a 402 never leaves you in a half-finished state.

See free plan limits for the full picture, or Yalango Premium to lift them.

Was this article helpful?
0

Comments

Sign in to join the conversation.