Skip to content

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 for 400 VALIDATION_FAILED-style responses; maps each invalid field to a message.

HTTP status codes ​

StatusMeaning
200Success.
201Resource created.
400Validation or business-rule failure.
401Authentication failed.
403Authenticated but not allowed.
404Resource not found (or not owned by your merchant).
409Conflict (duplicate).
429Rate limit exceeded — slow down and retry.
5xxServer error — retry with backoff.

Authentication errors ​

codeHTTPMeaning
MISSING_API_KEY401No Authorization: Bearer header.
INVALID_API_KEY_FORMAT401Key does not start with pk_live_.
INVALID_API_KEY401Key does not match any merchant.
MERCHANT_INACTIVE403Merchant account deactivated.

General errors ​

codeHTTPMeaning
REQUEST_FAILED4xxThe request failed before a more specific code could be assigned.
RATE_LIMITED429The API key exceeded its request allowance. Retry after the current window resets.
INTERNAL_ERROR5xxAn unexpected server error occurred. Retry with backoff and provide the X-Request-ID value to support if it continues.

Customer errors ​

codeHTTPMeaning
VALIDATION_FAILED400See errors for field details.
MAX_ADDRESSES_EXCEEDED400Customer already has 5 addresses.
CUSTOMER_NOT_FOUND404Customer not found or not linked to your merchant.
ADDRESS_NOT_FOUND404Address does not exist on this customer.
CUSTOMER_PHONE_DUPLICATE409Phone already exists for your merchant and customer type.
CUSTOMER_EMAIL_DUPLICATE409Email already exists for your merchant and customer type.
CUSTOMER_HAS_ORDERS409Customer has outstanding (non-terminal) orders and cannot be deleted.

Order errors ​

codeHTTPMeaning
CUSTOMER_REQUIRED400customerId missing.
SPECIAL_HANDLING_REQUIRED400specialHandlingTags empty.
INVALID_SPECIAL_HANDLING_TAG400Tag not in the allowed list.
INVALID_PACKAGE_SIDE400packageSide not in the allowed list.
INVALID_AMOUNT_TO_COLLECT400COD amount missing or negative.
AMOUNT_EXCEEDS_TOTAL400COD amount greater than pricing.total.
COD_NOT_ENABLED400COD orders are not enabled for the merchant.
PACKAGE_PHOTO_REQUIRED400Merchant requires a package photo.
INVALID_B2B_SIZE_TIER400orderType is b2b but b2bSizeTier is missing or not in the allowed list.
B2B_CUSTOMER_NOT_BUSINESS400B2B order for a customer that is not a business customer.
B2B_NOT_ENABLED400B2B delivery is not enabled for your merchant.
EXPRESS_NOT_ENABLED400Express delivery is not enabled for your merchant.
B2B_PRICING_NOT_CONFIGURED400No B2B delivery rate is configured for the destination.
VALIDATION_FAILED400Other field errors — see errors.
INSUFFICIENT_WALLET_BALANCE400Wallet cannot cover the delivery fee. Includes data: { required, balance, currency }.
CUSTOMER_NO_DELIVERY_ADDRESS400Customer has no address.
ORDER_NOT_DRAFT400activate called on an order that is not a draft.
ORDER_WINDOW_CLOSED400activate called outside the delivery partner's order window.
ORDER_NOT_EDITABLE403Update called on an order that is not pending.
ORDER_NOT_CANCELLABLE403Cancel called on an order that is not pending.
ORDER_NOT_FOUND404Order not found or not owned by your merchant.
BRANCH_NOT_FOUND404branchId does not exist under your merchant.

Webhook errors ​

codeHTTPMeaning
VALIDATION_FAILED400url missing or not https://, or invalid event names — see errors.
WEBHOOK_NOT_FOUND404Webhook not found or not owned by your merchant.
WEBHOOK_UNREACHABLE502Test ping could not be delivered to the webhook URL.

Rate limiting ​

The integration API allows 600 requests per 15-minute window per API key, with an additional per-IP limit for abuse protection. The response includes standard rate limit headers on every request:

HeaderMeaning
RateLimit-LimitMaximum requests allowed in the window.
RateLimit-RemainingRequests remaining in the current window.
RateLimit-ResetSeconds until the window resets.

When the limit is exceeded you receive 429 Too Many Requests with code RATE_LIMITED. Wait until the window resets (check RateLimit-Reset) before retrying.

Handling errors well ​

  • Branch on code, not message or HTTP status alone.
  • Treat 429 as a signal to back off — wait for RateLimit-Reset seconds before retrying.
  • Treat 5xx as transient — retry with exponential backoff and a sensible cap.
  • Surface errors field messages directly to your own form UI when relevant.
  • Log the full error envelope (minus secrets) for support.

Wasal Delivery Platform · Integration API v1.0.0