# Card tokenization

Save a card on file without charging it. `<rebill-save-card>` collects the card through a PCI-compliant iframe, tokenizes it server-side, and returns a `crd_...` identifier you can charge later with [`POST /v3/payments`](/api/reference/payments) or attach to a subscription.&#x20;

Use it when:

* You need a card-on-file for one-click purchases or manual charges later.
* You're onboarding a customer in a "no charge today" trial and want the card ready.
* You're running a marketplace where settlement happens out-of-band but you still need card credentials.

## Minimum render

```html
<rebill-save-card
  public-key="pk_your_public_key"
  processing-country="AR"
></rebill-save-card>

<script type="module">
  import 'rebill'

  document.querySelector('rebill-save-card').addEventListener('success', (event) => {
    const { card, customer } = event.detail
    // card.id → 'crd_...' — use it when you eventually charge
    // customer.id → 'cus_...' — either new or the one that matched on email
  })
</script>
```

## Attributes

| Attribute              | Type          | Required | Notes                                                                                                                                                                                                                                  |
| ---------------------- | ------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `public-key`           | string        | Yes      | Your organization's `pk_` key.                                                                                                                                                                                                         |
| `processing-country`   | string        | Yes      | ISO alpha-2 (`AR`, `BR`, `CL`, `CO`, `MX`, `US`). Determines which processor tokenizes the card. **Changing this later requires re-tokenization** — you can't use a card tokenized in Argentina to charge through a Mexican processor. |
| `customer-information` | object (JSON) | No       | Pre-fills or supplies fields when the equivalent sections are hidden. Shape below.                                                                                                                                                     |
| `redirect-urls`        | object (JSON) | No       | `{ approved: "https://your.app/card-saved" }`. When set, the component navigates to the URL after success instead of showing its built-in confirmation screen.                                                                         |
| `language`             | string        | No       | `'en' \| 'es' \| 'pt'`. Defaults to the country's language.                                                                                                                                                                            |
| `display`              | object (JSON) | No       | Section visibility toggles.                                                                                                                                                                                                            |
| `css`                  | string        | No       | Custom stylesheet (inline CSS or URL).                                                                                                                                                                                                 |

## `customer-information` shape

Flat structure — different from `<rebill-checkout>`, which nests the address. `email` and `fullName` are always required in the save-card flow. In addition, the `/preview/checkout-fields` contract marks identification, billing address and phone as required for card tokenization in every country. `identification` is auto-filled by the SDK only for USD and MXN; everywhere else the customer must provide a real document. All of address, identification and phone are required to charge the card afterwards.

```javascript
{
  email: "ana.perez@rebill.com",
  fullName: "Ana Perez",
  phoneNumber: "1123456789",
  countryCodePhoneNumber: "AR",  // ISO alpha-2, resolved to the dial prefix
  billingAddress: {
    country: "AR",
    state: "Buenos Aires",
    city: "Mar del Plata",
    zipCode: "7600",
    address: "Av. Córdoba 123",
    addInformation: "Apt 4B"  // optional
  },
  document: {
    type: "DNI",       // country-dependent: DNI, CURP, CPF, RUT, CC, etc.
    number: "12345678"
  }
}
```

`fullName` can't contain digits — a name with numbers returns a `400` (`customer.firstName: firstName must not contain numeric characters`).

The customer is matched by email if one exists in your organization; otherwise a new `cus_` record is created at tokenization time.

### Required fields by processing-country

| Country | Currency | Identification at tokenization                                           | Address / Phone | Charge with cardId              |
| ------- | -------- | ------------------------------------------------------------------------ | --------------- | ------------------------------- |
| AR      | ARS      | Real document, validated (DNI/CUIT/CUIL); also enforced by the processor | Required        | address + id + phone (required) |
| BR      | BRL      | Real document (CPF/CNPJ) + online tax-id validation                      | Required        | address + id + phone (required) |
| CL      | CLP      | Real document (RUT/RUN)                                                  | Required        | address + id + phone (required) |
| CO      | COP      | Real document (NIT/CC)                                                   | Required        | address + id + phone (required) |
| PE      | PEN      | Real document (no format check, min 6)                                   | Required        | address + id + phone (required) |
| UY      | UYU      | Real document (no format check, min 6)                                   | Required        | address + id + phone (required) |
| MX      | MXN      | Auto-filled by the SDK (placeholder), not asked                          | Required        | address + id + phone (required) |
| US      | USD      | Auto-filled by the SDK (placeholder), not asked                          | Required        | address + id + phone (required) |

Address and phone are required at tokenization in every country. The placeholder for MX/US only covers the identification document; address and phone must still be captured to charge the card.

## Requirements to charge a saved card

A `cardId` by itself is not enough to charge a saved card. The customer linked to the card must have: a billing address, an identification document (type + value), and a phone number. These three are required for every country and every processor, no exceptions. If any is missing, the charge is rejected with a `400` before it reaches the processor. Saving the card may succeed with incomplete data, but the charge will not — always capture real address, identification and phone at tokenization time.

## `display` flags

All default to `true`. Hide the corresponding section by setting to `false`:

| Flag             | Controls                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `submitButton`   | The built-in save button. Drive submission externally with `submit()`.                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `logo`           | Your organization logo header.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `footer`         | The Rebill-branded footer.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `billingAddress` | The billing address section. Pass data via `customer-information.billingAddress` when hidden.                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `phoneNumber`    | The phone number field.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `documentId`     | Controls the identification-document field. An identification document is required to tokenize a card in every country. In AR, BR, CL, CO, PE, UY the customer must enter a real document (validated client-side; BR also validates the tax-id online). In MX (MXN) and US (USD) the SDK auto-fills a placeholder, so you may hide it there. Hiding it anywhere else sends an empty document and both tokenization (country-dependent) and any later charge will fail — pass identification via `customer-information` instead. |
| `sandboxMode`    | Sandbox-only helper UI (test card shortcuts). Hide in production previews.                                                                                                                                                                                                                                                                                                                                                                                                                                                      |

**Important.** `billingAddress`, `documentId` and `phoneNumber` are displayed by default. Hiding a field does not remove it from the request — the SDK sends empty values (address) or a placeholder (identification in USD/MXN). If you hide any of them, you must provide that data through `customer-information`. Otherwise the card is saved with empty data and any later charge using the `cardId` will fail, because charging a saved card requires a real billing address, identification document and phone number.

## Events

The component emits four events:

| Event             | `event.detail`                                                                                | Fires when                                                                                                                                                                                                    |
| ----------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ready`           | `void`                                                                                        | The component finished mounting, loaded countries and required fields, and is ready for input.                                                                                                                |
| `success`         | `{ card: { id, brand, lastFour, expiration }, customer: { id, email, firstName, lastName } }` | The card was tokenized and stored. `card.id` is the `crd_...` you charge against later; `customer.id` is the `cus_...` (new or matched by email).                                                             |
| `error`           | `{ error }`                                                                                   | Validation, tokenization, or network failure.                                                                                                                                                                 |
| `successRedirect` | `{ url, data }`                                                                               | Fires **in addition to** `success` when `redirect-urls.approved` is set. The SDK is about to navigate the browser to `url`; save any state you need first. `data` carries the same shape as `success.detail`. |

### React example

```javascript
"use client"
import { useEffect, useRef } from 'react'
import 'rebill'

export default function SaveCard() {
  const ref = useRef(null)

  useEffect(() => {
    const el = ref.current
    if (!el) return

    const onSuccess = (e) => {
      const { card, customer } = e.detail
      // Store card.id on your user record to charge later.
    }
    const onError = (e) => {
      const { error } = e.detail
      // Surface a retry prompt; common causes: Luhn failure, expired card.
    }

    el.addEventListener('success', onSuccess)
    el.addEventListener('error', onError)
    return () => {
      el.removeEventListener('success', onSuccess)
      el.removeEventListener('error', onError)
    }
  }, [])

  return (
    <rebill-save-card
      ref={ref}
      public-key="pk_your_public_key"
      processing-country="AR"
    />
  )
}
```

## Common mistakes

* **Confusing save with charge.** Tokenization moves $0. Until you call `POST /v3/payments` (or attach the card to a subscription), the customer is not charged.
* **Using a sandbox card on a production org.** Sandbox cards (`4539 1488 0343 6467`, etc.) return `400 Sandbox cards are only available for sandbox organizations` when the `pk_` belongs to a production org.
* **Mismatching `processing-country` and card origin.** Tokenizing a Mexican card with `processing-country="AR"` works, but the charge later will route through the Argentine processor and may be declined for cross-border rules. Pick the country that matches where you plan to charge.
* **Assuming `successRedirect` replaces `success`.** Both events fire when `redirect-urls.approved` is set — `success` always, and `successRedirect` right after. Don't duplicate fulfillment logic; put side effects in `success` and use `successRedirect` only to save state before the browser navigates.

## Next

* [Checkout](/sdk/checkout) — tokenize AND charge in the same flow.
* [Renew subscription card](/sdk/renew-subscription-card) — replace the card on an existing subscription.
* [Cards API reference](/api/reference/cards) — the full `card` object shape returned to the `success` event.
