RailbedDocs

Testing

Test mode simulates payments end to end, with no card charged and no money moved. Make payments succeed, fall short or be declined on demand, send sample webhook events, and go live with confidence.

Test mode

Test mode is a complete, separate copy of your account. Test keys start with rb_test_, and everything they create is simulated: checkouts, payments, settlement and webhooks all behave as in Live mode, but no card is charged and no money moves. Switch the dashboard between Test and Live with the toggle at the top of each page.

Test modeLive mode
Secret keysrb_test_…rb_live_…
Card paymentsSimulated on Railbed's test provider pageReal, on the provider's page
SettlementSimulated, with the same checks as liveUSDC to your payout wallet
Webhook endpointsAny https:// address (for your own computer, a tunnel)Public https:// addresses only
WebhooksReal, signed HTTP requests to your endpointsThe same
POST /v1/payments/:id/simulateAvailableRefused

Test and live data never mix: a test key can't read or change a live payment, and each mode has its own endpoints and keys.

Simulate an outcome as a buyer

Open a test session's url (or any test checkout or payment link), enter an email and choose Pay. The test provider page offers three outcomes:

  • Simulate successful payment: about 97% of the order's value arrives, as a real provider's fee would leave it, and the payment becomes paid.
  • Simulate an underpayment: half arrives, so the payment is held for review, exactly as a live shortfall would be.
  • Simulate declined card: the payment becomes failed.

Simulate an outcome from your server

To test without a browser, start the session and simulate the outcome through the API. This is how automated tests should drive payments.

# Start it (the buyer would normally do this by choosing a provider)
curl -X POST \
  https://pay.railbed.io/v1/checkout_sessions/pay_7AAiYH0Ykt11ED4hmfiN/start \
  -H "Authorization: Bearer $RAILBED_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "customer_email": "buyer@example.com" }'

# Then decide how it ends: "paid", "underpaid" or "failed"
curl -X POST \
  https://pay.railbed.io/v1/payments/pay_7AAiYH0Ykt11ED4hmfiN/simulate \
  -H "Authorization: Bearer $RAILBED_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "outcome": "paid" }'

The simulated outcome runs the same settlement checks and sends the same webhooks as a live payment. Each session can end only once: simulating again on a finished payment returns it unchanged, so use a new session for each scenario. See Simulate a payment for the details.

Send sample webhook events

In Developers, choose Send test event on a Test endpoint and pick any event. Railbed sends a signed, realistic event with a made-up payment (its metadata.sample is "true", and it isn't in your payments or the API), then shows the exact body your server received and how it answered. Live endpoints can receive a ping only, so a live system never sees a payment that didn't happen.

Every delivery, test or real, appears in the endpoint's delivery log with its body, and can be sent again.

Receive webhooks on your own computer

Railbed sends webhooks from the internet, so it can't reach a server that only listens on your computer. While you build, expose your local server through a tunnel that gives it a public https:// address (for example Cloudflare Tunnel or ngrok), and add that address as a Test endpoint. When the tunnel's address changes, edit the endpoint: pending retries go to the new address.

A test plan worth running

Before going live, check that your integration handles each of these without a human:

ScenarioHow to cause itExpected result
A normal paymentSimulate paidOrder fulfilled once
The same event twiceResend a delivery from the delivery logNothing changes the second time
An underpaymentSimulate underpaidOrder not fulfilled; payment.held received
A declineSimulate failedOrder not fulfilled; buyer can start again
A buyer who never paysCreate a session and leave itOrder not fulfilled; payment.expired after 24 hours
A lost create responseSend the same create request twice with one Idempotency-KeyOne payment, the same id both times
Your server is downPoint the endpoint at a failing address, then fix itDeliveries retry; Retry now in the log delivers it
A forged webhookSend a request with a wrong signatureYour endpoint rejects it with a 4xx

Going live

  1. Add your payout wallet in Settings. It must be a self-custody Polygon wallet you control, not an exchange deposit address.
  2. Switch the dashboard to Live and create a live key and live webhook endpoints. Live endpoints need public https:// addresses.
  3. Put the live key and the live endpoint's signing secret on your production server. Keep the test ones for your test environment.
  4. Take one small real payment and follow it through: payment.paid received, the order fulfilled once, USDC in your wallet.

Updated · This page as Markdown