K
KiflyDeveloper Docs
Sign up →
Reference

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.

CodeStatusRetryableWhat it means
UCP_AGENT_PROFILE_REQUIRED401noSend a UCP-Agent header naming your published agent profile.
UCP_AGENT_PROFILE_INVALID400noThe UCP-Agent profile is not a usable https URL.
UCP_AGENT_PROFILE_RESERVED400noThe UCP-Agent profile is on a reserved domain or IP that nobody can fetch.
INVALID_PROFILE_URI400noThe agent profile URI could not be parsed.
INVALID_PROFILE_HASH400noThe agent profile hash is malformed.
SELLER_SCOPE_REQUIRED400noName the seller this call applies to.
INVALID_OTP401noThat verification code is wrong or expired.
INVALID_BODY400noThe request body did not match the expected shape.
INVALID_REQUEST_BODY400noThe request body did not match the expected shape.
INVALID_JSON400noThe request body was not valid JSON.
INVALID_PARAMS400noOne or more query parameters were rejected.
VALIDATION_FAILED422noThe request parsed but is not semantically valid.
INVALID_CURSOR400noThe cursor belongs to a different search, or is not a cursor Kifly issued.
INVALID_LIMIT400noThe limit parameter is out of range.
INVALID_SINCE400noThe since parameter is not a usable timestamp.
QUERY_TOO_LONG400noThe search query is longer than the platform limit.
INVALID_DELIVERS_TO400noThe delivers_to destination needs an ISO alpha-2 country, plus optional region, city or postal code.
METHOD_NOT_ALLOWED405noThat method is not served on this path.
ENDPOINT_DEPRECATED410noThis endpoint is retired. The response names its replacement.
IDEMPOTENCY_KEY_REQUIRED400noEvery mutating call needs an Idempotency-Key header.
IDEMPOTENCY_KEY_INVALID400noThe Idempotency-Key must be 16 to 64 characters.
IDEMPOTENCY_CONFLICT409noThat Idempotency-Key was already used with a different body.
SESSION_ID_REQUIRED400noName the checkout session this call applies to.
HANDLE_REQUIRED400noName the seller handle.
SELLER_HANDLE_REQUIRED400noName the seller handle.
SELLER_HANDLE_NOT_SUPPORTED400noA seller-scoped key already implies its seller. Drop the handle.
INVALID_WIDGET_EVENT_BATCH400noThe widget event batch was rejected.
CART_NOT_FOUND404noNo cart with that id, or it is not yours.
ITEM_NOT_FOUND404noNo line item with that id on this cart.
SESSION_NOT_FOUND404noNo checkout session with that id.
RECEIPT_NOT_FOUND404noNo receipt for that token.
DOC_NOT_FOUND404noNo documentation page with that slug. The response lists them all.
BUYER_NOT_FOUND404noNo buyer matches that token.
CART_CLOSED409noThis cart is closed. Start a new one.
CART_LOCKED_PAID409noThis cart is paid and can no longer change. Start a new one.
CART_SELLER_MISMATCH409noA cart holds one seller's products. Use a separate cart per seller.
CART_EMPTY400noThis cart has no items to act on.
EMPTY_PRICED_CART422noNothing in this cart carries a price.
CART_TOTAL_EXCEEDS_LIMIT400noThe cart total is over the platform limit. get_platform_limits has the number.
QUANTITY_EXCEEDS_LIMIT400noThat quantity is over the per-item limit.
INSUFFICIENT_STOCK409noFewer units are in stock than requested.
MEASURE_AMOUNT_REQUIRED400noThis product is sold by measure. Say how much.
MEASURE_AMOUNT_NOT_SUPPORTED400noThis product is not sold by measure.
MEASURE_AMOUNT_OUT_OF_RANGE400noThat measure is outside what the seller offers.
MIXED_FULFILLMENT400noOne cart cannot mix items fulfilled by Kifly with items fulfilled by the seller.
SHIP_TO_REQUIRED400noA shipping address is needed before this step.
INVALID_SHIPPING_ADDRESS400noThat shipping address was rejected.
INVALID_ADDRESS422noThat address could not be used.
INVALID_SHIPPING400noThe shipping details on this cart are not usable.
DELIVERY_UNAVAILABLE400noThis seller does not deliver to that address.
PAYMENT_REQUIRED402noPayment is required. The challenge names how to pay.
X402_PAYMENT_REJECTED402noThe x402 payment proof was rejected.
INVALID_X_PAYMENT400noThe X-Payment header could not be parsed.
INVALID_PAYMENT_SIGNATURE400noThe payment signature did not verify.
CURRENCY_NOT_SUPPORTED400noThat 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.

CodeStatusRetryableWhat it means
UNAUTHORIZED401noThis capability needs a Kifly token. Browsing, carts, payment links and feedback do not.
FORBIDDEN403noThe credential is valid but lacks the scope this call needs.
SELLER_KEY_REQUIRED403noThis call needs a seller-scoped key.
NETWORK_KEY_REQUIRED403noThis call needs a network key, not a seller-scoped one.
EMBED_TOKEN_REQUIRED403noThis call is for the on-site widget and needs its embed key.
BUYER_TOKEN_REQUIRED400noThis call needs a buyer token.
MISSING_BUYER_TOKEN400noSend 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.

CodeStatusRetryableWhat it means
CART_LOCKED_CHECKOUT409yesA checkout is in flight on this cart. Wait for it to settle.
VARIANT_SNAPSHOT_MISSING409yesNo cached price for that variant while the catalog is unreachable.
SHIPPING_PERSIST_FAILED502yesThe address could not be saved. Try again.
RATE_LIMIT429yesToo many requests. Retry after the stated delay.
RATE_LIMITED429yesToo many requests. Retry after the stated delay.
MEDUSA_UNAVAILABLE503yesThe commerce engine is unreachable.
STRIPE_UNAVAILABLE503yesThe payment processor is unreachable.
SHOPIFY_UNAVAILABLE503yesThe seller's storefront is unreachable.
SEARCH_UNAVAILABLE503yesSearch is temporarily unavailable.
SELLER_UNAVAILABLE503yesSeller data is temporarily unavailable.
REGISTRY_UNAVAILABLE503yesThe registry is temporarily unavailable.
CHECKOUT_UNAVAILABLE503yesCheckout is temporarily unavailable.
X402_FACILITATOR_UNAVAILABLE503yesThe x402 facilitator is unreachable.
CART_CREATE_FAILED503yesThe cart could not be created. Try again.
CART_LINES_UNAVAILABLE503yesThe cart's line items could not be read. Try again.
CART_FETCH_FAILED502yesThe cart could not be read. Try again.
CART_STATE_UNAVAILABLE503yesCart state is temporarily unreadable.
TRANSIENT_UPSTREAM_ERROR503yesA dependency failed transiently. Try again.
INTERNAL_ERROR503yesSomething 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.

CodeStatusRetryableWhat it means
PRODUCT_NOT_FOUND404noNo product with that id.
VARIANT_NOT_FOUND422noNo variant with that id on this product.
SELLER_NOT_FOUND404noNo seller matches that handle, domain or name.
SELLER_AMBIGUOUS409noMore than one seller matches that name. Retry with a handle.
VARIANT_OUT_OF_STOCK409noThat variant is out of stock.
PRODUCT_UNAVAILABLE409noThat product cannot be bought right now.
VARIANT_UNPRICED422noThat variant carries no price, so it cannot be sold.
SELLER_NOT_ACTIVE409noThat seller is not currently trading.
SELLER_NOT_PAYOUT_READY409noThis seller cannot be paid out yet, so the cart cannot settle.
X402_NOT_CONFIGURED501noThe x402 rail is not enabled here. Use the payment link.
SELLER_NOT_X402_READY409noThis seller does not settle over x402. Use the payment link.
AUTONOMOUS_RAIL_NOT_AVAILABLE409noNo autonomous rail is available for this cart.
SHOPIFY_NATIVE_HANDOFF_ONLY409noThis 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.

CodeStatusRetryableWhat it means
AGENT_DENIED403noThis agent is blocked from the network.
ORIGIN_NOT_ALLOWED403noThis embed key is not allowed from that origin.
NATIVE_CHECKOUT_UNMAPPED409noThis cart cannot be mapped onto the seller's own checkout.
PRICE_CHANGED409noThe seller's price changed since this cart was built. Re-confirm the new price with the buyer.
PAYMENT_LINK_FAILED502noThe payment link could not be created.
SERVER_MISCONFIGURED500noKifly is misconfigured for this call. Reporting it is the fastest fix.
SELLER_SCOPE_MISSING500noThis key is missing its seller binding. Reporting it is the fastest fix.

fix: "none" — Nothing to do

The request reached a final state.

CodeStatusRetryableWhat it means
CART_NOT_CANCELABLE409noThis 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

EndpointLimit
/api/mcp120 req / 60 s per token
/api/agent/*60 req / 60 s per token
/api/agent/feedback10 req / 60 s per token

Responses include x-ratelimit-limit, x-ratelimit-remaining, and x-ratelimit-reset headers on every request.

Error Reference: Kifly Docs