Documentation Index Fetch the complete documentation index at: https://docs.cravejs.com/llms.txt
Use this file to discover all available pages before exploring further.
The Crave Storefront API returns standard HTTP status codes with structured error bodies. This reference lists every error you may encounter and how to handle each one.
All error responses follow this structure:
{
"error" : "VALIDATION_ERROR" ,
"message" : "The 'quantity' field must be a positive integer." ,
"statusCode" : 400
}
Field Type Description errorstringMachine-readable error code messagestringHuman-readable description statusCodenumberHTTP status code
Handling errors with the SDK
The SDK throws an ApiError for any non-2xx response:
import { ApiError } from '@craveup/storefront-sdk' ;
try {
await storefront . cart . addItem ( locationId , cartId , payload );
} catch ( error ) {
if ( error instanceof ApiError ) {
console . error ({
status: error . status , // e.g. 400
statusText: error . statusText , // e.g. "Bad Request"
url: error . url , // the request URL
body: error . body , // raw response body (string)
});
// Parse the body for structured error info
const parsed = JSON . parse ( error . body ?? '{}' );
showToast ( parsed . message );
}
}
HTTP status codes
400 — Bad Request
The request body or query parameters are invalid.
Error Message Resolution VALIDATION_ERRORField-specific validation message Check the message for which field failed. Ensure required fields are present and types match. INVALID_PRODUCTProduct ID not found or unavailable Verify the productId exists and is available in the current menu. INVALID_MODIFIER_SELECTIONModifier selection violates group rules Check the modifier group’s min/max rules. Ensure the number of selected options is within range. CART_LOCKEDCart is locked for payment processing The cart cannot be modified while payment is in progress. Wait for completion or create a new session. INVALID_DISCOUNT_CODEDiscount code is invalid or expired Show the user that the promo code could not be applied. Verify the code and try again. MINIMUM_ORDER_NOT_METOrder does not meet the minimum amount Display the minimum order requirement and prompt the user to add more items.
401 — Unauthorized
Authentication failed.
Error Message Resolution MISSING_API_KEYNo API key provided Include the X-API-Key header in your request. INVALID_API_KEYAPI key is invalid or revoked Generate a new API key from the Dashboard. INVALID_AUTH_TOKENCustomer auth token is invalid or expired Refresh the customer’s JWT or redirect to login.
403 — Forbidden
The API key doesn’t have permission for this operation.
Error Message Resolution LOCATION_MISMATCHAPI key is not authorized for this location Use the API key scoped to the target location. Each key is location-specific. OPERATION_NOT_ALLOWEDThis operation is not permitted Check that the endpoint is available for storefront API keys (vs. admin keys).
404 — Not Found
The requested resource doesn’t exist.
Error Message Resolution LOCATION_NOT_FOUNDLocation ID does not exist Verify the locationId parameter. Check the Dashboard for valid IDs. CART_NOT_FOUNDCart ID does not exist or has expired Create a new ordering session to get a fresh cart. Carts expire after inactivity. PRODUCT_NOT_FOUNDProduct not available in current menu The product may be time-restricted. Check the active menu for the current time. MERCHANT_NOT_FOUNDMerchant slug does not match any account Verify the slug used in merchant.getBySlug().
409 — Conflict
The request conflicts with the current state.
Error Message Resolution DISCOUNT_ALREADY_APPLIEDA discount is already applied to this cart Remove the existing discount before applying a new one. SESSION_ALREADY_EXISTSAn ordering session already exists for this cart Reuse the existing session instead of creating a new one.
422 — Unprocessable Entity
The request was well-formed but the data cannot be processed.
Error Message Resolution LOCATION_CLOSEDLocation is not accepting orders at this time Check the order times endpoint and display operating hours to the user. DELIVERY_OUT_OF_RANGEDelivery address is outside the delivery zone Show the user that their address is too far. Use locations.getDistance() to check distance before setting delivery. FULFILLMENT_NOT_AVAILABLEThe selected fulfillment method is not enabled Check location.methodsStatus and only show available methods. INVALID_ORDER_TIMEThe requested order time is not available Fetch fresh order times and let the user pick a valid slot.
429 — Too Many Requests
You’ve exceeded the rate limit.
Error Message Resolution RATE_LIMIT_EXCEEDEDToo many requests Back off and retry. Check the Retry-After or X-RateLimit-Reset header for when to retry.
Rate limit headers:
Header Description X-RateLimit-LimitMaximum requests per window X-RateLimit-RemainingRequests remaining in current window X-RateLimit-ResetUnix timestamp when the window resets
500 — Internal Server Error
An unexpected error on the Crave server.
Error Message Resolution INTERNAL_ERRORAn unexpected error occurred Retry with exponential backoff. If the error persists, contact support.
502 / 503 — Service Unavailable
The API or an upstream service is temporarily unavailable.
Error Message Resolution SERVICE_UNAVAILABLEThe service is temporarily unavailable Retry after a few seconds. Check the Crave status page for outages.
Retry strategy
For transient errors (429, 500, 502, 503), implement exponential backoff:
async function withRetry < T >( fn : () => Promise < T >, maxRetries = 3 ) : Promise < T > {
for ( let attempt = 0 ; attempt <= maxRetries ; attempt ++ ) {
try {
return await fn ();
} catch ( error ) {
if (
error instanceof ApiError &&
[ 429 , 500 , 502 , 503 ]. includes ( error . status ) &&
attempt < maxRetries
) {
const delay = Math . min ( 1000 * 2 ** attempt , 10_000 );
await new Promise (( resolve ) => setTimeout ( resolve , delay ));
continue ;
}
throw error ;
}
}
throw new Error ( 'Max retries exceeded' );
}
// Usage
const cart = await withRetry (() => storefront . cart . get ( locationId , cartId ));
User-facing error messages
Map API errors to friendly messages for your UI:
function getUserMessage ( error : ApiError ) : string {
const body = JSON . parse ( error . body ?? '{}' );
switch ( error . status ) {
case 400 :
return body . message ?? 'Please check your input and try again.' ;
case 401 :
return 'Your session has expired. Please refresh the page.' ;
case 404 :
return 'This item is no longer available.' ;
case 409 :
return body . message ?? 'This action conflicts with your current order.' ;
case 422 :
return body . message ?? 'We cannot process this request right now.' ;
case 429 :
return 'Too many requests. Please wait a moment and try again.' ;
default :
return 'Something went wrong. Please try again.' ;
}
}
Next steps
SDK Reference Full SDK documentation with error handling examples.
REST API REST endpoint reference and tips.
Slack Community Ask questions and get help from the Crave team and community.
Discord Join our Discord server for real-time discussions.