Errors
The gateway returns errors as RFC 9457
problem documents with the application/problem+json content type. The type field
is a stable URI you can branch on.
{ "type": "https://api.paymee.online/errors/validation-error", "title": "Validation Error", "status": 422, "detail": "One or more fields failed validation.", "errors": [ { "field": "email", "code": "required", "message": "This field is required." } ]}| Field | Meaning |
|---|---|
type |
Stable URI identifying the error — branch on this. |
title |
Short, human-readable summary. |
status |
HTTP status code. |
detail |
Explanation specific to this occurrence. |
errors |
On validation-error only: one { field, code, message } per invalid field. |
existing_session_id |
On conflict from session creation: the session that already uses this merchant_reference. |
Key your handling on type (and errors[].code), never on title, detail or
message, which may change.
HTTP statuses
Section titled “HTTP statuses”| Status | Means |
|---|---|
400 |
The request is malformed (e.g. the body isn’t valid JSON). |
401 |
Missing, malformed, expired or revoked API key. |
404 |
The object doesn’t exist on this account. |
409 |
The request conflicts with an earlier one. |
422 |
The request is well-formed but was refused: a field failed validation, or a business rule refused it. |
429 |
Rate limit exceeded. |
500 |
Unexpected server error. Nothing was changed. |
Error type catalog
Section titled “Error type catalog”All type URIs are under https://api.paymee.online/errors/.
type suffix |
HTTP | Meaning | Retry? |
|---|---|---|---|
bad-request |
400 | Malformed request: the body isn’t valid JSON, or a header is invalid. | No |
unauthorized |
401 | Missing, malformed, expired, or revoked API key. | No |
forbidden |
403 | Authenticated, but not allowed. | No |
not-found |
404 | The session does not exist for this account. | No |
conflict |
409 | Same merchant_reference as an existing session, with a different amount or currency. Includes existing_session_id. |
No |
session-terminal |
409 | The session is already final (cancel). | No |
idempotency-key-reuse |
409 | The Idempotency-Key was already used for a different refund request. |
No |
validation-error |
422 | One or more fields failed validation (see errors). |
No |
invalid-state |
422 | Not allowed in the session’s current state (e.g. canceling a PROCESSING session, refunding one that didn’t succeed). |
No |
no-payment |
422 | The session has no successful payment to refund. | No |
partial-requires-settled |
422 | Partial refund before the payment has settled. See Refunds. | Later |
over-refund |
422 | The refund exceeds the amount left to refund. | No |
insufficient-funds |
422 | The refund can’t be funded from your balance. | Later |
refund-failed |
422 | The refund could not be recorded. | No |
rate-limit-exceeded |
429 | Too many requests. Wait Retry-After seconds. |
Yes |
error |
405 / 415 | Wrong HTTP method or content type. | No |
internal-error |
500 | Unexpected server error; nothing was changed. | Yes, with backoff |
New types may be added (see Versioning): give your code a
default branch.
Validation error codes
Section titled “Validation error codes”A validation-error lists each invalid field in errors. Nested fields are named with
dots, e.g. items.1 or metadata.cart_id.
Any field
errors[].code |
Meaning |
|---|---|
required |
The field is missing. |
blank |
A required text field is empty. |
null |
The field is null. |
invalid |
The value is malformed (e.g. not an email address, wrong JSON type). |
max_length |
The text is too long. |
min_value / max_value |
The number is out of range (e.g. max_attempts outside 1–10). |
invalid_choice |
Not one of the allowed values (e.g. refund_type). |
not_a_list / not_a_dict |
items isn’t a list, or one of its entries isn’t an object. |
amount and currency
errors[].code |
Meaning |
|---|---|
invalid_format |
Thousands separators, leading zeros, or not a decimal number. |
invalid_precision |
The decimals don’t match the currency: exactly 3 for TND, 2 for EUR. See Amounts & currency. |
invalid_value |
Zero or negative, or a foreign amount that rounds to nothing in TND. |
amount_too_large |
Over 999999.999 TND, before or after conversion. |
currency_unsupported |
No exchange rate is configured for this currency. See Amounts & currency. |
metadata
errors[].code |
Meaning |
|---|---|
too_many_keys |
More than 50 keys. |
key_too_long |
A key is longer than 40 characters. |
invalid_key_chars |
A key contains [ or ]. |
invalid_value_type |
A value is an object, a list or null (text, numbers and booleans are accepted). |
value_too_long |
A value is longer than 500 characters. |
return_url, cancel_url, webhook_url
errors[].code |
Meaning |
|---|---|
https_required |
The URL doesn’t use https://. |
invalid_domain |
The host isn’t a domain name with at least one dot (e.g. localhost). |
ip_not_allowed |
webhook_url uses an IP address instead of a domain name. |
invalid_scheme |
javascript: URLs are refused. |
url_too_long |
Over 2048 characters. |
Rate limits
Section titled “Rate limits”Limits apply per merchant account, separately for live (sk_live_) and test
(sk_test_) keys: test traffic never uses your live budget, and every key of the same
account shares that account’s budget.
Every request counts against the account-wide limit. Creating sessions and refunds also count against their own, lower limit.
| Budget | Endpoints | Live | Test |
|---|---|---|---|
| Account-wide | All gateway endpoints | 25 requests/second | 10 requests/second |
| Create | POST /gateway/sessions/ |
10 requests/second | 5 requests/second |
| Refund | POST /gateway/sessions/{id}/refund/ |
5 requests/second | 2 requests/second |
Over a limit, the API answers 429 Too Many Requests with a Retry-After
header giving the number of seconds to wait. Spread bulk work (backfills,
reconciliation) over time rather than sending it in bursts.

