Appearance
Error Reference
All errors share the standard envelope:
json
{
"success": false,
"message": "Human-readable description",
"code": "MACHINE_READABLE_CODE",
"errors": { "fieldName": "Field-level message" }
}message— a description suitable for logs. Do not match on this string; it may change.code— a stable machine-readable identifier. Match on this.errors— present only for400 VALIDATION_FAILED-style responses; maps each invalid field to a message.
HTTP status codes
| Status | Meaning |
|---|---|
200 | Success. |
201 | Resource created. |
400 | Validation or business-rule failure. |
401 | Authentication failed. |
403 | Authenticated but not allowed. |
404 | Resource not found (or not owned by your merchant). |
409 | Conflict (duplicate). |
429 | Rate limit exceeded — slow down and retry. |
5xx | Server error — retry with backoff. |
Authentication errors
code | HTTP | Meaning |
|---|---|---|
MISSING_API_KEY | 401 | No Authorization: Bearer header. |
INVALID_API_KEY_FORMAT | 401 | Key does not start with pk_live_ or pk_test_. |
INVALID_API_KEY | 401 | Key does not match any merchant. |
MERCHANT_INACTIVE | 403 | Merchant account deactivated. |
Customer errors
code | HTTP | Meaning |
|---|---|---|
VALIDATION_FAILED | 400 | See errors for field details. |
MAX_ADDRESSES_EXCEEDED | 400 | Customer already has 5 addresses. |
CUSTOMER_NOT_FOUND | 404 | Customer not found or not linked to your merchant. |
CUSTOMER_PHONE_DUPLICATE | 409 | Phone already exists for your merchant. |
CUSTOMER_EMAIL_DUPLICATE | 409 | Email already exists for your merchant. |
CUSTOMER_HAS_ORDERS | 409 | Customer has existing orders and cannot be deleted. |
Order errors
code | HTTP | Meaning |
|---|---|---|
CUSTOMER_REQUIRED | 400 | customerId missing. |
SPECIAL_HANDLING_REQUIRED | 400 | specialHandlingTags empty. |
INVALID_SPECIAL_HANDLING_TAG | 400 | Tag not in the allowed list. |
INVALID_PACKAGE_SIDE | 400 | packageSide not in the allowed list. |
INVALID_AMOUNT_TO_COLLECT | 400 | COD amount missing or negative. |
AMOUNT_EXCEEDS_TOTAL | 400 | COD amount greater than pricing.total. |
PACKAGE_PHOTO_REQUIRED | 400 | Merchant requires a package photo. |
VALIDATION_FAILED | 400 | Other field errors — see errors. |
INSUFFICIENT_WALLET_BALANCE | 400 | Wallet cannot cover the delivery fee (production only). Includes data: { required, balance, currency }. |
CUSTOMER_NO_DELIVERY_ADDRESS | 400 | Customer has no address. |
ORDER_NOT_DRAFT | 400 | activate called on an order that is not a draft. |
ORDER_WINDOW_CLOSED | 400 | activate called outside the delivery partner's order window. |
ORDER_NOT_FOUND | 404 | Order not found or not owned by your merchant. |
Webhook errors
code | HTTP | Meaning |
|---|---|---|
VALIDATION_FAILED | 400 | url missing or not https://, or invalid event names — see errors. |
WEBHOOK_NOT_FOUND | 404 | Webhook not found or not owned by your merchant. |
Sandbox errors
code | HTTP | Meaning |
|---|---|---|
SANDBOX_ONLY | 403 | advance-status called with a production key. |
INVALID_STATUS | 400 | Status not in the allowed lifecycle list. |
ORDER_NOT_FOUND | 404 | Sandbox order not found. |
Rate limiting
The integration API allows 600 requests per 15-minute window per API key. The response includes standard rate limit headers on every request:
| Header | Meaning |
|---|---|
RateLimit-Limit | Maximum requests allowed in the window. |
RateLimit-Remaining | Requests remaining in the current window. |
RateLimit-Reset | Seconds until the window resets. |
When the limit is exceeded you receive 429 Too Many Requests. Wait until the window resets (check RateLimit-Reset) before retrying.
Handling errors well
- Branch on
code, notmessageor HTTP status alone. - Treat
429as a signal to back off — wait forRateLimit-Resetseconds before retrying. - Treat
5xxas transient — retry with exponential backoff and a sensible cap. - Surface
errorsfield messages directly to your own form UI when relevant. - Log the full error envelope (minus secrets) for support.
