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

# Cobrar pagos locales con cuentas virtuales

> Dale a cada pagador sus propios datos bancarios locales, abona sus pagos al saldo fiat del comercio y relaciona cada depósito con el pagador mediante depositAlias.

Usa este flujo para cobrar pagos en moneda local (MXN, ARS, COP, BRL) de tus propios clientes hacia el saldo fiat de un comercio, también llamado saldo Pending Fund. Le das a cada pagador una cuenta virtual con sus propios datos bancarios, el pagador envía una transferencia local, y VelaFi abona el saldo del comercio y te envía un `FUNDING_WEBHOOK` que indica la cuenta virtual a la que llegó el dinero. Desde ese saldo puedes [dispersar pagos](https://docs.velafi.com/es/docs/use-cases/payouts-from-balance.md), mover fondos a otro comercio o comprar cripto.

## Cómo funciona

```mermaid theme={null}
sequenceDiagram
    participant You as Tu plataforma
    participant V as VelaFi
    participant P as Pagador
    You->>V: POST /v2/merchant/virtual/accounts (alias = ID del pagador)
    You->>V: GET /v2/merchant/virtual/addfunds (depositAlias)
    V-->>You: Datos bancarios de ese alias (fieldList)
    You->>P: Muestra los datos bancarios
    P->>V: Transferencia local (SPEI, CVU, Pix, Bre-B...)
    V->>V: Abona el saldo fiat del comercio
    V->>You: FUNDING_WEBHOOK (type DEPOSIT, status 2, depositAlias)
    You-->>V: HTTP 200 {"callbackStatus":"SUCCESS"}
    You->>V: GET /v2/merchant/funding/records (conciliar)
```

### Una cuenta o una por pagador

| Opción | Cómo obtienes los datos | Cómo sabes quién pagó | Úsala cuando |
| - | - | - | - |
| Cuenta de moneda del comercio | [`GET /v2/merchant/addfunds`](https://docs.velafi.com/es/api-reference/merchant/get-pending-fund-account) | Campos del pagador en el webhook (`payerName`, `payerAccount`, `taxId`), que dependen del riel | Fondeas tu propio saldo o tienes pocos pagadores |
| Una cuenta virtual por pagador | [`POST /v2/merchant/virtual/accounts`](https://docs.velafi.com/es/api-reference/merchant/create-multiple-virtual-account), después [`GET /v2/merchant/virtual/addfunds`](https://docs.velafi.com/es/api-reference/merchant/get-multiple-virtual-account) | `depositAlias` en el webhook y en el registro de fondeo | Cobras a muchos clientes y necesitas atribuir cada pago |

> [!NOTE]
>
> Una cuenta virtual sirve solo para atribución. No tiene saldo propio: cada depósito, en cualquier cuenta virtual, se abona al saldo único de la cuenta de moneda del comercio. Lleva los saldos por pagador en tu propio libro contable, indexados por `depositAlias`.

## Antes de empezar

* **Acceso a la API.** Una clave de API, la IP de tu servidor en la lista blanca y un token de negocio en el header `X-BH-TOKEN`. Consulta [Autenticación](https://docs.velafi.com/es/api-reference/authentication.md).
* **Un comercio verificado.** Consulta [Crear un comercio](https://docs.velafi.com/es/docs/guides/creating-merchant.md).
* **Una cuenta de moneda activa** para la moneda y el canal en los que quieres cobrar (status `2` en [Listar cuentas de comercio](https://docs.velafi.com/es/api-reference/merchant/get-a-list-of-merchant-accounts.md)). Consulta [Activar la cuenta de un comercio](https://docs.velafi.com/es/docs/guides/activating-merchant-account.md).
* **Un endpoint de `FUNDING_WEBHOOK`** registrado y que devuelva la confirmación requerida. Consulta [Webhooks](https://docs.velafi.com/es/docs/guides/webhooks.md) y [Configuración de webhooks](https://docs.velafi.com/es/api-reference/webhooks/webhook-setup.md).

### Canales que admiten cuentas virtuales

| Moneda | `paymentId` | Canal | Regla del alias |
| - | - | - | - |
| MXN | `105` | SPEI (Finco Pay) | Letras y dígitos, hasta 64 caracteres |
| MXN | `72` | SPEI (Tesored) | Letras y dígitos, hasta 64 caracteres |
| ARS | `63` | CBU/CVU (Momentum) | Letras y dígitos, hasta 64 caracteres |
| COP | `68` | ACH automático (link de pago) | De 6 a 21 letras mayúsculas o dígitos |
| COP | `69` | Bre-B | De 6 a 21 letras mayúsculas o dígitos |
| BRL | `90` | Pix (Genial) | Letras y dígitos, hasta 64 caracteres |
| BRL | `92` | Pix - Woovi (Avenia) | Letras y dígitos, hasta 64 caracteres |

El comercio ya debe tener una cuenta de moneda activa en ese canal. Una cuenta de moneda en un canal que no admite cuentas virtuales devuelve `-5084` (esta moneda no admite múltiples cuentas virtuales). `default`, en cualquier combinación de mayúsculas y minúsculas, está reservado.

## Paso a paso

**1. Crea una cuenta virtual para cada pagador**

Llama a [`POST /v2/merchant/virtual/accounts`](https://docs.velafi.com/es/api-reference/merchant/create-multiple-virtual-account) con el comercio, la moneda, el canal y un `alias` que tú elijas. Usa un ID estable de tu sistema, como tu ID de cliente, para que puedas relacionar los depósitos sin una tabla de búsqueda. El alias es permanente.

```bash cURL theme={null}
curl -X POST https://api.velafi.com/v2/merchant/virtual/accounts \
  -H "X-BH-TOKEN: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "merchantId": 100001,
    "fiat": "MXN",
    "paymentId": 105,
    "alias": "CUST0001"
  }'
```

```json Response theme={null}
{ "code": 200, "msg": "SUCCESS", "data": { "fiat": "MXN", "status": 1 } }
```

`status` es `1` (pendiente) mientras el canal configura la cuenta, `2` cuando está activa y `3` si falló. Las cuentas ARS (`63`) devuelven `2` de inmediato. Enviar el mismo alias otra vez mientras está pendiente devuelve `-5085`; una vez que está activa, `-5086`.

**2. Obtén los datos bancarios del alias**

Consulta periódicamente [`GET /v2/merchant/virtual/addfunds`](https://docs.velafi.com/es/api-reference/merchant/get-multiple-virtual-account) con `depositAlias` hasta que el `status` del registro sea `2` y después lee su `fieldList`. Las claves dependen del canal y se listan en [Claves de `fieldList` por método de pago](https://docs.velafi.com/es/api-reference/merchant/get-pending-fund-account#fieldlist-keys-by-payment-method).

```bash cURL theme={null}
curl -G https://api.velafi.com/v2/merchant/virtual/addfunds \
  -H "X-BH-TOKEN: YOUR_TOKEN" \
  --data-urlencode "merchantId=100001" \
  --data-urlencode "fiat=MXN" \
  --data-urlencode "paymentId=105" \
  --data-urlencode "depositAlias=CUST0001"
```

Guarda los datos asociados al pagador. Los links de imágenes QR en `fieldList` expiran una hora después de la respuesta, así que obtén uno nuevo cada vez que lo vuelvas a mostrar. Para fondear la cuenta principal del comercio, llama a [`GET /v2/merchant/addfunds`](https://docs.velafi.com/es/api-reference/merchant/get-pending-fund-account).

**3. Muestra al pagador qué debe hacer**

Muestra al pagador los datos de su alias. Lo que hace el pagador depende del riel:

| Riel | Lo que hace el pagador |
| - | - |
| MXN, SPEI (Finco Pay `105`, Tesored `72`) | Envía una transferencia SPEI a la CLABE (`Cuenta CLABE` o `clabeNumber`). |
| ARS, CBU/CVU (Momentum `63`) | Envía una transferencia bancaria al `CVU Number` (o a su `Alias`, cuando existe). |
| COP, ACH automático (`68`) | Abre el `paymentLink` y paga. |
| COP, Bre-B (`69`) | Envía una transferencia Bre-B a la `brebKey`. |
| BRL, Pix (Genial `90`) | Paga a la llave Pix (`Chave Pix - Random Pix`), con el código copia y pega o con el código QR. |
| BRL, Pix - Woovi (Avenia `92`) | Paga el QR Pix estático (`qrCodeLink`, `qrCode`) o la `pixKey`, cuando existe. |

**4. Maneja el webhook de depósito**

Cuando se abona el depósito, VelaFi crea un registro de fondeo de tipo `DEPOSIT` con status `2` y envía un `FUNDING_WEBHOOK`. Verifica el header `signature`, guarda el evento y devuelve HTTP `200` con `{"callbackStatus":"SUCCESS"}`. Abona al pagador identificado por `depositAlias` en tu libro contable. Consulta [Webhooks que debes manejar](#webhooks-to-handle).

**5. Revisa el saldo**

Lee el saldo del comercio con [`GET /v2/merchant/accounts`](https://docs.velafi.com/es/api-reference/merchant/get-a-list-of-merchant-accounts): el `balance` del registro de esa moneda y ese canal. Este es el monto disponible para pagos, transferencias y órdenes de on-ramp.

```bash cURL theme={null}
curl -G https://api.velafi.com/v2/merchant/accounts \
  -H "X-BH-TOKEN: YOUR_TOKEN" \
  --data-urlencode "merchantId=100001" \
  --data-urlencode "fiat=MXN"
```

## Webhooks que debes manejar

Suscríbete a `FUNDING_WEBHOOK`. Un solo webhook recibe los eventos de todos los comercios de tu cuenta. Un evento de depósito se ve así (todos los valores son strings):

```json FUNDING_WEBHOOK (DEPOSIT) theme={null}
{
  "webhookId": "ebab8a9663704e7cbbebe672c7c67912",
  "eventType": "FUNDING_WEBHOOK",
  "txId": "1123123123",
  "merchantId": "100001",
  "fiat": "MXN",
  "totalAmount": "1000",
  "amount": "1000",
  "fee": "0",
  "paymentId": "105",
  "type": "DEPOSIT",
  "status": "2",
  "depositAlias": "CUST0001",
  "payerName": "Example Payer",
  "payerAccount": "000000000000000002",
  "bankWebhookInfo": "{...}",
  "completedTime": "1737452344000",
  "createTime": "1737452292000",
  "updateTime": "1737452344000",
  "timestamp": "1737452344512"
}
```

| Campo | Úsalo para |
| - | - |
| `txId` | Identificar el registro de fondeo. Úsalo como tu clave de idempotencia, junto con `eventType` y `status`. |
| `type` | Enrutar el evento. Los depósitos son `DEPOSIT`. El mismo webhook también transporta `WITHDRAW` y `BUY_CRYPTO`. Las transferencias entre comercios no se envían. |
| `status` | `2` completado, `3` cancelado, `4` reembolsado. Los registros pendientes no se envían. |
| `depositAlias` | Atribuir el depósito a la cuenta virtual del pagador. |
| `amount`, `fee`, `totalAmount` | Registrar el monto neto y la comisión. |
| `payerName`, `payerAccount`, `taxId`, `cardNo` | Registrar quién envió el dinero. Se envían solo cuando el riel los proporciona, así que trátalos como opcionales. |
| `bankWebhookInfo` | Detalles específicos del proveedor como string JSON, por ejemplo, el `tracking_id` de SPEI o el `idCoelsa` de ARS. Consulta [Detalles de Bank Webhook Info](https://docs.velafi.com/es/api-reference/webhooks/funding-records-message-push.md#bank-webhook-info-details). |

La lista completa de campos está en [Evento de fondeo](https://docs.velafi.com/es/api-reference/webhooks/funding-records-message-push.md).

> [!WARNING]
>
> Una entrega cuenta como exitosa solo cuando tu endpoint devuelve un status `2xx` **y** el cuerpo JSON `{"callbackStatus":"SUCCESS"}`. Responde rápido: VelaFi espera como máximo 60 segundos, y un timeout cuenta como entrega fallida. Un `SUCCESS` simple, `{"received":true}`, un cuerpo vacío o tu propio JSON de error cuentan como fallas. Después de tres intentos fallidos el evento ya no se vuelve a enviar, y la Open API no tiene un endpoint de reenvío. Confirma primero y después procesa de forma asíncrona. Consulta [Entrega y reintentos](https://docs.velafi.com/es/api-reference/webhooks/webhook-setup.md#delivery-and-retries).

## Maneja las fallas

* **Eventos duplicados o fuera de orden.** El mismo evento puede llegar más de una vez, y un evento cuyo status cambió antes de la entrega se descarta. Haz que tu handler sea idempotente sobre `eventType` + `txId` + `status`, y lee el registro con [Listar registros de fondeo](https://docs.velafi.com/es/api-reference/merchant/retrieve-funding-records.md) cuando necesites su estado más reciente.
* **Webhooks perdidos.** Si tu endpoint estaba caído o respondió de forma incorrecta, no se reenvía nada. Ejecuta la conciliación de abajo de forma programada para que no se pierda ningún depósito.
* **Depósito sin `depositAlias`.** Los pagos a los datos de la cuenta principal del comercio, o los rieles que no reportan el alias, no tienen una cuenta virtual con la cual relacionarse. Retenlos para revisión manual usando los campos del pagador y `bankWebhookInfo`.
* **Falla la creación de la cuenta virtual.** `status` `3` significa que el canal rechazó la cuenta. `-5079` significa que la cuenta no está habilitada para esa moneda y ese canal, y `-5071` significa que la cuenta de moneda del comercio en ese canal no está activa. Revisa la cuenta del comercio antes de reintentar.
* **Alias de COP rechazado.** Para `68` y `69`, el alias debe tener de 6 a 21 letras mayúsculas o dígitos.

## Concilia

Los registros de fondeo son la fuente de verdad de lo que se abonó al saldo:

* [`GET /v2/merchant/funding/records`](https://docs.velafi.com/es/api-reference/merchant/retrieve-funding-records) con `type=DEPOSIT`, un `fiat` y una ventana `startTime`/`endTime` (la ventana se aplica a la hora de finalización). Compara cada registro con status `2` contra los webhooks que guardaste y procesa los que te hayan faltado. En los depósitos, `webhookInfo` contiene los mismos detalles del proveedor que `bankWebhookInfo`, incluido `depositAlias`.
* [`GET /v2/merchant/fiat/flows`](https://docs.velafi.com/es/api-reference/merchant/get-a-list-merchant-fiat-flow) para el historial del saldo línea por línea: cada línea tiene el cambio (`changed`), el saldo acumulado (`total`) y el `txId` relacionado. Úsalo para comprobar que el saldo en [Listar cuentas de comercio](https://docs.velafi.com/es/api-reference/merchant/get-a-list-of-merchant-accounts.md) es igual a la suma de tus movimientos.

Los registros de fondeo devuelven 100 registros por página de forma predeterminada (hasta 20,000 con `pageSize`), y los flujos fiat hasta 1,000 por página. Recorre las páginas con `currentPage`.

## Prueba en el sandbox

Usa `https://api-test.velafi.com` con credenciales de sandbox. Ahí puedes crear y listar cuentas virtuales, y abonar depósitos de prueba con el [simulador de depósitos fiat](https://docs.velafi.com/es/docs/sandbox.md#sandbox-testing-tools) (`POST /v2/platform/test/deposit`). Envía `depositAlias` para mandar el depósito a una cuenta virtual.

* **Los webhooks no se disparan en el sandbox.** Prueba tu handler enviándole tú mismo payloads de ejemplo, y revisa el resultado de cada depósito simulado con [Listar registros de fondeo](https://docs.velafi.com/es/api-reference/merchant/retrieve-funding-records.md).
* El simulador solo produce depósitos exitosos. No puede producir un depósito fallido o devuelto.

## Lista de verificación para salir a producción

* [ ] El endpoint de `FUNDING_WEBHOOK` verifica la firma y devuelve HTTP `200` con `{"callbackStatus":"SUCCESS"}` rápidamente, muy por debajo del timeout de 60 segundos.
* [ ] El handler es idempotente sobre `eventType` + `txId` + `status` e ignora los eventos que ya procesó.
* [ ] Cada pagador tiene su propia cuenta virtual, y el alias corresponde a un solo cliente en tu sistema.
* [ ] Tu libro contable lleva los saldos por pagador; no esperas que VelaFi mantenga un saldo por cuenta virtual.
* [ ] Los depósitos sin `depositAlias` van a una cola de revisión.
* [ ] Un proceso programado compara los registros de fondeo (`type=DEPOSIT`) con los webhooks guardados y procesa los faltantes.
* [ ] Los códigos QR y los links de pago se obtienen de nuevo antes de mostrarse.

Consulta también la [lista de verificación general para salir a producción](https://docs.velafi.com/es/docs/use-cases/go-live-checklist.md).


## Related topics

- [Casos de uso principales](https://docs.velafi.com/es/docs/use-cases/overview.md)
- [Dispersar moneda local desde el saldo](https://docs.velafi.com/es/docs/use-cases/payouts-from-balance.md)
- [Agent Skills](https://docs.velafi.com/es/docs/developer-tools/agent-skills.md)
- [Dar de alta a tus clientes como comercios](https://docs.velafi.com/es/docs/use-cases/onboard-your-customers.md)
- [Convertir moneda local a stablecoins](https://docs.velafi.com/es/docs/use-cases/convert-to-stablecoins.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.