Skip to content
Docs menu

Endpoints

Errors

Status codes, the error envelope, and the codes to branch on.

Errors use standard HTTP status codes and one envelope. code is stable, so branch on it. message is written for people and may change. field names the input at fault, when there is one, and request_id matches the 402pay-Request-Id header.

Status codes

StatusMeaning
400The request is malformed or a field is invalid.
401There's no valid key. The response has a WWW-Authenticate: Bearer header.
403The key can't do this, or the request came from the wrong place.
404Nothing with that ID belongs to your business, or the path doesn't exist.
405The path exists but doesn't take this method. The response is empty, with no request ID.
409The request conflicts with the object's current state.
410What's being paid has expired.
415The body isn't JSON.
429Too many requests or attempts.
500Something failed on our side.
503This deployment can't do it right now, such as sending an email or reaching a network.

Error codes

Requests and keys

CodeStatusWhen
invalid_request400A field is missing, unknown or invalid. field names it. Metadata refuses reserved names with "Metadata keys can't be named {key}." On POST /wallet, reused keys answer "These keys are already connected to another business." Text fields can't contain null characters ("{field} must not contain null characters.") or an escaped unpaired surrogate such as \ud800 ("{field} must be valid text.").
invalid_json400The body isn't valid JSON, or isn't UTF-8.
idempotency_key_required400POST /checkouts, POST /payments/{id}/request-remainder and POST /wallet/transactions need an Idempotency-Key header.
unsupported_media_type415A body was sent without Content-Type: application/json.
payload_too_large413The request body is larger than 1 MiB.
unauthenticated401No key was sent.
invalid_api_key401The key is invalid or revoked, it's a publishable key, or the Authorization header isn't Bearer followed by the key.
business_forbidden403The 402pay-Business header names a business the key or the signed-in person can't act for. With a secret key, leave the header out.
permission_denied403A restricted key doesn't have the access this route needs.
test_mode_unavailable403On a live business, whose payments are real money, a test key tried to create a payment, open a checkout or request a remainder, or to change what customers see or pay: links, checkout settings, accepting or canceling a payment, or blocking a customer.
session_required403The route is for the dashboard only, such as managing API keys or sending from your wallet, so an API key can't use it.
cross_site_request403A request signed in with a cookie came from another site.
edge_forbidden403The request didn't come through https://dash.402pay.co/api/v1, the API's only address.
not_found404Nothing with that ID belongs to your business, or the path doesn't exist.
idempotency_key_reused409With a secret key or a session, the key was already used for a different request.
idempotency_key_in_use409The first request with this key is still running. Try again in a moment.
rate_limited429Too many requests from one IP address, or more than 10 webhook test events and resends in a minute for one business. Wait for the Retry-After seconds.
internal_error500Something failed on our side. Retry with the same Idempotency-Key.
temporarily_unavailable503402pay paused something for now, such as new checkouts, card payments, a network or new sign-ups. Try again later.
upstream_unavailable503402pay can't be reached right now. Retry with the same Idempotency-Key.

Payments

CodeStatusWhen
invalid_email400customer_email on a payment, or email on a checkout, isn't a valid address. Other routes, such as customers, answer invalid_request with field set instead.
reference_in_use409The reference names a live payment for another amount or currency, or one that already received funds.
not_accepting409The business has no wallet yet, or its wallet can't receive on the network a remainder needs.
business_suspended403402pay suspended the business, so it can't create payments or open checkouts. Checkouts already open can still finish.
payment_not_cancelable409Funds have arrived, or the payment came from a link.
payment_in_flight409A transfer for the payment is on its way, so it can't be canceled.
payment_not_acceptable409Only underpaid and needs_review payments can be accepted.
payment_not_underpaid409Only an underpaid payment has a remainder to request.
remainder_unavailable409The quote is still live and the customer can still send the rest, or the payment has no checkout page left.
nothing_due409Nothing is left to collect on the payment.

Checkouts and receipts

CodeStatusWhen
email_required400The rail or the business needs the customer's email, and none was sent.
rail_unavailable400The business doesn't accept this rail.
asset_unavailable400The business doesn't accept this coin on this network.
amount_out_of_range400The price is outside what cards allow, $5 to $10,000.
invalid_tx_hash400A claim's transaction hash doesn't fit the checkout's network.
customer_blocked403The business has blocked the customer with this email.
link_not_found404No active link has this code.
payment_not_found404No payment has this code.
payment_paid409Funds already reached the payment: it's succeeded, underpaid or needs_review, so its page can't start another attempt.
payment_canceled409The business canceled the payment.
wrong_rail409The action is for crypto checkouts, and this one is paid by card.
checkout_canceled409The checkout was canceled.
checkout_failed409The checkout failed. Start a new one.
checkout_not_cancelable409Funds may already be on the way.
checkout_not_supersedable409The checkout can't be replaced now, because funds may be on the way or it collects a remainder.
checkout_not_claimable409Only an expired or canceled checkout takes a claim.
already_claimed409The business is already reviewing a claim for this checkout.
checkout_not_retryable409The card checkout can't start another attempt now.
route_in_progress409The customer's payment on the current secure payment page may still go through, so the checkout can't start another attempt until it finishes.
no_route409No further card-payment attempt is available.
stale_route409This card payment page is out of date.
checkout_not_awaiting409The checkout is not waiting for a card payment.
payment_expired410The payment passed its expires_at.
checkout_expired410The checkout's quote expired. Start a new one for a fresh address and amount.
link_archived410The link was archived, so its page takes no new payments.

Links and customers

CodeStatusWhen
link_has_payments409A link with payments can't be deleted. Archive it instead.
link_disabled409402pay disabled the link, so it can't be restored.
customer_exists409Another customer already has this email.

Dashboard and account

These come from routes only the dashboard and its sign-up and sign-in pages use.

CodeStatusWhen
business_required400The request didn't name a business in the 402pay-Business header.
invalid_credentials400The email and password don't match an account, or the current password is wrong. An unknown email, or an account without a password, gets the same answer as a wrong password.
challenge_failed400Sign-up, sign-in or a password reset came without a passed Cloudflare Turnstile check in the 402pay-Challenge header, or with one Cloudflare refused, one already used or one from another form. Complete the check again and resend.
weak_password400The new password breaks a rule: too short or long, too repetitive, without letters, too common, or found in a data breach. The message says which.
password_required400The sign-up is being finished in a different browser, so the password chosen at sign-up is needed too.
signup_browser_required400A sign-up with a passkey is being finished in a different browser. It has no password to prove who started it, so enter the code in the browser that did.
invalid_code400The code from the email, the authenticator code or the recovery code is wrong or malformed.
code_expired400The emailed code is more than 15 minutes old. Send a new one.
verification_expired400 or 409The sign-up, email change or new alert email was finished, canceled or replaced, or is more than a day old. Start again.
invalid_token400The password reset, undo or wallet change link was already used, replaced by a newer one or expired.
challenge_expired400Two-step sign-in timed out or was already used. Sign in again.
passkey_failed400The passkey couldn't be verified: its challenge is unknown, expired, already used or another browser's, or its signature, site, user verification or sign counter doesn't check out. Start again for a new challenge.
passkey_unknown400The passkey isn't on any account, because it was removed or never added, or at a step-up it isn't one of this account's.
password_reset_required403The password stopped working after too many failed sign-ins, or after an email change was undone. Reset it to sign in. The message says which.
reset_on_hold409An email change was undone, so nobody can choose a new password until the hold ends, a day later. Retry-After says when.
step_up_required403The change decides where payments go or who can reach the business, and the session hasn't proven its password or a passkey in the last 15 minutes. Confirm it at POST /sessions/current/step-up and send the request again. API keys are never asked.
too_many_attempts429Too many wrong codes or passwords: five wrong two-step codes lock the person's codes for 15 minutes, five wrong tries use up an emailed code, ten wrong sign-up codes in a day lock an address's sign-ups, and failed passwords lock the email (or the session, for a current password) for a while. Wait for the Retry-After seconds; signing in again doesn't reset a lock.
too_many_emails429We've sent this address as many emails as we can for now, a new code was asked for too soon, or the person started too many email changes or new alert emails in the last hour. Retry-After says when to try again.
email_unavailable503This deployment can't send email, so sign-up, password resets, email changes and new alert emails aren't available on it.
email_taken409Another account already uses this email address.
two_factor_setup_required409The two-step setup ended: it was never started in this session, or its QR code is more than 10 minutes old. Start again for a new one.
two_factor_enabled409Two-step verification is already on.
two_factor_disabled409Two-step verification is off.
passkey_exists409The passkey being added is already on an account.
passkey_limit409The account already has 10 passkeys. Remove one to add another.
last_sign_in_method409Removing this passkey would leave the account no way to sign in. Add another passkey or set a password first.
no_passkeys409A passkey step-up was asked for on an account without passkeys. Confirm with the password instead.
current_session409Sign out to end the session you're using.
publishable_key409A publishable key has no name or permissions to change.
api_key_revoked409A revoked key can't be changed.
wallet_exists409The business already has a wallet.
wallet_required409The business needs a wallet before it can finish setup.
referral_locked409The business already has a wallet, so the referral code it signed up with can't change.
external_wallet409The wallet keeps its own keys, so there's no recovery phrase here.
wallet_change_pending409The wallet is already set to be deleted. Cancel the deletion first, or wait for it.
wallet_change_applied409The wallet change already took effect, so it can't be canceled.
invalid_address400A send's address isn't valid for the network, or belongs to this wallet.
insufficient_funds409A send is for more than the wallet holds.
insufficient_fee_funds409A token send needs the network's own coin for its fee, and the wallet doesn't hold enough of it.
duplicate_transaction409That transaction was already sent, so it's on the wallet's history.
transaction_rejected409The network refused a send, such as when another transaction from the address got there first or the fee was too low. Nothing was sent, so read a fresh send context and sign again.
network_unavailable503The network a send or its context needs couldn't be reached. Retry with the same Idempotency-Key: the same signed transaction never goes out twice.

Rate limits

Some routes limit how often one IP address can call them, and answer 429 rate_limited with a Retry-After header, in seconds, once it's used up.

RouteLimit per IP address
POST /checkouts30 per 10 minutes.
POST /accounts10 per hour.
POST /accounts/verify and /accounts/verify/resend20 per 10 minutes, together.
POST /sessions30 per 10 minutes.
POST /sessions/two-factor30 per 10 minutes.
POST /passkeys/authentication/options and /passkeys/authentication/verify60 per 10 minutes, together.
POST /me/password, /me/two-factor, /sessions/current/step-up and /sessions/current/step-up/options20 per 10 minutes, together.
POST /me/passkeys/registration/options and POST /me/passkeys20 per 10 minutes, together.
POST /me/email10 per hour.
POST /password-resets5 per hour.
POST /password-resets/check, /password-resets/confirm, POST /email-changes/undo and POST /wallet-changes/cancel20 per 10 minutes, together.
GET /public/referrals/{code}60 per 10 minutes.

Sign-in and email also have limits that count per person, email address or code rather than per IP address, so they apply wherever the request comes from, and starting a new sign-in doesn't reset them:

WhatLimit
Failed passwords, per email5 in a row lock it for 1 minute, 10 for 5 minutes, 15 for 15 minutes, and 20 and every 5 after for an hour, with 429 too_many_attempts. After 100, the password stops working until it's reset: 403 password_reset_required. A success or a reset clears the count. A browser that signed in to the account before keeps a count of its own, which locks the same way but never turns the password off, so failures from elsewhere can't lock its owner out.
Wrong current passwords, per sessionThe same locks for current_password on /me/password, /me/email, /me/two-factor and /sessions/current/step-up, counted per session.
Two-step codes, per person5 wrong codes, counted across every challenge, lock that person's codes for 15 minutes. Every code check then answers 429 too_many_attempts.
Emailed codes, per code5 wrong tries, then 429 too_many_attempts until a new code is sent. A new code can be sent a minute after the last, up to 5 per sign-up, email change or new alert email.
Emails, per address5 an hour and 20 a day from sign-ups, password resets, email changes and new alert emails, and at most 3 reset links an hour. Past that, a resend or a new alert email answers 429 too_many_emails, and other requests answer as usual but send nothing.
Sign-up codes, per address10 wrong codes a day, across every sign-up for the address, then 429 too_many_attempts.
Email changes, per person3 started an hour, whether or not the address was free, then 429 too_many_emails.
New alert emails, per person3 started an hour across all their businesses, including ones since replaced or canceled, then 429 too_many_emails. Resending a code and addresses that apply at once don't count.

Each of these 429 answers carries a Retry-After header, in seconds.

Response400 Bad Request
{  "error": {    "code": "invalid_request",    "message": "amount must be a whole number of minor units between $1.00 and $1,000,000.00.",    "field": "amount",    "request_id": "req_6eb3d90a19234e358f603a74e004c874"  }}