> For the complete documentation index, see [llms.txt](https://plexo.gitbook.io/rest-api/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://plexo.gitbook.io/rest-api/sessions/tokenization-session.md).

# Tokenization Session Integration

Use a tokenization session when you want Plexo to host card entry and save a payment instrument for later use without charging the customer immediately.

Use this guide to create the session, launch the hosted tokenization flow, and retrieve the saved instrument in your application.

## What a tokenization session is

A tokenization session is a short-lived hosted flow created with `POST /v1/sessions` and `"type": "tokenization"`.

Your backend creates the session. Plexo returns a hosted tokenization URL in `actions`. The payer enters card details inside Plexo-hosted UI, and the result is a saved payment instrument that can be used later in other payment flows.

In practical terms, the flow looks like this:

```mermaid
sequenceDiagram
  participant Backend as Your backend
  participant Frontend as Your frontend
  participant Payer as Payer
  participant Plexo as Plexo hosted tokenization

  Backend->>Plexo: POST /v1/sessions (type=tokenization)
  Plexo-->>Backend: SessionDto with actions
  Backend-->>Frontend: Hosted session URL
  Frontend->>Payer: Open redirect or embedded tokenization
  Payer->>Plexo: Enter card details
  Plexo-->>Backend: Tokenization callback
  Backend->>Plexo: GET customer payment instruments
  Plexo-->>Backend: Saved instrument token
```

## Features

* Hosted tokenization without creating a payment immediately
* Token storage modes for different business needs: `store` and `temporal`
* Feature controls for `create`, `list`, `select`, and `delete`
* Optional fund verification through `verifyFunds`
* Redirect and embedded integration options returned in `actions`
* Tokenization callbacks through `settings.callbacks.tokenizationCallbackUrl`
* Customer-linked saved instruments through the customer payment instruments API
* Session listing for audit and troubleshooting with `GET /v1/sessions`

## When teams usually choose this flow

This flow is usually the right choice when:

* you want to save a card before any payment happens
* you need stored instruments for subscriptions, renewals, or future purchases
* you want the card-saving step separated from the payment step
* your product needs a hosted card-saving journey with minimal PCI exposure in your own systems

## Tokenization modes in plain language

* `store`: save the instrument for ongoing reuse until it is deleted
* `temporal`: save the instrument for short-lived reuse

## What your application needs before starting

You need:

* a merchant ID that belongs to your API credentials
* Basic authentication credentials for the target environment
* a unique session `referenceId`
* a customer ID if the saved instrument should remain attached to a customer record
* a callback URL if your backend needs asynchronous tokenization updates

## What your application is responsible for

Your application is responsible for:

* deciding when to create the tokenization session
* deciding which tokenization mode to use
* deciding whether the customer should be linked to the stored instrument
* launching the hosted flow in redirect or embedded mode
* handling tokenization callbacks in your backend
* reading and using the saved token later in your own payment flows

Plexo is responsible for:

* hosting the secure card-entry experience
* collecting card details inside the hosted flow
* storing the resulting payment instrument according to the requested settings
* returning the session links your frontend should use

## Step 1: Create the customer when you want reusable instruments

Customers are optional in some flows, but they are the recommended way to manage reusable saved payment instruments.

```http
POST /v1/customers
Authorization: Basic {credentials}
Content-Type: application/json

{
  "referenceId": "customer-1001",
  "email": "customer@example.com",
  "firstName": "Test",
  "lastName": "User"
}
```

If the saved instrument should be reused later, create the customer first and associate the session with that customer.

## Step 2: Create the tokenization session

Create the session from your backend.

This request shows a common integration payload, not every available field. For the full request surface, see [SessionRequest](/rest-api/api-reference/models.md#sessionrequest), [SessionSettings](/rest-api/api-reference/models.md#sessionsettings), and [TokenizationSettingsRequest](/rest-api/api-reference/models.md#tokenizationsettingsrequest).

```http
POST /v1/sessions
Authorization: Basic {credentials}
Content-Type: application/json

{
  "merchantId": 12345,
  "referenceId": "tok-session-1001",
  "type": "tokenization",
  "customerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "settings": {
    "paymentMethodTypes": ["card"],
    "tokenization": {
      "type": "store",
      "allowedCardTypes": ["credit", "debit"],
      "features": ["create", "list", "select", "delete"],
      "verifyFunds": {
        "amount": 1.00,
        "currency": "USD"
      }
    },
    "callbacks": {
      "tokenizationCallbackUrl": "https://merchant.example.com/callbacks/tokenization"
    },
    "redirects": {
      "defaultUrl": "https://merchant.example.com/tokenization/result",
      "cancelUrl": "https://merchant.example.com/tokenization/cancel"
    }
  }
}
```

### Important request details

* `settings.tokenization.type` supports `store` and `temporal`
* if `settings.tokenization.type` is omitted, the backend defaults it to `temporal`
* if `features` is omitted, the backend enables `list`, `create`, `select`, and `delete`
* `verifyFunds.currency` is currently validated against `USD` and `UYU`
* `allowedCardTypes`, field settings, and pre-filled cardholder data are optional refinements

## Step 3: Open the hosted tokenization flow

If session creation succeeds, Plexo returns hosted session URLs in `actions`.

```json
{
  "id": "5ef3b41d80ce4ec8879f9f8cf7d5c8d2",
  "referenceId": "tok-session-1001",
  "type": "tokenization",
  "status": "pending",
  "expiresAt": "2026-03-30T15:00:00Z",
  "actions": [
    {
      "rel": "REDIRECT",
      "href": "https://secure.example/tokenization/5ef3b41d80ce4ec8879f9f8cf7d5c8d2?t={sessionToken}"
    },
    {
      "rel": "EMBEDDED",
      "href": "https://secure.example/e/tokenization/5ef3b41d80ce4ec8879f9f8cf7d5c8d2?t={sessionToken}"
    }
  ]
}
```

In the current public response shape for tokenization sessions, the integration mode is exposed in `rel`, not `method`.

Use the action whose `rel` matches the experience you want:

* `REDIRECT` for a full-page handoff
* `EMBEDDED` for a hosted experience inside your interface

As with checkout sessions, use the URLs Plexo returns. Do not construct these URLs yourself.

### Embedded tokenization messages

Register your `message` listener before loading the `EMBEDDED` URL. Tokenization sends messages to its parent with `postMessage(..., '*')`. It requires no initialization message or handshake; do not send `tokenization-init` or apply the Checkout handshake to this flow.

Lifecycle messages use this envelope:

```json
{
  "plexo": {
    "version": 1,
    "event": "tokenization-ready",
    "allowIframe": true
  }
}
```

| Event                    | When it is sent                                                                                                                                                                                                           |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tokenization-ready`     | Hosted initialization has completed and the session UI mounts. Sent once per session mount, not on rerenders or failed/expired initialization.                                                                            |
| `tokenization-completed` | A successful tokenization result is available.                                                                                                                                                                            |
| `tokenization-failed`    | Tokenization returns an unsuccessful result other than user cancellation, or hosted initialization fails.                                                                                                                 |
| `tokenization-expired`   | The hosted flow detects session expiration.                                                                                                                                                                               |
| `tokenization-cancelled` | Confirmed session cancellation succeeds, or the result has error code `canceled-by-user`. Dismissing the dialog or a failed cancellation request does not emit it. Cancellation does not also emit `tokenization-failed`. |
| `tokenization-redirect`  | The embedded flow hands merchant navigation to the parent. Only this lifecycle event adds `redirectUrl` to `plexo`.                                                                                                       |

Lifecycle messages contain no result, `data`, token, session, raw error, or card fields. `redirectUrl` uses the configured merchant destination, including any configured substitutions. There is no `tokenization-pending` event; a loading indicator does not indicate a pending result.

The existing messages remain unchanged and use a separate shape without `version`:

* `tokenization-result`: `{ plexo: { event: 'tokenization-result', data: result, height: undefined, allowIframe: true } }`. `data` is the tokenization service response (`ServiceResponse<IPaymentInstrumentToken>`). Continue handling this event for result data; lifecycle events do not replace it.
* `height`: `{ plexo: { event: 'height', data: undefined, height: 640, allowIframe: true } }`. `height` is a numeric content height; `640` is an example.

#### Result timing and navigation

* Completion sends `tokenization-result` first, then the lifecycle outcome, before any redirect. Initialization failures and confirmed cancellation do not synthesize a `tokenization-result`.
* `settings.redirects.skipResultPage` is off when omitted. When enabled, a successful result with a redirect target requests navigation immediately. Otherwise, the flow displays its result page.
* On the result page, success with a redirect target starts a 20-second countdown. Manual return controls, when available, also request navigation. Set `redirectOnError` explicitly: `false` enables retry and the result page's manual return control. Unsuccessful results do not start the success countdown, even when `redirectOnError` is `true`.
* Embedded cancellation, successful skip-result navigation, result countdown, and manual/header return send `tokenization-redirect`. The parent must handle it: the iframe does not replace itself with the merchant page on these paths. Full-page tokenization continues to use `window.location.replace`.

#### Parent listener

Check both `event.origin` and `event.source` before reading a message. Use the exact origin of the returned hosted URL for the selected environment, and allow only your expected merchant redirect destinations. `allowIframe` is a payload field, not authentication.

This example assumes an existing iframe with ID `tokenization-frame`. Replace the synthetic URLs, register the listener, then assign the returned `EMBEDDED` URL to the iframe's `src`. Add your UI and result handling at the marked points; do not log result data.

```javascript
const frame = document.getElementById('tokenization-frame');
const hostedOrigin = 'https://secure.example';
const merchantOrigin = 'https://merchant.example.com';
const lifecycleEvents = new Set([
  'tokenization-ready', 'tokenization-completed', 'tokenization-failed',
  'tokenization-expired', 'tokenization-cancelled', 'tokenization-redirect'
]);

window.addEventListener('message', (event) => {
  if (event.origin !== hostedOrigin || event.source !== frame.contentWindow) return;
  const message = event.data?.plexo;
  if (!message || typeof message !== 'object' || message.allowIframe !== true) return;

  if (message.event === 'height') {
    if (Number.isFinite(message.height) && message.height > 0) {
      frame.style.height = `${message.height}px`;
    }
    return;
  }
  if (message.event === 'tokenization-result') {
    // Handle message.data using your existing tokenization-result handler.
    return;
  }
  if (message.version !== 1 || !lifecycleEvents.has(message.event)) return;
  if (message.event === 'tokenization-redirect') {
    if (typeof message.redirectUrl !== 'string') return;
    let target;
    try {
      target = new URL(message.redirectUrl);
    } catch {
      return;
    }
    if (target.protocol !== 'https:' || target.origin !== merchantOrigin) return;
    window.location.assign(target.href);
    return;
  }
  // Update your UI for the lifecycle event without assuming result data is present.
});
```

These are browser notifications. Keep server-side validation and the [tokenization callback](/rest-api/operations/callbacks.md#tokenization-session-callbacks) or customer instrument lookup in your backend; a browser event alone must not authorize later payments.

## Step 4: Read the saved instrument after completion

After the hosted flow finishes, there are two main ways your application can work with the result.

### Server-to-server tokenization updates

Use `settings.callbacks.tokenizationCallbackUrl` when your backend needs asynchronous information about the tokenization outcome.

For the callback request shape and examples, see [Callbacks](/rest-api/operations/callbacks.md#tokenization-session-callbacks).

### Customer instrument lookup

Use the customer payment instruments endpoint to read the reusable token linked to the customer.

```http
GET /v1/customers/3fa85f64-5717-4562-b3fc-2c963f66afa6/payment-instruments
Authorization: Basic {credentials}
```

This endpoint is the source of truth for the customer's saved payment instruments.

## Step 5: Troubleshoot or audit tokenization sessions

Use `GET /v1/sessions` when you need to audit or troubleshoot tokenization sessions created by your API key.

```http
GET /v1/sessions?merchantId=12345&referenceId=tok-session-1001&page=1&size=20
Authorization: Basic {credentials}
```

The public API currently documents session creation and paged session listing. It does not expose a public session-by-ID retrieval route in the controller-backed contract.

This session list is useful for implementation support, QA, product operations, and investigation of failed or incomplete tokenization attempts.

## Best Practices

* Create a customer first when the token should be reused later
* Use `store` for long-lived cards and `temporal` for short-lived reuse windows
* Treat the customer payment instruments endpoint as the source of truth for reusable tokens
* Use tokenization callbacks for backend automation, but keep customer instrument reads in your normal data flow
* Do not store PAN or CVV in your own systems
* Pick the tokenization mode based on the product promise you are making to the customer

## Related Resources

* [Sessions](/rest-api/sessions/sessions.md)
* [Tokenization Guide](/rest-api/customers-and-saved-methods/tokenization-guide.md)
* [Callbacks](/rest-api/operations/callbacks.md)
* [Customer Management Guide](/rest-api/customers-and-saved-methods/customer-management.md)
* [SessionRequest](/rest-api/api-reference/models.md#sessionrequest)
