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

# Link de captura

## Descripción

Los links de captura permiten obtener la información de un método de pago de un cliente sin que tengas que cumplir con la normativa PCI DSS. Cuando el cliente completa el formulario, OnePay envía este webhook con el identificador del método de pago capturado, para que puedas cobrarlo después sin volver a pedirle los datos.

El evento se llama `connect_link.completed` y se genera una vez por cada formulario completado.

El objeto `event` no incluye un identificador propio, así que para deduplicar hay que armarlo. **No alcanza con `connect_link.id`**: un link con `single_use: false` se puede completar muchas veces y todas las capturas comparten ese id, así que descartarlas por id te haría perder capturas legítimas. Usa `connect_link.id` junto con `connect_link.completed`, que es el número de captura y aumenta de a uno en cada una. Ese mismo campo te sirve para ordenar: si te llegan dos eventos del mismo link, el de `completed` más alto es el más reciente.

<Note>
  Cada entrega llega firmada. Antes de procesar el evento, verifica los headers como se explica en [Autenticación de los eventos](/client/webhooks/index).
</Note>

## Los dos identificadores de cliente

El payload trae dos identificadores de cliente, y son cosas distintas. Es el punto que más confusión genera, así que conviene tenerlo claro antes de integrar:

| Campo                      | Qué representa                                                                                          | ¿Sirve para cobrar?                           |
| -------------------------- | ------------------------------------------------------------------------------------------------------- | --------------------------------------------- |
| `connect_link.customer_id` | **Tu cliente.** El que enviaste al crear el link. `null` si el link se creó desde el panel sin cliente. | **Sí.** Es el que va en `charge.customer_id`. |
| `customer.id`              | El **dueño real del método de pago** capturado. Siempre es un cliente de tu empresa.                    | **Sí.**                                       |

<Note>
  **Usa `connect_link.customer_id` en tus cobros** siempre que lo tengas: es el cliente que tú registraste. Cuando el link se creó sin cliente —solo es posible desde el panel; la API exige `customer_id`— ese campo llega en `null` y el que debes usar es `customer.id`.
</Note>

<Warning>
  **Que los dos identificadores no coincidan no es un error.** El pagador puede elegir un método que ya tenía guardado contigo de un pago anterior, hecho a nombre de otro de tus clientes; en ese caso `customer.id` reporta ese cliente y no el que amarraste al link. El método sigue siendo cobrable: lo que `POST /charges` exige es que pertenezca a tu empresa.

  Si tu integración necesita que el método quede bajo un cliente concreto, compara los dos campos y actúa en consecuencia —no lo trates como una falla de la captura.
</Warning>

## Qué identificador usar después

| Para                  | Usa                                                                                               |
| --------------------- | ------------------------------------------------------------------------------------------------- |
| Cobrar con tarjeta    | `payment_method.id` en `card_id` de [`POST /charges`](/client/charges/create)                     |
| Cobrar con cuenta     | `payment_method.id` en `account_id` de [`POST /charges`](/client/charges/create)                  |
| Consultar el método   | [`GET /cards/{id}`](/client/cards/detail) o [`GET /accounts/{id}`](/client/accounts/detail)       |
| Dar de baja el método | [`DELETE /cards/{id}`](/client/cards/delete) o [`DELETE /accounts/{id}`](/client/accounts/delete) |

<Warning>
  **Una captura nueva no da de baja la anterior.** Si el mismo cliente vuelve a completar un link, el método anterior sigue activo y cobrable.

  El `payment_method.id` que recibas puede ser el mismo de antes —si el pagador eligió un método que ya tenía guardado contigo— o uno nuevo, si volvió a ingresar los datos. Guarda siempre el del último evento, y si no quieres conservar el anterior, dalo de baja con [`DELETE /cards/{id}`](/client/cards/delete) o [`DELETE /accounts/{id}`](/client/accounts/delete).
</Warning>

## Ejemplo

```json theme={null}
{
    "event": {
        "type": "connect_link.completed",
        "timestamp": 1787341999,
        "environment": "live",
        "company_id": "f1e2d3c4-b5a6-9788-7654-321fedcba098"
    },
    "customer": {
        "id": "9dd4158b-0e45-42bc-b56f-a4c1f856814d",
        "first_name": "Juan",
        "last_name": "Pérez",
        "email": "juan@example.com",
        "phone": "+573001234567",
        "document_type": "CC",
        "document_number": "1234567890",
        "is_test": false
    },
    "connect_link": {
        "id": "9e92f61e-e90f-4fbb-a551-080fd4fb4f6f",
        "customer_id": "9dd4158b-0e45-42bc-b56f-a4c1f856814d",
        "single_use": true,
        "visits": 2,
        "completed": 1,
        "external_id": "31231231231",
        "is_test": false,
        "allows": {
            "cards": true,
            "accounts": false,
            "wallets": true,
            "pse": true,
            "pse_debit": false,
            "breb": true,
            "card_extra": false,
            "full_extra": false,
            "realtime": false,
            "direct_account": false
        },
        "created_at": "2026-08-21T19:53:06.000000Z",
        "updated_at": "2026-08-21T19:53:19.000000Z",
        "url": "https://pagos.onepay.la/connect-link/9e92f61e-e90f-4fbb-a551-080fd4fb4f6f"
    },
    "payment_method_type": "card",
    "payment_method": {
        "id": "9e01eeae-2868-4564-9d04-84d1d1d027d2",
        "brand": "Visa",
        "last_four": "4242",
        "expiration_date": "10/2033",
        "label": "Visa ·4242",
        "card_name": "Juan Pérez",
        "country": "CO"
    }
}
```

<Note>
  El payload real incluye además `connect_link.company`, con la configuración de tu empresa. Se omite en este ejemplo porque no lo necesitas para cobrar.
</Note>

## El objeto `payment_method`

Su forma depende de `payment_method_type`.

### `card`

| Campo             | Tipo   | Descripción                                                       |
| ----------------- | ------ | ----------------------------------------------------------------- |
| `id`              | string | Identificador de la tarjeta. Es el que va en `card_id` al cobrar. |
| `brand`           | string | Franquicia (`Visa`, `Mastercard`, …).                             |
| `last_four`       | string | Últimos cuatro dígitos.                                           |
| `expiration_date` | string | Vencimiento, en formato `MM/YYYY`.                                |
| `label`           | string | Etiqueta lista para mostrar al usuario.                           |
| `card_name`       | string | Nombre del tarjetahabiente.                                       |
| `country`         | string | País emisor, en ISO 3166-1 alfa-2.                                |

### `account`

| Campo     | Tipo   | Descripción                                                         |
| --------- | ------ | ------------------------------------------------------------------- |
| `id`      | string | Identificador de la cuenta. Es el que va en `account_id` al cobrar. |
| `subtype` | string | Tipo de cuenta: `SAVINGS`, `CHECKING`, `ELECTRONIC_DEPOSIT`, …      |
| `title`   | string | Etiqueta lista para mostrar al usuario.                             |
| `bank`    | string | Nombre del banco.                                                   |

<Note>
  Una cuenta capturada con `subtype: SAVINGS` es una cuenta bancaria por riel ACH. **No es lo mismo que una billetera enrolada**: el enrolamiento de una billetera (Nequi, Daviplata) usa `subtype: ELECTRONIC_DEPOSIT` con el celular como número de cuenta, y requiere que el titular autorice la vinculación desde la app. Para capturar una billetera por link, habilita `allows.wallets`.
</Note>

### `wallet`

| Campo      | Tipo   | Descripción                           |
| ---------- | ------ | ------------------------------------- |
| `id`       | string | Identificador de la billetera OnePay. |
| `currency` | string | Moneda del saldo.                     |
| `balance`  | number | Saldo disponible.                     |
