Skip to main content

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​

CodeNameRetryDescription
200OK-Request successful
201Created-Resource created successfully
400Bad RequestNoMalformed request syntax
401UnauthorizedMaybe*Authentication failed
403ForbiddenNoInsufficient permissions
404Not FoundNoResource does not exist
409ConflictNoResource conflict (e.g., duplicate)
422Unprocessable EntityNoValidation error
429Too Many RequestsYesRate limit exceeded
500Internal Server ErrorYesServer-side error
502Bad GatewayYesUpstream service error
503Service UnavailableYesService temporarily unavailable

*Retry after refreshing access token

Error Response Format​

Most errors use the simple envelope:

{
"error": "error_code",
"error_description": "Human-readable description"
}

Validation errors include per-field details under error_properties (a map of field path → list of message strings):

{
"error": "invalid_properties",
"error_description": "Validation failed",
"error_properties": {
"purchase.amount": ["Amount should be greater than 0"],
"purchase.currency": ["Currency is required"]
}
}

Authentication Errors​

Error CodeHTTP StatusMessageSolution
invalid_client401Invalid client credentialsVerify client_id and client_secret
invalid_token401Token is expiredRequest new access token
invalid_token401Token validation failedCheck token format and environment
invalid_grant401Invalid grant typeUse client_credentials grant
unauthorized401Authorization requiredInclude Authorization header

Validation Errors​

Error CodeHTTP StatusCommon FieldsDescription
invalid_properties400VariousOne or more fields failed validation. Per-field details are returned in error_properties.

Common Field Errors​

FieldError MessageSolution
project_idProject is requiredInclude project_id in request or ensure your JWT token contains a project
project_idProject not foundVerify project ID exists and you have access
purchase.amountAmount must be greater than 0Use positive amount in minor units
purchase.amountInvalid amount formatUse a whole number in minor units (e.g., 1000 for €10.00)
purchase.currencyCurrency is requiredInclude currency code
purchase.currencyInvalid currencyUse valid ISO 4217 code
purchase.referenceReference is requiredInclude a reference (it does not need to be unique)
redirect_urls.success_urlInvalid URL formatUse valid HTTPS URL
redirect_urls.callback_urlInvalid URL formatUse valid HTTPS URL
lifetimeLifetime must be positiveUse a positive integer, or 0 to never expire. Split orders require 0.
experience.languageInvalid language codeUse supported language

Resource Errors​

Error CodeHTTP StatusMessageDescription
not_found404Order not foundOrder ID does not exist
not_found404Payment link not foundLink ID does not exist
not_found404Project not foundProject ID does not exist

Business Logic Errors​

Error CodeHTTP StatusMessageSolution
conflict409Order already completedOrder cannot be modified

Split Payment Errors​

Returned by order creation and payment-link creation when the request conflicts with the project's split policy. Request-validation problems return 400; policy, beneficiary, and override conflicts return 422. Some codes add details under error_properties.

Setup and request validation:

Error CodeHTTP StatusEndpointSolution
intermediary_account_required400OrderThe project's split setup is not complete — request activation through Paysera support
invalid_properties400OrderRequest validation failed (e.g. splits[].type must be variadic/tip; split_overrides.slots[].type must be fixed/percentage/remainder); fix the fields in error_properties
validation_split_expiration_not_allowed400Payment LinkSet lifetime: 0 — split-enabled orders need non-expiring links
validation_split_amount_mismatch400Payment LinkSet the link amount equal to the split order's full amount
policy_not_configured422OrderThe project owner needs to finish configuring the policy template
policy_invalid422OrderThe project's split policy is invalid — contact Paysera support

Standard splits (splits[]):

Error CodeHTTP StatusEndpointSolution
variadic_entry_required422OrderAdd a {type:"variadic", beneficiary_id:"..."} entry
variadic_entry_not_allowed422OrderRemove the variadic entry — the policy has no variadic slot
variadic_entry_requires_policy422OrderOnly send variadic entries when the project has a configured policy
split_variadic_count_mismatch422OrderSend exactly one variadic entry per variadic slot (error_properties.expected/actual)
split_variadic_slot_id_required422OrderMultiple variadic slots — set slot_id on each variadic entry (error_properties.entry_indexes)
split_variadic_slot_id_unknown422OrderA variadic slot_id matches no variadic slot (error_properties.slot_ids)
split_variadic_slot_id_duplicate422OrderUse each variadic slot_id at most once (error_properties.slot_ids)
variadic_beneficiary_required422OrderSet beneficiary_id on the variadic entry
tip_beneficiary_required422OrderSet beneficiary_id on the tip entry
tip_entries_without_tips_enabled422OrderHave payer tips enabled, or drop the tip entries
tip_beneficiary_consent_not_given422OrderTip recipient must give tax-agent consent (LT projects) (error_properties.recipient_name)
split_amount_too_low422OrderIncrease the order amount to meet the policy's minimum

Per-order overrides (split_overrides):

Error CodeHTTP StatusEndpointSolution
overrides_not_enabled422OrderRequest the per-order overrides capability (Paysera support)
split_overrides_require_policy422OrderOnly use overrides when the project has a configured policy
split_overrides_incomplete422OrderRestate every policy slot exactly once (error_properties.missing_slot_ids)
split_override_unknown_slot422OrderUse slot_ids from the split-policy response (error_properties.slot_ids)
split_override_duplicate_slot422OrderList each slot once (error_properties.slot_ids)
split_override_recipient_required422OrderAdd a recipient to the variadic slot (error_properties.slot_id)
split_override_recipient_not_allowed422OrderOmit recipient for the merchant slot (error_properties.slot_id)
split_override_recipient_invalid422OrderProvide exactly one of beneficiary_id/account (error_properties.slot_id)
split_override_value_invalid422Orderfixed > 0; percentage 1–10000; omit for remainder (error_properties.slot_id, type)
split_override_variadic_entry_not_allowed422OrderPut only tip entries in splits when using overrides
split_remainder_required422OrderMake exactly one slot remainder
split_too_many_remainders422OrderUse exactly one remainder slot
split_percentage_sum_exceeded422OrderKeep percentage slots below 100% in total

Recipient resolution (both paths):

Error CodeHTTP StatusEndpointSolution
split_beneficiary_not_found422OrderRegister the beneficiary, then reference its id (error_properties.beneficiary_ids)
split_beneficiary_account_not_found422OrderUse an existing Paysera EVP account (error_properties.missing_accounts)
splits_invalid422OrderReview the split entries against the project's policy

Rate Limiting Errors​

Rate limiting is enforced at the API gateway. On throttle, the gateway returns 429 Too Many Requests with a Retry-After header indicating the number of seconds to wait before retrying.

HeaderDescription
Retry-AfterSeconds to wait before retry

Rate Limit Handling Examples​

Implement exponential backoff when encountering rate limits:

<?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);
});

Server Errors​

HTTP StatusDescriptionSolution
500Internal server errorRetry with backoff
502Bad gateway (upstream service unreachable)Retry with backoff
503Service temporarily unavailableRetry with backoff

Server-side errors return the simple envelope (error, error_description).

Error Handling by Type​

PHP Example​

<?php

function handleError(int $httpCode, array $body): never
{
$error = $body['error'] ?? 'unknown_error';
$description = $body['error_description'] ?? 'Unknown error';
$properties = $body['error_properties'] ?? [];

match (true) {
$httpCode === 401 => throw new AuthenticationException($description),
$httpCode === 403 => throw new AuthorizationException($description),
$httpCode === 404 => throw new NotFoundException($description),
$httpCode === 409 => throw new ConflictException($description),
$httpCode === 400 => throw new ValidationException($description, $properties),
$httpCode === 429 => throw new RateLimitException($description),
default => throw new ApiException($description, $httpCode),
};
}

JavaScript Example​

function handleError(response, body) {
const { error, error_description, error_properties } = body;

switch (response.status) {
case 401:
throw new AuthenticationError(error_description);
case 403:
throw new AuthorizationError(error_description);
case 404:
throw new NotFoundError(error_description);
case 409:
throw new ConflictError(error_description);
case 400:
throw new ValidationError(error_description, error_properties);
case 429:
throw new RateLimitError(error_description, response.headers.get('Retry-After'));
default:
throw new ApiError(error_description, response.status);
}
}

User-Friendly Messages​

Error CodeUser Message
invalid_clientUnable to authenticate. Please contact support.
invalid_tokenSession expired. Please try again.
invalid_propertiesPlease check your input and try again.
not_foundThe requested item was not found.
conflictThis action cannot be completed. The item may already exist.
429 Too Many RequestsToo many requests. Please wait a moment.
500/502/503Service temporarily unavailable. Please try again.

Troubleshooting Guide​

SymptomCheckSolution
401 on all requestsCredentialsVerify client_id/secret
401 after workingTokenRefresh access token
400 with amountFormatUse minor units as an integer (e.g., 1000 for €10.00)
400 with URLProtocolUse HTTPS URLs
404 on orderIDVerify order UUID
409 on payment-link createDuplicate link nameUse a unique link name per order
429 frequentlyRequest rateImplement rate limiting