Errors
VaultsPay uses conventional HTTP status codes and returns a predictable JSON body for every error.
Error shape
{
"error": {
"code": "validation_failed",
"message": "email: must be a valid email address",
"type": "invalid_request",
"param": "email",
"request_id": "req_01HX7ABCDEFG..."
}
}Always log the request_id — it’s the fastest way for our support team to trace a specific call.
Status codes
| Status | Meaning |
|---|---|
200 | OK — request succeeded. |
201 | Created — new resource was created. |
202 | Accepted — async operation queued. |
204 | No Content — success, no body. |
400 | Bad Request — malformed or invalid request body. |
401 | Unauthorized — missing or invalid API key. |
403 | Forbidden — authenticated but not allowed to do this. |
404 | Not Found — resource does not exist or doesn’t belong to you. |
409 | Conflict — resource state prevents the action. |
422 | Unprocessable Entity — validation failed. |
429 | Too Many Requests — rate limit hit. |
500 | Server Error — we had a bad day. Retry with backoff. |
503 | Service Unavailable — maintenance / degraded mode. |
Error types
| Type | When used |
|---|---|
authentication | API key, signature, or credential problems. |
authorization | You are authenticated but not allowed to do this. |
invalid_request | Request is malformed or fails validation. |
resource_conflict | The current state of a resource blocks the requested action. |
rate_limit | Too many requests within the window. |
api_error | Something went wrong on our end. |
Common error codes
| Code | Type | Typical fix |
|---|---|---|
invalid_api_key | authentication | Rotate your key and re-send. |
unauthorized_ip | authentication | Add source IP to allow-list. |
validation_failed | invalid_request | Inspect param and fix the field. |
duplicate_email | resource_conflict | Retrieve the existing user instead. |
kyc_incomplete | resource_conflict | Complete KYC before issuing cards. |
non_zero_balance | resource_conflict | Sweep remaining funds before closing account. |
rate_limit_exceeded | rate_limit | Back off with exponential delay. |
idempotency_key_in_use | invalid_request | Same key replayed with a different body. |
server_error | api_error | Safe to retry with backoff. |
Handling errors
try {
const user = await vp.users.create(input)
} catch (err) {
switch (err.code) {
case 'duplicate_email':
return existingUserByEmail(input.email)
case 'validation_failed':
return showFieldError(err.param, err.message)
case 'rate_limit_exceeded':
return retryWithBackoff(() => vp.users.create(input))
default:
throw err
}
}