Save a Card Without Charging

Create an enrollment session so a customer saves a card first — for subscriptions or adding a payment method.

An enrollment session saves a customer's card without charging them — for subscription onboarding, adding a payment method, or any flow that needs a card on file before the first charge. It is a single-use checkout (valid up to 24 hours) that shows only the card form and a save-card button: no amount, no items, no other payment methods.

No payment is created, so the session's payment_id is 0 and no payment webhook is sent. Enrollment sessions always use the first-generation (v1) checkout design.

If Card-on-File is enabled for your account, saving the card runs a 3D Secure check with the card issuer (a verification window may appear), and the saved card can then be used for later payments without asking for the CVV. If it is not enabled, the card is saved directly. Your integration is the same in both cases.

Step by step

Send session_type: "enrollment" and the customer. The card is saved for this customer.

curl -X POST 'https://api-stage.tonder.io/checkout/v1/sessions' \
  -H 'Authorization: Token YOUR_TEST_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "session_type": "enrollment",
    "customer": { "first_name": "Ana", "last_name": "Garcia", "email": "ana@example.com" },
    "locale": "es",
    "return_url": "https://your-store.com/card-saved"
  }'
curl -X POST 'https://api.tonder.io/checkout/v1/sessions' \
  -H 'Authorization: Token YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "session_type": "enrollment",
    "customer": { "first_name": "Ana", "last_name": "Garcia", "email": "ana@example.com" },
    "locale": "es",
    "return_url": "https://your-store.com/card-saved"
  }'
{
  "id": "cs_97_0_abc123",
  "url": "https://stage-payflow.tonder.io/checkout/cs_97_0_abc123",
  "status": "pending",
  "session_type": "enrollment",
  "checkout_type": "hosted",
  "payment_id": 0,
  "locale": "es",
  "return_url": "https://your-store.com/card-saved",
  "expires_at": 1776370888,
  "customer": { "first_name": "Ana", "last_name": "Garcia", "email": "ana@example.com" }
}

Redirect the customer to url. They see the card form (cardholder name, card number, expiry, CVV) and a save-card button.

With Card-on-File, a 3D Secure verification may appear first. On success the page shows a "card saved" confirmation. If something fails — verification rejected, network error, session expired, invalid card — the customer sees an error and can retry without reloading.

The session becomes completed and, with redirect_on_completion: "always", the customer is sent to return_url. Confirm it from your backend with Get a session:

{ "id": "cs_97_0_abc123", "status": "completed", "session_type": "enrollment", "payment_id": 0 }

Fields

FieldTypeRequiredValuesDescription
session_typestringYesenrollmentMakes this a card-saving session.
customerobjectYesfirst_name, last_name, email (required); phone, address, identification (optional)The card is saved for this customer.
return_urlstringNoURLWhere the customer goes after saving the card.
localestringNoes (default), en, zhLanguage of the page. The customer can change it.
expires_atnumberNoUnix time in seconds30 minutes to 24 hours from now. Defaults to 24 hours.
external_idstringNo—Your reference.
metadataobjectNo—Any data you want back later.
ui_configobjectNoColors, font, shapes, labels, placeholdersAppearance for this session, on top of your saved business appearance.
checkout_typestringNohosted (default), embeddedUse embedded to show the page in an iframe.
post_message_enabledbooleanNotrue, falseSend events to your page. Requires embedded.
redirect_on_completionstringNoalways (default), nevernever keeps the customer on the page so your site handles navigation.

Payment fields are not allowed on enrollment: amount_total, currency, line_items, payment_method_types, payment_method_config, success_url, pending_url, cancel_url and submit_type return 400 E004.

Embedding and events

Create the session with checkout_type: "embedded" and post_message_enabled: true, and load url in an iframe as described in Embed the checkout. Enrollment sessions send three events, each with session_type: "enrollment":

EventWhen
checkout.initiatedThe card form has loaded.
checkout.completedThe card was saved (session_status: "completed").
checkout.failedSaving failed; the customer can retry.

Errors

HTTP statusCodeMeaningWhat to do
400E004A field is missing, has a value that is not allowed, or is a payment field.Read metadata.errors, fix the body and retry.
400E0014You asked for the payment of an enrollment session.There is no payment; use Get a session.
401 / 403—Missing or invalid API key.Check the Authorization header and the environment.
404E003No session with this id.Check the id and the environment.

Next steps

Was this page helpful?

On this page