Errors
Every error has a stable code, a message for you, and often a message you can show the user as-is.
Format
Errors use standard HTTP statuses and this body:
{
"error": {
"code": "RULE_VIOLATION",
"message": "The user hasn't allowed purchases at Target.",
"display_message": "You haven't allowed this app to buy from Target.",
"request_id": "req_2f3m0b4w5w546x1i0d29"
}
}codeis stable. Branch on it.messageis for you and your logs.display_message, when present, is written for the end user.request_idis also in theHarbor-Request-Idheader on every response. Include it when you email us.
A checkout that fails after it was created isn't an HTTP error: it comes back with status: "failed" and the same error object on the checkout.
Codes
| Code | HTTP | Meaning | What to do |
|---|---|---|---|
INVALID_REQUEST |
400 | A field is missing or wrong, the body isn't JSON, or an offer expired. | Fix the request. The message names the field. |
INVALID_API_KEY |
401 | The key is missing, wrong, or rolled. | Check Authorization: Bearer hk_…. |
INVALID_USER_TOKEN |
401 | The Harbor-User-Token is missing, wrong, or from another environment. |
Send the user through Approve again. |
INVALID_PUBLIC_TOKEN |
400 | The public token is wrong, expired, or already exchanged. | Start a new approval. |
NOT_FOUND |
404 | No such object for this key and user. | Check the id and environment. |
MERCHANT_NOT_SUPPORTED |
422 | Harbor can't reach this store yet. | See Stores and routes. |
MERCHANT_BLOCKED |
502 | The store refused or failed to answer. | Retry later. |
CONNECTION_NEEDS_USER |
409 | The user hasn't connected this store, or the connection needs them. | Send them through Approve. |
PRICE_CHANGED |
409 | The price moved since the offer. | Usually handled as a confirm next action. |
OUT_OF_STOCK |
409 | The item can't be bought now. | Tell the user. |
RULE_VIOLATION |
403 | The order breaks the user's limits or allowed stores. | Show display_message. |
USER_ACTION_REQUIRED |
409 | You called confirm before the checkout was ready. | Handle next_action first. |
PAYMENT_DECLINED |
402 | The store declined the payment. | Ask the user to check their payment method. |
BILLING_REQUIRED |
402 | Your account used this month's free live allowance and has no payment method. | Add one in the dashboard under Settings → Billing. Sandbox is never affected. |
RATE_LIMITED |
429 | Too many requests. | Back off and retry. |
IDEMPOTENCY_KEY_IN_USE |
409 | A request with the same Idempotency-Key is still running. |
Retry shortly with the same key. |
INTERNAL_ERROR |
500 | Something broke on our side. | Retry, and send us the request_id. |