Errors
Pinch uses conventional HTTP status codes to indicate the result of a request, with a structured JSON envelope for the details.
Error envelope
Every error response is a JSON object with this shape:
{
"error": {
"code": "invalid_request",
"message": "Field `providerOrderId` is required.",
"field": "providerOrderId",
"requestId": "req_8c2f9a1b3d4e5f"
}
}
| Field | Description |
|---|---|
error.code | Stable, machine-readable identifier. Use this in code, not message. |
error.message | Human-readable explanation. Safe to log; do not show to end users. |
error.field | Present on validation errors. The field that failed. |
error.requestId | Echo of the X-Request-Id response header. Include it when contacting support. |
HTTP status code conventions
| Status | When you'll see it |
|---|---|
200 | Success. |
400 | Bad request — malformed JSON or invalid field shape. |
401 | Unauthenticated — see Authentication. |
403 | Authenticated but not authorized for this resource (e.g. wrong merchant). |
404 | Resource not found — referenced an order or return that doesn't exist. |
409 | Conflict — duplicate providerOrderId or providerReturnId. |
422 | Unprocessable — field values failed validation (e.g. unknown currency code). |
429 | Rate limited — slow down and retry with backoff. |
500 | Internal error on Pinch. Retry with exponential backoff. |
502 / 503 | Upstream or capacity issue. Retry with exponential backoff. |
Error code catalog
Authentication
| Code | HTTP | Meaning | Fix |
|---|---|---|---|
unauthenticated | 401 | Missing Authorization header | Add the header |
invalid_api_key | 401 | Key format invalid or revoked | Rotate or recheck |
environment_mismatch | 401 | Key/base URL mismatch | Match pk_test_ ↔ qa-api.pinch.ai, pk_live_ ↔ api.pinch.ai |
forbidden | 403 | Key not authorized for this merchant or resource | Contact support |
Request shape
| Code | HTTP | Meaning | Fix |
|---|---|---|---|
invalid_request | 400 | Malformed JSON or required field missing | Validate payload against the schema |
unprocessable_entity | 422 | Field present but value invalid | Check field constraints |
unknown_field | 422 | Field not in schema | Remove or check spelling |
invalid_currency_code | 422 | Currency must be ISO 4217 numeric (e.g. 840 for USD) | Use the numeric code |
invalid_timestamp | 422 | Timestamp must be epoch milliseconds as a string | Pass String(Date.now()) |
Resource state
| Code | HTTP | Meaning | Fix |
|---|---|---|---|
not_found | 404 | Resource does not exist | Verify the ID |
order_not_found | 404 | Return references an order Pinch hasn't seen | Send the /v1/order first |
duplicate_order | 409 | providerOrderId already exists for this merchant | Treat as success — Pinch is idempotent by providerOrderId |
duplicate_return | 409 | providerReturnId already exists | Same as above |
Capacity
| Code | HTTP | Meaning | Fix |
|---|---|---|---|
rate_limited | 429 | You're exceeding your rate limit | Retry with exponential backoff |
internal_error | 500 | Pinch failed internally | Retry with backoff; contact support if persistent |
bad_gateway | 502 | Upstream issue | Retry with backoff |
service_unavailable | 503 | Temporary unavailability | Retry with backoff |
Idempotency
POST /v1/order and POST /v1/return are idempotent on providerOrderId and providerReturnId respectively. Retrying the same identifier returns the original decision rather than creating a duplicate.
For other endpoints, use exponential backoff on transient failures:
attempt 1 → wait 1s
attempt 2 → wait 2s
attempt 3 → wait 4s
attempt 4 → wait 8s
attempt 5 → give up, alert
Always honor Retry-After if Pinch returns it in a 429 or 503 response.
Request IDs
Every response includes an X-Request-Id header. Log it alongside your application logs. When you contact support@pinch.ai about a specific failure, include the request ID — Pinch can pull the full trace.
See also
- Authentication —
401causes and fixes - Versioning — how breaking changes are signaled
- API overview — base URL, conventions, headers