How errors work
When a request fails, Tabby responds with a4xx/5xx HTTP status code and a JSON error body:
errors array instead of a single error string:
- Branch your handling on the HTTP status code and
errorType. PossibleerrorTypevalues:bad_data,not_authorized,no_permission,not_found,conflict; a500carriesinternal. erroris a human-readable English message to aid debugging — log it, but don’t parse it and never show it to customers.- On
500or a network failure, retry per your retry policy; for captures and refunds always retry with the same idempotency key — your own uniquereference_idin the request body, see Idempotent requests — so retries can’t duplicate money movement. - Use the base URL that matches the merchant’s region:
api.tabby.ai(UAE, Kuwait) orapi.tabby.sa(KSA) — see Base URLs. Calling the wrong region returns403(see below). - A pre-scoring rejection is not an error:
POST /api/v2/checkoutreturns200 OKwithstatus: "rejected". For handling and the customer-facing rejection messages, see Show rejection.
Quick reference
POST /api/v2/checkout
Creates a checkout session. Authenticate with the Secret Key: Authorization: Bearer {secret_key}.
400 Bad Request — could not decode request
400 Bad Request — could not decode request
400 Bad Request — currency / merchant_code mismatch
400 Bad Request — currency / merchant_code mismatch
currency in the payload does not match the country assigned to your merchant_code (e.g. a UAE merchant_code used with SAR). Use the correct currency for the country.400 Bad Request — field validation failed
400 Bad Request — field validation failed
field points at the offending path. The same envelope covers unsupported currency, wrong formats, and similar per-field issues.400 Bad Request — payment validation failed
400 Bad Request — payment validation failed
error. Read the error field for the specific cause.403 Forbidden — no permission
403 Forbidden — no permission
- You are passing the
tokenparameter, but it is not enabled for your integration. Removetokenfrom the payload. - The request hit the wrong regional base URL — the body then also carries
"error": "merchant region does not match cluster region". Use the base URL that matches the merchant’s region:api.tabby.ai(UAE, Kuwait) orapi.tabby.sa(KSA).
404 Not Found
404 Not Found
404.500 Internal Server Error
500 Internal Server Error
500, contact the Tabby Integrations team and consider hiding Tabby temporarily. Follow tabby-status.com for maintenance and incident updates.GET /api/v2/payments/{id}
Retrieves the current state of a payment. Successful responses and payment statuses are covered in Payment statuses.
400 Bad Request — invalid payment id
400 Bad Request — invalid payment id
payment_id is not a valid UUID. Fix the format.404 Not Found — no such payment
404 Not Found — no such payment
payment_id is visible to your API key — either the id is wrong, or the payment belongs to a different store / API key. Check the payment_id and that you query with the same key that created the session.500 Internal Server Error
500 Internal Server Error
500 persists, contact the Tabby Integrations team and check tabby-status.com.GET /api/v2/payments
Retrieves a list of payments filtered by query parameters. Errors use the same envelopes as GET /api/v2/payments/{id}:
400 Bad Request(bad_data) — an invalid query-parameter value:"error": "failed to decode request".401 Unauthorized(not_authorized) — missing/wrongAuthorizationheader.500 Internal Server Error(internal) — retry per your retry policy.
PUT /api/v2/payments/{id}
Updates a payment (e.g. reference_id). Errors use the same envelopes as the other Payments endpoints:
400 Bad Request(bad_data) — malformed body:"error": "failed to decode request".401 Unauthorized(not_authorized) — missing/wrongAuthorizationheader.404 Not Found(not_found) —"error": "no such payment": wrongpayment_id, or a payment of a different store / API key.500 Internal Server Error(internal) — retry per your retry policy.
POST /api/v2/payments/{id}/captures
Captures funds from an AUTHORIZED payment.
400 Bad Request — invalid amount or body
400 Bad Request — invalid amount or body
amount has a wrong value — negative, too many decimal places, etc. An empty or truncated request body returns the same envelope with "error": "EOF".400 Bad Request — amount exceeds remaining
400 Bad Request — amount exceeds remaining
- Total 100, capture request 150.
- Total 100, one successful capture of 50, another capture for 100.
- Total 100, one successful capture of 100, another capture for 100.
400 Bad Request — already closed
400 Bad Request — already closed
CLOSED state — usually a duplicate capture of an already fully-captured payment, or a capture after close. Check the payment status; if your first capture actually succeeded, no action is needed.400 Bad Request — invalid payment id
400 Bad Request — invalid payment id
payment_id is not a valid UUID. Fix the format.404 Not Found — no such payment
404 Not Found — no such payment
payment_id is visible to your API key — wrong id, or a payment of a different store / API key.409 Conflict — concurrent request
409 Conflict — concurrent request
500 Internal Server Error
500 Internal Server Error
GET /api/v2/payments/{id} first and check already-applied captures before retrying. If 500 persists, contact the Tabby Integrations team and check tabby-status.com.POST /api/v2/payments/{id}/refunds
Refunds a captured (CLOSED) payment.
400 Bad Request — invalid amount format
400 Bad Request — invalid amount format
amount has a wrong value — too many decimal places for the currency, zero or negative ("error": "refund amount is less then or equals zero"), or not a number at all ("error": "error decoding string 'NaN': can't convert NaN to decimal").400 Bad Request — amount exceeds refundable
400 Bad Request — amount exceeds refundable
- Captured 100, refund request 150.
- Captured 100, one successful refund of 50, another refund for 100.
- Captured 100, one successful refund of 100, another refund for 100.
400 Bad Request — cannot refund payment
400 Bad Request — cannot refund payment
CLOSED or has no captures. Check the payment status and act accordingly.400 Bad Request — already closed
400 Bad Request — already closed
GET /api/v2/payments/{id}.404 Not Found — no such payment
404 Not Found — no such payment
payment_id is visible to your API key — wrong id, or a payment of a different store / API key.409 Conflict
409 Conflict
- Active dispute on the payment — the body carries
"error": "payment is disputed". The refund is blocked until the dispute is resolved; see Disputes. - Concurrent refunds on the same payment — the body carries
"error": "could not acquire lock: payment is locked". Another request is being processed; retry shortly with the same idempotency key.
500 Internal Server Error
500 Internal Server Error
GET /api/v2/payments/{id} first and check already-applied refunds before retrying. If 500 persists, contact the Tabby Integrations team and check tabby-status.com.POST /api/v2/payments/{id}/close
Closes an AUTHORIZED payment (e.g. when the order is cancelled before capture).
400 Bad Request — payment already expired
400 Bad Request — payment already expired
AUTHORIZED earlier, but the authorization expired before close was called. No action is needed — the customer is not charged; treat the payment as expired.400 Bad Request — already closed
400 Bad Request — already closed
CLOSED — usually a duplicate close call. No action is needed.400 Bad Request — invalid payment id
400 Bad Request — invalid payment id
payment_id is not a valid UUID. Fix the format.404 Not Found — no such payment
404 Not Found — no such payment
payment_id is visible to your API key — wrong id, or a payment of a different store / API key.500 Internal Server Error
500 Internal Server Error
GET /api/v2/payments/{id} to check the current status before retrying. If 500 persists, contact the Tabby Integrations team and check tabby-status.com.Webhooks — /api/v1/webhooks
Applies to POST /api/v1/webhooks, GET /api/v1/webhooks, GET /api/v1/webhooks/{id}, PUT /api/v1/webhooks/{id}, DELETE /api/v1/webhooks/{id}. Authenticate with the Secret Key.
400 Bad Request — invalid webhook url
400 Bad Request — invalid webhook url
url is not a valid, publicly reachable HTTPS URL. Fix the URL.400 Bad Request — webhook already exists
400 Bad Request — webhook already exists
GET /api/v1/webhooks instead of re-creating.400 Bad Request — max number of webhooks reached
400 Bad Request — max number of webhooks reached
DELETE /api/v1/webhooks/{id} before adding new.400 Bad Request — malformed request
400 Bad Request — malformed request
id in the path is not a valid UUID.404 Not Found — no such webhook
404 Not Found — no such webhook
id exists for your merchant. List the registered webhooks with GET /api/v1/webhooks.500 Internal Server Error
500 Internal Server Error
500 persists, contact the Tabby Integrations team and check tabby-status.com.Disputes — /api/v1/disputes
Applies to GET /api/v1/disputes, GET /api/v1/disputes/{disputeId}, POST /api/v1/disputes/{disputeId}/provide-evidence, POST /api/v1/disputes/approve, POST /api/v1/disputes/challenge, POST /api/v1/disputes/attachments/upload. Authenticate with the Secret Key. See Disputes for the flow itself.
400 Bad Request
400 Bad Request
dispute_id format, missing required fields). Read the error field for the specific cause.404 Not Found — dispute not found
404 Not Found — dispute not found
disputeId is visible to your API key. Check the id against GET /api/v1/disputes.409 Conflict (provide-evidence)
409 Conflict (provide-evidence)
GET /api/v1/disputes/{disputeId} and check its status.500 Internal Server Error
500 Internal Server Error
500 persists, contact the Tabby Integrations team and check tabby-status.com.