Skip to content

Limits, errors and retries.

Rate limits and other limits, idempotency keys, the approval window, and every error code the Agent API and MCP endpoint return, with what to do about each.

Oct 23, 2026
On this page

This page is for developers, and for owners who read an error their AI client showed them. It lists the limits, explains how to repeat a call safely, and gives every error code with the action to take.

MCP tools and the Agent API share one error format and one set of codes. Over HTTP the codes arrive with an HTTP status. Over MCP a failed tool call returns isError: true, and the same JSON is in the result text, so the model can read it and correct itself.

The error envelope

{
  "error": true,
  "code": "VALIDATION_FAILED",
  "message": "The request data did not pass validation.",
  "retry_strategy": "fix_request",
  "details": {
    "errors": { "card_id": ["The card_id field is required."] }
  }
}

details is optional. Framework errors on agent paths use the same envelope.

Retry strategies

Every error declares what to do next.

retry_strategy What to do
no_retry The same request will fail again. Stop, and change the request or the setup.
fix_request Change the input and send it again. Read details and message.
backoff The condition is temporary. Wait, then retry. Honor Retry-After. Retry a change only with the same idempotency key.
retry_later The platform can't do this right now, for example Apple Wallet signing isn't set up. Try later. Don't loop.
contact_support A person must act first: the platform owner turns on a feature, raises a limit or restores an account.

For backoff, wait the Retry-After seconds when the answer has them. Otherwise wait longer after each try, for example 1, 2, 4, 8 and 16 seconds, then stop.

Limits

Limit Value
Requests per key 60 a minute. Each POST to /mcp counts as one request, including initialize and tools/list.
Requests per AI connection 120 a minute for a browser sign-in connection or a key created on the AI connections page.
Requests per network address 3,000 a minute across all keys. The operator can change it with AGENT_IP_RATE_LIMIT. Behind a reverse proxy, set TRUSTED_PROXIES so each caller keeps its own address.
Failed sign-ins 20 a minute per network address and key prefix. Reward Loyalty refuses further attempts before it checks the key.
Request body 256 KiB.
Rows per page of a record list 100, with a total.
Tools per list A connection's tool list stays within 90 tools and 150 KB. Larger sets move into tool families.
Email campaign send Up to 25 emails per call. Send the rest with send_next_campaign_batch.
Webhook test and sample sends 10 a minute per endpoint.
Apple Wallet sample checks 5 a minute.
Voiding achievements 20 a minute for the platform owner.
Browser sign-in 10 client registrations a minute per address. 30 token and revoke requests a minute per address.

A response to an authenticated request carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. A 429 carries Retry-After.

Idempotency

An idempotency key lets you repeat a change without doing it twice. Use it whenever a call might time out.

  • Over MCP, every tool that changes data takes a required idempotency_key argument.
  • Over HTTP, send an Idempotency-Key header. It is optional.
  • Format. 1 to 80 characters from A-Z, a-z, 0-9, hyphen and underscore. A UUID works.
  • A new change gets a new key. Generate a fresh random value for each change.
  • A retry reuses the key. Repeat the same request with the same key. Reward Loyalty returns the stored answer, and over HTTP it adds Idempotent-Replayed: true. Nothing runs twice.
  • A different request under the same key returns 409 IDEMPOTENCY_CONFLICT.
  • A request that is still running returns 409 IDEMPOTENCY_IN_PROGRESS with Retry-After: 1. Retry with the same key. A request that stops without finishing releases its key. Only when its process was killed outright does a later call wait 15 minutes to take the key over.
  • Only successful answers are stored. That includes a 202 that prepared an approval, so a repeat returns the same approval. If a call fails, the key is released and you can try again, with the same key.
  • An idempotency key belongs to one credential and one operation. The same value sent by another connection starts fresh there. Sent again for another record of the same operation, it returns 409 IDEMPOTENCY_CONFLICT.
  • A replay is checked again. If the connection has since lost the scope or the plan feature, the replay is refused and nothing is returned.

Reward Loyalty keeps each stored answer for 7 days, encrypted. The scheduled task agent-receipts-retention removes older ones. It runs with the other scheduled tasks and from the Health center, and it needs no queue worker.

Stored-money operations (selling a stored-money pass, spending from it and reversing a spend) and a purchase sent with a source_reference keep their own retry rules. A stored-money operation takes a UUID as its operation key, in the same header or argument. Production checklist covers purchases.

The approval window

A request for approval closes 10 minutes after the AI client prepared it. The owner's decision doesn't extend it. After the owner approves, the AI client must run the change inside the same 10 minutes. See Approvals.

Error codes

Each row gives the code, the HTTP status, the retry strategy and when it happens. A code whose status or strategy differs by case has a row per case, or says so in its row.

Sign-in and access

Code HTTP Retry When it happens
AUTH_MISSING_KEY 401 no_retry The request carried no credential. Send Authorization: Bearer <key> or X-Agent-Key. At /mcp the answer includes a WWW-Authenticate challenge that points to sign-in discovery.
AUTH_INVALID_KEY 401 no_retry The key is malformed, unknown or wrong. Also: a browser sign-in token is expired or invalid, or it was sent anywhere except /mcp.
AUTH_KEY_REVOKED 401 no_retry The key or connection was ended.
AUTH_KEY_EXPIRED 401 no_retry The key or connection passed its end date.
AUTH_AMBIGUOUS_KEY 400 fix_request The request sent both Authorization: Bearer and X-Agent-Key with different values. Send one.
AUTH_OWNER_INACTIVE 403 contact_support The account that owns the key is inactive. Every key it owns stops working.
AUTH_ANONYMOUS_MEMBER 403 no_retry Anonymous members can't use keys.
AUTH_WRONG_ROLE 403 no_retry The credential's role doesn't fit the endpoint, for example a business key on an admin path, or an admin manager's key on a platform path. At /mcp, an owner who can't connect an AI client (an admin manager or a business sub-role) gets contact_support.
AUTH_INSUFFICIENT_SCOPE 403 no_retry The credential lacks the scope the call needs. details.required_scope names it when one scope is required. Money records need the explicit read:money scope.
FEATURE_DISABLED 403 contact_support A switch, plan feature or permission the call depends on is off. Business keys see it when the Agent API permission is withdrawn or a plan feature is missing. details.permission names the feature when there is one. At /mcp, a business owner without the Agent API gets this answer.
ORIGIN_NOT_ALLOWED 403 no_retry The request carried an Origin header, which means it came from a web page. Call the API from a server or a desktop client.
DEMO_MODE 403 no_retry A demo installation refuses changes and approvals. Reads still work.
DEMO_PREVIEW 403 no_retry A store connection in the demo preview is read-only.
READ_THROUGH_NOT_ALLOWED 403 no_retry The X-Agent-Partner header was sent by a credential that can't use it, or on a path that isn't a business read. Only the platform owner's credential can read another business. Approvals aren't readable through another business.
READ_THROUGH_READ_ONLY 403 no_retry A change was sent with read-through to another business. Reading through works for reads only.
FORBIDDEN 403 no_retry A framework refusal on an agent path with no more specific code. Stored-money operations also use it; see Stored-money passes.

Request shape

Code HTTP Retry When it happens
VALIDATION_FAILED 422 fix_request The request didn't pass validation. details.errors maps each field to its messages. Over MCP, a call whose arguments don't match the tool's schema also fails this way.
BAD_REQUEST 400 fix_request The request couldn't be read.
UNSUPPORTED_MEDIA_TYPE 415 fix_request Send the body as application/json.
PAYLOAD_TOO_LARGE 413 fix_request The body is larger than 256 KiB. details.max_bytes gives the limit. Send fewer items per call.
METHOD_NOT_ALLOWED 405 fix_request The path doesn't accept this method. GET and DELETE on /mcp get this answer with Allow: POST.
NOT_FOUND 404 no_retry The record or path doesn't exist, belongs to someone else, or is hidden from this credential. A wrong approval id or nonce also answers this.
INVALID_FORMAT 422 fix_request GET /tools was called with a format it doesn't offer.
MISSING_CARD_ID 422 fix_request A member discovery call that needs a card_id didn't send one.
MISSING_INPUT 422 fix_request A member discovery call needs a url or an identifier.
UNRESOLVABLE_INPUT 404 fix_request The url or identifier didn't resolve to a card.
CONFLICT 409 no_retry A framework conflict on an agent path with no more specific code.
GONE 410 no_retry A framework answer for a resource that is no longer available.

Limits and capacity

Code HTTP Retry When it happens
RATE_LIMITED 429 backoff A limit was reached. details.scope tells which: the key's own limit (no scope), the network address (ip), failed sign-ins (failed_authentication), or a per-action limit such as test webhooks. Wait for Retry-After seconds.
LIMIT_REACHED 422 contact_support The business reached a plan limit for the thing it tried to create. details names the resource. For member card codes the strategy is fix_request, because a smaller batch fits.
RESOURCE_UNAVAILABLE 404 no_retry The list, form or feature isn't available on this installation or to this account, for example member cards when they are off.

Repeated calls

Code HTTP Retry When it happens
INVALID_IDEMPOTENCY_KEY 422 fix_request The idempotency key isn't 1 to 80 characters from A-Z, a-z, 0-9, hyphen and underscore.
IDEMPOTENCY_CONFLICT 409 fix_request The key was already used for a different request. Use a new key for a new request.
IDEMPOTENCY_IN_PROGRESS 409 backoff A request with this key is still running. Retry with the same key after Retry-After (1 second).

Approval errors

Code HTTP Retry When it happens
APPROVAL_PENDING 409 backoff The owner hasn't decided yet. Give them the review link and try again.
APPROVAL_REJECTED 409 no_retry The owner rejected the change. It won't run.
APPROVAL_STALE 409 fix_request The record changed after the owner reviewed it, or an earlier run failed partway. Check the record, then prepare the change again.
APPROVAL_USED 409 no_retry The approval already ran. Read the approval to get its result.
APPROVAL_EXPIRED 410 fix_request The 10 minutes passed. Prepare the change again.
APPROVAL_IN_PROGRESS 409 backoff The change is running now. Read the approval in a moment.
APPROVAL_REQUIRED 409 no_retry An email send to members was called without an approval the owner gave. Nothing was sent. Prepare the send and let the owner approve it.
APPROVAL_MISMATCH 409 no_retry The request isn't the change the owner approved, so nothing ran. Prepare the change again. A run that couldn't finish answers INTERNAL_ERROR instead.

Server and platform

Code HTTP Retry When it happens
INTERNAL_ERROR 500 backoff An unexpected error. Retry with backoff only if the call is safe to repeat. For a change, check the result first.
UNAVAILABLE 503 backoff The service is temporarily unavailable.
TOOLS_UNAVAILABLE 503 backoff The tool definitions aren't available yet on this installation. Ask the platform owner.
SPEC_UNAVAILABLE 503 backoff The API description could not be read, so Reward Loyalty can't tell whether a change needs approval. It refuses every change until it can read it again, which can happen for a moment while an update rewrites it. Nothing changed, reads still answer, and an approval already given stays open. Try again shortly. If it lasts, ask the platform owner.
PLATFORM_UNAVAILABLE 409 retry_later Apple Wallet signing isn't set up on this platform. Try later. Don't loop.

Changes, corrections and records

Code HTTP Retry When it happens
WRITE_REFUSED 422 fix_request A business owner's change: the dashboard form refused it, and message says why, for example a plan rule or an unoffered choice.
WRITE_REFUSED 409 no_retry A platform owner's change: the console refused it, and message says why.
SETTING_NOT_AGENT_WRITABLE 422 fix_request A setting the Agent API can't change: credentials, uploads, language settings, the AI and Agent API switches, or the billing provider. details names it. Nothing was saved.
CREDENTIALS_EXCLUDED 422 fix_request A store connection change tried to set credentials, tokens or addresses. Those are set in Reward Loyalty. Nothing changed.
TRANSLATION_CONFLICT 409 fix_request A translation edit used an old or missing revision. Read the current texts, then send the batch again with their revisions.
LANGUAGE_POLICY_CONFLICT 409 fix_request The languages changed since the revision was read. Read them again and prepare the change with the current revision.
RETENTION_CHANGED 409 fix_request The activity log retention changed after the purge was prepared. Nothing was deleted.
BLANK_CARDS_CHANGED 409 fix_request The blank cards aren't the ones the owner reviewed. Prepare the deletion again.
RESOURCE_PROTECTED 422 fix_request The record is protected. An email campaign still targets the segment (fix_request), or the club can't be deleted (no_retry).
RECORD_UNDELETABLE 409 no_retry The record is marked undeletable, so the dashboard never deletes it.
LEDGER_ENTRY_CHANGED 409 fix_request A correction named a ledger entry that is no longer the last one. Read the ledger again. If the newest stamp entry was already undone, the strategy is no_retry and the member needs new stamps first.
NOTHING_TO_UNDO 409 no_retry There is nothing left to undo or delete, or the redemption was already voided. Nothing changed.
UNDO_REFUSED 409 no_retry The platform owner's undo was refused for a reason in message, for example the entry can't be undone.
ALREADY_VOIDED 409 no_retry The achievement is already voided.

Counter: points, stamps and vouchers

Code HTTP Retry When it happens
CARD_INACTIVE 422 no_retry The card, its club or the business isn't active.
INSUFFICIENT_POINTS 422 no_retry The member doesn't have enough points for the reward or deduction.
INSUFFICIENT_BALANCE 422 no_retry A member's own redemption asks for more points than any enrolled card holds.
REWARD_NOT_AVAILABLE 422 no_retry The reward isn't on offer: it hasn't started, has ended, or is switched off. For a member key it is 403 when no enrolled card offers it.
REWARD_NOT_LINKED 422 fix_request The reward isn't offered on this card.
TRANSACTION_FAILED 422 fix_request The purchase couldn't be processed. Check the input.
REDEMPTION_FAILED 422 fix_request The redemption couldn't be processed. Check the input.
DEDUCTION_FAILED 422 fix_request The deduction couldn't be processed. Check the input.
STAMP_FAILED 422 no_retry Stamps couldn't be added. message says why.
REDEEM_FAILED 422 no_retry The stamp reward couldn't be redeemed. message says why.
VOUCHER_INVALID 422 no_retry The voucher code isn't valid. details.error_code says why.
VOUCHER_REDEEM_FAILED 422 no_retry The voucher couldn't be redeemed. message says why.
CODE_POOL_EXHAUSTED 422 backoff Every points claim code is in use. Wait for some to expire, then retry.
CODE_ALREADY_USED 409 no_retry The points claim code was already used, so it is kept for its history.
PASS_ISSUE_FAILED 422 no_retry The pass couldn't be sold. message says why.
PASS_SCAN_FAILED 422 no_retry The pass couldn't be scanned. message says why.
PASS_UNDO_FAILED 422 no_retry The last pass visit couldn't be undone. message says why.
PURCHASE_CURRENCY_MISMATCH 422 no_retry The sale currency differs from the card currency. Nothing is recorded. Amounts are never converted.
SOURCE_COMPLETED_AT_OUT_OF_RANGE 422 no_retry A new sale can be at most 7 days old and 5 minutes in the future.
PURCHASE_REFERENCE_IN_FLIGHT 409 backoff The same sale reference is still being processed. Retry the identical request.
PURCHASE_REFERENCE_CONFLICT 409 no_retry The sale reference was recorded with different sale facts. Don't retry.
PURCHASE_REFERENCE_CONSUMED 410 no_retry The original purchase was corrected or removed. The sale stays settled. Don't retry.
PURCHASE_RETRYABLE_FAILURE 503 backoff A temporary failure interrupted the sale. Retry the identical request with backoff.
PURCHASE_CLAIM_KEY_UNAVAILABLE 503 contact_support The application key that protects sale records isn't configured. The operator must restore it from backup.

Email campaigns, store connections and reports

Code HTTP Retry When it happens
CAMPAIGN_CHANGED 409 fix_request The draft, its segment or its audience changed after the owner reviewed it. Nothing was sent.
CAMPAIGN_INCOMPLETE 422 fix_request The draft is missing something it needs before it can send, such as a subject or a body.
CAMPAIGN_NOT_DRAFT 409 no_retry Only a draft can be changed or sent this way. Continue a campaign that is sending with send_next_campaign_batch.
CAMPAIGN_NOT_SENDING 409 no_retry The campaign is still a draft, or has nothing left to send.
CAMPAIGN_SENDING 409 backoff The campaign is sending, so it can't be deleted yet.
INTEGRATION_NOT_CONNECTED 409 no_retry The store is already disconnected. Nothing changed.
INTEGRATION_NOT_ACTIVE 409 no_retry The store connection isn't active, so it can't be paused or used.
INTEGRATION_CANNOT_RESUME 409 no_retry The store connection can't be resumed from its state. details.state shows it.
MEMBER_NOT_IN_PROGRAM 422 fix_request The member isn't in the card's program, so points can't be redeemed for a store coupon.
INVALID_CARD 422 fix_request The card can't be used for a store coupon redemption.
REDEMPTION_REFUSED 422 fix_request The store coupon redemption was refused. message says why.
REDEMPTION_INCOMPLETE 502 contact_support The store coupon redemption didn't finish cleanly. details carries the coupon code and whether points were taken. Check the store.
MONEY_PASS_USE_MONEY_ANALYTICS 409 fix_request The pass holds stored money. Use get_money_pass_analytics.
VISIT_PASS_USE_PASS_ANALYTICS 409 fix_request The pass counts visits. Use get_pass_analytics.

Stored-money passes

Stored-money pass operations (sell_prepaid_pass, spend_pass_money, reverse_pass_money_spend, the pass setup and the money analytics) add the codes below. They arrive in the same envelope. A 422 is fix_request and a 5xx is backoff. A 409 is no_retry, except the conflicts you clear by changing the request (fix_request) and the ones a person must clear (contact_support). The rows below say which. A reused operation key with a different body gets 409 IDEMPOTENCY_CONFLICT with fix_request.

Code HTTP Retry When it happens
MONETARY_PASS_FORMAT_REQUIRED 409 fix_request A pass detail call for a stored-money pass needs pass_format=2. Send it again with that format.
INVALID_PASS_FORMAT 422 fix_request The pass_format value isn't one the API offers.
MONETARY_PASS_REQUIRED 422 fix_request The call needs a stored-money pass and got a visit pass.
INVALID_AMOUNT 422 fix_request An amount isn't a whole number in the currency's minor unit.
INVALID_MONETARY_FIELDS 422 fix_request The request carries fields a stored-money operation doesn't accept.
INVALID_EXTERNAL_REFERENCE 422 fix_request The external reference must be 1 to 100 characters without control characters. external_source must be pos_receipt, invoice or manual_record.
INVALID_REASON 422 fix_request The reason isn't one of the allowed reason codes.
INVALID_OPERATION_KEY 422 fix_request The operation key isn't a UUID.
INVALID_PAYMENT_RECORD 422 fix_request A sale must record payment_received: true and match the product's price and currency.
CURRENCY_MISMATCH 422 fix_request The currency differs from the pass's currency.
INVALID_BALANCE_TYPE 422 fix_request The pass balance_type isn't uses or money.
BALANCE_TYPE_IMMUTABLE 422 fix_request A pass product can't change between visits and money once created.
INVALID_MONETARY_TEMPLATE 422 fix_request The stored-money product settings are invalid.
INVALID_MONETARY_SETUP 422 fix_request The stored-money setup isn't complete or valid.
MONETARY_TEMPLATE_OWNERSHIP_IMMUTABLE 422 fix_request The product's owner can't change.
MONETARY_CURRENCY_LOCKED 422 fix_request The currency can't change after sales exist.
REPORT_PERIOD_REQUIRED 422 fix_request A stored-money report needs a period.
REPORT_CURRENCY_REQUIRED 422 fix_request A stored-money report needs a currency.
REPORT_TIMEZONE_REQUIRED 422 fix_request A stored-money report needs a time zone.
REPORT_RETENTION_GAP 409 no_retry The report period reaches back past the retained data.
UNAUTHORIZED 401 no_retry The key is invalid, inactive, or no longer matches its owner when the stored-money operation checks it.
FORBIDDEN 403 no_retry The key lacks write:passes or write:pass-money, or the pass belongs to another business or club.
MONETARY_PASS_ACTION_REQUIRED 409 fix_request A visit-pass action, such as a scan or an undo of a visit, was sent for a stored-money pass. Use the money action instead.
BUSINESS_UNAVAILABLE 403 no_retry The business can't use stored-money operations now.
MONETARY_SALES_DISABLED 403 no_retry Stored-money sales aren't switched on, ready or allowed for this business or pass.
MONETARY_TEMPLATE_LIMIT 403 no_retry The business reached its limit of stored-money products.
SALE_UNAVAILABLE 403 no_retry The sale can't be used here, for example the member is inactive or the product changed.
MEMBER_UNAVAILABLE 404 no_retry The member can't receive a stored-money pass.
ACCOUNT_RESTRICTED 409 no_retry The pass account is restricted, voided or under integrity review, or its member is inactive.
REFUND_PENDING 409 contact_support A refund is pending on the account, so it can't change until a person settles the refund in Reward Loyalty.
TERMS_CHANGED 409 fix_request The terms version sent with the sale isn't the current one. Read the current terms and send the sale with their version.
SALE_REFERENCE_ALREADY_RECORDED 409 no_retry A sale with this external reference already exists.
SALE_ALREADY_RESOLVED 409 no_retry The sale was already claimed or closed.
SPEND_REFERENCE_ALREADY_RECORDED 409 no_retry A spend with this external reference already exists on the account.
BALANCE_CHANGED 409 fix_request The balance isn't the expected_balance_minor the call sent. Read the balance again, check the spend still makes sense, and send it with the current balance.
INSUFFICIENT_BALANCE 409 no_retry The pass balance is lower than the amount to spend. The member's own reward redemption uses the points code of the same name.
BALANCE_CONFLICT 409 no_retry The entry would take the balance below zero or above the pass's starting balance.
TRANSACTION_ALREADY_REVERSED 409 no_retry The spend was already reversed.
OPERATION_UNAVAILABLE 409 no_retry The earlier result for this operation key isn't available.
RECORD_REMOVED 410 no_retry A privacy removal erased the earlier result. Never replace its key to repeat the money action.