Error Catalog

What you'll learn

  • The standard error response format used across all API endpoints
  • Every error code the API can return, organized by domain
  • HTTP status codes and when each is used
  • Best practices for handling errors in your frontend

Prerequisites


Overview

The Blaze ECOM Storefront API uses a consistent error format across all endpoints. Every error response follows the JSON specification, returning one or more structured error objects in an errors array.

Errors are identified by a machine-readable code field (e.g., empty_cart, invalid_token) which stays stable across API versions, making it safe to match against in your frontend logic. The detail field provides a human-readable message suitable for displaying to end users.


Error Response Format

All error responses return a JSON body with the following structure:

{
  "errors": [
    {
      "code": "empty_cart",
      "status": 400,
      "detail": "The cart is empty.",
      "fields": [],
      "extra_info": {}
    }
  ]
}

Error Object Fields

Field Type Description
code string | null Machine-readable error code (e.g., empty_cart, invalid_token). Stable across versions. May be null for generic validation errors.
status integer HTTP status code for this error (e.g., 400, 401, 404).
detail string Human-readable error message. Safe to display to end users.
fields string[] List of field names related to the error (e.g., ["email"], ["phone_number"]). Empty array when not field-specific.
extra_info object Additional context for the error. Structure varies by error type. Empty object when no extra context is available.

Multiple Errors

A single response can contain multiple errors — for example, when an Ecto changeset validation fails on several fields:

{
  "errors": [
    {
      "code": null,
      "status": 422,
      "detail": "can't be blank",
      "fields": ["email"],
      "extra_info": {}
    },
    {
      "code": null,
      "status": 422,
      "detail": "can't be blank",
      "fields": ["password"],
      "extra_info": {}
    }
  ]
}

Extra Info Examples

Some errors include extra_info with additional context:

Cart already submitted — includes the order UUID so the frontend can redirect:

{
  "code": "cart_already_submitted",
  "status": 400,
  "detail": "This cart has already been submitted",
  "fields": [],
  "extra_info": {
    "order": { "uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }
  }
}

Invalid promo code — echoes back the code that was rejected:

{
  "code": "invalid_promo_code",
  "status": 400,
  "detail": "Coupon code does not exist.",
  "fields": ["promo_code"],
  "extra_info": {
    "promo_code": "SUMMER20"
  }
}

Invalid cart items — lists the items that are problematic:

{
  "code": "invalid_cart",
  "status": 400,
  "detail": "Invalid items in the cart",
  "fields": ["cart"],
  "extra_info": {
    "items": [{ "id": "item-uuid", "reason": "out_of_stock" }]
  }
}

POS API error codes — external error codes from integrated POS systems:

{
  "code": "bad_request",
  "status": 400,
  "detail": "Inventory type does not match",
  "fields": [],
  "extra_info": {
    "api_error_code": "TZ00003"
  }
}

HTTP Status Codes

Status Code Meaning When It's Used
400 Bad Request Invalid input, business rule violations, missing fields, cart errors, payment issues. The most common error status.
401 Unauthorized Invalid or expired JWT token, wrong credentials, inactive user, invalid SSO token.
403 Forbidden User does not have permission to access the resource.
404 Not Found Resource does not exist (store, product, order, kiosk, etc.).
422 Unprocessable Entity Ecto changeset validation failures — field-level validation errors on create/update.
429 Too Many Requests Rate limit exceeded. See Rate Limiting.
500 Internal Server Error Unexpected server error. These are never intentional — report them to support.

Error Codes by Domain

Authentication Errors

Error Code HTTP Status Message When It Occurs
bad_login 401 Wrong Credentials Email/phone and password combination is incorrect.
inactive_user 401 The user for the given credentials is inactive. The account exists but has been deactivated.
user_is_not_confirmed 400 User was not confirmed User has not completed account confirmation (e.g., email/phone verification). Also returned when trying to reset password or update email for an unconfirmed user.
phone_number_requires_confirmation 400 Phone number requires confirmation. Login or registration requires phone verification before proceeding.
email_requires_confirmation 400 Email requires confirmation. Login or registration requires email verification before proceeding.
invalid_verification_code 400 Invalid verification code The verification code submitted during phone/email confirmation is wrong.
verification_not_available 400 Verification is no longer available. Request another code. The verification code has expired. A new one must be requested.
failed_to_request_verification_code 400 Failed to request verification code. The system was unable to send a verification code (SMS/email provider failure).
verification_code_blocked 400 Failed to request verification code. Too many verification code requests — the user is temporarily blocked.
account_already_verified 400 There is a verified account with the phone number {phone}. Attempting to verify an account when another verified account already uses that phone number.
invalid_token 400 This token is no longer valid. Please request another link. Password reset or email confirmation token has expired or already been used.
invalid_credentials 401 Invalid user credentials. Generic authentication failure — credentials do not match any account.
invalid_sso_token 401 Invalid or expired SSO token SSO token provided in the request is invalid or has expired.
missing_authorization_header 401 Missing Authorization header An authenticated endpoint was called without the Authorization: Bearer header.
bad_current_password_match 400 Current password is wrong Password change failed because the current password provided doesn't match.
invalid_password 400 The password does not match with your existing account in the Blaze point of sales. User tried to register with an email/phone that exists in the POS but provided the wrong POS password.
pos_not_allowed 401 The user for the given credentials is not allowed access to the store's POS. User is authenticated but not authorized for POS access.
url_expired 403 URL expired A time-limited URL (e.g., magic link) has expired.
logout_unsuccessful 400 Logout was unsuccessful. Server-side logout failed (token invalidation error).

OAuth & SSO Errors

Error Code HTTP Status Message When It Occurs
oauth_login_missing_client 400 You must provide a client ID OAuth login request is missing the client_id parameter.
oauth_login_invalid_client 400 Invalid client ID The client_id provided does not match a registered OAuth application.
oauth_login_missing_store 400 You must provide a store ID OAuth login request is missing the store identifier.
oauth_login_invalid_store 400 Invalid store ID The store ID in the OAuth request does not match a valid store.
oauth_auth0_failed_to_register 400 Failed to register user with Auth0: {detail} Auth0 provider rejected the user registration.
authentication_oauth_invalid_state 400 Invalid state parameter The OAuth state parameter doesn't match expected value (possible CSRF).
authentication_oauth_missing_redirect_uri 400 Missing redirect URI OAuth request is missing the required redirect_uri.
authentication_oauth_invalid_redirect_uri 400 Invalid redirect URI The redirect_uri does not match any registered redirect URIs.
authentication_oauth_invalid_callback 400 Invalid callback parameters OAuth callback received invalid or missing parameters.

User & Account Errors

Error Code HTTP Status Message When It Occurs
invalid_user 400 Sorry, we couldn't find any user matching your information. No user matches the provided fields (used during registration/lookup).
email_already_exists 400 Email is already in use. Please contact Retailer Support. Attempting to register or update with an email that another account already uses.
phone_already_exists 400 Phone number is already in use. Please contact Retailer Support. Attempting to register or update with a phone number that another account already uses.
locked_verified_user_uploads 400 Need to update your ID/Medical Info? Please contact Support. User tried to change ID/medical documents on a verified account.
name_and_dob_update_not_alowed 400 Need to update your name or birthday info? Please contact Support. User tried to update name or date of birth on a verified account.
user_is_not_linked 400 User is not linked to any POS profile Sync was requested but the user has no linked POS profile.
non_customer_user 400 User is not a customer An operation requiring a customer role was attempted by a non-customer user.
invalid_phone_number 400 Invalid phone number The phone number format is invalid.
us_phone_number_required 400 US phone number is required. The operation requires a US-formatted phone number.
verified_phone_number_required 400 Phone number must be verified. The operation requires a verified phone number.
registration_with_email_is_required 400 Email is required for registration Store settings require an email address during registration.
registration_with_phone_is_required 400 Phone number is required for registration Store settings require a phone number during registration.
registration_with_drivers_license_id_is_required 400 Driver's License ID is required for registration Store settings require a driver's license ID during registration.
registration_with_state_residency_is_required 400 State residency is required for registration Store settings require state residency information during registration.
consumer_not_found 404 User not found The referenced user/consumer does not exist.
failed_to_update_email 400 The email could not be updated in the POS. Please contact us. Email update was rejected by the POS system.
failed_register 400 Oops, looks like this is not the phone number we have on file in the POS. Please try again or contact us to access your account. Phone-based registration failed because the POS has a different phone number on file.
expected_same_email_for_phone_number 400 A different email was found assigned to {phone}. Please contact us. The phone number exists in the POS but is linked to a different email.
expected_one_result_for_phone_number 400 Your phone is associated with multiple profiles in our different stores. Please contact us to setup your profile. Phone number matches multiple POS profiles across stores.
expected_one_result_for_email 400 Your email is associated with multiple profiles in our different stores. Please contact us to setup your profile. Email matches multiple POS profiles across stores.
expected_one_result_for_drivers_license 400 Your driver's license is associated with multiple profiles in our different stores. Please contact us to setup your profile. Driver's license matches multiple POS profiles.
no_matching_email_to_dl_match 400 POS profile unable to match email and ID, please contact us to update your profile. Email and ID document don't match the same POS profile.
no_matching_phone_to_dl_match 400 POS profile unable to match phone and ID, please contact us to update your profile. Phone and ID document don't match the same POS profile.
age_not_allowed 400 The allowed minimum age is {age} User does not meet the store's minimum age requirement.
dob_is_required 400 Please update your date of birth in your profile. Date of birth is missing and required for the requested operation.
user_already_verified 400 The identity of this user is already verified by {service} Identity verification was requested but user is already verified.
unique_email_already_confirmed 400 There's already a confirmed customer with the same email ({email}). You can't reset the password and activate this User Cannot activate a user because another confirmed user has the same email.
user_active_on_pos 400 Only customers deactivated on POS can be reset Account reset is only available for POS-deactivated customers.
not_a_member 400 The POS still has not accepted your membership User's membership is pending POS acceptance.
user_is_no_store_manager 400 User is no store manager. Operation requires store manager role.
group_mismatch 400 Customer and store groups do not match Customer belongs to a different group than the requested store.
resource_id_mismatch 400 Resource ID in the URL and data do not match The id in the URL path doesn't match the id in the JSON data payload.

Cart Errors

Error Code HTTP Status Message When It Occurs
empty_cart 400 The cart is empty. Attempting to submit or validate an empty cart.
invalid_cart 400 Invalid items in the cart Cart contains items that are invalid (unavailable, wrong inventory type, etc.). extra_info.items lists the problematic items.
invalid_cart_item 400 Your order has one or more unavailable items One or more cart items are no longer available for purchase.
invalid_item 404 This product is no longer available A specific product referenced in the cart no longer exists or is delisted.
out_of_stock 400 This product is out of stock for your location A cart item is out of stock at the relevant location/ZIP code. extra_info includes item details.
invalid_promo_code 400 Coupon code does not exist. The promotion/coupon code is invalid, expired, or not applicable. extra_info.promo_code echoes back the rejected code.
duplicate_promo_code 400 Coupon already applied The promo code has already been applied to this cart.
cannabis_weight_limit_exceeded 400 Your order has exceeded the cannabis weight limit by {amount} {uom}. Cart exceeds the legal cannabis weight limit for the jurisdiction.
cart_already_submitted 400 This cart has already been submitted Cart was already submitted as an order. extra_info.order.uuid contains the order ID.
cart_already_processing 400 This cart is already being processed A submission is already in progress for this cart.
cart_total_changed 400 Your cart totals have changed, please confirm new values Cart totals were recalculated and differ from what the user confirmed. Frontend should re-validate.
under_order_minimum 400 Cart is under the minimum total ${amount}. Cart total is below the store's minimum order amount.
cart_data_required_for_customer 400 Additional shopping cart data is required for this payment processor The payment processor requires additional cart data that is missing.
invalid_cart_submission_state_transition 400 Cart submission status transition to '{next}' failed. Cart submission state machine rejected the transition.
failed_to_submit_cart 400 There was a unexpected problem submitting the cart. Please try again. Server-side error during cart submission.

Order Errors

Error Code HTTP Status Message When It Occurs
order_already_paid 400 This order has already been paid. Payment was attempted on an order that is already paid.
order_already_completed 400 This order has already been completed. An action was attempted on an already-completed order.
order_user_mismatch 400 Order belongs to another user. User tried to access or modify an order that belongs to a different account.
order_sync_limit_reached 400 This order has reached the limit of days to sync. Order can no longer be synced with the POS because the time window has expired.
related_order_not_found 404 Related order not found. A referenced order (e.g., for reorder or tip) does not exist.
already_tipped 400 Tip already processed. A tip was already applied to this order.

Payment Errors

Error Code HTTP Status Message When It Occurs
payment_failed 400 Payment authorization failed. Payment authorization or capture was declined by the payment processor. extra_info may include order.uuid.
missing_payment_source 400 Online payment requires a payment source. No payment source (card, bank) was provided for an online payment.
invalid_payment_source 400 Some required fields are missing for adding the payment source. Payment source is missing required fields. fields lists the missing ones.
missing_payment_source_identifier 400 Online payment requires a payment source id or token Neither a payment source ID nor a tokenized card was provided.
expired_payment_token 400 Online payment card has expired. Please try again. The payment card token has expired.
invalid_payment_token 400 Online payment card is invalid. Please try another one. The payment card token is invalid or rejected.
payment_source_not_found 400 Online payment source not found. The referenced payment source does not exist.
payment_customer_not_found 400 Online payment customer not found. No matching customer record exists at the payment processor.
payment_option_not_found 400 Online payment option not found. The selected payment option is not configured for this store.
charge_not_authorized 400 Payment not yet authorized. Attempting to capture a payment that has not been authorized.
charge_canceled 400 Payment canceled by {service}. The payment was canceled by the payment service.
no_match_for_payment 400 The given payment does not match the associated order. Payment details don't match the order they're being applied to.
no_match_for_payment_customer 400 Customer does not match the one from the external payment source data. Customer on the order doesn't match the customer on the payment source.
guest_cannot_add_source 400 Cannot add sources in guest checkout. Guest checkout users cannot save payment sources.
missing_billing_address 400 Billing address is required. Payment processor requires a billing address.
missing_payment_postal_code 400 Online payment requires a postal code. Payment processor requires a postal code for card verification.
missing_payment_cres 400 Invalid challenge result (cres) 3D Secure challenge response is missing or invalid.
missing_payment_cavv 400 Can't authenticate cardholder 3D Secure CAVV (cardholder authentication) is missing.
missing_cardholder_name 400 Missing cardholder name Cardholder name is required by the payment processor.
missing_transaction_id 400 Online payment requires a transaction ID. Transaction ID is required but was not provided.
missing_customer_signature 400 Missing customer signature Customer signature is required for this payment method.
missing_customer_auth_key 400 Missing customer auth key Customer authentication key is required for bank account operations.
missing_curstomer_return_url 400 Missing return URL for bank account connection Return URL is required for bank account linking flow.
multiple_bank_accounts 400 Only a single active bank account is supported for making payments User has multiple active bank accounts but the processor only supports one.
invalid_payment_secret_key 400 External payment secret key is invalid. Payment provider secret key configuration is incorrect.
invalid_payment_public_key 400 External payment public key is invalid. Payment provider public key configuration is incorrect.
not_found_payment_config 404 Payment configuration was not found. No payment configuration exists for the store.
invalid_payment_config 400 External payment configuration is invalid. Payment configuration is malformed or incomplete.
invalid_payment_account_config 400 External payment configurations in a group must be for the same payment service account. Group stores have mismatched payment accounts.
tips_not_allowed 400 Tips are not allowed for the selected payment option The payment method does not support tipping.
promotions_not_allowed 400 Promotions are not allowed for the selected payment option The payment method does not support promotions.
invalid_gift_card_amount 400 Invalid gift card amount. Gift card amount is invalid (e.g., zero, negative, or exceeds limits).

Delivery & Address Errors

Error Code HTTP Status Message When It Occurs
missing_zip_code 400 Zip code is required. Delivery address is missing a ZIP/postal code.
invalid_zip_code 400 Zip code is invalid for {country}. ZIP/postal code format is invalid for the specified country.
missing_address 400 Address is required. Delivery address is required but not provided.
geo_data_required 400 Delivery address geo location data is required for this delivery mode. Delivery mode requires latitude/longitude coordinates.
zip_code_required 400 Delivery address Zip Code is required for this delivery mode. Delivery mode requires a ZIP code for zone-based delivery.
no_deliveries_at_location 400 Sorry, we don't deliver to that location. The delivery address is outside the store's delivery area.
no_delivery_fee 400 We don't do deliveries to that location. No delivery fee is configured for the given location (delivery unavailable).
schedule_closed 400 Sorry, our schedule is closed for express delivery. Express delivery is not available at the current time.

Store & Configuration Errors

Error Code HTTP Status Message When It Occurs
bad_request 400 Missing X-Store header. The required X-Store header was not included in the request.
bad_request 400 Missing X-Group header. The required X-Group header was not included (group endpoints).
bad_request 400 Missing X-App-Mode header. The required X-App-Mode header was not included.
bad_request 400 Missing X-Kiosk header. The required X-Kiosk header was not included (kiosk endpoints).
not_found 404 Store does not exist. The store UUID in X-Store doesn't match any store.
not_found 404 Group does not exist. The group UUID in X-Group doesn't match any group.
not_active 404 Store is not active. The store exists but is deactivated.
bad_request 404 Group is inactive. The group exists but is inactive.
not_found 404 Kiosk does not exist. The kiosk UUID in X-Kiosk doesn't match any kiosk.
not_active 400 Kiosk is not active. The kiosk exists but is deactivated.
kiosk_not_from_store 400 Kiosk does not belong to the specified store. The kiosk UUID doesn't belong to the store specified in X-Store.
kiosk_not_allowed 400 This store does not allow Kiosks Kiosk mode is not enabled for this store.
developer_key_invalid 400 Developer Key is invalid. The Blaze developer key is invalid.
blaze_developer_key_missing 400 Blaze developer key is missing. Blaze developer key was not provided for POS integration.
invalid_pos_api_key 400 Online Store Code is invalid. The POS API key/store code is invalid.
invalid_integration 400 Invalid POS integration. The POS integration type is not recognized.
store_pos_config_mismatch 400 The shop for the given keys does not match. POS configuration keys don't match the store.
another_pos_is_configured 400 Store already has another POS configured. Trying to add a POS when one is already configured.
only_one_pos_allowed 400 Only one POS can be integrated with a store. Multiple POS integrations are not supported.
not_available_for_pos 400 {pos} POS does not support this action. The requested action is not available for the store's POS type.
missing_store_site 400 Store requires a site for integrations. Store needs a site configured before integrations can be set up.
page_exists 400 footer link already exists A store page with the same name already exists.
group_name_already_exists 400 The given group name already exists. Group creation failed because the name is taken.
missing_pos_integration_data 400 Missing POS integration data. POS integration data is required but not provided.
group_already_has_plan 400 The given group already has a Plan ({existing}), and it's different from the one specified ({given}). Group already has a different plan assigned.
deployment_integration_not_configured 400 There is no deployment integration configured. Deployment action requires an integration that hasn't been set up.
no_sms_provider 400 SMS provider not defined in the store Store has no SMS provider configured for sending verification codes.
inactive_service_config 400 {service} configuration is inactive. A required third-party service configuration is inactive.
missing_service_config 400 {service} configuration is missing. A required third-party service configuration doesn't exist.
another_rewards_system_is_configured 400 Please deactivate the currently active reward service. Can't add a new rewards system while another is active.
invalid_service_config 400 API Key configuration is invalid. Third-party service API key is invalid.
invalid_template_key 400 Berbix template key configuration is invalid. Identity verification template key is misconfigured.
sh_deferred_capture_is_on 400 This cannot be changed while the POS Split Payment setting is active. Configuration change blocked because POS split payment is active.
pos_not_allowed_for_reset 400 POS is not allowed for account reset The store's POS type does not support account reset.

Marketing & Promotions Errors

Error Code HTTP Status Message When It Occurs
invalid_marketing_source 400 The given marketing source is not valid for this store. Marketing source value is not in the store's configured list.
required_marketing_source 400 The marketing source is required in this store. Store requires a marketing source but none was provided.
marketing_source_not_allowed 400 Marketing source is not allowed in this store. Marketing source feature is disabled for this store.
invalid_update_campaign_status 400 Only draft or scheduled campaigns can be edited. Attempting to edit a campaign that is already sent or in progress.
target_stores_not_from_group 400 Target stores ({stores}) are not from this group. Campaign targets stores outside the group.

Loyalty & Rewards Errors

Error Code HTTP Status Message When It Occurs
no_loyalty 400 No Loyalty provider found for store. Store has no loyalty program configured.
no_growth 400 No Growth provider found for store. Store has no Growth loyalty/rewards provider configured.
multiple_matching_accounts 400 Multiple ECOM accounts found for matching member. Please contact support. Loyalty member matches multiple ECOM accounts.
member_is_banned 400 Unable to check in customer Loyalty member is banned. extra_info.member_id is included.
member_not_in_queue 400 Unable to check in customer Loyalty member is not in the check-in queue.

Identity Verification Errors

Error Code HTTP Status Message When It Occurs
missing_identity_verification_data 400 Missing identity verification data Required identity verification fields are missing.
invalid_document_type 400 Invalid document type The uploaded document type is not accepted.
invalid_file_format 400 Invalid file format The uploaded file format is not supported.
s3_key_length_exceeded 400 Upload failed. The URL is larger than what is currently allowed. File upload URL exceeds length limits.

General Errors

Error Code HTTP Status Message When It Occurs
bad_request 400 Invalid request parameters Generic invalid request — usually malformed JSON or missing required fields.
not_found 404 Not found. The requested resource does not exist.
forbidden 403 Client not allowed to access the requested resource User does not have permission for the requested action.
required 400 Field is required. A required field is missing. fields specifies which one.
not_supported 400 Functionality not supported The requested functionality is not available.
invalid_value 400 Invalid value for {field}. A field has an invalid value. fields specifies which field and valid choices may be listed.
product_recommendations_not_allowed 400 Product recommendations are not allowed for this store. Product recommendation feature is disabled.
unsupported_geometry_type 400 Unsupported geometry type. GeoJSON geometry type is not supported (delivery zones).
cannot_update_keys 400 Cannot update payment configuration keys. Payment config keys are locked and cannot be changed.
not_implemented 400 Export is not implemented for {resource}. Data export is not available for the requested resource type.
invalid_data_for_webhook_url 400 Can't build the webhook URLs. Webhook URL generation failed due to missing configuration.

Changeset Validation Errors

Ecto changeset errors are returned with HTTP status 422 and a null code. These are field-level validation errors that occur on create and update operations.

{
  "errors": [
    {
      "code": null,
      "status": 422,
      "detail": "can't be blank",
      "fields": ["email"],
      "extra_info": {}
    }
  ]
}

Common changeset validation messages include:

Message When It Occurs
can't be blank A required field was not provided.
has already been taken A unique field (email, phone) already exists.
is invalid Field value doesn't match the expected type or format.
has invalid format Field value doesn't match the expected pattern (e.g., email format).
must be at least N character(s) String field is shorter than the minimum length.
must be at most N character(s) String field exceeds the maximum length.
is not a valid email Email format validation failed.

Handling Errors

General Strategy

  1. Check status first — Route to the appropriate handler based on HTTP status code.
  2. Match on code — Use the machine-readable code for specific error handling logic.
  3. Display detail — Show the detail message to the user.
  4. Use extra_info — Leverage additional context when available (e.g., redirect to an order on cart_already_submitted).

JavaScript Example

async function handleApiResponse(response) {
  if (response.ok) return response.json();

  const body = await response.json();
  const errors = body.errors || [];
  const firstError = errors[0];

  switch (response.status) {
    case 401:
      // Session expired or invalid credentials
      if (firstError?.code === "inactive_user") {
        showNotification("Your account has been deactivated.");
      } else {
        clearAuth();
        redirectToLogin();
      }
      break;

    case 403:
      redirectToLogin();
      break;

    case 404:
      showNotification("The requested resource was not found.");
      break;

    case 429:
      const retryAfter = response.headers.get("Retry-After") || 30;
      await delay(retryAfter * 1000);
      // Retry the request
      break;

    default:
      // Handle by error code
      handleErrorByCode(firstError);
  }
}

function handleErrorByCode(error) {
  switch (error?.code) {
    case "cart_already_submitted":
      const orderUuid = error.extra_info?.order?.uuid;
      if (orderUuid) redirectToOrder(orderUuid);
      break;

    case "cart_total_changed":
      revalidateCart();
      break;

    case "phone_number_requires_confirmation":
    case "email_requires_confirmation":
      redirectToVerification();
      break;

    case "out_of_stock":
    case "invalid_cart_item":
    case "invalid_cart":
      refreshCart();
      showNotification(error.detail);
      break;

    default:
      showNotification(error?.detail || "An error occurred.");
  }
}

Error Code Constants

Define error codes as constants to avoid typos:

const ErrorCodes = {
  EMPTY_CART: "empty_cart",
  INVALID_CART: "invalid_cart",
  INVALID_CART_ITEM: "invalid_cart_item",
  OUT_OF_STOCK: "out_of_stock",
  CART_ALREADY_SUBMITTED: "cart_already_submitted",
  CART_TOTAL_CHANGED: "cart_total_changed",
  INVALID_PROMO_CODE: "invalid_promo_code",
  DUPLICATE_PROMO_CODE: "duplicate_promo_code",
  PAYMENT_FAILED: "payment_failed",
  PHONE_REQUIRES_CONFIRMATION: "phone_number_requires_confirmation",
  EMAIL_REQUIRES_CONFIRMATION: "email_requires_confirmation",
  INVALID_TOKEN: "invalid_token",
  BAD_LOGIN: "bad_login",
  INACTIVE_USER: "inactive_user",
  MISSING_AUTHORIZATION: "missing_authorization_header",
  NO_DELIVERIES_AT_LOCATION: "no_deliveries_at_location",
};

Best Practices

  1. Always check the errors array — Never assume a single error. Multiple validation errors can occur simultaneously.
  2. Use code for logic, detail for display — Codes are stable; messages may change between versions.
  3. Handle 401 globally — Set up a response interceptor that catches 401s and redirects to login.
  4. Handle cart_already_submitted gracefully — Use the extra_info.order.uuid to redirect the user to their order instead of showing a raw error.
  5. Handle cart_total_changed by re-validating — When prices change between cart load and submission, re-fetch the cart and ask the user to confirm.
  6. Don't ignore fields — When fields is populated, highlight the relevant form fields for the user.
  7. Log extra_info.api_error_code — POS-originated errors include an api_error_code that can help your support team diagnose issues.