Errors
The shape of API errors, the HTTP codes and what to do with each code.
- Decide with the HTTP code and
error.code, which is stable.
- On a
400 invalid_request, read details.field and details.code.
- Retry only what can be retried, respecting
Retry-After.
A call without a secret key
curl -s https://api-epay.dev.n1co.dev/v1/payment_intents/pi_UGF5bWVudEludGVudEV4YW1w
401 Unauthorized
{
"error": {
"code": "invalid_api_key",
"message": "a valid secret key is required: Authorization: Bearer sk_..."
}
}
The error envelope#
| Field |
Description |
error.code |
Stable code. Use it in your code. |
error.message |
English text for your logs. It can change; do not show it. |
error.details |
Extra data for some codes, such as field and code. |
Messages never echo what you sent. Validation reports only the first failing field.
HTTP codes#
| HTTP |
Meaning |
Retry? |
400 |
The request is not valid. |
No. Fix the request. |
401 |
The key is missing or not valid. |
No. Check your key. |
404 |
The object does not exist in your store. |
No. |
409 |
Conflict with the current state. |
Depends on the code. |
413 |
The body is over 16 KiB. |
No. |
415 |
Content-Type is not application/json. |
No. |
422 |
n1co did not accept the request. |
Depends on the code. |
429 |
Too many requests. |
Yes, after Retry-After. |
500 |
Internal error. |
Yes, with increasing backoff. |
503 |
n1co is not available right now. |
Yes, after Retry-After when present. |
General codes#
error.code |
HTTP |
What to do |
invalid_request |
400 |
Read details.field and details.code and fix. |
invalid_api_key |
401 |
Check Authorization: Bearer sk_…. |
request_too_large |
413 |
Reduce the body to 16 KiB or less. |
unsupported_media_type |
415 |
Send Content-Type: application/json. |
rate_limited |
429 |
Wait the seconds in Retry-After. |
internal_error |
500 |
Retry later. If it persists, contact n1co. |
n1co_api_unavailable |
503 |
Retry after Retry-After. |
platform_access_pending |
503 |
ePay's access to your store is not ready. Retry after Retry-After. |
A details.code of unknown_field means an undocumented key; details.field names it, as customer.<key> inside the customer. Names are case-sensitive.
Setup#
Codes of POST /v1/setup. None of them stores anything: you can repeat the setup.
error.code |
HTTP |
What to do |
invalid_request |
400 |
The body or the webhook_url is not valid; the message names the field. |
invalid_credentials |
401 |
n1co rejected the client id or the client secret. |
store_already_enabled |
409 |
There was nothing to change. details has store_id and publishable_key. |
client_id_in_use |
409 |
That application is already bound to another store. |
setup_conflict |
409 |
Another setup of the store ran at the same time. Retry. |
missing_roles |
422 |
details.missing_roles lists the missing roles. |
client_app_not_found |
422 |
n1co does not know the application. Check the client id. |
rate_limited |
429 |
5 per minute per client_id, 60 per minute in total. Wait for Retry-After. |
n1co_api_unavailable |
503 |
Repeat after Retry-After (30 s). |
platform_access_pending |
503 |
Access to your application is not ready yet. Repeat after Retry-After. |
platform_certificate_mismatch |
503 |
A configuration problem on n1co's side. Contact n1co. |
Card sessions and cards#
error.code |
HTTP |
What to do |
card_session_not_found |
404 |
The session does not exist in your store. |
card_not_found |
404 |
payment_method is not a card of the customer with that customer.id. |
card_unavailable |
409 |
The card can no longer be used. The buyer types their card again. |
details.code |
Meaning |
missing_customer, invalid_customer |
customer is missing or not an object. |
missing_id, invalid_id, missing_name, invalid_name, missing_email, invalid_email, missing_phone, invalid_phone |
A customer field; details.field is customer.<field>. |
unknown_field |
An undocumented key; inside the customer, details.field is customer.<key>. |
invalid_page_origins |
page_origins is not valid. |
Payments#
error.code |
HTTP |
What to do |
payment_intent_not_found |
404 |
The intent does not exist in your store. |
payment_intent_not_cancelable |
409 |
It can be canceled only in requires_payment_method or requires_action; see details.status. |
When creating a payment intent, details.code can be:
details.code |
Meaning |
missing_amount, invalid_amount |
amount is missing or not an integer from 1 to 1000000000. |
missing_currency, invalid_currency |
currency is missing or not an ISO 4217 code. |
currency_not_supported |
The currency does not have two decimal places. |
currency_mismatch |
Your store charges in another currency. |
missing_customer, invalid_customer, customer field codes |
As for card sessions. |
invalid_description, invalid_reference, invalid_metadata |
The field does not meet its rules. |
invalid_billing, missing_country, invalid_country, invalid_state, invalid_postal_code |
The billing details are not valid. |
invalid_page_origins |
page_origins is not valid. |
invalid_payment_method |
payment_method is not a card id. |
Payment failures#
A failed attempt is not an HTTP error: it arrives in the intent's last_error, with code, decline_code and message. n1co.js translates message for the buyer.
last_error.code |
What happened |
What to do |
card_declined |
The bank declined the charge; decline_code has its code. |
Another card, or the buyer calls their bank. |
card_rejected |
n1co did not accept the new card. |
Ask for another card. |
card_unavailable |
The saved card stopped working. |
Charge with the card element. |
billing_required |
The card needs a billing address. |
Confirm again with billing. |
invalid_request |
n1co refused the request. |
Ask for another card. |
authentication_failed |
3D Secure was not completed. |
Let the buyer retry. |
authentication_expired |
3D Secure expired without an answer (10 minutes). |
Let the buyer retry. |
provider_error |
n1co answered something that could not be used. |
Retry in a few minutes. |
outcome_unknown |
Whether there was a charge is unknown; the intent stays processing. |
Do not charge again. Wait for the webhook. |
currency_mismatch, amount_mismatch |
n1co charged another currency or amount; it was voided and canceled. |
Create another intent. |
Refunds#
error.code |
HTTP |
What to do |
payment_intent_not_found |
404 |
The intent does not exist in your store. |
refund_not_found |
404 |
The refund does not exist in your store. |
payment_intent_not_refundable |
409 |
details.reason says why (next table). |
refund_exists |
409 |
It already has a refund that is not sent again now; details.refund is its id. |
refund_in_progress |
409 |
It is being sent; wait for Retry-After. |
n1co_api_unavailable, platform_access_pending |
503 |
Nothing was sent. The next POST sends it. |
details.reason |
What happened |
not_succeeded |
The intent is not succeeded. |
order_unknown |
The payment has no n1co order number. Contact n1co. |
attempts_exhausted |
The refund was already sent 3 times. |
details.code |
Meaning |
unknown_field |
An undocumented key, including amount. |
missing_payment_intent, invalid_payment_intent |
payment_intent is missing or not valid. |
invalid_reason |
reason is not 1 to 150 characters long or has control characters. |
invalid_metadata |
metadata is not valid. |
A refusal from n1co arrives in the refund's last_error:
last_error.code |
status |
What to do |
refund_rejected |
failed |
Read message, n1co's text. Send again or contact n1co. |
provider_error |
failed |
Send again later or contact n1co. |
order_not_found |
failed |
n1co does not know the order. Contact n1co. |
outcome_unknown |
pending |
Wait for the webhook; send again after 3 minutes. |
Events#
error.code |
HTTP |
What to do |
event_not_found |
404 |
The event does not exist in your store. |
details.code |
Meaning |
invalid_limit |
limit is not an integer from 1 to 100. |
invalid_type |
type is not an event type. |
unknown_parameter, duplicate_parameter, invalid_query |
An undocumented, repeated or unreadable parameter. |
Errors in the browser#
Errors from capture() and confirmPayment() come from n1co.js, not the API. They are in the n1co.js reference.
When to retry#
| Situation |
Retry |
429 and 503 with Retry-After |
Wait those seconds and repeat. |
500, or a network error with no response |
Repeat with increasing backoff. |
409 setup_conflict |
Repeat right away. |
400, 401, 404, 413, 415 |
Do not repeat without fixing. |