Skip to content
ripper docs Open the console

Errors

collect() never rejects for a payment outcome: it resolves { success: false, error }. error.code is the SDK error code; error.drop_code is the API error code underneath it, which support can look up, and error.request_id is the request id carried on every response. Shopper copy never shows a code.

const result = await ripper.collect({ amount: 4200, currency: 'GBP' });
if (!result.success) {
  console.log(result.error.code); // 'origin_not_allowed' — this page is not on the integration's allowed origins
  console.log(result.error.drop_code, result.error.request_id);
}

This page is ordered for a reader holding an SDK error code from a browser. If you are holding an HTTP status from a server log instead, Errors by HTTP status is the same information ordered for that. Both are generated from one catalogue, so they cannot disagree with each other or with the API.

Everything below is generated from the error catalogue, which is checked against the code on every run. If a table here disagrees with what you see, the catalogue is wrong and the test that proves it is broken.

The SDK error codes #

collect() resolves with one of these in error.code. Only runtime_unavailable rejects instead.

code when it happens from these API codes what your page should do
amount_unverified Session creation answers 422 while the integration requires a verified amount. Confirm answers 422 because a hold could not be bounded. amount_unverified Send verifiable items, or create the session from your server.
attempts_exhausted A third soft decline. Authenticate answers 409 after three attempts. A reload onto a session that a SOFT decline ended, which is the reading that means the attempts ran out. A session ended by any other category reports declined instead. attempts_exhausted Offer a new checkout or another payment method.
config_unavailable The config read answers 404: an unknown, revoked or inactive key, an unknown integration, or a live-only key on a test integration. No key on the script tag. A 304 with no cached body, or a malformed config. The live card-capture SDK will not load. The API answers public_key_missing, handle_not_found, resource_not_found or key_revoked. handle_not_found, key_revoked, public_key_missing, resource_not_found, unauthorized Check the key, integration and handle, and show a fallback.
currency_unknown Session creation answers 400 currency_required. currency_required Pass a currency, or configure a default on the integration.
declined A decline that ended the session: hard, fraud, network or provider error. A failed payment. Authenticate answers 409 session_declined. A reload onto a session that a non-soft decline ended, or onto a voided hold. Only a soft decline with an attempt left re-arms instead; every other category ends the session, so re-arming on one would offer a tap the API refuses. session_declined Offer another method or a new session. Read the last decline on your server for the reason: the browser never sees a decline code.
internal Invalid collect() options, where the message begins with "invalid request". Unexpected exceptions. Unmapped or non-JSON error bodies. Every API code that has no closer match. capture_window_ended, compat_provider_unknown, hold_already_decided, hold_duration_out_of_range, idempotency_key_missing, idempotency_key_reused, integration_builtin, integration_name_taken, internal_error, invalid_request, invalid_url, metadata_too_large, operation_in_progress, origin_invalid, permission_denied, unknown_event_type Log the API code and request id. For option errors, read the message: it is developer text, not shopper copy.
merchant_not_ready The API answers acquiring_profile_incomplete, routing_unavailable, merchant_not_active or key_live_only. acquiring_profile_incomplete, key_live_only, merchant_not_active, routing_unavailable This is merchant configuration, not something the shopper can fix. Show that payments are unavailable.
network_error A fetch throws. The config read, session creation and state read try once; authenticate and confirm back off over one, two, four and eight seconds, five tries in all. The session-creation rate limit of 20 per minute per address is expected to surface this way, per a code comment that has not been verified. none — this one is client-side only If collect() resolved, offer a retry.
origin_not_allowed Session creation answers 403 origin_not_allowed. origin_not_allowed Add the page's origin to the integration's allowed origins.
payment_pending The 60-second processing ceiling is reached, which adds a pending status and a payment id. The confirm answer is lost and the state read also fails. A reload onto a session whose payment is still outstanding. A second collect() while a payment is locked, with no request made. The API answers session_processing, or session_completed because the payment was already made in another tab. session_completed, session_processing Never charge again. Poll your server for the outcome, by session read or webhook.
runtime_unavailable The loader's manifest fetch fails. The runtime script fails to load. The manifest's API origin does not match the origin the loader was built with. none — this one is client-side only Catch the rejection and show your own fallback. This is the only outcome that rejects rather than resolves, and it carries a bare code with no message or request id.
session_expired The client's own timer fires as the shopper taps pay. The API answers 409 session_expired. The API answers 401 unauthorized anywhere, including on session creation. session_expired Create a new session and call collect() again. If it happens immediately, check the key or the client secret rather than the clock.
try_again The API answers authentication_incomplete out of sequence, three_ds_provider_unavailable, store_unavailable, card_data_rejected or customer_email_required. Card tokenisation fails. The 3-D Secure component itself fails to load, is dismissed, or is abandoned in the browser. This is not the same as the provider answering "not authenticated", which is a hard decline. authentication_incomplete, card_data_rejected, customer_email_required, store_unavailable, three_ds_provider_unavailable Nothing, while it re-arms. If it reached session creation or the config read instead, collect() resolves and you call it again.
user_cancelled Escape inside the checkout while the pay button is not locked. The abort signal was already aborted, or is aborted before the pay button locks. A later collect() supersedes this one. none — this one is client-side only Treat it as the shopper leaving. Nothing was charged. Show your own cart or pay button again.

API error codes #

Every code the API can answer (38 at this release), on the page for what you were doing when you met it.

Authenticating your calls #

code HTTP caused by what it means how to fix it can a retry succeed? what the shopper sees
key_live_only 403 your settings A live-only key was used while the effective mode is test. Turn live payments on, set the integration mode to auto, or use a key that allows test mode. no — Never until the mode is fixed. "This checkout is not ready yet. Please try again later."
key_revoked 401 your settings The key was revoked. Issue a new key and deploy it. no — Never. A new key is needed. "This checkout is not available right now. Please try again later."
merchant_not_active 403 your settings The account cannot take payments in its current state. Finish onboarding, or resolve the account status with ripper. no — Never until the account is active. "This checkout is not ready yet. Please try again later."
permission_denied 403 your settings The secret key lacks the permission this route needs. Use a key that can create payments, for creates, or read transactions, for reads. no — nothing changes the answer nothing — no shopper meets this
public_key_missing 401 your settings The merchant has no publishable key, so no browser can load the checkout. Create or activate the publishable key. no — Never until a publishable key exists. nothing — no shopper meets this
unauthorized 401 your code, your settings The credential is missing, invalid or expired, or the key's IP or origin allow-list blocked the call. The reason is withheld from browsers. From a server, send the ripper API key header. The Stripe-compatible routes take a bearer token instead. In a browser, check the key on the script tag and that the client secret matches the session id. no — Never with this credential. "This checkout is not available right now. Please try again later."

Setting up the integration #

code HTTP caused by what it means how to fix it can a retry succeed? what the shopper sees
acquiring_profile_incomplete 422 your settings, ripper Your live acquiring details are incomplete, so the charge cannot be sent. Complete the live acquiring profile: active, BIN, currency and merchant category code, plus the merchant ID for 3-D Secure. Contact ripper support if it already looks complete. After the profile is completed. The same session can then confirm. "This checkout is not ready yet. Please try again later."
hold_duration_out_of_range 400 your settings The hold duration must be between one and five days. Set a duration of one to five days. The default is five. no — nothing changes the answer nothing — no shopper meets this
integration_builtin 409 your settings The built-in integrations cannot be created, renamed or removed, and their origins are set by ripper. Use a custom integration instead. no — nothing changes the answer nothing — no shopper meets this
integration_name_taken 409 your settings An active integration already has that name. Pick another name. no — nothing changes the answer nothing — no shopper meets this
origin_invalid 400 your settings An allowed origin must be exactly a scheme, host and optional port: https, or http only for localhost and 127.0.0.1. No path and no wildcard. Enter an origin such as https://shop.example. no — nothing changes the answer nothing — no shopper meets this
origin_not_allowed 403 your settings The page's origin, or a missing origin, is not in the integration's allowed origins. Add the exact origin, such as https://shop.example, to that integration's allowed origins. Hosted-page origins are managed by ripper. no — Never until the origin is added. "This page is not allowed to take payments for this merchant."
routing_unavailable 503 your settings, ripper No single acquirer could be chosen for this live payment, because there were none or several. Contact ripper to fix live routing for this currency. no — Not by waiting. This is configuration, not a transient fault. "This checkout is not ready yet. Please try again later."

Creating sessions from your server #

code HTTP caused by what it means how to fix it can a retry succeed? what the shopper sees
card_data_rejected 400 your code, the shopper A value that looks like a card number was sent in a free-text field. It is never echoed back. Remove it from metadata, the customer name or email, the statement descriptor, the order reference, and item sku, name or type. Order references need fewer than 13 digits, or a letter. no — Never with the same payload. "Something went wrong. Please try again."
compat_provider_unknown 404 your code ripper only emulates Stripe. Use the Stripe-compatible path, or the native API. no — nothing changes the answer nothing — no shopper meets this
idempotency_key_missing 400 your code This write needs an idempotency key header of one to 255 printable ASCII characters. Send a unique key for each logical create. The Stripe-compatible create also accepts Stripe's own header, but not both with different values. no — Never as sent. nothing — no shopper meets this
idempotency_key_reused 409 your code The key was used for a different request or endpoint, or its first request is still running. A different request needs its own key. This one code covers both a key already used for a different request and a key whose first request is still running, so do not tell them apart by the code. After a refusal a new key is safe, because the refused request created nothing; after a timeout reuse the same key, because that request may have created a session. Only when the first request with this key is still running, which is a retry of an attempt that returned nothing — never a retry after a refusal. A different body or endpoint is refused for as long as this key's record lives. nothing — no shopper meets this
invalid_request 400 your code A field is malformed. The message names the field, never the value. Read the message. Amounts are positive minor units; a server create needs a three-letter currency; the confirmation URL must be https on an approved origin and at most 512 characters; the order reference is at most 64 characters with no control characters; at most 100 items; the body must be JSON. no — Never as sent. "Something went wrong on our side. Please try again in a moment."
metadata_too_large 400 your code More than 50 metadata entries, more than 8 KB of metadata, or a statement descriptor suffix longer than 22 characters. Trim the metadata or the suffix. no — nothing changes the answer "Something went wrong on our side. Please try again in a moment."
resource_not_found 404 your code There is no such session, payment, integration or hold for this merchant. Another merchant's id looks the same as an unknown one. Check the id, and that you are using the same merchant's key and the same mode. no — nothing changes the answer "This checkout is not available right now. Please try again later."

In the browser checkout #

code HTTP caused by what it means how to fix it can a retry succeed? what the shopper sees
amount_unverified 422 your code, your settings The integration requires a verified amount, and this one could not be verified. Send items that match the price list, rely on the integration default, create the session from your server, or set the amount trust policy to allow unverified amounts. no — Never as sent. The request has to change. "The amount could not be verified for this order."
attempts_exhausted 409 the shopper The session used all three of its attempts. Create a new session. no — Never on this session. Create a new one. "Too many attempts. Please start again with a different card."
authentication_incomplete 409 the shopper 3-D Secure was not finished: either awaiting the challenge, or never started. Nothing, if you use the SDK. If you call the API directly, finish the challenge or authenticate first, then post the confirm again. The same request, once the challenge is finished. nothing — no shopper meets this
currency_required 400 your code, your settings No currency was given and none could be resolved. Pass a currency, or set the integration's default. The order is: integration default, then the one active live acquiring profile, then the registered country. A server create with no currency gets invalid_request instead. no — Never as sent. "This checkout has no currency configured yet."
customer_email_required 400 the shopper, your code Every payment needs the shopper's email address. Pass the customer email to collect() or to the session create, or call setEmail(). Direct API callers send it on confirm. The same request, with the customer email. "Enter your email address so we can send your receipt."
handle_not_found 404 your settings, your code There is no checkout for this handle or key. The config read also answers it for an unknown integration name, a revoked or inactive key, and a live-only key on a test integration. Check the key on the script tag, the handle, the integration name, and the key and merchant status. no — Never. The 404 is not cached. "This checkout is not available right now. Please try again later."
session_completed 409 the shopper This session has already been paid. Treat it as paid. Read the session or payment from your server, and do not charge again. no — nothing changes the answer "This payment has already been completed."
session_declined 409 the shopper The session ended on a hard or fraud decline, or on its last soft decline. Create a new session. no — Never on this session. "Your card was declined. Please try another card."
session_expired 409 the shopper, your code The session's 30 minutes ran out before the payment was made. Create a new session, or call collect() again. no — Never on this session. "This checkout has expired. Please start again."
session_processing 409 the shopper Another tab is charging this session right now. Do not retry the charge. Read the outcome instead. After a wait, by reading the state rather than charging again. "This payment is already being processed in another tab."

Capturing or voiding holds #

code HTTP caused by what it means how to fix it can a retry succeed? what the shopper sees
capture_window_ended 409 ripper The window for charging this hold has ended, or is unknown, so it can only be released. Release the hold, and take a new payment if you still need one. no — Never. The hold can only be released. nothing — no shopper meets this
hold_already_decided 409 your settings The held payment has already been captured or voided. Read the payment to see how it was decided. no — nothing changes the answer nothing — no shopper meets this
operation_in_progress 409 ripper, your settings Another capture or void on this payment is still open. Wait, then read the payment. After a wait. The same decision id replays. nothing — no shopper meets this

Webhooks #

code HTTP caused by what it means how to fix it can a retry succeed? what the shopper sees
invalid_url 400 your code A webhook URL must be absolute, public and https. Do not use localhost, .local, .internal, a loopback address or a private IP literal. no — Never as sent. nothing — no shopper meets this
unknown_event_type 400 your code An event filter named an event the registry does not know. The refusal lists the allowed values. Use a value from the allowed list the refusal returns. no — nothing changes the answer nothing — no shopper meets this

Transient — safe to retry #

code HTTP caused by what it means how to fix it can a retry succeed? what the shopper sees
internal_error 500 ripper An unplanned fault. The message is always empty. Retry idempotently. If it persists, quote the request id to support. After a wait. On a create, reuse the same idempotency key. "Something went wrong on our side. Please try again in a moment."
store_unavailable 503 ripper A ripper store was unreachable. Nothing was created and nothing was charged twice. Retry with the same idempotency key. The wait in seconds appears only in the message. After about five seconds, with the same request and the same idempotency key. "Something went wrong. Please try again."
three_ds_provider_unavailable 503 ripper The 3-D Secure provider is down. This is not a decline. Let the shopper try again. After a wait. "Something went wrong. Please try again."

What your page is told #

For these, error.message carries a sentence written for you rather than for the shopper.

code the message your page receives
unauthorized The API did not accept this checkout's publishable key. Check that data-key is a current publishable key for this merchant, and that the key's allowed origins and IP addresses include this page.

Only on the Stripe-compatible layer #

code type what it means
card_declined card_error A soft decline, reported with the decline code and the element still mounted for a retry. The native SDK never exposes a decline code, so this is compatibility behaviour only.
email_required validation_error No shopper email was available anywhere, so the confirm resolves before any request and focuses the email field. The native code is customer_email_required.
not_supported_by_ripper api_error The Stripe feature is not emulated: the split card elements, several other element types, redirects, token and payment-method creation, SetupIntents, wallets, and Stripe's own test card numbers.