---
name: nopan-errors
description: Apply this guide when interpreting or handling errors from the Nopan Payments API — non-2xx HTTP responses, Nopan `reasonCode` values, deciding whether to retry, or debugging integration failures. Relevant for any failing Nopan request the user is troubleshooting, and for designing retry and error-handling logic in production code.
---

# Nopan errors

Nopan returns structured errors: a standard HTTP status code **plus** a Nopan-specific `reasonCode` for finer diagnosis. Use the status to pick the response category, and the `reasonCode` to identify the precise cause and decide on retry.

> Full reference (with current code lists, examples, and retry guidance per code): [Error Handling](https://docs.nopan.com/guides/errors).

> **Match existing patterns** — translate Nopan `reasonCode` families into the project's existing payment-error taxonomy and reuse the shared retry/backoff utility used by other providers. Do not introduce a Nopan-specific error type or a parallel retry policy. The retry rules below tell you *what's safe to retry*; the project's existing utility tells you *how*. See [`nopan-integration`](https://docs.nopan.com/skills/nopan-integration.md) Step 0.

## Error response shape

Errors share a consistent envelope across the API. Fetch [Error Handling](https://docs.nopan.com/guides/errors) for the current schema — the OpenAPI also documents it under each endpoint's error responses.

## HTTP status — first-cut interpretation

| Status | What it means | First thing to check |
|---|---|---|
| `400 Bad Request` | Payload malformed, missing field, or pre-validation failure | Field validation; mTLS cert presence; `Content-Digest` matches body |
| `401 Unauthorized` | Auth failed | Token expired? Signature valid? `keyid` known? Algorithm matches key curve? |
| `403 Forbidden` | Authenticated but not authorized | Scope on the token; certificate trust; WAF rule |
| `404 Not Found` | Resource doesn't exist (or doesn't belong to you) | `transactionId` correctness; environment (sandbox vs prod) |
| `409 Conflict` | Idempotency or state conflict | Did you replay an idempotency key with a different payload? |
| `413 Payload Too Large` | WAF rejected oversized body | Trim payload; check it isn't accidentally including binary |
| `422 Unprocessable Entity` | Request is syntactically valid but rules forbid it | Lifecycle: refunding an unsettled payment, capturing twice, etc. |
| `423 Locked` | Resource is in a transient locked state | Wait and retry once after backoff |
| `429 Too Many Requests` | Rate limit hit | Honor `Retry-After`; back off exponentially |
| `500 Internal Server Error` | Unexpected Nopan-side failure | Safe to retry with backoff if idempotent |
| `501 Not Implemented` | Operation not supported (e.g. scheme doesn't allow partial refund) | Don't retry; change the request |
| `502 Bad Gateway` | Upstream provider issue | Retry with backoff |
| `504 Gateway Timeout` | Upstream provider didn't respond in time | **Important — see below** |

### The `504` rule for payment mutations

A `504` on a mutating call (`initiate`, `charge`, `capture`, etc.) means the request **may or may not have succeeded** on the scheme side. Do **not** invent a new idempotency key and retry blindly — that risks double charging.

**Correct recovery:**

1. Retry **with the same idempotency key** to get the stored response if Nopan finished processing.
2. If still ambiguous, call `GET /payments/{transactionId}/status` (or `/events`) to determine actual state.
3. Only proceed with new operations once the state is known.

## `reasonCode` families

Use the family to classify, then drill into the exact code.

| Family | Type | Examples of causes |
|---|---|---|
| `1xxx` | Payment & Risk | Insufficient funds, risk/fraud rejection, velocity threshold |
| `2xxx` | Customer & Session | Shopper canceled, session expired, abandoned |
| `3xxx` | Idempotency & Rate Limits | Duplicate idempotency key with different body, rate limit |
| `4xxx` | Request Validation & Authentication | Missing field, invalid token, bad signature, untrusted cert |
| `5xxx` | Business Rules | Refund not allowed, capture not allowed, lifecycle violation |
| `6xxx` | Webhooks & Security | Webhook delivery issue, WAF blocked request |
| `8xxx` | Provider & Downstream | Provider timeout, unsupported operation, provider rejection |
| `9xxx` | Internal | Nopan-side unexpected failure |

The full per-code table (one row per code, with description and recommended action) lives at [Error Handling](https://docs.nopan.com/guides/errors). **Fetch it whenever you need a specific code** — the list grows as new schemes are added.

## Retry decision rules

Default to **don't retry** unless the rule below says it's safe.

| Situation | Retry? | How |
|---|---|---|
| `4xxx` validation error (`400`/`401`/`403`/`422`) | **No** — fix the request | Re-read field; re-build signature; refresh token |
| `409 Conflict` from idempotency | **No** | Use the original response; do not change the key |
| `429 Too Many Requests` | **Yes** | Honor `Retry-After`, exponential backoff |
| `423 Locked` | **Yes** (once or twice) | Short backoff |
| `500` Internal | **Yes** if idempotency key was sent | Backoff; preserve the key |
| `502` / `504` | **Yes** (carefully) | Preserve idempotency key; verify state if mutating |
| `1xxx` payment-decline | **No** | Surface the decline to the shopper; don't auto-retry |
| `2xxx` shopper canceled | **No** | Treat as terminal-negative |
| `8xxx` provider timeout | **Conditional** | Retry with same idempotency key; if ambiguous, reconcile with `/status` |

## Common auth-related codes worth memorizing

These show up in nearly every first integration. The exact numbers are stable but treat them as a hint — the canonical table is at [Error Handling](https://docs.nopan.com/guides/errors).

- **Client certificate not provided / invalid** → `400`, code in the `4xxx` cert family. Action: present a valid mTLS cert.
- **Token expired or revoked** → `401`, `4061`. Action: re-call `/auth/token`.
- **Missing or invalid token** → `401`, `4970`. Action: include `Authorization: Bearer <token>`.
- **Authenticated but forbidden** (wrong scope, cert trust mismatch) → `403`, `4971`. Action: request the right scope on the next token call.
- **Invalid request signature** → `401`, in the `4xxx` signature family. Action: rebuild the signature base; verify algorithm matches key curve; check clock skew on `created`.

## Logging and observability

- Always log the `reasonCode`, the `transactionId` (when present), and a request correlation ID.
- **Never log** the access token, the signing key, certificate material, or PII from the payload.
- For repeated failures, the portal's request inspection tools and the Signature Debugger ([sandbox](https://portal.nopan.com/sandbox/signing-keys)) are usually faster than reading logs.

## Decision rules

- **First step on any failure** → read both the HTTP status and the `reasonCode`. Don't act on one alone.
- **Got `5xxx` (business rules)** → don't retry; the lifecycle state forbids the operation. Reconcile via `/status`.
- **Got `1xxx`/`2xxx`** → it's the shopper's payment, not your code. Communicate it.
- **Got `4xxx`** → it's your request. Fix it.
- **Got `8xxx`/`9xxx` or 5xx** → it's a transient platform/provider issue. Backoff and retry with the same idempotency key.
- **Unsure if a mutation succeeded** → never retry without preserving the key; reconcile via `GET /payments/{transactionId}/status`.

## Related guides

- Auth-specific failures and signature mistakes → [`nopan-authentication`](https://docs.nopan.com/skills/nopan-authentication.md).
- Lifecycle-related rejections (refund/cancel/capture rules) → [`nopan-payments`](https://docs.nopan.com/skills/nopan-payments.md).
- Reproducing error scenarios deterministically → [`nopan-testing`](https://docs.nopan.com/skills/nopan-testing.md).
- Webhook-side error handling → [`nopan-webhooks`](https://docs.nopan.com/skills/nopan-webhooks.md).