Error Codes Reference
Complete reference of all HTTP status codes and error responses.
Complete reference of all error codes returned by Paysera Checkout APIs.
HTTP Status Codes​
| Code | Name | Retry | Description |
|---|---|---|---|
| 200 | OK | - | Request successful |
| 201 | Created | - | Resource created successfully |
| 400 | Bad Request | No | Malformed request syntax |
| 401 | Unauthorized | Maybe* | Authentication failed |
| 403 | Forbidden | No | Insufficient permissions |
| 404 | Not Found | No | Resource does not exist |
| 409 | Conflict | No | Resource conflict (e.g., duplicate) |
| 422 | Unprocessable Entity | No | Validation error |
| 429 | Too Many Requests | Yes | Rate limit exceeded |
| 500 | Internal Server Error | Yes | Server-side error |
| 502 | Bad Gateway | Yes | Upstream service error |
| 503 | Service Unavailable | Yes | Service temporarily unavailable |
*Retry after refreshing access token
Error Response Format​
{
"error": "error_code",
"message": "Human-readable description",
"details": [
{
"field": "field_name",
"message": "Field-specific error"
}
]
}
Authentication Errors​
| Error Code | HTTP Status | Message | Solution |
|---|---|---|---|
invalid_client | 401 | Invalid client credentials | Verify client_id and client_secret |
invalid_token | 401 | Token is expired | Request new access token |
invalid_token | 401 | Token validation failed | Check token format and environment |
invalid_grant | 401 | Invalid grant type | Use client_credentials grant |
unauthorized | 401 | Authorization required | Include Authorization header |
Validation Errors​
| Error Code | HTTP Status | Common Fields | Description |
|---|---|---|---|
validation_error | 422 | Various | One or more fields failed validation |
Common Field Errors​
| Field | Error Message | Solution |
|---|---|---|
project_id | Project is required | Include project_id in request or ensure your JWT token contains a project |
project_id | Project not found | Verify project ID exists and you have access |
purchase.amount | Amount must be greater than 0 | Use positive amount in minor units |
purchase.amount | Invalid amount format | Use whole number string (e.g., "1000" for €10.00) |
purchase.amount.currency | Currency is required | Include currency code |
purchase.amount.currency | Invalid currency | Use valid ISO 4217 code |
purchase.reference | Reference is required | Include unique reference |
redirect_urls.success_url | Invalid URL format | Use valid HTTPS URL |
redirect_urls.callback_url | Invalid URL format | Use valid HTTPS URL |
lifetime | Lifetime must be positive | Use positive integer |
experience.language | Invalid language code | Use supported language |
Resource Errors​
| Error Code | HTTP Status | Message | Description |
|---|---|---|---|
not_found | 404 | Order not found | Order ID does not exist |
not_found | 404 | Payment link not found | Link ID does not exist |
not_found | 404 | Project not found | Project ID does not exist |
Business Logic Errors​
| Error Code | HTTP Status | Message | Solution |
|---|---|---|---|
conflict | 409 | Order with reference exists | Use unique reference |
conflict | 409 | Order already completed | Order cannot be modified |
invalid_state | 409 | Cannot refund pending order | Wait for completion |
invalid_state | 409 | Order is cancelled | Cannot process payment |
amount_exceeded | 422 | Refund exceeds available | Reduce refund amount |
currency_mismatch | 422 | Currency must match | Use original currency |
method_unavailable | 422 | Payment method unavailable | Choose different method |
limit_exceeded | 422 | Amount exceeds method limit | Reduce amount or change method |
Rate Limiting Errors​
| Error Code | HTTP Status | Headers | Solution |
|---|---|---|---|
rate_limited | 429 | Retry-After, X-RateLimit-* | Wait and retry |
Rate Limit Headers​
| Header | Description |
|---|---|
Retry-After | Seconds to wait before retry |
X-RateLimit-Limit | Request limit per window |
X-RateLimit-Remaining | Remaining requests |
X-RateLimit-Reset | Unix timestamp of reset |
Rate Limit Handling Examples​
Implement exponential backoff when encountering rate limits:
- PHP
- JavaScript
- Python
<?php
class RateLimitHandler
{
private int $maxRetries = 3;
private int $baseDelay = 1000; // milliseconds
public function executeWithRetry(callable $request): mixed
{
$attempt = 0;
while ($attempt < $this->maxRetries) {
try {
return $request();
} catch (RateLimitException $e) {
$attempt++;
if ($attempt >= $this->maxRetries) {
throw $e;
}
$delay = $this->calculateDelay($attempt, $e->getRetryAfter());
usleep($delay * 1000);
}
}
}
private function calculateDelay(int $attempt, ?int $retryAfter): int
{
if ($retryAfter !== null) {
return $retryAfter * 1000; // Convert seconds to milliseconds
}
// Exponential backoff: 1s, 2s, 4s...
return $this->baseDelay * pow(2, $attempt - 1);
}
}
// Usage
$handler = new RateLimitHandler();
$result = $handler->executeWithRetry(function() use ($client, $payload) {
return $client->createOrder($payload);
});
class RateLimitHandler {
constructor(maxRetries = 3, baseDelay = 1000) {
this.maxRetries = maxRetries;
this.baseDelay = baseDelay;
}
async executeWithRetry(request) {
let attempt = 0;
while (attempt < this.maxRetries) {
try {
return await request();
} catch (error) {
if (error.status !== 429) {
throw error;
}
attempt++;
if (attempt >= this.maxRetries) {
throw error;
}
const retryAfter = error.headers?.get('Retry-After');
const delay = this.calculateDelay(attempt, retryAfter);
await this.sleep(delay);
}
}
}
calculateDelay(attempt, retryAfter) {
if (retryAfter) {
return parseInt(retryAfter, 10) * 1000;
}
return this.baseDelay * Math.pow(2, attempt - 1);
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
// Usage
const handler = new RateLimitHandler();
const result = await handler.executeWithRetry(() => createOrder(payload));
import time
from typing import Callable, TypeVar
T = TypeVar('T')
class RateLimitHandler:
def __init__(self, max_retries: int = 3, base_delay: float = 1.0):
self.max_retries = max_retries
self.base_delay = base_delay
def execute_with_retry(self, request: Callable[[], T]) -> T:
attempt = 0
while attempt < self.max_retries:
try:
return request()
except RateLimitError as e:
attempt += 1
if attempt >= self.max_retries:
raise
delay = self._calculate_delay(attempt, e.retry_after)
time.sleep(delay)
def _calculate_delay(self, attempt: int, retry_after: int | None) -> float:
if retry_after is not None:
return float(retry_after)
return self.base_delay * (2 ** (attempt - 1))
# Usage
handler = RateLimitHandler()
result = handler.execute_with_retry(lambda: create_order(payload))
Server Errors​
| Error Code | HTTP Status | Message | Solution |
|---|---|---|---|
internal_error | 500 | Internal server error | Retry with backoff |
gateway_error | 502 | Bad gateway | Retry with backoff |
service_unavailable | 503 | Service unavailable | Retry with backoff |
Error Handling by Type​
PHP Example​
<?php
function handleError(int $httpCode, array $body): never
{
$error = $body['error'] ?? 'unknown_error';
$message = $body['message'] ?? 'Unknown error';
match ($httpCode) {
401 => throw new AuthenticationException($message),
403 => throw new AuthorizationException($message),
404 => throw new NotFoundException($message),
409 => throw new ConflictException($message),
422 => throw new ValidationException($message, $body['details'] ?? []),
429 => throw new RateLimitException($message),
default => throw new ApiException($message, $httpCode),
};
}
JavaScript Example​
function handleError(response, body) {
const { error, message, details } = body;
switch (response.status) {
case 401:
throw new AuthenticationError(message);
case 403:
throw new AuthorizationError(message);
case 404:
throw new NotFoundError(message);
case 409:
throw new ConflictError(message);
case 422:
throw new ValidationError(message, details);
case 429:
throw new RateLimitError(message, response.headers.get('Retry-After'));
default:
throw new ApiError(message, response.status);
}
}
User-Friendly Messages​
| Error Code | User Message |
|---|---|
invalid_client | Unable to authenticate. Please contact support. |
invalid_token | Session expired. Please try again. |
validation_error | Please check your input and try again. |
not_found | The requested item was not found. |
conflict | This action cannot be completed. The item may already exist. |
rate_limited | Too many requests. Please wait a moment. |
internal_error | Service temporarily unavailable. Please try again. |
Troubleshooting Guide​
| Symptom | Check | Solution |
|---|---|---|
| 401 on all requests | Credentials | Verify client_id/secret |
| 401 after working | Token | Refresh access token |
| 422 with amount | Format | Use minor units as string (e.g., "1000" for €10.00) |
| 422 with URL | Protocol | Use HTTPS URLs |
| 404 on order | ID | Verify order UUID |
| 409 on create | Reference | Use unique reference |
| 429 frequently | Request rate | Implement rate limiting |