Integration
Error Codes
Complete reference of API error codes, HTTP status mappings, and resolution guidance.
Overview
PaymentHooks uses conventional HTTP status codes to indicate the success or failure of an API request. Every error response follows a consistent JSON envelope so your integration can programmatically inspect the error.code field and take the appropriate action.
Error response format
All API errors return the standard ApiResponse envelope with data: null and a populated error object.
{"data": null,"error": {"code": "VALIDATION_ERROR","message": "amount is required","fields": { "amount": "Required" },"details": {}}}
| Field | Type | Description |
|---|---|---|
| code | string | Machine-readable error constant (e.g. VALIDATION_ERROR). |
| message | string | Human-readable description of the error. |
| fields | object? | Per-field validation messages. Present only for VALIDATION_ERROR. |
| details | object? | Additional context (traceId, upstream error, etc.). |
HTTP status codes
HTTP status codes are grouped into client errors (4xx) and server errors (5xx).
| Status | Label | Description |
|---|---|---|
400 | Bad Request | The request body or query parameters are invalid. |
401 | Unauthorized | No valid API key or session was provided. |
403 | Forbidden | The authenticated principal lacks the required permission or scope. |
404 | Not Found | The requested resource does not exist or belongs to another tenant. |
409 | Conflict | The request conflicts with the current state of the resource. |
422 | Unprocessable Entity | The request is well-formed but contains semantic errors. |
429 | Too Many Requests | Rate limit exceeded. Back off and retry with exponential delay. |
500 | Internal Server Error | An unexpected error occurred on the server. |
503 | Service Unavailable | A downstream dependency (database, gateway) is temporarily unavailable. |
Error code reference
Each error code maps to a specific HTTP status and carries a fixed meaning. Use the code field for programmatic branching, not the HTTP status alone.
VALIDATION_ERRORHTTP 400One or more request fields failed validation.
- Required field is missing (e.g. customerId, amount).
- Field value is out of range or wrong type.
- Idempotency-Key exceeds 200 characters.
Check the fields object in the error response for per-field details. Fix the flagged values and retry.
CSRF_INVALIDHTTP 401The CSRF token is missing or does not match the session.
- CSRF token was not included in the request headers.
- Token expired or was generated for a different session.
Fetch a fresh CSRF token from the session endpoint and include it in subsequent mutating requests.
FORBIDDENHTTP 403The authenticated user or API key does not have the required permission.
- Role-based access control blocks the action (e.g. merchant-only endpoint called by admin).
- API key scope is too narrow for the requested operation.
Use an API key with the correct scope or sign in with an account that has the required role.
INSUFFICIENT_SCOPEHTTP 403The API key is valid but missing a required scope.
- The key was created with limited scopes and the endpoint requires an additional one.
Create a new API key with the required scope or update the existing key's permissions.
NOT_FOUNDHTTP 404The requested resource does not exist.
- Incorrect resource ID in the URL path.
- Resource was deleted or belongs to a different merchant.
Verify the resource ID. List resources first to confirm the ID exists within your account.
CONFLICTHTTP 409The request conflicts with current resource state.
- Attempting to delete a business entity that still has active API keys.
- Duplicate resource creation detected.
Resolve the conflicting state first (e.g. revoke keys), then retry the request.
IDEMPOTENCY_CONFLICTHTTP 409The idempotency key was already used with different request parameters.
- Re-using an Idempotency-Key with a different request body.
Use a unique Idempotency-Key for each distinct request. Reuse the same key only for exact retries.
INVALID_IDEMPOTENCY_KEYHTTP 400The idempotency key format is invalid.
- Key is empty or exceeds the maximum length.
- Key contains disallowed characters.
Provide a non-empty string of at most 200 characters as the Idempotency-Key header.
RATE_LIMITEDHTTP 429Too many requests in a given time window.
- Exceeding the per-endpoint or per-key request quota.
- Burst of webhook simulation requests.
Implement exponential backoff. Check Retry-After header for the recommended wait time.
RATE_LIMIT_EXCEEDEDHTTP 429The API rate limit has been exceeded.
- High-frequency automated calls from a single API key.
Reduce request frequency. Contact support to increase your rate limit if needed.
INTERNAL_ERRORHTTP 500An unexpected server-side error occurred.
- Unhandled exception in application code.
- Database query failure or connection timeout.
Retry with exponential backoff. If the error persists, contact support with the traceId from the response.
EXTERNAL_API_ERRORHTTP 502A call to an external API (e.g. currency provider) failed.
- Third-party API returned an error or timed out.
Retry the request. If the issue persists, the external service may be experiencing an outage.
INVALID_PAYLOADHTTP 400The webhook or callback payload is malformed.
- Missing required fields in an incoming webhook (e.g. payment_request_id).
Verify the payload structure matches the expected schema for the provider.
INVALID_PROVIDERHTTP 400The specified gateway provider is not recognised.
- Typo in the provider slug in the webhook URL.
- Provider not yet supported.
Check the list of supported providers in the gateway marketplace.
SIGNATURE_INVALIDHTTP 401Webhook signature verification failed.
- The webhook signing secret is incorrect or rotated.
- The request body was modified in transit.
Ensure your webhook signing secret matches the one configured in PaymentHooks.
CONNECTION_FAILEDHTTP 422The gateway connection test failed.
- Invalid gateway credentials (API key, secret).
- Gateway sandbox/live mode mismatch.
Double-check credentials and mode. Use the gateway test endpoint to validate before connecting.
REFRESH_FAILEDHTTP 500Currency exchange rate refresh failed.
- Upstream currency API returned an error or was unreachable.
Retry the refresh. Cached rates remain valid until a successful refresh occurs.
Handling errors
const res = await fetch('/api/v1/payments', { method: 'POST', ... });const json = await res.json();if (json.error) {switch (json.error.code) {case 'VALIDATION_ERROR':// Inspect json.error.fields for per-field messagesbreak;case 'RATE_LIMITED':case 'RATE_LIMIT_EXCEEDED':// Back off and retrybreak;case 'UNAUTHORIZED':// Re-authenticate or refresh API keybreak;default:// Log and surface the error}}