Merchant API
References

Errors

A closed union of error codes. Switch on the code, not the message.

Every Merchant API error response carries the same envelope:

{
  "error": {
    "code": "validation_failed",
    "message": "amount must be a positive integer string"
  }
}

The code field is a value in a closed union. Adding a code is a compatibility break that gets versioned and announced. You can — and should — write a switch over the union and cover every branch.

The message is human-readable detail for logs and dashboards. Do not parse it. Do not branch on it.

The closed union

CodeTypical HTTPMerchant meaning
api_key_missing401No Authorization header was sent.
api_key_malformed401The header was present but the value was not a valid key.
api_key_invalid401The key was not recognised.
api_key_revoked401The key was valid but has been revoked. Rotate.
merchant_inactive401The merchant is disabled or soft-deleted.
merchant_kyb_not_approved403KYB is not in approved state. Money operations are gated until approval.
ip_not_allowed403The request IP address is not in the merchant IP allowlist.
rate_limited429Too many requests on this key. Back off and retry.
validation_failed400The request body or query failed schema validation. The message names the offending field.
invalid_currency400The currency is not enabled for this merchant.
invalid_country400The country is not enabled for this merchant.
routing_unavailable422No payment route is available to serve this request right now.
insufficient_available_balance422The merchant's available balance cannot cover amount + fee.
approval_required422The requested action depends on the payout approval state; for cancellation, the payout is outside the cancellable approval window.
amount_below_minimum422Amount is below the configured per-transaction minimum.
amount_above_maximum422Amount exceeds the configured per-transaction maximum.
duplicate_merchant_reference409An intent with this merchant_reference already exists for the merchant.
idempotency_conflict409The Idempotency-Key was reused with a different request body, or the original request is in flight.
payment_method_invalid400The payment method hint is unknown, retired, or ineligible for this currency, country, or amount.
not_found404The resource does not exist, or it belongs to another merchant or environment.
internal_error500The platform failed in a way that is not the caller's fault. Safe to retry with the same idempotency key.

Beta scope

Two areas are out of scope for the beta and have no public endpoint or error code:

  • Refunds are deferred. There is no refund endpoint and no refund-specific error code in the beta. A succeeded payment intent cannot be reversed through the Merchant API.
  • P2P actions are not part of the public beta contract.

When these ship, their endpoints and any new codes are announced in the changelog and the OpenAPI spec ahead of release.

Closed-union promise

The set above is the contract. Removing or changing the meaning of an existing code is a major-version break. Adding a new code is a minor-version break that is announced in the changelog and the OpenAPI spec ahead of release.

In TypeScript, treat the union as exhaustive:

function explain(code: MerchantErrorCode): string {
  switch (code) {
    case "api_key_missing":
    case "api_key_malformed":
    case "api_key_invalid":
    case "api_key_revoked":
      return "Authentication problem. Check your key.";
    case "ip_not_allowed":
      return "This network is not allowed for the merchant.";
    case "rate_limited":
      return "Slow down. Retry after a backoff.";
    case "validation_failed":
    case "invalid_currency":
    case "invalid_country":
    case "payment_method_invalid":
      return "Request shape is wrong. Fix and retry.";
    case "amount_below_minimum":
    case "amount_above_maximum":
    case "insufficient_available_balance":
    case "approval_required":
    case "routing_unavailable":
      return "Business rule blocked the request.";
    case "duplicate_merchant_reference":
    case "idempotency_conflict":
      return "Conflict. Reconcile and retry with a fresh ref.";
    case "merchant_inactive":
    case "merchant_kyb_not_approved":
      return "Merchant state blocks this operation.";
    case "not_found":
      return "Not found in this environment.";
    case "internal_error":
      return "Platform error. Retry with the same idempotency key.";
  }
}

The compiler will tell you when a new code lands.

On this page