Payments

A payment is what a checkout session became. Read it to fulfil orders, list payments to reconcile, and simulate outcomes in Test mode.

On this page

The payment object

A payment has every field of its checkout session, with object set to "payment", plus:

FieldTypeDescription
paid_atinteger or nullWhen it became paid, in Unix seconds
providerstring or nullThe provider the buyer chose, such as stripe or paypal. Null when the buyer paid in crypto
methodstringHow the money that settled (or is held) arrived: card, or crypto when the buyer sent stablecoins from their own wallet (crypto payments)
hold_reasonstring or nullWhy it's held, in plain words. Null otherwise
hold_acceptablebooleanFor a held payment: whether you can accept it as paid in the dashboard
canceled_atinteger or nullWhen you canceled it (payment links only). A canceled payment's status is expired
settlementobjectWhat arrived and where it went. See below

The settlement object:

FieldTypeDescription
networkstring or nullCrypto payments: the network the money arrived on, such as base or polygon. Null for card, which always settles on Polygon
coinstring or nullWhat was delivered, usually polygon_usdc (polygon_usdt is also possible). Crypto payments name their network, such as base_usdc
value_coinstring or nullHow much arrived at the payment's deposit address, before fees
merchant_receivedstring or nullHow much was forwarded to your wallet, in the coin (six decimal places). Can be null for a while after paid and fill in later. Stays null for a held payment you accepted as paid
txid_instring or nullThe transaction that delivered the money (on Polygon, or on network for crypto)
txid_outstring or nullThe transaction that forwarded it to your wallet
payout_walletstring or nullThe wallet it went to, fixed when the buyer started

amount and currency are always the price you set; value_coin and merchant_received are what actually moved. Look up both transactions on a Polygon block explorer to see them for yourself.

Retrieve a payment

GET/v1/payments/:id

Returns the current state of a payment of yours in the key's mode. This is the authority for fulfilment: when it says paid, the money arrived and passed Railbed's settlement checks. What to deliver is on its order, from order_id.

curl https://pay.railbed.io/v1/payments/pay_7AAiYH0Ykt11ED4hmfiN \
  -H "Authorization: Bearer $RAILBED_SECRET_KEY"
Response
{
  "id": "pay_7AAiYH0Ykt11ED4hmfiN",
  "object": "payment",
  "url": "https://pay.railbed.io/p/pay_7AAiYH0Ykt11ED4hmfiN",
  "status": "paid",
  "livemode": true,
  "amount": "49.00",
  "currency": "USD",
  "description": "Pro Membership",
  "reference": "order_1042",
  "customer_email": "buyer@example.com",
  "created": 1790380525,
  "expires_at": 1790466925,
  "started_at": 1790380611,
  "metadata": { "user_id": "player_1042" },
  "order_id": "ord_M4tQx8ZkP1vRn6WcLs2B",
  "paid_at": 1790381342,
  "provider": "stripe",
  "hold_reason": null,
  "hold_acceptable": false,
  "canceled_at": null,
  "settlement": {
    "coin": "polygon_usdc",
    "value_coin": "47.53",
    "merchant_received": "46.341750",
    "txid_in": "0x0c651ba1d59c7a32e8b1f4bd2c7e0e4f96a55d13a6b0f2d1c8e7a9b4f3d29b58",
    "txid_out": "0x8202d1373e0a9c4f1b6d5e2c7a8f9b0e1d2c3b4a5f6e7d8c9b0a1f2e3d7356ff",
    "payout_wallet": "0xF977814e90dA44bFA03b6295A0616a897441aceC"
  }
}
200 OK

A held payment looks like this in part:

A held payment (trimmed)
{
  "id": "pay_Kx81mQv2PzR0dT7eWcYa",
  "object": "payment",
  "status": "held",
  "amount": "49.00",
  "currency": "USD",
  "paid_at": null,
  "hold_reason": "The provider sent 24.50 USDC, below 90% of the order’s 49.00 USD value.",
  "hold_acceptable": true,
  "settlement": { "coin": "polygon_usdc", "value_coin": "24.50", "merchant_received": null }
}
200 OK

Reading a payment past its expires_at marks an unpaid one expired.

List payments

GET/v1/payments

Returns your payments in the key's mode, newest first. Use it to reconcile, not to find new payments quickly: it lists by creation time, so recheck unfinished payments you saved by id.

ParameterTypeDescription
limitinteger1–100. Default 20
starting_afterstringA payment id from the previous page's next_cursor
curl "https://pay.railbed.io/v1/payments?limit=50" \
  -H "Authorization: Bearer $RAILBED_SECRET_KEY"
Response
{
  "data": [
    {
      "id": "pay_7AAiYH0Ykt11ED4hmfiN",
      "object": "payment",
      "status": "paid",
      "amount": "49.00",
      "currency": "USD"
    },
    {
      "id": "pay_Kx81mQv2PzR0dT7eWcYa",
      "object": "payment",
      "status": "held",
      "amount": "49.00",
      "currency": "USD"
    }
  ],
  "has_more": true,
  "next_cursor": "pay_Kx81mQv2PzR0dT7eWcYa"
}
200 OK

Each item is a full payment object (trimmed here). An invalid limit is 400 invalid_limit; a cursor that isn't one of your payments in this mode is 400 invalid_cursor.

Simulate a payment

POST/v1/payments/:id/simulate

Test mode only. Simulates an outcome for a started test payment. Simulated money goes through the same settlement checks and webhooks as a live payment. A card decline keeps the payment open for retry.

FieldTypeDescription
outcomestring Requiredpaid (about 97% of the value arrives), underpaid (half arrives, so it's held), declined (stays open for another provider, no failed webhook), or failed (terminal Test failure with a payment.failed webhook)
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 response is the payment after the outcome. A declined outcome leaves it open for another provider on the same session. Simulating a finished payment returns it unchanged.

StatusCodeWhen
400invalid_outcomeoutcome is missing or not one of the four supported values
403live_paymentThe payment is a Live payment
409not_startedStart the session first, with Start a checkout session

Updated · This page as Markdown