# Recopilar consentimiento con enlaces de consentimiento

Un enlace de consentimiento te permite recopilar una autorización de débito directo sin necesidad de construir tu propia interfaz de usuario. Creas el enlace con una llamada a la API y envías la URL a tu cliente. Tu cliente lo abre en su navegador, ingresa su CLABE, revisa y acepta la autorización de débito directo, y la firma electrónicamente con un código que Belvo deposita en su cuenta.

Cuando tu cliente termina, Belvo ha creado un método de pago y un consentimiento confirmado para ellos. Son los mismos recursos que de otro modo crearías tú mismo con la API de Débito Directo, por lo que puedes enviar solicitudes de pago de inmediato.

En esta guía, tú:

- Crearás un enlace de consentimiento para un cliente existente, con los términos de pago que deben autorizar.
- Compartirás el enlace con tu cliente y verás qué hacen en el widget de enlace de consentimiento.
- Manejarás la redirección de vuelta a tu aplicación.
- Escucharás los webhooks y confirmarás el resultado.


Los enlaces de consentimiento reemplazan dos pasos de la API
Un enlace de consentimiento reemplaza los pasos de **Crear un método de pago** y **Crear un consentimiento** de la guía Pagos por Débito Directo vía API. Aún creas el cliente con la API, y aún creas solicitudes de pago con la API.

## Requisitos previos

Antes de comenzar, asegúrate de:

1. Generar tus claves API.
2. Configurar un webhook para escuchar eventos.
3. Configurar la lista blanca de IPs.
4. Pedir a tu representante de Belvo que habilite los enlaces de consentimiento para tu cuenta. Los enlaces de consentimiento utilizan la validación de centavos para entregar el código de firma, por lo que el consentimiento de validación de centavos debe estar activo para tu cuenta.
5. Crear un cliente para la persona a la que deseas debitar. El widget muestra el nombre del cliente y un RFC o CURP enmascarado de este registro, así que asegúrate de que los datos sean correctos.


## Descripción general del flujo de datos


```mermaid
sequenceDiagram
    participant App as Your application
    participant Customer as Customer
    participant Widget as Consent link widget
    participant Belvo as Belvo
    participant Bank as Customer's bank

    Note over App,Bank: 1. Create the consent link
    App->>Belvo: POST /consents/links
    Belvo-->>App: 201 - Created + id + consentLinkUrl

    Note over App,Bank: 2. Share the link
    App->>Customer: Send consentLinkUrl (SMS, email, WhatsApp, or redirect)
    Customer->>Widget: Open consentLinkUrl

    Note over App,Bank: 3. Customer completes the widget
    Widget->>Belvo: Submit CLABE
    Belvo->>Bank: Send a $0.01 MXN deposit with a code
    Widget->>Belvo: Accept the authorization
    Customer->>Widget: Enter the code from the deposit
    Widget->>Belvo: Verify the code (electronic signature)
    Belvo-->>Widget: Link completed

    Note over App,Bank: 4. Confirm the result
    Belvo->>App: WEBHOOK consent_confirmed (consentId, paymentMethodId)
    Widget->>App: Redirect to callbackUrl?status=completed
    App->>Belvo: GET /consents/links/{id}
    Belvo-->>App: 200 + status completed
```

## Crear un enlace de consentimiento

Para crear un enlace de consentimiento, realiza una llamada `POST /consents/links` con el ID del cliente y los términos de pago que deben autorizar.

Sandbox

```curl Crear una Solicitud de Enlace de Consentimiento (Sandbox)
curl -i -X POST \
  'https://api.sandbox.directdebit.belvo.com/consents/links' \
  -H 'Content-Type: application/json' \
  -H 'api-key-id: YOUR_API_KEY_ID' \
  -H 'api-key-secret: YOUR_API_KEY_SECRET' \
  -d '{
    "customerId": "0d1a377b-b4c5-4a94-9e2e-83e59d1f6a9c",
    "expiresIn": 72,
    "callbackUrl": "https://www.your-app.com/direct-debit/return",
    "terms": {
      "chargeType": "RECURRING",
      "chargeAmount": 420.00,
      "paymentFrequency": "MONTHLY",
      "serviceOrCreditDescription": "Préstamo personal",
      "termDescription": "12 meses",
      "interestRate": "1,0% mensual",
      "numberOfCharges": 12,
      "firstChargeDate": "2026-11-10",
      "isPayrollLinked": false
    }
  }'
```

Producción

```curl Crear una Solicitud de Enlace de Consentimiento (Producción)
curl -i -X POST \
  'https://api.directdebit.belvo.com/consents/links' \
  -H 'Content-Type: application/json' \
  -H 'api-key-id: YOUR_API_KEY_ID' \
  -H 'api-key-secret: YOUR_API_KEY_SECRET' \
  -d '{
    "customerId": "0d1a377b-b4c5-4a94-9e2e-83e59d1f6a9c",
    "expiresIn": 72,
    "callbackUrl": "https://www.your-app.com/direct-debit/return",
    "terms": {
      "chargeType": "RECURRING",
      "chargeAmount": 420.00,
      "paymentFrequency": "MONTHLY",
      "serviceOrCreditDescription": "Préstamo personal",
      "termDescription": "12 meses",
      "interestRate": "1,0% mensual",
      "numberOfCharges": 12,
      "firstChargeDate": "2026-11-10",
      "isPayrollLinked": false
    }
  }'
```

| Parámetro  | Tipo | Requerido | Descripción |
|  --- | --- | --- | --- |
| `customerId` | string (UUID) | true | El `customerId` del cliente que debe autorizar el débito directo. El cliente debe pertenecer a tu cuenta. |
| `terms` | object | false | Los términos de pago que tu cliente revisa y autoriza en el widget. Para más detalles, consulta la tabla Objeto Terms a continuación. |
| `expiresIn` | integer | false | El número de horas hasta que el enlace expire. Mínimo `1`, máximo `720` (30 días). Por defecto: `72`. |
| `callbackUrl` | string | false | La URL a la que el widget redirige a tu cliente cuando termina o abandona el flujo. Belvo añade el resultado como parámetros de consulta. La URL debe usar `https`, no debe contener credenciales y puede tener un máximo de 2048 caracteres. Solo puedes establecerla cuando creas el enlace. Para más detalles, consulta Manejar la redirección a tu URL de callback. |


### Objeto de términos

Todos los términos son opcionales. El widget solo muestra los términos que envías, así que envía cada término que aplique al acuerdo con tu cliente.

Envía valores sin formato, no texto formateado
Envía `chargeAmount` como un número JSON (por ejemplo, `420.00`), no como una cadena. Belvo rechaza valores preformateados como `"$420.00 MXN"` o `"420.00"`. El monto siempre está en pesos mexicanos (MXN), y Belvo lo formatea para tu cliente.

Envía `chargeType` y `paymentFrequency` en mayúsculas (por ejemplo, `RECURRING` y `MONTHLY`). Belvo rechaza valores en minúsculas.

| Parámetro  | Tipo | Descripción |
|  --- | --- | --- |
| `chargeType`
 | string (enum)
 | El tipo de cargo que tu cliente autoriza. Puede ser uno de:
- `RECURRING`: Cargos que se repiten en un horario, como cuotas de préstamos o suscripciones.
- `SINGLE`: Un solo cargo.

Para `SINGLE`, el widget etiqueta el monto y la fecha como un cargo único ("Monto de cargo (cargo único)" y "Fecha del cargo").
 |
| `chargeAmount` | number | El monto de cada cargo, en MXN. Debe ser al menos `1`. Belvo lo redondea a dos decimales. Por ejemplo, `1234.5` se muestra a tu cliente como "$1,234.50 MXN". |
| `paymentFrequency` | string (enum) | Con qué frecuencia cobras a tu cliente. Puede ser uno de: `MONTHLY` (mostrado como "Mensual"), `BIWEEKLY` (mostrado como "Quincenal"), o `WEEKLY` (mostrado como "Semanal"). |
| `serviceOrCreditDescription` | string | Una descripción del servicio o crédito, en español. Por ejemplo, `Préstamo personal`. |
| `termDescription` | string | Una descripción del plazo del acuerdo, en español. Por ejemplo, `12 meses`. |
| `interestRate` | string | La tasa de interés, formateada como deseas que tu cliente la lea. Por ejemplo, `1,0% mensual`. |
| `numberOfCharges` | integer | El número total de cargos. Debe ser al menos `1`. |
| `firstChargeDate` | string | La fecha del primer cargo, en formato `YYYY-MM-DD`. Por ejemplo, `2026-11-10`. |
| `isPayrollLinked` | boolean | Indica si el crédito está vinculado a la nómina de tu cliente. |


Permite que tu cliente revise el contrato completo
Tu cliente solo puede abrir el contrato completo de domiciliación (**Revisar contrato de domiciliación**) cuando el enlace tiene un `chargeAmount`, y también un `paymentFrequency` para cargos `RECURRING`. Asegúrate de enviar estos términos.

Recibirás la siguiente respuesta de nuestra API. Asegúrate de guardar el `id` para verificar el estado del enlace más tarde, y envía el `consentLinkUrl` a tu cliente.


```json Create a Consent Link Response Body
{
  "id": "b8e1c2f4-5a6d-4e7f-8a9b-0c1d2e3f4a5b", // [!code highlight]
  "consentLinkUrl": "https://portal.sandbox.directdebit.belvo.com/consent.html?token=aB3dE6fG9hJ2kL5mN8pQ1rS4", // [!code highlight]
  "status": "active",
  "step": "bank_account",
  "customerId": "0d1a377b-b4c5-4a94-9e2e-83e59d1f6a9c",
  "terms": {
    "chargeType": "RECURRING",
    "chargeAmount": 420,
    "paymentFrequency": "MONTHLY",
    "serviceOrCreditDescription": "Préstamo personal",
    "termDescription": "12 meses",
    "interestRate": "1,0% mensual",
    "numberOfCharges": 12,
    "firstChargeDate": "2026-11-10",
    "isPayrollLinked": false
  },
  "expiresAt": "2026-10-03T15:00:00.000Z",
  "callbackUrl": "https://www.your-app.com/direct-debit/return"
}
```

| Parámetro  | Tipo | Descripción |
|  --- | --- | --- |
| `id` | string (UUID) | El ID de Belvo del enlace de consentimiento. |
| `consentLinkUrl` | string | La URL que envías a tu cliente. |
| `status` | string | El estado del enlace. Para los valores posibles, consulta Estados del enlace de consentimiento. |
| `step` | string | La pantalla en la que se encuentra tu cliente mientras el enlace está `active`. Para los valores posibles, consulta Pasos del enlace de consentimiento. |
| `customerId` | string (UUID) | El `customerId` al que pertenece el enlace. |
| `terms` | object | Los términos, exactamente como los enviaste. |
| `expiresAt` | string | La marca de tiempo ISO-8601 cuando el enlace expira. |
| `completedAt` | string | La marca de tiempo ISO-8601 cuando tu cliente completó el enlace. Solo presente para enlaces `completed`. |
| `callbackUrl` | string | La URL de callback, si configuraste una. |


## Comparte el enlace con tu cliente

Envía el `consentLinkUrl` a tu cliente por SMS, correo electrónico o WhatsApp, o redirígelo desde tu aplicación. El widget funciona en cualquier navegador móvil o de escritorio, está en español y no requiere que tu cliente inicie sesión.

Trata el enlace como un secreto
Cualquiera con el `consentLinkUrl` puede abrir el widget para tu cliente. Solo envíalo a tu cliente y no lo registres ni lo añadas a herramientas de análisis. Si crees que un enlace fue compartido con la persona equivocada, revócalo y crea uno nuevo. Consulta Gestionar enlaces de consentimiento.

## Lo que ve tu cliente

Tu cliente pasa por las siguientes pantallas. El widget guarda su progreso, por lo que si cierra la página y vuelve a abrir el enlace antes de que expire, continuará en la misma pantalla.

### 1. Bienvenido

La pantalla de bienvenida explica cómo funciona el proceso:

1. Tu cliente confirma y revisa el débito directo.
2. Belvo deposita $0.01 MXN en su cuenta, con un código.
3. Tu cliente ingresa el código para autorizar el débito directo.


Para continuar, tu cliente debe aceptar los Términos y Condiciones y el Aviso de Privacidad de Belvo.

Si configuras un `callbackUrl`, una flecha de retroceso permite a tu cliente salir del flujo. Belvo los redirige a tu `callbackUrl` con `status=cancelled&error=user_cancelled`.

Pantalla de bienvenida del enlace de consentimiento
### 2. Confirmar datos personales y CLABE

El widget muestra el nombre completo de tu cliente y el RFC o CURP enmascarado del registro del cliente. Tu cliente no puede editar estos valores.

Tu cliente ingresa su CLABE de 18 dígitos. El widget verifica que la CLABE sea válida, y Belvo identifica el banco a partir de ella. La cuenta debe estar a nombre de tu cliente. Los enlaces de consentimiento solo aceptan cuentas CLABE, no tarjetas de débito.

Cuando tu cliente toca **Continuar**, Belvo crea el método de pago y envía inmediatamente el depósito de $0.01 MXN con el código.

Si el nombre o ID es incorrecto, tu cliente puede tocar **No soy yo** y luego **Salir sin autorizar**. Belvo los redirige a tu `callbackUrl` con `status=cancelled&error=customer_data_mismatch`. Corrige los datos del cliente y crea un nuevo enlace.

Pantalla de datos personales y CLABE del enlace de consentimiento
### 3. Revisa y acepta la autorización

El widget muestra un resumen de los términos que enviaste, junto con el número de cuenta enmascarado, el banco y el nombre de tu empresa como beneficiario. También informa a tu cliente que hoy no se cobra nada.

Para cargos `RECURRING`, el título dice "Revisa y autoriza tus cargos recurrentes". Para cargos `SINGLE`, dice "Revisa y autoriza tu cargo único". El resumen solo tiene una fila por cada término que enviaste.

Cuando tu cliente toca **Continuar**, acepta la autorización. Belvo sella el documento de autorización y lo almacena como el archivo `contract` del consentimiento.

Resumen de autorización para cargos recurrentes
**Cargo único**

Este enlace de ejemplo tiene `"chargeType": "SINGLE"` y solo envía `chargeAmount` y `firstChargeDate`, por lo que el resumen muestra el monto, la fecha del cargo, la cuenta y el beneficiario.

Resumen de autorización para un cargo único
**Revisión del contrato**

Con **Revisar contrato de domiciliación**, tu cliente lee el contrato completo de domiciliación, rellenado con sus datos y tus términos, y puede descargar una copia en PDF antes de aceptar.

Revisión del contrato de domiciliación
### 4. Espera el depósito

Si el depósito aún no ha llegado, el widget le indica a tu cliente que busque un depósito de $0.01 MXN en su aplicación bancaria. El código está en la descripción de la transacción.

El widget verifica automáticamente el depósito y pasa a la siguiente pantalla cuando llega. Si el depósito ya llegó mientras tu cliente revisaba la autorización, el widget omite esta pantalla.

Esperando el depósito de verificación
### 5. Ingresar el código y autorizar

Tu cliente ingresa el código de 6 dígitos de la descripción del depósito y toca **Autorizar**. Ingresar el código es la firma electrónica de autorización de tu cliente.

Tu cliente tiene 3 intentos para ingresar el código correcto. Si no pueden encontrar el depósito, **No recibí el depósito** explica dónde encontrar el código. Si tu cliente ingresó la CLABE incorrecta, el depósito nunca llega. Pueden finalizar el flujo desde el mismo diálogo, y necesitas crear un nuevo enlace para ellos.

Pantalla de código de verificación
### 6. Autorización confirmada

Cuando el código es correcto, el consentimiento se confirma y el enlace se marca como `completed`. El widget muestra un resumen de los términos autorizados.

Cuando tu cliente toca **Cerrar**, Belvo los redirige a tu `callbackUrl` con `status=completed`.

Pantalla de autorización confirmada
**Contrato firmado**

Con **Contrato de domiciliación**, tu cliente ve la evidencia de la firma electrónica: la fecha y hora de la firma (hora de Ciudad de México), el folio de la firma, el dispositivo, una dirección IP enmascarada y los detalles del depósito de verificación. También pueden descargar el contrato firmado como un PDF.

Contrato firmado con detalles de firma electrónica
### Pantallas de error

**Enlace no disponible**

El widget muestra esta pantalla cuando el enlace ha expirado, ha sido revocado, ya se ha completado, ha fallado o es inválido. Por razones de seguridad, el widget muestra el mismo mensaje en cada caso. Se le pide a tu cliente que solicite un nuevo enlace de tu parte.

Pantalla de enlace no disponible
**Autorización fallida**

El widget muestra esta pantalla cuando Belvo no puede completar una acción mientras tu cliente está en el flujo, por ejemplo, cuando la validación de la cuenta falla después de que han enviado su CLABE. La pantalla incluye un ID que tu cliente puede compartir con el soporte de Belvo en cobros@belvo.com.

Pantalla de autorización fallida
## Manejar la redirección a tu URL de callback

Si configuras un `callbackUrl`, Belvo redirige a tu cliente a esta cuando terminan o abandonan el flujo. Belvo mantiene cualquier parámetro de consulta que tu URL ya tenga y añade los siguientes:

| `status` | `error` | Cuándo |
|  --- | --- | --- |
| `completed` | No presente | Tu cliente autorizó el débito directo y tocó **Cerrar** en la pantalla de confirmación. |
| `cancelled` | `user_cancelled` | Tu cliente salió desde la pantalla de bienvenida. |
| `cancelled` | `customer_data_mismatch` | Tu cliente indicó que el nombre o ID en el widget no es el suyo. |



```text Ejemplo de redirección
https://www.your-app.com/direct-debit/return?status=completed
```

La redirección nunca incluye el token de enlace ni ningún dato del cliente.

No confíes solo en la redirección
Usa la redirección para actualizar tu interfaz de usuario, pero siempre confirma el resultado con la API o webhooks antes de crear solicitudes de pago. Cualquiera puede abrir tu URL de callback con cualquier parámetro, y tu cliente puede cerrar la página sin ser redirigido. Además, ignora cualquier valor de parámetro que no reconozcas, ya que podríamos añadir nuevos.

## Escuchar webhooks y confirmar el resultado

Un enlace de consentimiento crea un método de pago regular y un consentimiento, por lo que recibes los mismos webhooks que en el flujo de Pagos por Débito Directo vía API:

- `consent_update` con `consent_confirmed`: Tu cliente ingresó el código correcto y el consentimiento está confirmado. El campo `details.id` es el `consentId` y `details.paymentMethodId` es el método de pago que el enlace creó.
- `payment_method_update` con `payment_method_registration_successful` o `payment_method_registration_failed`: El resultado de la validación de la cuenta. Los métodos de pago creados por un enlace de consentimiento tienen `ConsentLink` como su `reference`.


Para ver los payloads completos de los webhooks, consulta nuestra documentación de Webhooks de Pagos (México).

Para verificar el estado del enlace en cualquier momento, realiza una llamada `GET /consents/links/{id}`. Un estado `completed` significa que tu cliente terminó el flujo.

Sandbox

```curl Get a Consent Link Request (Sandbox)
curl -i -X GET \
  'https://api.sandbox.directdebit.belvo.com/consents/links/{id}' \
  -H 'api-key-id: YOUR_API_KEY_ID' \
  -H 'api-key-secret: YOUR_API_KEY_SECRET'
```

Producción

```curl Get a Consent Link Request (Production)
curl -i -X GET \
  'https://api.directdebit.belvo.com/consents/links/{id}' \
  -H 'api-key-id: YOUR_API_KEY_ID' \
  -H 'api-key-secret: YOUR_API_KEY_SECRET'
```

Para identificar el método de pago que el enlace creó, utiliza el valor `details.paymentMethodId` del webhook `consent_confirmed`. No lo busques solo por `customer_id`, ya que tu cliente puede tener más de un método de pago. Para confirmar a qué cliente pertenece el método de pago, realiza una llamada GET para obtener los detalles de un método de pago y compara su `customer` con el `customerId` del enlace. Esto solo confirma el cliente: si creaste más de un enlace de consentimiento para el mismo cliente, no te dice qué enlace creó el método de pago.

¡Hecho!
Tu cliente ha autorizado el débito directo, y tienes un método de pago con un consentimiento confirmado. Ahora puedes crear solicitudes de pago para este cliente.

## Probar enlaces de consentimiento en Sandbox

En Sandbox, Belvo no envía un depósito real de $0.01 MXN, por lo que no puedes leer un código de un estado de cuenta bancario. En su lugar, controlas el resultado del flujo con la CLABE y el código que tu tester ingresa en el widget. Usa el `consentLinkUrl` que obtienes de la API de Sandbox.

### Elige el resultado de validación de cuenta

Ingresa una de las siguientes CLABEs en la pantalla de datos personales y CLABE:

| CLABE  | Resultado |
|  --- | --- |
| `012180000000000015` | La validación de la cuenta falla. El método de pago es `failed`, el estado del enlace cambia a `failed`, y el widget muestra una pantalla de error. Para más detalles, consulta Pantallas de error. |
| `012180000000000028` | El depósito nunca llega. El método de pago permanece en `pending_validation`, y el enlace se mantiene en el paso `awaiting_deposit` hasta que expira. Úsalo para probar la pantalla de espera. |
| Cualquier otra CLABE válida | El depósito llega inmediatamente. El enlace avanza al paso de `verification` tan pronto como tu evaluador acepta la autorización, y el widget omite la pantalla de espera. |


Los métodos de pago que creas con estas CLABEs usan `failed` o `pending` como su `reference` en lugar de `ConsentLink`. Las CLABEs mágicas solo funcionan en Sandbox. En Producción, Belvo las trata como cualquier otra CLABE.

### Ingresa el código de verificación

En Sandbox, el código de verificación siempre es `123456`. Ingresa cualquier otro código para probar el mensaje de código incorrecto. Tu evaluador tiene 3 intentos para ingresar el código correcto.

### Probar otros estados de enlaces

- **Expirado:** crea un enlace con `"expiresIn": 1` y ábrelo después de una hora.
- **Revocado:** realiza una llamada `POST /consents/links/{id}/revoke`, y luego abre el enlace.


## Referencia de enlace de consentimiento

### Estados de los enlaces de consentimiento

| Estado | Descripción |
|  --- | --- |
| `active` | El enlace puede ser utilizado. Verifica `step` para ver en qué pantalla se encuentra tu cliente. |
| `completed` | Tu cliente autorizó el débito directo. El consentimiento está confirmado. |
| `expired` | El enlace alcanzó su fecha de `expiresAt` antes de que tu cliente lo completara. |
| `revoked` | Revocaste el enlace. |
| `failed` | La validación de la cuenta falló, por ejemplo, porque el titular de la cuenta no coincide con el cliente. Crea un nuevo enlace para que tu cliente pueda intentarlo de nuevo con una cuenta diferente. |


Solo los enlaces `active` pueden ser abiertos. Para cualquier otro estado, el widget muestra la pantalla de **Enlace no disponible**.

### Pasos del enlace de consentimiento

| Paso | Descripción |
|  --- | --- |
| `bank_account` | Tu cliente aún no ha enviado su CLABE. |
| `authorization` | Tu cliente envió su CLABE y está revisando la autorización. |
| `awaiting_deposit` | Tu cliente aceptó la autorización y está esperando el depósito de $0.01 MXN. |
| `verification` | El depósito llegó y tu cliente debe ingresar el código. |


Cuando un enlace está `completed`, `step` mantiene el último paso en el que estaba tu cliente. Siempre verifica `status` primero.

### Administrar enlaces de consentimiento

| Solicitud | Descripción |
|  --- | --- |
| `GET /consents/links` | Lista tus enlaces de consentimiento, paginados. Soporta los parámetros de consulta `page` y `limit`. |
| `GET /consents/links/{id}` | Obtiene los detalles de un enlace de consentimiento. |
| `POST /consents/links/{id}/revoke` | Revoca un enlace de consentimiento. El enlace ya no se puede abrir. Revocar un enlace no cambia un método de pago o consentimiento que el enlace ya haya creado. |


### Errores

| Estado HTTP | Descripción |
|  --- | --- |
| `400` | El cuerpo de la solicitud es inválido. Por ejemplo, `chargeAmount` es una cadena o es menor que `1`, `chargeType` está en minúsculas, o `callbackUrl` no utiliza `https`. |
| `404` | El cliente o el enlace de consentimiento no existe o no pertenece a tu cuenta. |