NeverDown API
NeverDown is a drop-in replacement for the Stripe API. Same endpoints, same request params, same object shapes, same webhook signature scheme. Behind that surface every charge is scored and routed across all of your processor accounts, with automatic failover when one degrades or freezes.
- const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
+ const stripe = new Stripe(process.env.NEVERDOWN_SECRET_KEY, {
+ host: "router.neverdown.ai",
+ protocol: "https",
+ });Base URL: https://router.neverdown.ai/v1 (also served at https://router.neverdown.ai/api/public/v1). All requests accept application/x-www-form-urlencoded or JSON, and all responses are JSON.
Quickstart
Create a key under Developers in your console, then charge a card:
curl https://router.neverdown.ai/v1/payment_intents \
-u nd_test_yourkey: \
-H "Idempotency-Key: order_1041" \
-d amount=4999 \
-d currency=usd \
-d confirm=true \
-d "payment_method_data[type]=card" \
-d "payment_method_data[card][number]=4242424242424242" \
-d "payment_method_data[card][exp_month]=12" \
-d "payment_method_data[card][exp_year]=2030" \
-d "payment_method_data[card][cvc]=123"{
"id": "pi_...",
"object": "payment_intent",
"amount": 4999,
"currency": "usd",
"status": "succeeded",
"latest_charge": "ch_...",
"neverdown": {
"processor": "stripe",
"routing_score": 0.87,
"attempts": [{ "account": "Stripe — Primary", "status": "approved", "latency_ms": 412 }]
}
}Authentication
Keys look like nd_test_… and nd_live_…. Send them as a bearer token or as the HTTP Basic username (what Stripe SDKs do automatically). Keys are hashed at rest and shown once at creation. Rate limit: 300 requests per minute per key.
Authorization: Bearer nd_live_xxx
Idempotency-Key: <your unique key> # POST requests, replayed for 24hPayment Intents
/v1/payment_intentscreate (optionally confirm)/v1/payment_intents/:idretrieve/v1/payment_intents/:idupdate/v1/payment_intents/:id/confirmauthorize & route/v1/payment_intents/:id/capturemanual capture/v1/payment_intents/:id/cancelcancel/v1/payment_intentslistSupported params: amount, currency, confirm, customer, payment_method, payment_method_data[card][…], capture_method, description, receipt_email, statement_descriptor, metadata[…], off_session.
Charges
/v1/chargeslegacy one-step charge/v1/charges/:idretrieve/v1/chargeslist (filter by payment_intent)/v1/charges/:id/refundlegacy refundcurl https://router.neverdown.ai/v1/charges \
-u nd_live_yourkey: \
-d amount=2500 -d currency=usd -d source=tok_...Refunds
/v1/refundscharge or payment_intent, full or partial/v1/refunds/:idretrieve/v1/refundslistCustomers & payment methods
/v1/customerscreate/v1/customers/:idretrieve/v1/customers/:idupdate/v1/customers/:iddelete/v1/payment_methodstokenize a card/v1/payment_methods/:id/attachattach to customer/v1/payment_methods/:id/detachdetach/v1/payment_methodslist by customer/v1/tokenslegacy card tokenCard vault & PCI
Card numbers you send are encrypted with AES-256-GCM under a versioned server-held key and stored in a vault table that no client, dashboard, or API key can read. Only the last four digits, brand, BIN range, expiry, and a merchant-scoped fingerprint are exposed in API responses. The full number is decrypted for a few milliseconds inside the authorization path and never logged. Re-charging uses the reusable pm_… token, so a card entered once works across every processor NeverDown routes to.
Handling raw card data on your servers places you in PCI DSS scope (SAQ D). Send cards over TLS only, and keep them out of your own logs.
Webhooks
Register endpoints in the console or over the API. Deliveries carry both NeverDown-Signature and Stripe-Signature headers in the identical t=…,v1=… HMAC-SHA256 format, so existing verification code keeps working — just swap in the NeverDown endpoint secret. Failed deliveries retry three times.
const event = stripe.webhooks.constructEvent(
rawBody,
req.headers["stripe-signature"],
process.env.NEVERDOWN_WEBHOOK_SECRET,
);Event types: payment_intent.succeeded, payment_intent.payment_failed, payment_intent.canceled, charge.succeeded, charge.failed, charge.captured, charge.refunded, customer.created, payment_method.attached, payment_method.detached.
Errors & decline codes
Errors use the Stripe envelope and status codes: 400 invalid request, 401 bad key, 402 card declined, 404 missing resource, 429 rate limited.
{
"error": {
"type": "card_error",
"code": "card_declined",
"decline_code": "insufficient_funds",
"message": "Your card has insufficient funds.",
"payment_intent": { "id": "pi_...", "status": "requires_payment_method" }
}
}Every processor's native decline reason is normalised to a canonical NeverDown reason first, then mapped to the matching Stripe decline code, so your existing retry logic behaves the same no matter which processor handled the attempt.
Routing metadata
Every PaymentIntent and Charge carries an extra neverdown object — ignore it and the response is Stripe-shaped, or read it to see which processor won, the routing score, and each failover attempt.
"neverdown": {
"processor": "authorize_net",
"processor_account_id": "…",
"routing_decision_id": "…",
"routing_score": 0.74,
"attempts": [
{ "account": "Stripe — Primary", "status": "error", "reason": "processor_unavailable", "latency_ms": 2100 },
{ "account": "Authorize.Net", "status": "approved", "reason": null, "latency_ms": 380 }
]
}Test cards
| Number | Behaviour |
|---|---|
| 4242 4242 4242 4242 | Approves |
| 4000 0000 0000 0002 | Generic decline |
| 4000 0000 0000 9995 | Insufficient funds |
| 4000 0000 0000 0069 | Expired card |
| 4000 0000 0000 0127 | Incorrect CVC |
| 4000 0000 0000 0119 | Processing error — triggers failover |
Compatibility matrix
| Stripe feature | NeverDown |
|---|---|
| PaymentIntents (create, confirm, capture, cancel) | Supported |
| Charges + legacy refunds | Supported |
| Refunds (full and partial) | Supported |
| Customers, PaymentMethods, Tokens | Supported |
| Events + signed webhooks | Supported |
| Idempotency keys | Supported |
| Stripe.js / Elements | Not yet — post card data server-side |
| 3D Secure / SCA | Not yet |
| Subscriptions, Invoices, Connect | Not planned |
Ready to switch?
Create an account, add your processors, and mint a test key in a couple of minutes.
Get started