> ## Documentation Index
> Fetch the complete documentation index at: https://docs.y.uno/llms.txt
> Use this file to discover all available pages before exploring further.

# Enrollment

> Save a customer's payment method for future use, without charging.

Enrollment lets you tokenize and save a customer's payment method without processing a charge. Use it to register a card or other method that the customer can use in future payments.

The same `Transaction` class handles enrollment. Only the session type changes. On Web the enrollment transaction exposes `start()`, `secureFields()`, and `unmount()`. The payment-only methods (`getPaymentMethodsViews`, `submit`, `updateCheckoutSession`) and the payment-only config fields are not available.

<Note>
  The session type is what selects the mode: passing `checkoutSession` runs a **payment**, while passing `customerSession` runs an **enrollment**. Exactly one of the two must be provided. On iOS the choice is made at compile time: `TransactionConfig` has one initializer per session type, so a config with both or neither cannot be written. On Android and Web, supplying both, or neither, fails at construction time with a validation error. On Android it reads `Exactly one of checkoutSession or customerSession must be provided`. On Web it reads `Provide either checkoutSession or customerSession, not both.` or `A checkoutSession or customerSession is required.` See [Where do I start?](/docs/yuno-sdk/where-do-i-start) for the full decision guide.
</Note>

## Before you start

Your backend must create the resources required for enrollment:

* Create the customer. See [`POST /v1/customers`](https://docs.y.uno/reference/customers/the-customer-object).
* Create the customer session. See [`POST /v1/customers/sessions`](https://docs.y.uno/reference/customer-sessions-enrollment/create-customer-session).
* Create the payment method. See [`POST /v1/customers/sessions/{customer_session}/payment-methods`](https://docs.y.uno/reference/payment-methods-checkout/enroll-payment-method-checkout).

## Implementation

Pass the `customerSession` (instead of `checkoutSession`) in `TransactionConfig` and call `start()`. On Android pass the method the customer chose in `paymentSelected`, the same way you do for a payment. On iOS `start(paymentSelected:)` takes the same object, but the method to enroll is the one your backend created on the customer session: the SDK reads it from the session and does not use `paymentMethodType` to select it. On Web, `start()` renders the SDK form for the method your backend enrolled on the customer session, and `paymentMethod` is needed only for a headless enrollment (see Skip the form). The SDK delivers the final status to `onStatus` once enrollment is complete.

Rendering and selecting the payment method to enroll is your responsibility. The SDK does not present a list of enrollable methods. To fetch the available methods, call [`GET /v1/customers/sessions/{customer_session}/payment-methods`](https://docs.y.uno/reference/payment-methods-checkout/retrieve-payment-methods-to-enroll-checkout). On iOS and Web, the choice reaches the SDK through the customer session, with the `POST` call from Before you start.

<Tabs>
  <Tab title="Web">
    ```typescript theme={"theme":{"light":"github-dark","dark":"github-dark-dimmed"}}
    const transaction = sdkPayments.transaction({
        customerSession: 'session-from-backend',
        countryCode: 'US',
        language: 'en', // optional, falls back to browser language
        elementSelector: '#enrollment-form',
        onStatus: (result) => {
            console.log('Enrollment status:', result.status)
        },
    })

    await transaction.start()
    // For headless enrollment, call start({ paymentMethod: { type: 'CARD', data } })
    // instead. The config's elementSelector is ignored. See "Skip the form" below.
    ```

    `elementSelector` is optional on Web. Without it the SDK appends its own container to the end of `<body>` and renders the form there.
  </Tab>

  <Tab title="iOS">
    ```swift theme={"theme":{"light":"github-dark","dark":"github-dark-dimmed"}}
    let config = SdkPayments.TransactionConfig(
        customerSession: "session-from-backend",
        countryCode: "US",
        language: "en",          // optional, falls back to device language
        appearance: nil,         // optional
        controller: self
    )

    let paymentSelected = SdkPayments.PaymentMethodSelected(
        paymentMethodType: "CARD"  // The customer session decides the method to enroll.
        // transactionData: ...   // optional. See "Skip the form" below.
    )

    SdkPayments.Transaction(config: config)
        .start(paymentSelected: paymentSelected)
    ```
  </Tab>

  <Tab title="Android">
    ```kotlin theme={"theme":{"light":"github-dark","dark":"github-dark-dimmed"}}
    val config = TransactionConfig(
        customerSession = "session-from-backend",
        countryCode = "US",
        language = "en",          // optional, falls back to device language
        appearance = null,        // optional
        controller = this
    )

    val paymentSelected = PaymentMethodSelected(
        paymentMethodType = "CARD",
        // transactionData = ... // optional. See "Skip the form" below.
    )

    Transaction(config)
        .start(activity = this, paymentSelected = paymentSelected)
    ```
  </Tab>
</Tabs>

### Skip the form

If you collect the customer's data in your own UI, pass it via `transactionData` (`data` on Web) on the `PaymentMethodSelected`. The SDK will skip its built-in form and tokenize directly: a headless flow, which ignores the `elementSelector` on the transaction config (it applies only to form-based flows). See [`TransactionData`](/docs/yuno-sdk/reference/objects-you-pass#transaction-data) for the full data shape.

<Note>
  `vaultedToken` on `PaymentMethodSelected` is ignored during enrollment. The flow's purpose is to produce a new vaulted token, so there's nothing linked yet to reference.
</Note>

## Notes

* A 3DS challenge can occur during enrollment.
* `createPayment` does not apply because there is no payment to create. On Web the enrollment config does not accept it (TypeScript rejects the property). On iOS and Android it is not invoked.
* When enrollment succeeds, `onStatus` delivers the final status, with the same payload shape as payment flows (`status`, `substatus`, `message`). The vaulted token is not surfaced to the client: retrieve it from your backend's list-customer-payment-methods endpoint after the success status arrives, and store it against your customer to use in future payments.

## Related

* [Sessions](/docs/basic-concepts/sessions). Checkout vs customer sessions.
* [`TransactionConfig`](/docs/yuno-sdk/reference/objects-you-pass#transaction-config). Full reference.
* [`onStatus`](/docs/yuno-sdk/controllers/on-status). Receives the final status.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.