# Error Message Reference: [Product or API name]

> A catalogue of every error your product or API can return: a stable
> code, the message users see, the cause, the fix and a link to more
> help. For HTTP APIs, each entry maps to a problem type in the format
> of RFC 9457, *Problem Details for HTTP APIs* (July 2023, obsoletes RFC
> 7807). Replace every `[bracketed]` value and every row marked
> *Example*. The worked example uses a fictional service, the Larkspan
> Billing API.

<!--
Guidance: How to use this template
- One entry per error code. The code never changes meaning once
  published; retire codes instead of reusing them.
- Write the fix first in your head: if you cannot say what the reader
  should do, the error is not ready to ship.
- Publish each entry at a stable URL. For HTTP APIs that URL can be the
  `type` URI in the problem details response, so a developer who sees
  the error can open its documentation directly.
- Keep the catalogue generated from, or checked against, the source of
  truth in code so it cannot drift.
-->

## Document control

<!-- Guidance: Record which product version the catalogue matches and who approves new codes. -->

| Field | Value |
|---|---|
| Document ID | [DOC-ERR-001] |
| Product and version | [Larkspan Billing API v3] *(Example)* |
| Version | [1.0] |
| Status | [Draft / Approved / Superseded] |
| Owner | [@docs-lead] |
| Approvers/reviewers | [@api-lead], [@support-lead], [@security-reviewer] |
| Source of truth | [Path to error registry in code, for example `errors/registry.yaml`] |
| Classification | [Public] |
| Last updated | YYYY-MM-DD |

### Revision history

| Version | Date | Author | Change |
|---|---|---|---|
| 1.0 | YYYY-MM-DD | [@name] | First published catalogue |
| 1.1 | YYYY-MM-DD | [@name] | *Example:* Added BIL-PAY-004, retired BIL-AUTH-002 |

## 1. Purpose and audience

<!-- Guidance: Say who reads this page and in what situation. Most readers arrive from a search or a link in an error, in the middle of a failure. -->

This reference helps three groups:

- **Developers integrating the API**, who receive an error response and
  need to know whether to retry, fix the request or contact support.
- **End users of applications**, who see a message in the interface and
  follow its "Learn more" link.
- **Support staff**, who use the code to find the known cause and fix
  quickly.

Each entry answers four questions in order: what happened, why, what to
do now, and where to get more help.

## 2. Error code scheme

<!-- Guidance: Define the code format once and keep it. Codes must be searchable, unique and readable aloud on a support call. -->

Format: `<PRODUCT>-<AREA>-<NNN>`, for example `BIL-PAY-003`.

| Part | Rule | Values *(Example)* |
|---|---|---|
| PRODUCT | Three letters, fixed per product | `BIL` |
| AREA | Three or four letters for the functional area | `AUTH`, `VAL`, `PAY`, `LIM`, `SYS` |
| NNN | Three-digit sequence within the area, never reused | `001` to `999` |

Rules:

- A code identifies one cause. If two causes need different fixes, they
  need two codes.
- Never reuse a retired code. Mark it **Retired** in the catalogue with
  the date and the replacement code, if any.
- The code appears in the API response, in logs and in the interface
  (small print is fine), so all three can be matched.

## 3. Problem details format (HTTP APIs)

<!-- Guidance: If your API returns HTTP errors, use the RFC 9457 members consistently. Decide which extension members you add and document them here. -->

Responses use the media type `application/problem+json`. RFC 9457
section 3.1 defines five standard members; this API uses them as
follows.

| Member | RFC 9457 section | How this API uses it |
|---|---|---|
| `type` | 3.1.1 | URI of the catalogue entry for the error, for example `https://docs.example.com/errors/BIL-PAY-003` |
| `status` | 3.1.2 | The HTTP status code, repeated for convenience; the status line remains authoritative |
| `title` | 3.1.3 | Short summary of the problem type; the same for every occurrence of the type |
| `detail` | 3.1.4 | Explanation of this occurrence, focused on helping the client correct it |
| `instance` | 3.1.5 | URI identifying this occurrence, for example the request ID path |

Extension members (RFC 9457 section 3.2) used by this API:

| Member | Type | Meaning |
|---|---|---|
| `code` | string | Catalogue code, for example `BIL-PAY-003` |
| `retryable` | boolean | Whether the same request may succeed if retried later |
| `errors` | array | For validation errors, one object per invalid field with `pointer` and `detail` |

Clients must ignore extension members they do not recognise (RFC 9457
section 3.2), so you can add members later without breaking them.

*Example response:*

```json
{
  "type": "https://docs.example.com/errors/BIL-PAY-003",
  "title": "Card declined by the issuer",
  "status": 402,
  "detail": "The card issuer declined payment for invoice INV-20817. No money was taken.",
  "instance": "/requests/7f3c9a2e",
  "code": "BIL-PAY-003",
  "retryable": false
}
```

When no specific type applies, RFC 9457 section 4.2.1 allows
`about:blank`; the problem then means nothing beyond the HTTP status
code. Prefer a specific catalogue type for every error you document.
Check the IANA "HTTP Problem Types" registry before inventing a type
that may already be registered.

## 4. Writing rules for entries

<!-- Guidance: These rules keep entries consistent. Add your own house rules from the UX writing guide. -->

1. **Title**: name the problem, not the code path. "Card declined by the
   issuer", not "PaymentProcessorException".
2. **Detail**: say what happened to the user's data. "No money was
   taken" or "Your changes were saved" removes the worst worry first.
3. **Fix**: one numbered list of actions the reader can take, in the
   order they should try them.
4. **No blame**: describe the input, not the person. "The date is in
   the past", not "You entered an invalid date".
5. **No secrets**: never include stack traces, internal host names,
   SQL, or whether an account exists. RFC 9457 section 5 warns against
   exposing implementation details.
6. **Retry advice**: say whether to retry and when, and include the
   `Retry-After` header where it is sent.
7. **Same words everywhere**: the interface message, the `title` and the
   catalogue title match.

## 5. Error catalogue

<!-- Guidance: One row per code in the summary table, then one detailed entry per code. Sort by area, then number. -->

### 5.1 Summary

| Code | HTTP status | Title | Retryable | Status |
|---|---|---|---|---|
| BIL-AUTH-001 *(Example)* | 401 | Access token expired | No (refresh first) | Active |
| BIL-AUTH-002 *(Example)* | 401 | API key format invalid | No | Retired YYYY-MM-DD, no replacement (API keys withdrawn in v3) |
| BIL-VAL-001 *(Example)* | 422 | Request field is invalid | No | Active |
| BIL-PAY-001 *(Example)* | 422 | No payment method on file | No | Active |
| BIL-PAY-003 *(Example)* | 402 | Card declined by the issuer | No | Active |
| BIL-PAY-004 *(Example)* | 402 | Customer authentication required | No (complete authentication first) | Active |
| BIL-LIM-001 *(Example)* | 429 | Too many requests | Yes, after `Retry-After` | Active |
| BIL-SYS-001 *(Example)* | 503 | Service temporarily unavailable | Yes, with backoff | Active |

### 5.2 BIL-PAY-003: Card declined by the issuer *(Example)*

| Field | Value |
|---|---|
| HTTP status | 402 Payment Required |
| `type` | `https://docs.example.com/errors/BIL-PAY-003` |
| Interface message | "Your card was declined. No money was taken. Try another card or contact your bank." |
| Retryable | No, not with the same card |
| Introduced | v3.0 |

**What happened.** The card issuer refused the payment. Larkspan did not
charge the card.

**Common causes.**

- Insufficient funds or credit limit reached.
- The issuer flagged the payment for fraud checks.
- The card is expired or blocked.

**How to fix.**

1. Ask the customer to use a different card, or to contact their bank.
2. Do not retry the same card automatically; repeated attempts may cause
   the issuer to block it.
3. If declines affect many customers at once, check the status page at
   [URL] and contact support with the `instance` value.

**Related.** BIL-PAY-001, BIL-PAY-004.

### 5.3 BIL-VAL-001: Request field is invalid *(Example)*

| Field | Value |
|---|---|
| HTTP status | 422 Unprocessable Content |
| `type` | `https://docs.example.com/errors/BIL-VAL-001` |
| Retryable | No, correct the request first |

**What happened.** One or more fields failed validation. The `errors`
array lists each field as a JSON Pointer with its own explanation.

**How to fix.** Correct each field listed in `errors` and send the
request again. The API checks all fields at once, so one response lists
every problem.

### 5.4 [CODE]: [Title]

| Field | Value |
|---|---|
| HTTP status | [Code and reason phrase] |
| `type` | [URI] |
| Interface message | [Text] |
| Retryable | [Yes / No, with condition] |
| Introduced | [Version] |

**What happened.** [One or two sentences.]

**Common causes.** [List.]

**How to fix.** [Numbered steps.]

**Related.** [Codes.]

## 6. Handling guidance for clients

<!-- Guidance: Tell integrators how to react to classes of errors so they build robust clients, not one handler per code. -->

```mermaid
flowchart TD
  A["Error response received"] --> B{"Status 4xx or 5xx?"}
  B -->|"4xx"| C{"retryable is true?"}
  C -->|"Yes, for example 429"| D["Wait for Retry-After, then retry"]
  C -->|No| E["Show message, ask user to correct input"]
  B -->|"5xx"| F["Retry with exponential backoff, limited attempts"]
  F --> G{"Still failing?"}
  G -->|Yes| H["Show status page link, log code and instance"]
  G -->|No| I["Continue"]
  D --> I
```

- Log `code` and `instance` with every failure; support asks for both.
- Never parse `detail` text in code; it can change and may be localised.
  Branch on `code` or `type`.

## 7. Governance

<!-- Guidance: Decide how new codes are added and how the catalogue stays in step with code. -->

| Step | Owner | Check |
|---|---|---|
| Developer proposes a new code in the registry file | Engineer | Code unique, area correct |
| Writer drafts title, message, cause and fix | Docs | Writing rules in section 4 |
| Security reviews `detail` content | Security | No internal data disclosed |
| CI fails if a code in the registry has no catalogue entry | Build | Automated |
| Entry published with the release | Docs | Link from `type` resolves |

## 8. References

<!-- Guidance: List the specifications and related documents. -->

- RFC 9457, *Problem Details for HTTP APIs*, M. Nottingham, E. Wilde,
  S. Dalal, July 2023, Proposed Standard, obsoletes RFC 7807:
  https://www.rfc-editor.org/rfc/rfc9457.
- IANA HTTP Problem Types registry:
  https://www.iana.org/assignments/http-problem-types.
- WCAG 2.2, success criteria 3.3.1 Error Identification and 3.3.3 Error
  Suggestion, for interface messages: https://www.w3.org/TR/WCAG22/.
- Related templates: `docs/troubleshooting`, `docs/kb-article`,
  `docs/ux-writing-guide`, `architecture/rest-api-specification`,
  `architecture/api-design-guidelines`, `dev/api-reference`.

## Standard and licence note

Based on RFC 9457, *Problem Details for HTTP APIs* (IETF, July 2023),
which is freely available; section numbers are cited and the members
are described in original wording. This template is original text
written for this collection. Check the current RFC status and the IANA
registry before relying on them. Template licence: MIT.
