Error Reference
Every agent-facing failure returns the same envelope. Branch on code and fix. Never parse error or message — that prose is written for people and is reworded freely.
{
"error": "cart_not_found",
"code": "CART_NOT_FOUND",
"fix": "change_input",
"retryable": false,
"docs": "https://kifly.ai/docs/errors#cart_not_found",
"request_id": "req_0b4f…"
}
Always present: error, code, fix, retryable, docs, request_id.
Present where they add something: message, next_step, required_scope, retry_after_seconds, details.
code decides the HTTP status, not the other way round. One code is always returned with the same status, so a client that branches on code never has to disambiguate by reading the status too.
request_id rides every failure, in the body and in the x-request-id header. Quote it in a bug report and we can find the exact request.
On MCP, the identical detail arrives as structuredContent on the tool result, alongside the human sentence. There is nothing to parse there either.
The machine-readable version of this page, generated from the same source, is at GET /api/agent/errors — 102 codes.
What to do, by fix
fix: "change_input" — Fix the request, then call again
The call will keep failing identically until an argument changes.
| Code | Status | Retryable | What it means |
|---|---|---|---|
UCP_AGENT_PROFILE_REQUIRED | 401 | no | Send a UCP-Agent header naming your published agent profile. |
UCP_AGENT_PROFILE_INVALID | 400 | no | The UCP-Agent profile is not a usable https URL. |
UCP_AGENT_PROFILE_RESERVED | 400 | no | The UCP-Agent profile is on a reserved domain or IP that nobody can fetch. |
INVALID_PROFILE_URI | 400 | no | The agent profile URI could not be parsed. |
INVALID_PROFILE_HASH | 400 | no | The agent profile hash is malformed. |
SELLER_SCOPE_REQUIRED | 400 | no | Name the seller this call applies to. |
INVALID_OTP | 401 | no | That verification code is wrong or expired. |
INVALID_BODY | 400 | no | The request body did not match the expected shape. |
INVALID_REQUEST_BODY | 400 | no | The request body did not match the expected shape. |
INVALID_JSON | 400 | no | The request body was not valid JSON. |
INVALID_PARAMS | 400 | no | One or more query parameters were rejected. |
VALIDATION_FAILED | 422 | no | The request parsed but is not semantically valid. |
INVALID_CURSOR | 400 | no | The cursor belongs to a different search, or is not a cursor Kifly issued. |
INVALID_LIMIT | 400 | no | The limit parameter is out of range. |
INVALID_SINCE | 400 | no | The since parameter is not a usable timestamp. |
QUERY_TOO_LONG | 400 | no | The search query is longer than the platform limit. |
INVALID_DELIVERS_TO | 400 | no | The delivers_to destination needs an ISO alpha-2 country, plus optional region, city or postal code. |
METHOD_NOT_ALLOWED | 405 | no | That method is not served on this path. |
ENDPOINT_DEPRECATED | 410 | no | This endpoint is retired. The response names its replacement. |
IDEMPOTENCY_KEY_REQUIRED | 400 | no | Every mutating call needs an Idempotency-Key header. |
IDEMPOTENCY_KEY_INVALID | 400 | no | The Idempotency-Key must be 16 to 64 characters. |
IDEMPOTENCY_CONFLICT | 409 | no | That Idempotency-Key was already used with a different body. |
SESSION_ID_REQUIRED | 400 | no | Name the checkout session this call applies to. |
HANDLE_REQUIRED | 400 | no | Name the seller handle. |
SELLER_HANDLE_REQUIRED | 400 | no | Name the seller handle. |
SELLER_HANDLE_NOT_SUPPORTED | 400 | no | A seller-scoped key already implies its seller. Drop the handle. |
INVALID_WIDGET_EVENT_BATCH | 400 | no | The widget event batch was rejected. |
CART_NOT_FOUND | 404 | no | No cart with that id, or it is not yours. |
ITEM_NOT_FOUND | 404 | no | No line item with that id on this cart. |
SESSION_NOT_FOUND | 404 | no | No checkout session with that id. |
RECEIPT_NOT_FOUND | 404 | no | No receipt for that token. |
DOC_NOT_FOUND | 404 | no | No documentation page with that slug. The response lists them all. |
BUYER_NOT_FOUND | 404 | no | No buyer matches that token. |
CART_CLOSED | 409 | no | This cart is closed. Start a new one. |
CART_LOCKED_PAID | 409 | no | This cart is paid and can no longer change. Start a new one. |
CART_SELLER_MISMATCH | 409 | no | A cart holds one seller's products. Use a separate cart per seller. |
CART_EMPTY | 400 | no | This cart has no items to act on. |
EMPTY_PRICED_CART | 422 | no | Nothing in this cart carries a price. |
CART_TOTAL_EXCEEDS_LIMIT | 400 | no | The cart total is over the platform limit. get_platform_limits has the number. |
QUANTITY_EXCEEDS_LIMIT | 400 | no | That quantity is over the per-item limit. |
INSUFFICIENT_STOCK | 409 | no | Fewer units are in stock than requested. |
MEASURE_AMOUNT_REQUIRED | 400 | no | This product is sold by measure. Say how much. |
MEASURE_AMOUNT_NOT_SUPPORTED | 400 | no | This product is not sold by measure. |
MEASURE_AMOUNT_OUT_OF_RANGE | 400 | no | That measure is outside what the seller offers. |
MIXED_FULFILLMENT | 400 | no | One cart cannot mix items fulfilled by Kifly with items fulfilled by the seller. |
SHIP_TO_REQUIRED | 400 | no | A shipping address is needed before this step. |
INVALID_SHIPPING_ADDRESS | 400 | no | That shipping address was rejected. |
INVALID_ADDRESS | 422 | no | That address could not be used. |
INVALID_SHIPPING | 400 | no | The shipping details on this cart are not usable. |
DELIVERY_UNAVAILABLE | 400 | no | This seller does not deliver to that address. |
PAYMENT_REQUIRED | 402 | no | Payment is required. The challenge names how to pay. |
X402_PAYMENT_REJECTED | 402 | no | The x402 payment proof was rejected. |
INVALID_X_PAYMENT | 400 | no | The X-Payment header could not be parsed. |
INVALID_PAYMENT_SIGNATURE | 400 | no | The payment signature did not verify. |
CURRENCY_NOT_SUPPORTED | 400 | no | That currency is not settled on this rail. |
fix: "add_credential" — Get a credential, or a wider scope
The request itself is fine. See the OAuth metadata at /.well-known/oauth-authorization-server, which supports Dynamic Client Registration.
| Code | Status | Retryable | What it means |
|---|---|---|---|
UNAUTHORIZED | 401 | no | This capability needs a Kifly token. Browsing, carts, payment links and feedback do not. |
FORBIDDEN | 403 | no | The credential is valid but lacks the scope this call needs. |
SELLER_KEY_REQUIRED | 403 | no | This call needs a seller-scoped key. |
NETWORK_KEY_REQUIRED | 403 | no | This call needs a network key, not a seller-scoped one. |
EMBED_TOKEN_REQUIRED | 403 | no | This call is for the on-site widget and needs its embed key. |
BUYER_TOKEN_REQUIRED | 400 | no | This call needs a buyer token. |
MISSING_BUYER_TOKEN | 400 | no | Send the x-kifly-buyer-token header. |
fix: "wait_and_retry" — Retry the same call later
Nothing is wrong with the request. Back off using retry_after_seconds where it is present, and reuse the same Idempotency-Key.
| Code | Status | Retryable | What it means |
|---|---|---|---|
CART_LOCKED_CHECKOUT | 409 | yes | A checkout is in flight on this cart. Wait for it to settle. |
VARIANT_SNAPSHOT_MISSING | 409 | yes | No cached price for that variant while the catalog is unreachable. |
SHIPPING_PERSIST_FAILED | 502 | yes | The address could not be saved. Try again. |
RATE_LIMIT | 429 | yes | Too many requests. Retry after the stated delay. |
RATE_LIMITED | 429 | yes | Too many requests. Retry after the stated delay. |
MEDUSA_UNAVAILABLE | 503 | yes | The commerce engine is unreachable. |
STRIPE_UNAVAILABLE | 503 | yes | The payment processor is unreachable. |
SHOPIFY_UNAVAILABLE | 503 | yes | The seller's storefront is unreachable. |
SEARCH_UNAVAILABLE | 503 | yes | Search is temporarily unavailable. |
SELLER_UNAVAILABLE | 503 | yes | Seller data is temporarily unavailable. |
REGISTRY_UNAVAILABLE | 503 | yes | The registry is temporarily unavailable. |
CHECKOUT_UNAVAILABLE | 503 | yes | Checkout is temporarily unavailable. |
X402_FACILITATOR_UNAVAILABLE | 503 | yes | The x402 facilitator is unreachable. |
CART_CREATE_FAILED | 503 | yes | The cart could not be created. Try again. |
CART_LINES_UNAVAILABLE | 503 | yes | The cart's line items could not be read. Try again. |
CART_FETCH_FAILED | 502 | yes | The cart could not be read. Try again. |
CART_STATE_UNAVAILABLE | 503 | yes | Cart state is temporarily unreadable. |
TRANSIENT_UPSTREAM_ERROR | 503 | yes | A dependency failed transiently. Try again. |
INTERNAL_ERROR | 503 | yes | Something failed on our side. Try again. |
fix: "choose_another" — Pick a different item, variant or seller
This one cannot serve the request, however the call is phrased.
| Code | Status | Retryable | What it means |
|---|---|---|---|
PRODUCT_NOT_FOUND | 404 | no | No product with that id. |
VARIANT_NOT_FOUND | 422 | no | No variant with that id on this product. |
SELLER_NOT_FOUND | 404 | no | No seller matches that handle, domain or name. |
SELLER_AMBIGUOUS | 409 | no | More than one seller matches that name. Retry with a handle. |
VARIANT_OUT_OF_STOCK | 409 | no | That variant is out of stock. |
PRODUCT_UNAVAILABLE | 409 | no | That product cannot be bought right now. |
VARIANT_UNPRICED | 422 | no | That variant carries no price, so it cannot be sold. |
SELLER_NOT_ACTIVE | 409 | no | That seller is not currently trading. |
SELLER_NOT_PAYOUT_READY | 409 | no | This seller cannot be paid out yet, so the cart cannot settle. |
X402_NOT_CONFIGURED | 501 | no | The x402 rail is not enabled here. Use the payment link. |
SELLER_NOT_X402_READY | 409 | no | This seller does not settle over x402. Use the payment link. |
AUTONOMOUS_RAIL_NOT_AVAILABLE | 409 | no | No autonomous rail is available for this cart. |
SHOPIFY_NATIVE_HANDOFF_ONLY | 409 | no | This seller settles on their own checkout. Hand the buyer the link. |
fix: "ask_human" — A human has to act
Surface it to the person you are acting for, or report it with submit_feedback.
| Code | Status | Retryable | What it means |
|---|---|---|---|
AGENT_DENIED | 403 | no | This agent is blocked from the network. |
ORIGIN_NOT_ALLOWED | 403 | no | This embed key is not allowed from that origin. |
NATIVE_CHECKOUT_UNMAPPED | 409 | no | This cart cannot be mapped onto the seller's own checkout. |
PRICE_CHANGED | 409 | no | The seller's price changed since this cart was built. Re-confirm the new price with the buyer. |
PAYMENT_LINK_FAILED | 502 | no | The payment link could not be created. |
SERVER_MISCONFIGURED | 500 | no | Kifly is misconfigured for this call. Reporting it is the fastest fix. |
SELLER_SCOPE_MISSING | 500 | no | This key is missing its seller binding. Reporting it is the fastest fix. |
fix: "none" — Nothing to do
The request reached a final state.
| Code | Status | Retryable | What it means |
|---|---|---|---|
CART_NOT_CANCELABLE | 409 | no | This cart is past the point where it can be cancelled. |
Common pitfalls (not errors — a valid 200 that isn't what you expected)
"My search only ever returns one seller's products." You're holding a seller API key (kfa_live_). It authenticates as that one store and is scoped to it at the database level — this is intentional (a seller key must never read another seller's catalog), not a bug, and it returns a normal 200 because from its own point of view the request succeeded. There is no way to widen a seller key's scope after the fact. If you need the whole network, switch to OAuth or a network key (kfn_live_) — see MCP Integration → Authentication.
Retry strategy
Retry when retryable is true. Use exponential backoff starting from retry_after_seconds where the body carries it, and the Retry-After header on a 429.
Always reuse the same Idempotency-Key when retrying — that is what makes a retry exactly-once even if the network drops after the server commits.
Rate limits
| Endpoint | Limit |
|---|---|
/api/mcp | 120 req / 60 s per token |
/api/agent/* | 60 req / 60 s per token |
/api/agent/feedback | 10 req / 60 s per token |
Responses include x-ratelimit-limit, x-ratelimit-remaining, and x-ratelimit-reset headers on every request.