Skip to main content

Recurring and saved methods

Saved methods are available on rails that support mandates

Saving a method and charging it again works on rails that support mandates. On a rail without mandate support, setup_future_usage, an explicit mandate_data block and a zero-amount setup all complete with 200 succeeded and return mandate_id: null. Nothing is stored, and the later off-session charge is refused with ERR_4088. Treat a missing mandate_id on the first payment as the signal, not the status of that payment.

Your dashboard shows what is enabled for your account; ask us to enable a mandate-capable rail.

Save a payment method once, then charge it again without the customer re-entering anything. This powers two flows over the same API:

  • One-click: a returning customer pays with a method they already saved.
  • Off-session (recurring): you charge a saved method later with no customer present, for subscriptions, top-ups, or usage billing.

Both work by saving a method against a customer_id on the first payment, then referencing the token TensorRail returns on later payments. You never handle or store card data: the token is a TensorRail reference, not the underlying credential.

Where it applies

Saving and reuse are available for methods that support it (such as cards). Methods that are inherently single-use in a market are charged fresh each time; the API shape is the same, so you can write one integration and let the platform apply what each method supports.

1. Save a method on the first payment​

Set setup_future_usage and attach a customer_id. Use off_session when you intend to charge later with no customer present (subscriptions), or on_session when the customer will return and confirm themselves (one-click).

setup_future_usage saves the method used by this payment, so a confirming call still has to say how to pay. Omitting the payment method with confirm: true is refused with ERR_2002: A payment token or payment method data or ctp service details is required.

curl -X POST https://api.tensorrail.com/payments \
-H "api-key: rail_full_test_xxx" \
-H "Content-Type: application/json" \
-d '{
"amount": 50000,
"currency": "INR",
"customer_id": "cus_8x2Kp",
"setup_future_usage": "off_session",
"confirm": true,
"payment_method": "upi",
"payment_method_type": "upi_collect",
"payment_method_data": { "upi": { "upi_collect": { "vpa_id": "success@upi" } } },
"return_url": "https://yourshop.com/checkout/complete"
}'

Once the payment succeeds, the response carries the token you store against your customer:

{
"payment_id": "pay_N5cPeGw6uS2QIMjnsjVF",
"status": "succeeded",
"customer_id": "cus_8x2Kp",
"payment_method_id": "pm_9c1f7e4a2d6b4f8b8c1e3a5d",
"mandate_id": "man_2d6a4f8b8c1e3a5d9e7b2f10"
}
FieldStore it?Use it for
payment_method_idYesCharging the saved method again (one-click and off-session)
mandate_idIf presentCharging under a mandate the customer authorised for recurring debits

Keep payment_method_id (and mandate_id, when the method uses a mandate) on your customer record. That is all you need to charge again.

2. Charge off-session (recurring)​

To bill later with no customer present, create a payment that references the saved token and set off_session. Confirm in the same call.

curl -X POST https://api.tensorrail.com/payments \
-H "api-key: rail_full_test_xxx" \
-H "Idempotency-Key: sub-cus_8x2Kp-2026-08" \
-H "Content-Type: application/json" \
-d '{
"amount": 50000,
"currency": "INR",
"customer_id": "cus_8x2Kp",
"recurring_details": { "type": "payment_method_id", "data": "pm_9c1f7e4a2d6b4f8b8c1e3a5d" },
"off_session": true,
"confirm": true
}'

Give each recurring charge a stable, period-based Idempotency-Key (for example one per customer per billing month). If a retry fires for the same period, the duplicate is rejected rather than double-charging.

If the method was saved under a mandate, reference mandate_id instead of recurring_details; everything else about the call is the same.

3. One-click for returning customers​

For a returning customer who is present, charge the payment_method_id you stored on their record. Present your saved-method choice in your own UI, then confirm the payment against the token: no card fields, no re-entry. The call is the same as an off-session charge, without off_session (the customer is here to complete any step-up the method requires):

{
"amount": 50000,
"currency": "INR",
"customer_id": "cus_8x2Kp",
"recurring_details": { "type": "payment_method_id", "data": "pm_9c1f7e4a2d6b4f8b8c1e3a5d" },
"confirm": true,
"return_url": "https://yourshop.com/checkout/complete"
}

If the method needs authentication (for example a 3-D Secure challenge), the response is requires_customer_action with a next_action; forward the customer to it exactly as in Accept a payment.

Lifecycle and webhooks​

A saved method is backed by a mandate, which has its own lifecycle independent of any one payment:

Recurring charges emit the same events as any other payment (payment_succeeded, payment_failed, and the intermediate states). Drive your subscription state from those webhooks rather than the create response, so an off-session charge that completes asynchronously is reflected correctly. See Handle webhooks.

Your server holds the schedule​

Everything above is you charging a saved method on your own schedule: you hold the billing logic (the plan, the dates, the retries), and each charge is an ordinary payment with its own webhooks, refunds and disputes. That is how recurring billing works on TensorRail; the API has no separate subscription objects.

Security​

  • You store TensorRail tokens (pm_…, man_…), never card numbers. The tokens are scoped to your account and are meaningless elsewhere.
  • Card details never reach your servers or your database: they stay with the card processor that captured them. A mandate stays with the provider that registered it, and a saved token works only with that processor or provider.
  • Revoking a saved method or mandate stops future charges against it.

Next steps​