> ## 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.

# Headless mode

> Migrate Web Headless integrations (yuno.apiClientPayment) to the unified Transaction API.

Headless was a pure-tokenization client: the merchant collected card data in their own UI, generated a token, and made their own backend call to create the payment.

In the unified API the same scenario is a headless `start()`. Pass the pre-collected data inside `data` on the `paymentMethod` you give to `start()`, override [`createPayment`](/docs/yuno-sdk/controllers/create-payment) to POST to your backend (manual mode), and let the SDK orchestrate tokenization, 3DS, and status polling automatically. If you don't want the SDK to continue the flow after creating the payment, set `autoContinuePayment` to `false` on the [`TransactionConfig`](/docs/yuno-sdk/reference/objects-you-pass#transaction-config) object.

## Before you start

* Load the unified SDK bundle instead of the legacy one and initialize it as the side-by-side shows: `window.Yuno.initialize(...)` becomes `SdkPayments.initialize(...)`. Your public API key and the checkout sessions your backend creates do not change ([Before you begin](/docs/yuno-sdk/get-started#before-you-begin)).
* Decide who creates the payment. The checkout session's `workflow` must match that decision:

| Who creates the payment | In Headless you had | In the unified API | Session `workflow` |
| - | - | - | - |
| Your backend | Always: `generateToken`, then your own backend call | Override `createPayment` | Default (`SDK_CHECKOUT`) |
| The SDK | No equivalent: Headless never created the payment | No override | `SDK_SEAMLESS` |

<Warning>
  A default-workflow session with no `createPayment` override ends in `INTERNAL_ERROR`: the backend rejects the SDK's payment creation. See [`createPayment`](/docs/yuno-sdk/controllers/create-payment).
</Warning>

## Side-by-side

<CodeGroup>
  ```typescript Before. Headless (apiClientPayment) theme={"theme":{"light":"github-dark","dark":"github-dark-dimmed"}}
  const yuno = await window.Yuno.initialize('your-public-api-key')

  const apiClientPayment = await yuno.apiClientPayment({
      checkout_session: 'session-from-backend',
      country_code: 'CO',
  })

  // Merchant collects card data in their own UI, then:
  const oneTimeToken = await apiClientPayment.generateToken({
      payment_method: {
          type: 'CARD',
          card: {
              detail: {
                  holder_name: 'John Doe',
                  number: '4111111111111111',
                  security_code: '123',
                  expiration_month: 12,
                  expiration_year: 28,
              },
          },
          third_party_data: null,
      },
  })

  // Merchant POSTs to their backend
  const paymentId = await myBackend.pay({ oneTimeToken, checkoutSession })

  // If 3DS needed, merchant calls SDK again to challenge (bespoke per integration)
  ```

  ```typescript After. Unified Transaction (headless) theme={"theme":{"light":"github-dark","dark":"github-dark-dimmed"}}
  const sdkPayments = await SdkPayments.initialize('your-public-api-key')

  const transaction = sdkPayments.transaction({
      checkoutSession: 'session-from-backend',
      countryCode: 'CO',
      createPayment: async (token) => {
          await myBackend.pay({ token: token.token })
      },
      onStatus: (result) => console.log('done:', result.status),
  })

  await transaction.start({
      paymentMethod: {
          type: 'CARD',
          data: {
              card: {
                  holderName: 'John Doe',
                  number: '4111111111111111',
                  securityCode: '123',
                  expirationMonth: 12,
                  expirationYear: 28,
              },
          },
      },
  })
  ```
</CodeGroup>

## What changes

Grouped in the order you edit the code. **Renamed**: same role, new name. **Moved**: same value, new owner. **Removed**: nothing to call. **New**: no legacy counterpart. The last column is the only thing you have to do beyond the rename.

### Initialization and config

| Headless | Unified | Change | What to do |
| - | - | - | - |
| `window.Yuno.initialize(publicApiKey)` | `SdkPayments.initialize(publicApiKey)` | Renamed | The global is `window.SdkPayments`. As before, `await` it: it resolves to the `SdkPayments` instance you create transactions from. |
| `checkout_session`, `country_code` arguments of `apiClientPayment` | `checkoutSession`, `countryCode` on the transaction config | Moved | Set them once in the config. |
| `holder_name`, `number`, `security_code`, `expiration_month`, `expiration_year` under `payment_method.card.detail` (argument of `generateToken`) | `holderName`, `number`, `securityCode`, `expirationMonth`, `expirationYear` under `paymentMethod.data.card` | Moved | Card data goes inline on `start()`, nested under `data.card`, in the unified `TransactionData` shape. That shape supports more fields to cover not only cards but also alternative payment methods (APMs) such as bank transfers, tickets, wallets, and more. See the full shape in [`TransactionData`](/docs/yuno-sdk/reference/objects-you-pass#transaction-data). |
| *(none)* | `paymentMethod.vaultedToken` | New | For vaulted cards, pass `vaultedToken` on `paymentMethod` and only `securityCode` under `data.card`: `transaction.start({ paymentMethod: { type: 'CARD', vaultedToken: 'tok_saved_abc', data: { card: { securityCode: '123' } } } })`. |

### Callbacks

| Headless | Unified | Change | What to do |
| - | - | - | - |
| Your own backend call after `generateToken` | `createPayment(token)` | Moved | Wire it on the transaction config: `token` is the same token `generateToken` used to return directly to your code, now delivered as the argument of your override; there's no separate call to fetch it. POST it to your backend and resolve the Promise: the SDK continues from there. See [`createPayment`](/docs/yuno-sdk/controllers/create-payment) and [`OneTimeToken`](/docs/yuno-sdk/reference/objects-you-receive#one-time-token). |
| *(no result callback)* | `onStatus(result)` | New | The SDK now drives the full lifecycle (tokenization, 3DS, status polling) and reports the final status here. See [`Status`](/docs/yuno-sdk/reference/objects-you-receive#status). |

### Entry points

| Headless | Unified | Change | What to do |
| - | - | - | - |
| `yuno.apiClientPayment({ checkout_session, country_code })` | `sdkPayments.transaction({ checkoutSession, countryCode, createPayment })` | Renamed | The factory consolidates the API-client and Transaction surfaces: no separate `apiClientPayment` surface, one `sdkPayments.transaction(config)`. |
| `apiClientPayment.generateToken(cardData)` | `transaction.start({ paymentMethod: { type: 'CARD', data: { card } } })` | Renamed | You no longer tokenize yourself: build the `paymentMethod` with your pre-collected card data (see Initialization and config), then `start`. The SDK tokenizes and calls `createPayment` with the token. |
| `apiClientPayment.getThreeDSecureChallenge(...)` (rare) | *(removed)* | Removed | Delete the call. Headless used to require bespoke 3DS handling per integration; the SDK orchestrates 3DS internally once `createPayment` resolves. |
| `yuno.continuePayment()` after backend POST | *(removed)* | Removed | Delete the call: the Promise contract drives progression. Resolve `createPayment` and the SDK continues. |

## Related

* [`createPayment`](/docs/yuno-sdk/controllers/create-payment). The mode-flip callback.
* [`TransactionData`](/docs/yuno-sdk/reference/objects-you-pass#transaction-data). Per-method headless data shape.
* [`OneTimeToken`](/docs/yuno-sdk/reference/objects-you-receive#one-time-token). Token payload sent to your backend.


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