Error response format
All error responses follow this structure:| Field | Type | Description |
|---|---|---|
error | string | Machine-readable error code |
message | string | Human-readable description |
statusCode | number | HTTP status code |
Handling errors with the SDK
The SDK throws anApiError for any non-2xx response:
HTTP status codes
400 — Bad Request
The request body or query parameters are invalid.| Error | Message | Resolution |
|---|---|---|
VALIDATION_ERROR | Field-specific validation message | Check the message for which field failed. Ensure required fields are present and types match. |
INVALID_PRODUCT | Product ID not found or unavailable | Verify the productId exists and is available in the current menu. |
INVALID_MODIFIER_SELECTION | Modifier selection violates group rules | Check the modifier group’s min/max rules. Ensure the number of selected options is within range. |
CART_LOCKED | Cart 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_CODE | Discount 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_MET | Order 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_KEY | No API key provided | Include the X-API-Key header in your request. |
INVALID_API_KEY | API key is invalid or revoked | Generate a new API key from the Dashboard. |
INVALID_AUTH_TOKEN | Customer 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_MISMATCH | API key is not authorized for this location | Use the API key scoped to the target location. Each key is location-specific. |
OPERATION_NOT_ALLOWED | This 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_FOUND | Location ID does not exist | Verify the locationId parameter. Check the Dashboard for valid IDs. |
CART_NOT_FOUND | Cart ID does not exist or has expired | Create a new ordering session to get a fresh cart. Carts expire after inactivity. |
PRODUCT_NOT_FOUND | Product not available in current menu | The product may be time-restricted. Check the active menu for the current time. |
MERCHANT_NOT_FOUND | Merchant 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_APPLIED | A discount is already applied to this cart | Remove the existing discount before applying a new one. |
SESSION_ALREADY_EXISTS | An 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_CLOSED | Location is not accepting orders at this time | Check the order times endpoint and display operating hours to the user. |
DELIVERY_OUT_OF_RANGE | Delivery 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_AVAILABLE | The selected fulfillment method is not enabled | Check location.methodsStatus and only show available methods. |
INVALID_ORDER_TIME | The 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_EXCEEDED | Too many requests | Back off and retry. Check the Retry-After or X-RateLimit-Reset header for when to retry. |
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests per window |
X-RateLimit-Remaining | Requests remaining in current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
500 — Internal Server Error
An unexpected error on the Crave server.| Error | Message | Resolution |
|---|---|---|
INTERNAL_ERROR | An 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_UNAVAILABLE | The 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:User-facing error messages
Map API errors to friendly messages for your UI: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.
Email Support
Reach out to hello@craveup.com for direct support.