Error Reference
Complete API error reference. HTTP status codes, error response format, common error messages, rate limit headers, and how SDKs map errors to typed exceptions.
Error Reference
All PayzCore API errors follow a consistent JSON format. This page documents every error status code, the response structure, common error messages, and how to handle them.
Response Format
Every error response includes an error field with a human-readable message. Some errors include additional fields for context.
Standard Error
{
"error": "Description of what went wrong"
}Validation Error (with details)
{
"error": "Invalid request body",
"details": [
{
"code": "invalid_type",
"path": ["amount"],
"message": "Expected number, received string"
},
{
"code": "too_small",
"path": ["external_ref"],
"message": "String must contain at least 1 character(s)"
}
]
}Rate Limit Error (with plan info)
{
"error": "Daily API call limit exceeded. Upgrade your plan for unlimited access.",
"limit": 500,
"plan": "free"
}HTTP Status Codes
400 Bad Request
Validation errors caused by invalid parameters, missing required fields, or unsupported values.
| Error Message | Cause |
|---|---|
Invalid request body | JSON parse error or schema validation failure. Check details array for field-level errors. |
USDC is not supported on TRC20 | Unsupported chain+token combination. See Supported Chains. |
Amount must be at least $X.XX (project minimum) | Payment amount is below the project's configured minAmount. |
Project has no wallet assigned | The project needs a wallet before creating payments. |
Wallet not found | The wallet linked to the project was deleted or is missing. |
Wallet has no xPub configured for CHAIN (FAMILY family) | The wallet is missing the xPub key for the requested chain's address family (tron or evm). |
No static addresses available for CHAIN | Static wallet mode is configured but no addresses are registered for this chain. |
Specified address does not belong to this project's wallet | The address parameter (dedicated mode) references an address not in the wallet's static address pool. |
No addresses available for this chain. Contact merchant. | All static addresses in the pool are already assigned (dedicated mode). |
Invalid pool match method | Pool mode configuration error. |
Invalid address mode | Project has an unrecognized address mode. |
Invalid limit or offset | Pagination parameters must be positive integers. limit max is 100. |
Invalid status filter | Status must be one of: pending, confirming, partial, paid, overpaid, expired, cancelled. |
Invalid created_after | Date parameter is not a valid ISO 8601 string. |
Invalid updated_after | Date parameter is not a valid ISO 8601 string. |
How to fix: Check the details array for specific field-level validation errors. Correct the request parameters and retry.
401 Unauthorized
Authentication failed. The API key is missing, invalid, or malformed.
| Error Message | Cause |
|---|---|
Missing x-api-key header | The x-api-key header was not included in the request. |
Invalid API key | The API key does not match any active project. |
How to fix: Verify your API key is correct and included in the x-api-key header. API keys start with pk_live_. If you lost your key, an admin can regenerate it from the project settings.
403 Forbidden
The request was authenticated but is not allowed due to access restrictions.
| Error Message | Cause |
|---|---|
Project is deactivated | An admin has deactivated this project. |
Account suspended. Contact support. | The project owner's account has been suspended. |
How to fix: Contact PayzCore support or your account administrator. Deactivated projects cannot make API calls until reactivated.
404 Not Found
The requested resource does not exist or is not accessible by this API key.
| Error Message | Cause |
|---|---|
Payment not found | The payment ID does not exist or belongs to a different project. |
How to fix: Verify the payment ID is correct. Each project can only access its own payments.
409 Conflict
The request conflicts with an existing resource.
| Error Message | Cause |
|---|---|
Duplicate external_order_id | A payment with the same (external_order_id, external_ref, chain, token) already exists. The existing payment is returned with "existing": true. |
Note: This is not strictly an error. PayzCore uses external_order_id for idempotency. When a duplicate is detected, the response contains "existing": true with the original payment data. This allows safe retries without creating duplicate payments.
429 Too Many Requests
Rate limit exceeded. There are two types of rate limits:
Per-Minute Rate Limit (burst protection)
Limits the number of requests per API key per minute. Default: 60 requests/minute.
{
"error": "Rate limit exceeded. Try again later."
}Response headers:
| Header | Value | Description |
|---|---|---|
X-RateLimit-Limit | 60 | Maximum requests per window |
X-RateLimit-Remaining | 0 | Remaining requests in current window |
X-RateLimit-Reset | 1708444800 | Unix timestamp (seconds) when the window resets |
Daily Limit (plan-based)
Limits total API calls per day based on your plan.
{
"error": "Daily API call limit exceeded. Upgrade your plan for unlimited access.",
"limit": 500,
"plan": "free"
}Response headers:
| Header | Value | Description |
|---|---|---|
X-RateLimit-Limit | 500 | Daily limit for your plan |
X-RateLimit-Remaining | 0 | Remaining calls today |
X-RateLimit-Reset | 1708473600 | Unix timestamp (seconds) when the daily counter resets (midnight UTC) |
X-RateLimit-Daily | true | Indicates this is a daily limit (not per-minute) |
Plan limits:
| Plan | API Calls/Day | Webhooks/Day |
|---|---|---|
| Free | 500 | 100 |
| Pro | 25,000 | 10,000 |
Admin-configured custom overrides may apply per user.
Capacity Limit (pool mode)
When using pool+micro_amount mode, all available offsets for the requested amount may be exhausted:
{
"error": "Payment capacity exceeded. Please try again later."
}How to fix for per-minute limits: Wait for the reset time indicated in the X-RateLimit-Reset header. Implement exponential backoff in your client.
How to fix for daily limits: Wait until midnight UTC, or upgrade to the Pro plan for higher limits.
How to fix for capacity limits: Wait for existing payments on the pool to resolve (paid/expired), or add more static addresses.
500 Internal Server Error
An unexpected error occurred on the server.
{
"error": "Failed to create payment"
}How to fix: Retry the request with exponential backoff. If the error persists, check the health endpoint and contact support.
Recommended retry strategy:
| Attempt | Delay |
|---|---|
| 1 | 1 second |
| 2 | 2 seconds |
| 3 | 4 seconds |
| 4 | 8 seconds |
| 5 | Give up, alert your team |
SDK Error Handling
The official SDKs map HTTP errors to typed exception classes, making it easy to handle specific error types.
Node.js SDK
import {
PayzCoreError,
ValidationError,
AuthenticationError,
ForbiddenError,
NotFoundError,
RateLimitError,
} from '@payzcore/node'
try {
const payment = await payzcore.payments.create({
amount: 50,
chain: 'TRC20',
external_ref: 'customer-123',
})
} catch (err) {
if (err instanceof ValidationError) {
// 400 - Check err.details for field-level errors
console.error('Validation:', err.message, err.details)
} else if (err instanceof AuthenticationError) {
// 401 - Invalid API key
console.error('Auth:', err.message)
} else if (err instanceof ForbiddenError) {
// 403 - Project inactive or account suspended
console.error('Forbidden:', err.message)
} else if (err instanceof NotFoundError) {
// 404 - Resource not found
console.error('Not found:', err.message)
} else if (err instanceof RateLimitError) {
// 429 - Rate limited
console.error('Rate limited:', err.message)
console.error('Retry after:', err.retryAfter, 'seconds')
console.error('Is daily limit:', err.isDaily)
} else if (err instanceof PayzCoreError) {
// Other API errors (500, etc.)
console.error('API error:', err.status, err.message)
}
}Error Class Hierarchy
| HTTP Status | SDK Class | Properties |
|---|---|---|
| 400 | ValidationError | message, status, code, details (field-level errors) |
| 401 | AuthenticationError | message, status, code |
| 403 | ForbiddenError | message, status, code |
| 404 | NotFoundError | message, status, code |
| 429 | RateLimitError | message, status, code, retryAfter (seconds), isDaily (boolean) |
| Other | PayzCoreError | message, status, code |
All error classes extend PayzCoreError, which extends Error. You can catch PayzCoreError as a catch-all for any API error.
Python SDK
from payzcore import PayzCoreError, ValidationError, RateLimitError
try:
payment = client.payments.create(
amount=50, chain="TRC20", external_ref="customer-123"
)
except ValidationError as e:
print(f"Validation: {e.message}, details: {e.details}")
except RateLimitError as e:
print(f"Rate limited, retry after: {e.retry_after}s")
except PayzCoreError as e:
print(f"API error {e.status}: {e.message}")PHP SDK
use PayzCore\Exceptions\ValidationException;
use PayzCore\Exceptions\RateLimitException;
use PayzCore\Exceptions\PayzCoreException;
try {
$payment = $client->payments->create([
'amount' => 50, 'chain' => 'TRC20', 'external_ref' => 'customer-123'
]);
} catch (ValidationException $e) {
echo "Validation: " . $e->getMessage();
} catch (RateLimitException $e) {
echo "Rate limited, retry after: " . $e->getRetryAfter() . "s";
} catch (PayzCoreException $e) {
echo "API error {$e->getStatusCode()}: {$e->getMessage()}";
}Best Practices
- Always check the status code first. Different status codes require different handling strategies.
- Parse the
detailsarray on 400 errors. It contains field-level validation information that helps you fix the request. - Implement retry logic for 429 and 500 errors. Use the
X-RateLimit-Resetheader for rate limits and exponential backoff for server errors. - Do not retry 400, 401, 403, or 404 errors. These indicate issues that need to be fixed in your code or configuration, not transient failures.
- Use
external_order_idfor idempotency. This prevents duplicate payment creation during retries and returns the existing payment safely. - Log error responses. Store the full error response (including
details) for debugging and support requests. - Use typed SDK exceptions. The official SDKs provide specific error classes that make error handling clean and type-safe.