Breaking: the public API now returns a small set of generic error codes for missing resources, credential failures, and server failures. Branch on code, find the input in param, and read the facts in details[0]. Error handling and Authentication describe each code.
Not found#
An unknown ID in the path, the query, or the body returns 404 RESOURCE_NOT_FOUND. param names where the ID came from, such as order_id, promotion_id, or to_delivery_method_id. details[0].resource_type is the missing resource's type, such as promotion, or delivery_method for to_delivery_method_id, and details[0].resource_id is the ID you sent. It replaces every per-resource code, such as ORDER_NOT_FOUND, GIFT_CARD_NOT_FOUND, PROMOTION_NOT_FOUND, DISCOUNT_NOT_FOUND, SUBSCRIPTION_OFFER_NOT_FOUND, PAYMENT_LINK_NOT_FOUND, CHECKOUT_SESSION_NOT_FOUND, INVOICE_NOT_FOUND, PAYMENT_METHOD_NOT_FOUND, DISPUTE_NOT_FOUND, IMAGE_ASSET_NOT_FOUND, REPORT_NOT_FOUND, the INVENTORY_*_NOT_FOUND codes, DELIVERY_RESOURCE_NOT_FOUND, and CUSTOMER_ACCOUNT_RESOURCE_NOT_FOUND. A missing Flint Wallet, formerly FLINT_WALLET_NOT_FOUND, has details[0].resource_type flint_wallet and no param.
These lookups returned another status and now return 404:
| Former code | Former status |
|---|
CREDIT_NOTE_INVOICE_LINE_NOT_FOUND, MERCHANT_ENVIRONMENT_NOT_FOUND, ORDER_CHARGE_NOT_FOUND, ORDER_LINE_ITEM_NOT_FOUND, REFUND_ADJUSTMENT_NOT_FOUND, RISK_LIST_ALIAS_NOT_FOUND, SANDBOX_NOT_FOUND | 400 |
PAYOUT_DESTINATION_NOT_FOUND, PAYOUT_NOT_FOUND | 409 |
FULFILLMENT_METHOD_UNAVAILABLE for a delivery method that doesn't exist | 409 |
FULFILLMENT_METHOD_UNAVAILABLE stays 409 for a method that isn't active, or for a zone, location set, or rate callback that is missing or not active.
Authentication and authorization#
A credential failure at 401 uses one of two codes:
AUTHENTICATION_REQUIRED when no credential was sent. It replaces API_KEY_REQUIRED, AUTH_REQUIRED, CHECKOUT_SESSION_REQUIRED, CHECKOUT_SESSION_AUTH_REQUIRED, CHECKOUT_CREDENTIAL_REQUIRED, ONBOARDING_SESSION_REQUIRED, CUSTOMER_SESSION_REQUIRED, and BUYER_INVOICE_CREDENTIAL_REQUIRED.INVALID_CREDENTIAL when a credential was sent but can't be used. details[0].reason says why, and remediation.next_steps says what to do for that reason:
details[0].reason | Former codes |
|---|
malformed | INVALID_AUTHORIZATION_HEADER, INVALID_API_KEY, CHECKOUT_SESSION_SECRET_REQUIRED |
unknown | API_KEY_NOT_FOUND, INVALID_OAUTH_TOKEN, INVALID_PARTNER_TOKEN, INVALID_BEARER_TOKEN, INVALID_CHECKOUT_SESSION, INVALID_ONBOARDING_SESSION, INVALID_CUSTOMER_SESSION, BUYER_INVOICE_CREDENTIAL_INVALID, AUTHENTICATION_FAILED |
revoked | API_KEY_REVOKED, and API_KEY_SANDBOX_UNAVAILABLE for a key whose sandbox was archived or is inactive |
expired | API_KEY_EXPIRED, CUSTOMER_SESSION_EXPIRED |
mode_mismatch | API_KEY_MODE_MISMATCH, SANDBOX_SELECTION_REQUIRED for a test key not bound to a sandbox, and API_KEY_SCOPE_UNSUPPORTED |
wrong_credential_type | EXTERNAL_API_KEY_REQUIRED, CHECKOUT_CREDENTIAL_REQUIRED for merchant authentication on a checkout-only route, PARTNER_AUTH_UNSUPPORTED, ONBOARDING_PARTNER_AUTH_UNSUPPORTED |
The reason set can grow, so treat an unfamiliar reason like unknown. EXTERNAL_API_KEY_REQUIRED and the merchant-authentication case of CHECKOUT_CREDENTIAL_REQUIRED returned 403 and now return 401.
A 403 is INSUFFICIENT_SCOPE, unchanged, or FORBIDDEN with details[0].reason set to the former code in lower case, such as checkout_recovery_restricted. FORBIDDEN replaces MERCHANT_ACCESS_REQUIRED, SANDBOX_MANAGEMENT_REQUIRES_LIVE_KEY, PARTNER_APP_MANAGEMENT_REQUIRES_LIVE_KEY, DEMO_SESSION_ROUTE_NOT_ALLOWED, CHECKOUT_LAUNCH_TOKEN_RESTRICTED, CHECKOUT_RECOVERY_RESTRICTED, CHECKOUT_RECOVERY_ATTEMPT_MISMATCH, CHECKOUT_SESSION_PAYMENT_REQUIRED, CHECKOUT_SESSION_ORDER_MISMATCH, OAUTH_CONTEXT_MISMATCH, SANDBOX_NOT_ACCESSIBLE, SANDBOX_SELECTION_FORBIDDEN, and ENVIRONMENT_SELECTION_FORBIDDEN. AUTHORIZATION_FAILED becomes FORBIDDEN with reason not_permitted. Paying an order with your API key and save_payment_method: true stays 403, now FORBIDDEN with reason not_checkout_session and param save_payment_method, because only the buyer's checkout session can save a card.
These keep their codes: 400 AMBIGUOUS_AUTH, 400 SANDBOX_SELECTION_REQUIRED for an onboarding request when the merchant has no default sandbox, 400 ME_CUSTOMER_ID_FORBIDDEN, the 400 cases of CHECKOUT_SESSION_REQUIRED and INVALID_CUSTOMER_SESSION, the refresh-token codes CUSTOMER_SESSION_REFRESH_EXPIRED and CUSTOMER_SESSION_REFRESH_REUSED, the verification codes INVALID_VERIFICATION, VERIFICATION_ALREADY_USED, and VERIFICATION_ATTEMPTS_EXCEEDED, 401 CHECKOUT_SESSION_AUTH_UNAVAILABLE, and refusals that depend on the request rather than the credential, such as CHECKOUT_SESSION_UPDATE_FIELD_NOT_ALLOWED and REQUEST_BLOCKED.
Server errors#
500 INTERNAL_ERROR replaces the 500 codes that asked you to retry the same request, such as IDEMPOTENCY_LOAD_FAILED, SANDBOX_LIST_FAILED, CHECKOUT_SESSION_LOOKUP_FAILED, AUTH_CONTEXT_MISSING, ENVIRONMENT_LOOKUP_FAILED, IDENTITY_RESOLUTION_FAILED, and PAYMENT_METHOD_DOMAINS_UNAVAILABLE.502 EXTERNAL_SERVICE_ERROR replaces ORDER_TAX_CALCULATION_FAILED and PAYMENT_PROCESSOR_ERROR.503 SERVICE_UNAVAILABLE replaces the 503 codes, such as DELIVERY_SERVICE_UNAVAILABLE, DELIVERY_PREVIEW_UNAVAILABLE, CUSTOMER_VERIFICATION_UNAVAILABLE, GIFT_CARDS_UNAVAILABLE, RISK_EVALUATION_UNAVAILABLE, PAYOUT_ENTRIES_UNAVAILABLE, REPORTING_UNAVAILABLE, PAYMENT_METHOD_DOMAIN_REGISTRATION_FAILED, PROCESSING_FEE_PRICING_UNAVAILABLE, IDENTITY_UNAVAILABLE, and OAUTH_UNAVAILABLE. Retry-After is still sent when Flint knows the delay.504 REQUEST_TIMEOUT replaces the other 504 codes.
These server codes stay, because their recovery differs from a plain retry: AUTOMATIC_TAX_UNAVAILABLE, ORDER_TOTALS_UNAVAILABLE, PAYMENT_PROCESSING_UNAVAILABLE, PROFILE_UPDATE_STATUS_UNKNOWN, IDEMPOTENCY_RECOVERY_REQUIRED, DANGLING_EXPANSION_REFERENCE, FLAT_TAX_REFUND_STATE_INVALID, FULFILLMENT_EVENT_SUBJECT_INVALID, SENSITIVE_IDEMPOTENCY_RESULT_INVALID, and the image ingestion codes IMAGE_PROCESSING_FAILED, IMAGE_PROCESSING_CAPACITY_EXCEEDED, IMAGE_PROCESSING_TIMEOUT, IMAGE_SOURCE_TIMEOUT, and IMAGE_SOURCE_UNAVAILABLE. An image that fails processing in a way a retry can't fix returns 400 IMAGE_FORMAT_UNSUPPORTED instead of IMAGE_PROCESSING_FAILED. *_UNAVAILABLE codes returned with a 4xx status, such as PAYMENT_OPTION_UNAVAILABLE and INVENTORY_UNAVAILABLE, keep their names.
Validation#
Four more validation codes now return 400 INVALID_REQUEST, with the same param:
| Former code | details[0].code |
|---|
NULL_NOT_ALLOWED | INVALID_VALUE |
INVALID_FIELD_TYPE | INVALID_VALUE |
UNKNOWN_FIELD | UNKNOWN_FIELD |
INVALID_EXPAND, EXPANSION_LIMIT_EXCEEDED | INVALID_VALUE, with param expand |
Per-operation error codes#
Each operation's x-flint-error-codes is now generated from the route's authentication schemes, body, idempotency, pagination, expand support, path parameters, and handler. It lists exactly the codes the operation can return, top-level code and details[].code alike, and only public codes. A route that takes no body no longer lists body-size or content-type errors, and a route without expand no longer lists expand errors.