Errors

Error response format, status codes, and error handling guidance.


All API errors return a consistent JSON body regardless of the HTTP status code. This document describes the shape, the error codes you may receive, and how to handle errors programmatically.


Error response format

{
  "message": "Human-readable description of what went wrong.",
  "error_code": "PAYMENT_ALREADY_REFUNDED"
}
FieldTypeAlways presentDescription
messagestringYesHuman-readable explanation of the error.
error_codestringYesMachine-readable code. Use this for programmatic error handling.

Correlation ID (request tracing)

Every response — success or error — includes an x-correlation-id header containing a unique ID for the request:

x-correlation-id: 9f3a2b1c-4d5e-6f7a-8b9c-0d1e2f3a4b5c

Log this value alongside every error. When contacting support, include the correlation ID and the Advance team can locate the full request trace immediately.

You can also supply your own correlation ID via the x-correlation-id request header and we'll echo it back:

POST /v1/plans
x-correlation-id: my-system-request-id-abc123

Bulk operation errors

When an operation fails because specific items are in an invalid state, a context object is included with the IDs of the affected items:

{
  "message": "Some payables can't be submitted — they must be in NEW or REVISION_REQUIRED status.",
  "error_code": "BAD_REQUEST",
  "context": {
    "invalid_ids": ["pay_aaa111", "pay_bbb222"]
  }
}

HTTP status codes

StatusMeaning
200Success
400Bad request — the request was invalid or the operation is not allowed
401Unauthorized — missing or invalid API key
403Forbidden — your API key does not have permission for this action
404Not found — the requested resource does not exist
422Unprocessable — validation failed or a database constraint was violated
500Internal server error — something went wrong on our end

Error codes

Payment errors

error_codeStatusDescription
PAYMENT_ALREADY_REFUNDED400The payment has already been fully refunded.
PAYMENT_STATUS_NOT_REFUNDABLE400Only Captured or Settled payments can be refunded.
PAYMENT_MISSING_PAYRIX_TRANSACTION_ID400The payment cannot be refunded through the API. Contact support.
PAYMENT_REQUEST_EXPIRED_EXCEPTION400The payment request has passed its payment_expiration.
PAYMENT_REQUEST_ALREADY_PAID400This payment request has already been paid.
PAYMENT_NOT_FOUND404No payment found with the given ID.
PAYMENT_REQUEST_NOT_FOUND404No payment request found with the given ID.

Plan and invoice errors

error_codeStatusDescription
CHECKOUT_DETAILS_ALREADY_PAID400This invoice has already been paid.
CHECKOUT_DETAILS_CANCELLED400This plan has been cancelled. No payment is needed.
CHECKOUT_DETAILS_SETTLED400This invoice has been settled. No payment is needed.
INVOICE_NOT_FOUND404No invoice found with the given ID.
PLAN_VERSION_CONFLICT409Another edit to the plan was saved at the same time. Read the plan again and resend your edit.
PLAN_NOT_EDITABLE409The plan can no longer be edited, for example because it has received a payment. The message says why.
PLAN_NOT_DELETABLE409The plan can't be deleted because a payment was collected or its funds have already been moved. Cancel or refund it instead.
PLAN_PAYOUTS_NOT_RECALCULATED422The plan's payouts could not be recalculated, so the edit was not saved. Contact support.

Resource errors

error_codeStatusDescription
NOT_FOUND404Generic not-found for HTTPException-based routes.
ITEM_NOT_FOUND404A specific resource was not found.
MISSING_REQUIRED_FIELDS400The resource is missing required fields.
BAD_REQUEST400The request or operation is not valid.

Payable errors

error_codeStatusDescription
PAYABLE_NOT_VOIDABLE409The payable can't be voided in its current status (for example processing or paid).
PAYABLE_GROUP_INCOMPLETE400The payable belongs to an endorsement group and can't be approved on its own.

Money movement errors

error_codeStatusDescription
IDEMPOTENCY_KEY_REUSED422The idempotency key was already used for a different request. Use a new key.
IDEMPOTENCY_REQUEST_IN_PROGRESS409A request with this idempotency key hasn't finished. Check the transfer's status before retrying.
ACCOUNT_NOT_ELIGIBLE422An internal transfer named an account that isn't one of your Advance accounts.
recipient_not_found404The market, producer or vendor doesn't exist.
PAYOUTS_NOT_ENABLED400The source account doesn't have payouts enabled.

Authentication and authorization errors

error_codeStatusDescription
UNAUTHORIZED401Missing or invalid API key.
FORBIDDEN403The API key does not have permission for this resource or action.

Validation errors

error_codeStatusDescription
VALIDATION_ERROR422Request body or query parameter failed validation.
FOREIGN_KEY_VIOLATION422A referenced resource (e.g., insured_id) does not exist.
UNIQUE_CONSTRAINT_VIOLATION422A record with these values already exists.

Server errors

error_codeStatusDescription
INTERNAL_SERVER_ERROR500An unexpected error occurred. Include the x-correlation-id response header value in your support request.

Handling errors in code

Check error_code first

Never string-match on message — it may change. Use error_code for all programmatic decisions:

import requests

response = requests.post("/v1/payments/pay_xyz/refund", ...)

if not response.ok:
    error = response.json()
    code = error.get("error_code")

    if code == "PAYMENT_ALREADY_REFUNDED":
        # Payment was already refunded — treat as success
        pass
    elif code == "PAYMENT_STATUS_NOT_REFUNDABLE":
        # Notify user the payment status doesn't allow refunds
        raise ValueError(error["message"])
    else:
        # Unexpected error — log the x-correlation-id header for support
        ref = response.headers.get("x-correlation-id", "unavailable")
        raise RuntimeError(f"Refund failed [{code}]. Correlation ID: {ref}")
const response = await fetch('/v1/payments/pay_xyz/refund', { method: 'POST', ... });

if (!response.ok) {
  const error = await response.json();

  if (error.error_code === 'PAYMENT_ALREADY_REFUNDED') {
    // already done — no action needed
  } else {
    const ref = response.headers.get('x-correlation-id') ?? 'unavailable';
    console.error(`Error ${error.error_code}: ${error.message} (ref: ${ref})`);
    throw new Error(error.message);
  }
}

Bulk operations

When submitting multiple items and receiving a context.invalid_ids response, retry with only the valid subset:

error = response.json()
invalid = set(error.get("context", {}).get("invalid_ids", []))
valid_ids = [id for id in submitted_ids if id not in invalid]
# retry with valid_ids

Contacting support

Include the x-correlation-id response header value in your support request or API integration error logs. This is the single most useful piece of information for diagnosing issues.


Retry guidance

StatusRetry?
400No — the request itself is invalid. Fix the request before retrying.
401 / 403No — check your API key and permissions.
404No — the resource does not exist.
422No — validation or constraint failure. Fix the data.
429Yes, with backoff — you are being rate limited.
500Yes, with exponential backoff — transient server error. If it persists, contact support with the x-correlation-id header value.

Did this page help you?