> ## 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.

# Dispersar moneda local desde el saldo

> Envía pagos en moneda local desde el saldo fiat de un comercio a un beneficiario guardado, dales seguimiento con FUNDING_WEBHOOK y mueve saldo entre tus comercios.

Usa este flujo para dispersar moneda local (MXN, ARS, COP, BRL, PEN) desde el saldo fiat de un comercio, también llamado saldo Pending Fund, a una cuenta bancaria o llave Pix que guardaste como beneficiario. Llamas a `POST /v2/merchant/claimfunds`, VelaFi descuenta el saldo y envía el pago por el riel local, y un `FUNDING_WEBHOOK` te dice si se completó. El mismo saldo también se puede mover a otro de tus comercios con `POST /v2/merchant/transfer`.

El saldo normalmente proviene de depósitos. Consulta [Cobrar pagos locales con cuentas virtuales](https://docs.velafi.com/es/docs/use-cases/collect-with-virtual-accounts.md).

## Cómo funciona

```mermaid theme={null}
sequenceDiagram
    participant You as Tu plataforma
    participant V as VelaFi
    participant B as Banco del beneficiario
    You->>V: POST /v2/payments (guardar beneficiario)
    V-->>You: id (userPaymentId)
    You->>V: POST /v2/merchant/claimfunds (clientId, amount, userPaymentId)
    V->>V: Descuenta amount + comisión del saldo
    V-->>You: txId, fee, totalAmount
    V->>B: Pago local (SPEI, CVU, Pix, Bre-B...)
    V->>You: FUNDING_WEBHOOK (type WITHDRAW, status 2 o 3)
    You-->>V: HTTP 200 {"callbackStatus":"SUCCESS"}
```

## 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 con una cuenta de moneda activa** en un canal que admita pagos (consulta abajo). Consulta [Activar la cuenta de un comercio](https://docs.velafi.com/es/docs/guides/activating-merchant-account.md).
* **Saldo en esa cuenta de moneda**, proveniente de depósitos en el mismo canal. Consulta [Cobrar pagos locales con cuentas virtuales](https://docs.velafi.com/es/docs/use-cases/collect-with-virtual-accounts.md).
* **Un endpoint de `FUNDING_WEBHOOK`** registrado y que devuelva la confirmación requerida. Consulta [Configuración de webhooks](https://docs.velafi.com/es/api-reference/webhooks/webhook-setup.md).

### Canales que admiten pagos desde el saldo

| Moneda | Canal | `paymentId` del beneficiario |
| - | - | - |
| MXN | SPEI (Finco Pay) | `105` |
| MXN | SPEI (Tesored) | `72` |
| ARS | CBU/CVU (Momentum) | `63` |
| COP | Cuenta COP (Cobre) | `68`, `69` |
| BRL | Pix (Genial) | `90` |
| BRL | Pix - Woovi (Avenia) | `92` |
| PEN | Transferencia bancaria | `95` (pago mínimo de 10 PEN) |

Tres reglas aplican a cada pago:

1. **Mismo canal.** El pago sale por el canal de la cuenta de moneda que tiene el saldo. Solo el saldo que entró por ese canal (o por VelaFi Pending Fund) se puede pagar por él.
2. **Misma cuenta de moneda del comercio.** El beneficiario debe estar guardado bajo el mismo comercio, para la misma moneda y el mismo canal que esa cuenta. Un beneficiario guardado bajo otro comercio, o para otro canal (por ejemplo, un beneficiario de Tesored contra un saldo de Finco Pay), se rechaza.
3. **Monto más comisión.** El saldo debe cubrir `amount` más la comisión del pago.

## Paso a paso

**1. Guarda el beneficiario**

Obtén la plantilla de campos del canal con [`GET /v2/payments/templates`](https://docs.velafi.com/es/api-reference/beneficiary/get-payment-templates) y después guarda el destino con [`POST /v2/payments`](https://docs.velafi.com/es/api-reference/beneficiary/add-beneficiary) bajo el comercio que tiene el saldo. Consulta [Administrar beneficiarios](https://docs.velafi.com/es/docs/guides/managing-beneficiaries.md) para ver las plantillas por canal.

```bash cURL theme={null}
curl -X POST https://api.velafi.com/v2/payments \
  -H "X-BH-TOKEN: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "merchantId": 100001,
    "paymentId": 105,
    "country": "Mexico",
    "fiat": "MXN",
    "fieldJson": {
      "Account Type": "clabe",
      "Account Number": "000000000000000001",
      "Beneficiary Name": "Example Beneficiary",
      "Bank Code": ""
    }
  }'
```

Guarda el `id` devuelto: es el `userPaymentId` para los pagos. Paga solo a beneficiarios con `status` `1` (válido). Si el número de cuenta ya está guardado, la respuesta tiene `status` `3` y `sameAccountNumberId`; usa ese ID en lugar de crear un registro nuevo.

**2. Revisa el saldo**

Lee `balance` con [`GET /v2/merchant/accounts`](https://docs.velafi.com/es/api-reference/merchant/get-a-list-of-merchant-accounts) para el comercio, la moneda y el canal. Deja margen para la comisión.

**3. Crea el pago**

Llama a [`POST /v2/merchant/claimfunds`](https://docs.velafi.com/es/api-reference/merchant/claim-pending-fund). Siempre envía tu propio `clientId` único.

```bash cURL theme={null}
curl -X POST https://api.velafi.com/v2/merchant/claimfunds \
  -H "X-BH-TOKEN: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "merchantId": 100001,
    "clientId": "payout-0001",
    "fiat": "MXN",
    "amount": 1000,
    "userPaymentId": 456
  }'
```

```json Response theme={null}
{
  "code": 200,
  "msg": "SUCCESS",
  "data": {
    "txId": 1123123123,
    "merchantId": 100001,
    "clientId": "payout-0001",
    "fiat": "MXN",
    "totalAmount": 1010,
    "amount": 1000,
    "fee": 10,
    "userPaymentId": 456,
    "createTime": "1737452292000"
  }
}
```

`amount` es lo que recibe el beneficiario. `fee` es la comisión de pago configurada para el canal y tu cuenta, y `totalAmount` (`amount` + `fee`) se descuenta del saldo cuando la llamada es exitosa. Los montos se redondean hacia abajo a la precisión de la moneda. Una respuesta `200` significa que el pago fue aceptado, no que ya llegó: está pendiente hasta que el webhook o el registro de fondeo indiquen lo contrario.

**4. Espera el resultado**

Maneja el `FUNDING_WEBHOOK` con `type` `WITHDRAW` para este `txId` (consulta [Webhooks que debes manejar](#webhooks-to-handle)). Si no recibes ninguno, lee el registro con [`GET /v2/merchant/funding/records`](https://docs.velafi.com/es/api-reference/merchant/retrieve-funding-records) usando `txId` o `clientId`.

## Estados del pago

| Estado | Significado | Saldo |
| - | - | - |
| `1` pendiente | Aceptado y en proceso de envío. Un registro recién creado puede mostrar `0` brevemente; filtrar por `status=1` devuelve ambos. | `totalAmount` queda retenido (ya descontado). |
| `2` completado | El canal reportó el pago como pagado. | Permanece descontado. |
| `3` cancelado | El pago falló o fue rechazado antes de completarse. | `totalAmount`, comisión incluida, se abona de vuelta. Aparece una línea `WITHDRAW_ROLLBACK` en los flujos fiat. |
| `4` reembolsado | Un pago completado fue devuelto a VelaFi y revertido. | `totalAmount` se abona de vuelta con una línea `WITHDRAW_ROLLBACK`. |

`FUNDING_WEBHOOK` se envía para `2`, `3` y `4`, no para pendiente.

## Webhooks que debes manejar

El evento del pago es un `FUNDING_WEBHOOK` con `type` `WITHDRAW`. `totalAmount` es negativo para los retiros.

```json FUNDING_WEBHOOK (WITHDRAW, canceled) theme={null}
{
  "eventType": "FUNDING_WEBHOOK",
  "txId": "1123123123",
  "clientId": "payout-0001",
  "merchantId": "100001",
  "fiat": "MXN",
  "totalAmount": "-1010",
  "amount": "1000",
  "fee": "10",
  "userPaymentId": "456",
  "type": "WITHDRAW",
  "status": "3",
  "failCode": "...",
  "failReason": "...",
  "bankOrderId": "...",
  "createTime": "1737452292000",
  "updateTime": "1737452350000",
  "timestamp": "1737452350512"
}
```

* Relaciona el evento con tu pago por `clientId` o `txId`.
* Haz que el handler sea idempotente sobre `eventType` + `txId` + `status`. El mismo evento puede llegar más de una vez, y un pago puede pasar de `2` a `4` más tarde, así que maneja un reembolso después de una finalización.
* `failCode` y `failReason` se envían solo para pagos cancelados que tienen un motivo registrado. Muchas fallas llegan sin motivo; no dependas de ellos para decidir qué hacer.
* `bankOrderId` es la referencia de la transferencia en el proveedor de pagos, cuando está disponible. Guárdala para las solicitudes de soporte.
* Devuelve HTTP `200` con `{"callbackStatus":"SUCCESS"}` rápidamente. VelaFi espera como máximo 60 segundos; un timeout o cualquier otra respuesta cuenta como entrega fallida. Consulta [Entrega y reintentos](https://docs.velafi.com/es/api-reference/webhooks/webhook-setup.md#delivery-and-retries).

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

## Maneja las fallas

### Errores al crear el pago

Si `claimfunds` devuelve un error, no se creó ningún registro de fondeo y no se descontó nada. Códigos comunes (consulta [Códigos de error](https://docs.velafi.com/es/docs/error-codes.md)):

| Código | Causa | Qué hacer |
| - | - | - |
| `-1131` | No hay suficiente saldo de este canal para cubrir `amount` + `fee`. | Espera depósitos o reduce el monto. |
| `-1174` | El `clientId` ya lo usa un registro de fondeo de tu cuenta. | El pago ya existe: búscalo por `clientId`. No crees otro con el mismo ID. |
| `-4027` | `userPaymentId` no existe o pertenece a otra cuenta. | Revisa el ID del beneficiario. |
| `-5017` | El beneficiario no es válido (no tiene status `1`). | Usa un beneficiario válido o guárdalo de nuevo. |
| `-4001` | La solicitud no pasó la validación; por ejemplo, la cuenta de moneda del comercio en ese canal no admite pagos o no está activa. | Revisa el canal contra la tabla de arriba y el estado de la cuenta. |
| `-1181` | Los pagos están deshabilitados para este comercio. | Contacta al soporte de VelaFi. |
| `-5051` | La moneda del beneficiario es distinta de `fiat`. | Usa un beneficiario de la misma moneda. |
| `-5070` | El beneficiario no pertenece a la cuenta de moneda de este comercio en ese canal. | Guarda el beneficiario bajo el mismo comercio y el mismo canal que el saldo. |
| `-5030` | El pago excede el límite de retiro de la cuenta. | Contacta a VelaFi para revisar el límite. |
| `-5050` | El monto está por debajo del mínimo (para PEN, 10). | Aumenta el monto. |
| `-1146` | Se estaba procesando otro pago o transferencia para el mismo comercio y la misma moneda. | Reintenta después de una breve espera, con el mismo `clientId`. |

### Timeouts y reintentos

La validación de `clientId` hace que los reintentos sean seguros siempre que reutilices el mismo `clientId`:

1. Si la llamada excede el tiempo de espera o devuelve un error de red, no crees un nuevo `clientId`. Busca el pago con `GET /v2/merchant/funding/records?clientId=...`.
2. Si existe un registro, el pago se creó: sigue su estado.
3. Si no existe ninguno, envía la misma solicitud otra vez con el mismo `clientId`. Si la primera solicitud sí se procesó, recibes `-1174` en lugar de un segundo pago.

Un `clientId` duplicado devuelve el error `-1174`, no el pago original. Lee el original en los registros de fondeo.

### Pagos fallidos

Cuando un pago termina en status `3`, el `totalAmount` completo regresa al saldo. Un `clientId` no se puede reutilizar, ni siquiera para un pago fallido, así que para volver a intentarlo:

1. Revisa los datos del beneficiario (número de cuenta, tipo de llave, nombre del titular) y corrige o vuelve a guardar el beneficiario si es necesario.
2. Crea un nuevo pago con un `clientId` **nuevo**, por ejemplo `payout-0001-r1`, y vincúlalo al original en tu sistema.

No reintentes automáticamente en un ciclo. Si el mismo beneficiario falla repetidamente sin un `failReason`, contacta al soporte de VelaFi con el `txId` y el `bankOrderId`.

## Mueve saldo entre comercios

Para mover saldo de uno de tus comercios a otro sin una transferencia bancaria, usa [`POST /v2/merchant/transfer`](https://docs.velafi.com/es/api-reference/merchant/transfer-pending-funds). Ambos comercios deben pertenecer a tu cuenta y tener una cuenta de moneda activa para el mismo `fiat` y `paymentId`, en un canal que admita pagos.

**1. Revisa la comisión**

Llama a [`GET /v2/merchant/transfer_fee`](https://docs.velafi.com/es/api-reference/merchant/get-transfer-pending-funds-fee) con `fiat`. `feeType` `0` es un monto fijo y `1` es una fracción del monto (`0.01` = 1%). La `fee` que devuelve la transferencia en sí es el monto que realmente se cobra.

**2. Crea la transferencia**

```bash cURL theme={null}
curl -X POST https://api.velafi.com/v2/merchant/transfer \
  -H "X-BH-TOKEN: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "transfer-0001",
    "fromMerchantId": 100001,
    "toMerchantId": 100002,
    "fiat": "MXN",
    "paymentId": 105,
    "fiatAmount": 1000
  }'
```

El remitente debe tener disponible `fiatAmount` + comisión de ese canal. La transferencia se completa en la misma llamada: la respuesta devuelve `fromId` (el registro `TRANSFER_OUT` del remitente) y `toId` (el registro `TRANSFER_IN` del destinatario), ambos con status `2`. El destinatario recibe `fiatAmount`, y al remitente se le descuenta `totalFiatAmount`.

Las transferencias siguen la misma regla de `clientId` que los pagos: un `clientId` que ya usa cualquier registro de fondeo de tu cuenta devuelve `-1174`. Envía siempre uno, para que puedas buscar la transferencia después de un timeout. En los registros de fondeo, el registro `TRANSFER_OUT` lleva tu `clientId`; el registro `TRANSFER_IN` lleva `TRANSFER_IN_` seguido de tu `clientId`. Busca ambos por `txId` (`fromId`, `toId`).

## Concilia

* [`GET /v2/merchant/funding/records`](https://docs.velafi.com/es/api-reference/merchant/retrieve-funding-records) es la fuente de verdad de cada pago y transferencia. Filtra por `type=WITHDRAW` (o `TRANSFER_OUT`, `TRANSFER_IN`), `fiat` y una ventana de tiempo, y verifica que cada pago que creaste tenga un estado final (`2`, `3` o `4`). Investiga los que sigan pendientes.
* [`GET /v2/merchant/fiat/flows`](https://docs.velafi.com/es/api-reference/merchant/get-a-list-merchant-fiat-flow) muestra cada movimiento del saldo: `WITHDRAW` cuando se crea el pago, `WITHDRAW_ROLLBACK` cuando un pago cancelado o reembolsado se abona de vuelta, y `TRANSFER_OUT` / `TRANSFER_IN` para las transferencias. El `total` de cada línea es el saldo acumulado después de ese movimiento.

## Prueba en el sandbox

Usa `https://api-test.velafi.com` con credenciales de sandbox. Fondea un comercio de prueba con el [simulador de depósitos fiat](https://docs.velafi.com/es/docs/sandbox.md#sandbox-testing-tools), guarda un beneficiario y después llama a `claimfunds` y `transfer` contra ese saldo. Úsalo para probar la validación de tus solicitudes, los códigos de error de arriba y tu lógica de reintentos con `clientId`.

* **Los webhooks no se disparan en el sandbox.** Da seguimiento a cada pago con [Listar registros de fondeo](https://docs.velafi.com/es/api-reference/merchant/retrieve-funding-records.md), y prueba tu handler de webhooks con payloads de ejemplo, incluidos retiros cancelados (`3`) y reembolsados (`4`).
* Los simuladores no pueden producir un depósito fallido o devuelto.

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

* [ ] Cada pago y cada transferencia envía un `clientId` único que guardas antes de hacer la llamada.
* [ ] Ante un timeout, buscas el `clientId` antes de reintentar y reenvías con el mismo `clientId`.
* [ ] Un pago fallido se reintenta solo con un `clientId` nuevo, después de revisar los datos del beneficiario.
* [ ] Los beneficiarios se guardan bajo el mismo comercio y el mismo canal que el saldo, y solo se usan beneficiarios con `status` `1`.
* [ ] La revisión del saldo incluye la comisión.
* [ ] El handler de `FUNDING_WEBHOOK` maneja `WITHDRAW` con status `2`, `3` y `4`, y funciona cuando falta `failReason`.
* [ ] Un proceso programado marca los pagos que siguen pendientes después de tu tiempo de liquidación esperado.

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 fondeada con stablecoins](https://docs.velafi.com/es/docs/use-cases/payouts-funded-by-stablecoins.md)
- [Convertir moneda local a stablecoins](https://docs.velafi.com/es/docs/use-cases/convert-to-stablecoins.md)
- [Cobrar pagos locales con cuentas virtuales](https://docs.velafi.com/es/docs/use-cases/collect-with-virtual-accounts.md)
- [Agent Skills](https://docs.velafi.com/es/docs/developer-tools/agent-skills.md)


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