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

# Aceptar un pago con un clic usando Apple Pay

> >-

Usa una única integración para aceptar pagos a través de botones de pago con un clic. El componente Express Checkout es una funcionalidad del SDK de Fintoc que permite a tus clientes pagar con botones de wallet, sin abrir el widget completo. El método de pago soportado actualmente es **Apple Pay**.

Los clientes ven el botón de Apple Pay según su dispositivo y navegador. Si Apple Pay no está disponible en el dispositivo, el botón queda oculto.

<Warning>
  **Antes de comenzar: tu dominio debe estar habilitado para Apple Pay.** Apple Pay no se cargará hasta que Fintoc registre tu dominio con Apple, por lo que el botón permanecerá oculto en un dominio no registrado. Consulta [Habilitar Apple Pay](#enabling-apple-pay) para iniciar el proceso antes de integrar.
</Warning>

Aceptar pagos con Apple Pay usando Express Checkout requiere seis pasos:

1. Configura tu servidor para crear un `Checkout Session`
2. Configura el SDK de Fintoc en tu frontend
3. Crea y monta el componente Express Checkout
4. Maneja el callback `onPaymentRequest`
5. Envía el pago a Fintoc
6. Prueba la integración

***

# Paso 1: Configura tu servidor

> **Lado del servidor**

Express Checkout llama al callback `onPaymentRequest` después de que el cliente autoriza la hoja de Apple Pay. En ese callback debes crear una **Checkout Session** desde tu backend y devolver su `session_token` al navegador.

Expone un endpoint en tu servidor que cree una Checkout Session con la API de Fintoc:

**Node**

```javascript theme={null}
// server.js (Node example)
app.post("/api/create-checkout", async (req, res) => {
  const response = await fetch("https://api.fintoc.com/v2/checkout_sessions", {
    method: "POST",
    headers: {
      Authorization: process.env.FINTOC_SECRET_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      amount: 1000,
      currency: "CLP",
      payment_methods: ["card"],
      recipient_account: { id: "acc_a1b2c3d4e5" },
      // ...any other fields your flow requires
    }),
  });

  const session = await response.json();
  res.json({ session_token: session.session_token });
});
```

<Warning>
  Nunca expongas tu secret key en el navegador. Siempre mantén la llamada de creación de Checkout Session en tu servidor.
</Warning>

***

# Paso 2: Configura el SDK de Fintoc

> **Lado del cliente**

Express Checkout está disponible automáticamente como una funcionalidad del SDK de Fintoc. Incluye el script de Fintoc en tu página de checkout agregándolo al `<head>` de tu archivo HTML. Siempre carga el SDK directamente desde `js.fintoc.com` para recibir actualizaciones de seguridad. No incluyas el script en un bundle ni hospedes una copia por tu cuenta.

```html theme={null}
<head>
  <title>Checkout</title>
  <script src="https://js.fintoc.com/v1/"></script>
</head>
```

***

# Paso 3: Crea y monta el Express Checkout

> **Lado del cliente**

El componente Express Checkout renderiza el botón de wallet dentro de un iframe que envía de manera segura la información de pago a Fintoc a través de una conexión HTTPS. La dirección de la página de checkout también debe comenzar con `https://`, no con `http://`, para que tu integración funcione.

Primero, crea un nodo DOM vacío (contenedor) con un ID único en tu formulario de pago:

```html theme={null}
<div id="apple-pay-container">
  <!-- Express Checkout will be inserted here -->
</div>
<div id="error-message">
  <!-- Display an error message to your customers here -->
</div>
```

Cuando el formulario se haya cargado, crea una instancia del widget y monta Express Checkout en el nodo DOM contenedor:

```javascript theme={null}
const widget = window.Fintoc.create({
  product: "payments",
  publicKey: "pk_test_...",
  country: "cl",

  expressCheckout: {
    container: "apple-pay-container",
    amount: 1000,
    currency: "CLP",
  },

  onPaymentRequest: async ({ payment_method_type, wallet }) => {
    const res = await fetch("/api/create-checkout", { method: "POST" });
    const { session_token } = await res.json();
    return { sessionToken: session_token };
  },

  onSuccess: (data) => console.log("Payment succeeded", data),
  onExit: (reason) => console.log("Widget closed", reason),
  onEvent: (eventName, metadata) => console.log(eventName, metadata),
});
```

Los botones de Apple Pay pueden tener los siguientes estilos:

<Frame caption="Estilos de botón: negro, blanco y blanco con contorno">
  <img src="https://mintcdn.com/fintoc-49b8bee8/YQmOnq8Zegydl6oL/images/561c75e5fcefe7d9d425ebf84aeef3319c52f1faf85c723cf386406727337137-apple-pay_buttons.png?fit=max&auto=format&n=YQmOnq8Zegydl6oL&q=85&s=2cb710e2686837190232688296dbe678" width="1652" height="160" data-path="images/561c75e5fcefe7d9d425ebf84aeef3319c52f1faf85c723cf386406727337137-apple-pay_buttons.png" />
</Frame>

***

# Paso 4: Maneja el callback onPaymentRequest

> **Lado del cliente**

`onPaymentRequest` se ejecuta cuando el SDK necesita un `sessionToken` para continuar con el flujo. Para Apple Pay, el SDK lo llama después de que el cliente autoriza la hoja de Apple Pay. Cuando llamas a `widget.open()` para transferencia bancaria, el SDK llama al mismo callback antes de abrir el widget. En ese callback debes llamar a tu servidor, obtener un `session_token` y devolverlo al SDK.

El callback recibe un único argumento con información sobre el método solicitado:

| Campo                 | Tipo                | Descripción                                                                                            |
| --------------------- | ------------------- | ------------------------------------------------------------------------------------------------------ |
| `payment_method_type` | `string`            | `"card"` para pagos con wallet. `"bank_transfer"` cuando se llama a `widget.open()`.                   |
| `wallet`              | `string` (opcional) | La wallet específica seleccionada, por ejemplo `"apple_pay"`. `undefined` para transferencia bancaria. |

Tu callback **debe** resolverse con `{ sessionToken: string }` en un máximo de **30 segundos**, o el SDK emite `payment_error`.

<Info>
  Puedes usar los campos `payment_method_type` y `wallet` para reutilizar un único endpoint tanto para wallets como para transferencia bancaria, o para enrutar a diferentes endpoints si la lógica de tu backend difiere.
</Info>

***

# Paso 5: Envía el pago a Fintoc

> **Lado del cliente**

Una vez que el cliente autoriza el pago con wallet, el SDK completa automáticamente el flujo. No necesitas llamar a un método `confirmPayment` por tu cuenta.

La secuencia es:

1. El SDK abre la hoja de Apple Pay y solicita un token de pago a Apple Pay.
2. Una vez que el cliente autoriza, el SDK emite `processing_express_checkout_payment`.
3. El SDK llama a tu callback `onPaymentRequest` para obtener un `sessionToken` fresco.
4. El SDK envía ambos tokens al backend de Fintoc, que crea el Payment Resource y cobra a la wallet.
5. Cuando el pago alcanza `status === 'succeeded'`, el SDK llama a `onSuccess(data)` con el recurso resultante.

<Info>
  Si el estado del pago es distinto de `succeeded`, o cualquier paso del flujo falla, el SDK emite `payment_error` en lugar de llamar a `onSuccess`.
</Info>

### Manejo del estado de carga durante el procesamiento del pago

Mientras Express Checkout procesa un pago, debes mostrar un estado de carga para dar retroalimentación clara a tu cliente y evitar interacciones duplicadas. Manéjalo desde los callbacks `onEvent` y `onSuccess` que ya pasas a `Fintoc.create`:

* `processing_express_checkout_payment` se dispara una vez que el cliente autoriza el pago. Úsalo para mostrar tu indicador de carga mientras el SDK obtiene un `sessionToken` fresco desde tu servidor y envía el pago.
* El pago luego se resuelve a través de `onSuccess` cuando es exitoso, o a través de un evento `payment_error` cuando falla. Usa ambos para limpiar el indicador de carga.

Una implementación típica se ve así:

```javascript theme={null}
window.Fintoc.create({
  // ...
  onEvent: (eventName) => {
    if (eventName === "processing_express_checkout_payment") {
      // Show loading state (e.g. spinner, disable buttons)
      setLoading(true);
    }
    if (eventName === "payment_error") {
      // Hide loading state after a failed attempt
      setLoading(false);
    }
  },
  onSuccess: () => {
    // Hide loading state after a successful payment
    setLoading(false);
  },
});
```

Siempre limpia el estado de carga tanto en `onSuccess` como en `payment_error` para que la UI nunca quede atascada después de un intento de pago.

***

# Paso 6: Prueba la integración

Antes de pasar a producción, prueba la integración en un dispositivo que soporte Apple Pay.

**Requisitos para probar:**

* Usa tu public key de prueba y una cuenta de destinatario de prueba.
* Abre tu checkout en iOS o macOS.
* Asegúrate de que tu dominio de staging esté habilitado para Apple Pay. Si aún no lo has hecho, sigue [Habilitar Apple Pay](#enabling-apple-pay) primero.

**Checklist de integración:**

* [ ] El botón de Apple Pay se renderiza al cargar la página en un dispositivo soportado.
* [ ] `express_checkout_ready` se dispara con `wallets.applePay === true`.
* [ ] Autorizar la hoja de Apple Pay dispara `onPaymentRequest` con `payment_method_type: 'card'`, `wallet: 'apple_pay'`.
* [ ] `processing_express_checkout_payment` se dispara mientras el pago está en curso.
* [ ] `onSuccess` se dispara con el recurso de pago después de una autorización exitosa.
* [ ] Cancelar la hoja de Apple Pay **no** emite `payment_error`.
* [ ] Llamar a `widget.open()` (fallback de transferencia bancaria) invoca `onPaymentRequest` con `payment_method_type: 'bank_transfer'` y abre el widget.

***

# Configuraciones opcionales

## Escuchar el evento express\_checkout\_ready

Después del montaje, Express Checkout no mostrará botones hasta que el SDK se inicialice y verifique la disponibilidad de wallets. Para animar el elemento cuando aparezca el botón, escucha el evento `express_checkout_ready`. Inspecciona el valor `wallets` para determinar qué botones mostrar, si los hay:

```javascript theme={null}
// Optional: hide the element until we know if a button will show
const container = document.getElementById("apple-pay-container");
container.style.visibility = "hidden";

window.Fintoc.create({
  // ...
  onEvent: (eventName, metadata) => {
    if (eventName === "express_checkout_ready") {
      if (metadata.wallets.applePay) {
        container.style.visibility = "initial";
      } else {
        // No buttons will show; fall back to bank transfer only
      }
    }
  },
});
```

## Estilizar el botón

Puedes ajustar la apariencia del botón de Apple Pay a través de los campos opcionales de `expressCheckout`.

```javascript theme={null}
expressCheckout: {
  container: "apple-pay-container",
  amount: 1000,
  currency: "CLP",

  // Height in pixels. Defaults to 44. Range [40, 100].
  buttonHeight: 52,
  // Border radius in pixels. Defaults to 4. Range [0, 100].
  buttonBorderRadius: 12,
  // Specify the label shown inside the button.
  // Defaults to "plain" for Apple Pay.
  buttonType: { applePay: "buy" },
  // Specify the color scheme of the button.
  // Defaults to "black".
  buttonStyle: { applePay: "white" },
  // Specify the language for the Apple Pay label.
  // Defaults to "es-ES".
  locale: { applePay: "es-MX" },
}
```

| Opción                 | Tipo                          | Default   | Descripción                                      |
| ---------------------- | ----------------------------- | --------- | ------------------------------------------------ |
| `buttonHeight`         | `number` (px)                 | `44`      | Altura del botón. Acotado a `[40, 100]`.         |
| `buttonBorderRadius`   | `number` (px)                 | `4`       | Radio del borde del botón. Acotado a `[0, 100]`. |
| `buttonType.applePay`  | `"buy"`, `"pay"`, o `"plain"` | `"plain"` | Etiqueta mostrada dentro del botón de Apple Pay. |
| `buttonStyle.applePay` | `"black"` o `"white"`         | `"black"` | Esquema de color del botón de Apple Pay.         |
| `locale.applePay`      | `"es-ES"` o `"es-MX"`         | `"es-ES"` | Idioma para la etiqueta del botón de Apple Pay.  |

<Info>
  Los valores fuera del rango permitido se acotan en lugar de rechazarse. Por ejemplo, `buttonHeight: 200` se trata como `100`.
</Info>

<br />

El mismo objeto `widget` devuelto por `Fintoc.create` expone los métodos habituales del widget. Cuando `expressCheckout` está configurado, llamar a `widget.open()` invoca automáticamente `onPaymentRequest` con `payment_method_type: 'bank_transfer'` antes de abrir el widget, por lo que no necesitas una segunda inicialización.

```javascript theme={null}
document
  .getElementById("bank-transfer-button")
  .addEventListener("click", () => widget.open());
```

***

# Referencia de eventos

Express Checkout usa el mismo callback `onEvent` que el resto del widget ([referencia de eventos del widget](/es/docs/resources/widget/widget-events)), además de los eventos específicos de este componente:

| Evento                                | Payload                               | Cuándo se dispara                                                                                                                                                                                                                 |
| ------------------------------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `express_checkout_ready`              | `{ wallets: { applePay?: boolean } }` | Una vez que el SDK termina de inicializarse. El objeto `wallets` lista las wallets que se renderizaron exitosamente. Si está vacío, ninguna está disponible, por ejemplo en un navegador no soportado o un dominio no verificado. |
| `processing_express_checkout_payment` | None                                  | Después de que el cliente confirma el pago con wallet y el SDK está intercambiando tokens con tu servidor y el backend de Fintoc.                                                                                                 |
| `payment_error`                       | None                                  | El pago con wallet falló en algún paso: `onPaymentRequest` rechazó o expiró por tiempo, el proveedor de wallet devolvió un error, o el estado del pago resultante no es `succeeded`.                                              |
| `express_checkout_error`              | None                                  | Un error interno impidió que el botón se renderizara, por ejemplo cuando el SDK falla al cargar o el contenedor no se encuentra.                                                                                                  |

***

# Referencia completa de opciones

## Fintoc.create(options)

| Parámetro          | Tipo                                  | Requerido | Descripción                                                                                 |
| ------------------ | ------------------------------------- | --------- | ------------------------------------------------------------------------------------------- |
| `product`          | `"payments"`                          | Sí        | Valor literal `"payments"` para Express Checkout.                                           |
| `publicKey`        | `string`                              | Sí        | Tu publishable key.                                                                         |
| `country`          | `"cl"` o `"mx"`                       | No        | País de destino. Por defecto `"cl"`.                                                        |
| `expressCheckout`  | `ExpressCheckoutConfig`               | Sí        | Configuración para el botón de wallet.                                                      |
| `onPaymentRequest` | `(data) => Promise<{ sessionToken }>` | Sí        | Callback que devuelve un `sessionToken` cuando el SDK necesita uno para continuar el flujo. |
| `onSuccess`        | `(data) => void`                      | No        | Callback que recibe el recurso de pago una vez que el pago alcanza `succeeded`.             |
| `onExit`           | `(reason?: string) => void`           | No        | Callback que se ejecuta cuando el widget se cierra.                                         |
| `onEvent`          | `(eventName, metadata?) => void`      | No        | Callback que recibe cada evento del widget.                                                 |

## ExpressCheckoutConfig

| Parámetro              | Tipo                          | Requerido | Descripción                                                                                              |
| ---------------------- | ----------------------------- | --------- | -------------------------------------------------------------------------------------------------------- |
| `container`            | `string`                      | Sí        | `id` del elemento DOM donde el SDK renderiza el botón de wallet.                                         |
| `amount`               | `number`                      | Sí        | Monto a cobrar, en la unidad menor de la moneda. Por ejemplo, CLP no tiene decimales y MXN usa centavos. |
| `currency`             | `string`                      | Sí        | Código ISO 4217 de tres letras de la moneda, por ejemplo `"CLP"` o `"MXN"`.                              |
| `buttonHeight`         | `number`                      | No        | Altura del botón en px. Rango `[40, 100]`. Default `44`.                                                 |
| `buttonBorderRadius`   | `number`                      | No        | Radio del borde del botón en px. Rango `[0, 100]`. Default `4`.                                          |
| `buttonType.applePay`  | `"buy"`, `"pay"`, o `"plain"` | No        | Etiqueta del botón de Apple Pay. Default `"plain"`.                                                      |
| `buttonStyle.applePay` | `"black"` o `"white"`         | No        | Esquema de color de Apple Pay. Default `"black"`.                                                        |
| `locale.applePay`      | `"es-ES"` o `"es-MX"`         | No        | Idioma del botón de Apple Pay. Default `"es-ES"`.                                                        |

***

# Habilitar Apple Pay

Apple Pay no se cargará en un dominio hasta que Fintoc lo haya registrado con Apple. El registro es un prerrequisito tanto para pruebas como para producción. Completa el registro para cada dominio que mostrará el botón, tanto en staging como en producción. Cada dominio registrado debe usar HTTPS.

El proceso funciona así:

1. **Avisa a Fintoc que quieres usar Apple Pay.** Contacta a tu account manager, contacto de customer success, o contacto de ventas, y comparte los dominios que planeas integrar.
2. **Hospeda el archivo de verificación que Fintoc te envía.** Fintoc te envía un archivo de asociación de dominio. Hospédalo en cada dominio bajo la ruta `/.well-known/apple-developer-merchantid-domain-association`, de modo que sea accesible en `https://your-domain.com/.well-known/apple-developer-merchantid-domain-association`. El archivo debe devolver `200 OK` y ser descargable.
3. **Confirma que el archivo está activo.** Avísale a Fintoc una vez que el archivo esté hospedado en cada dominio. Fintoc luego registra cada dominio con Apple.
4. **Prueba tu integración.** Una vez que tus dominios estén registrados, el botón de Apple Pay puede cargarse y puedes seguir los [pasos de prueba](#paso-6-prueba-la-integración) en un dispositivo soportado.

<Warning>
  Si un dominio no está registrado, el botón de Apple Pay permanecerá oculto y `express_checkout_ready` reporta que no hay wallet de Apple Pay disponible (`wallets.applePay` no es `true`). Confirma que el dominio esté habilitado antes de depurar tu integración.
</Warning>

***

# Ver también

* [Aceptar un pago](/es/docs/payments/accept-a-payment): guía estándar de integración de Checkout Session.
* [Integración Web](/es/docs/resources/widget/web-integration): guía completa de integración del widget.
* [Escuchar eventos del Widget](/es/docs/resources/widget/widget-events): catálogo completo de eventos.
* [Integración WebView](/es/docs/resources/widget/webview): integrar el widget dentro de una app nativa.
