# 1. Resolver llave
RECIPIENT=$(curl -s -X POST https://consola.mouvlatam.com/api/transfers/resolve-key \
-H "Authorization: Bearer mvk_..." \
-H "Content-Type: application/json" \
-d '{ "keyValue": "3115551234" }')
# 2. Cotizar
QUOTE=$(curl -s -X POST https://consola.mouvlatam.com/api/transfers/quote \
-H "Authorization: Bearer mvk_..." \
-H "Content-Type: application/json" \
-d '{ "amount": 100000, "keyValue": "3115551234" }')
# 3. Enviar
curl -X POST https://consola.mouvlatam.com/api/transfers/send \
-H "Authorization: Bearer mvk_..." \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg name "$(echo $RECIPIENT | jq -r .recipient.fullName)" \
--arg doc "$(echo $RECIPIENT | jq -r .recipient.idValue)" \
--arg keyType "$(echo $RECIPIENT | jq -r .keyType)" \
'{
amount: 100000,
destination: { brebKey: { type: $keyType, value: "3115551234" } },
targetName: $name,
targetDocument: $doc,
reference: "factura-001"
}')"
// Flujo end-to-end BREB
async function sendBreb(keyValue, amount, reference) {
const headers = {
'Authorization': `Bearer ${process.env.MOUV_API_KEY}`,
'Content-Type': 'application/json',
};
// 1. Resolver
const resolve = await fetch('https://consola.mouvlatam.com/api/transfers/resolve-key', {
method: 'POST', headers, body: JSON.stringify({ keyValue }),
}).then(r => r.json());
if (!resolve.found) throw new Error('Llave no encontrada');
// 2. Cotizar
const quote = await fetch('https://consola.mouvlatam.com/api/transfers/quote', {
method: 'POST', headers, body: JSON.stringify({ amount, keyValue }),
}).then(r => r.json());
if (!quote.canAfford) throw new Error(`Saldo insuficiente: ${quote.message}`);
// 3. Enviar
const send = await fetch('https://consola.mouvlatam.com/api/transfers/send', {
method: 'POST', headers, body: JSON.stringify({
amount,
destination: { brebKey: { type: resolve.keyType, value: keyValue } },
targetName: resolve.recipient.fullName,
targetDocument: resolve.recipient.idValue,
reference,
}),
}).then(r => r.json());
return send;
}
{
"id": "8e39f393-...-uuid",
"status": "PENDING",
"amount": 100000,
"totalFee": 1100,
"ivaAmount": 209,
"netAmount": 98900,
"currency": "COP",
"rail": "BREB",
"targetName": "JUAN PEREZ",
"targetDocument": "1018485810",
"reference": "factura-001",
"createdAt": "2026-05-25T20:00:00.000Z"
}
{
"id": "8e39f393-...",
"status": "AWAITING_APPROVAL",
"approvalId": "appr_...",
"threshold": 2,
"expiresAt": "2026-05-26T20:00:00.000Z",
"amount": 100000,
"rail": "BREB"
}
Retiros (Outflows)
POST /transfers/send
Ejecutar retiro BREB o ACH
POST
/
api
/
transfers
/
send
# 1. Resolver llave
RECIPIENT=$(curl -s -X POST https://consola.mouvlatam.com/api/transfers/resolve-key \
-H "Authorization: Bearer mvk_..." \
-H "Content-Type: application/json" \
-d '{ "keyValue": "3115551234" }')
# 2. Cotizar
QUOTE=$(curl -s -X POST https://consola.mouvlatam.com/api/transfers/quote \
-H "Authorization: Bearer mvk_..." \
-H "Content-Type: application/json" \
-d '{ "amount": 100000, "keyValue": "3115551234" }')
# 3. Enviar
curl -X POST https://consola.mouvlatam.com/api/transfers/send \
-H "Authorization: Bearer mvk_..." \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg name "$(echo $RECIPIENT | jq -r .recipient.fullName)" \
--arg doc "$(echo $RECIPIENT | jq -r .recipient.idValue)" \
--arg keyType "$(echo $RECIPIENT | jq -r .keyType)" \
'{
amount: 100000,
destination: { brebKey: { type: $keyType, value: "3115551234" } },
targetName: $name,
targetDocument: $doc,
reference: "factura-001"
}')"
// Flujo end-to-end BREB
async function sendBreb(keyValue, amount, reference) {
const headers = {
'Authorization': `Bearer ${process.env.MOUV_API_KEY}`,
'Content-Type': 'application/json',
};
// 1. Resolver
const resolve = await fetch('https://consola.mouvlatam.com/api/transfers/resolve-key', {
method: 'POST', headers, body: JSON.stringify({ keyValue }),
}).then(r => r.json());
if (!resolve.found) throw new Error('Llave no encontrada');
// 2. Cotizar
const quote = await fetch('https://consola.mouvlatam.com/api/transfers/quote', {
method: 'POST', headers, body: JSON.stringify({ amount, keyValue }),
}).then(r => r.json());
if (!quote.canAfford) throw new Error(`Saldo insuficiente: ${quote.message}`);
// 3. Enviar
const send = await fetch('https://consola.mouvlatam.com/api/transfers/send', {
method: 'POST', headers, body: JSON.stringify({
amount,
destination: { brebKey: { type: resolve.keyType, value: keyValue } },
targetName: resolve.recipient.fullName,
targetDocument: resolve.recipient.idValue,
reference,
}),
}).then(r => r.json());
return send;
}
{
"id": "8e39f393-...-uuid",
"status": "PENDING",
"amount": 100000,
"totalFee": 1100,
"ivaAmount": 209,
"netAmount": 98900,
"currency": "COP",
"rail": "BREB",
"targetName": "JUAN PEREZ",
"targetDocument": "1018485810",
"reference": "factura-001",
"createdAt": "2026-05-25T20:00:00.000Z"
}
{
"id": "8e39f393-...",
"status": "AWAITING_APPROVAL",
"approvalId": "appr_...",
"threshold": 2,
"expiresAt": "2026-05-26T20:00:00.000Z",
"amount": 100000,
"rail": "BREB"
}
Ejecuta un retiro. Un único endpoint maneja ambos rails (BREB + ACH) — el sistema discrimina por la forma del campo
Pollea el estado vía
destination:
destination.brebKey→ BREB (debita wallet BREB, dispatcha a red Bre-B)destination.bankAccount→ ACH (debita wallet ACH, dispatcha a banco destino)
WRITE
Body común
Body BREB
Número de documento del titular. Sacalo de
/transfers/resolve-key → recipient.idValue. SARLAFT obligatorio.Body ACH
ID del banco. Consultalo en
GET /dictionaries/banks/ach.Response 201
Ejemplos
Retiro BREB
# 1. Resolver llave
RECIPIENT=$(curl -s -X POST https://consola.mouvlatam.com/api/transfers/resolve-key \
-H "Authorization: Bearer mvk_..." \
-H "Content-Type: application/json" \
-d '{ "keyValue": "3115551234" }')
# 2. Cotizar
QUOTE=$(curl -s -X POST https://consola.mouvlatam.com/api/transfers/quote \
-H "Authorization: Bearer mvk_..." \
-H "Content-Type: application/json" \
-d '{ "amount": 100000, "keyValue": "3115551234" }')
# 3. Enviar
curl -X POST https://consola.mouvlatam.com/api/transfers/send \
-H "Authorization: Bearer mvk_..." \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg name "$(echo $RECIPIENT | jq -r .recipient.fullName)" \
--arg doc "$(echo $RECIPIENT | jq -r .recipient.idValue)" \
--arg keyType "$(echo $RECIPIENT | jq -r .keyType)" \
'{
amount: 100000,
destination: { brebKey: { type: $keyType, value: "3115551234" } },
targetName: $name,
targetDocument: $doc,
reference: "factura-001"
}')"
// Flujo end-to-end BREB
async function sendBreb(keyValue, amount, reference) {
const headers = {
'Authorization': `Bearer ${process.env.MOUV_API_KEY}`,
'Content-Type': 'application/json',
};
// 1. Resolver
const resolve = await fetch('https://consola.mouvlatam.com/api/transfers/resolve-key', {
method: 'POST', headers, body: JSON.stringify({ keyValue }),
}).then(r => r.json());
if (!resolve.found) throw new Error('Llave no encontrada');
// 2. Cotizar
const quote = await fetch('https://consola.mouvlatam.com/api/transfers/quote', {
method: 'POST', headers, body: JSON.stringify({ amount, keyValue }),
}).then(r => r.json());
if (!quote.canAfford) throw new Error(`Saldo insuficiente: ${quote.message}`);
// 3. Enviar
const send = await fetch('https://consola.mouvlatam.com/api/transfers/send', {
method: 'POST', headers, body: JSON.stringify({
amount,
destination: { brebKey: { type: resolve.keyType, value: keyValue } },
targetName: resolve.recipient.fullName,
targetDocument: resolve.recipient.idValue,
reference,
}),
}).then(r => r.json());
return send;
}
Retiro ACH
curl -X POST https://consola.mouvlatam.com/api/transfers/send \
-H "Authorization: Bearer mvk_..." \
-H "Content-Type: application/json" \
-d '{
"amount": 5000000,
"destination": {
"bankAccount": {
"bankId": 27,
"accountTypeId": 20,
"accountNumber": "59455583201",
"documentTypeId": 1,
"documentNumber": "1018485810",
"holderFirstName": "Juan",
"holderLastName": "Pérez"
}
},
"reference": "nomina-mayo-2026"
}'
{
"id": "8e39f393-...-uuid",
"status": "PENDING",
"amount": 100000,
"totalFee": 1100,
"ivaAmount": 209,
"netAmount": 98900,
"currency": "COP",
"rail": "BREB",
"targetName": "JUAN PEREZ",
"targetDocument": "1018485810",
"reference": "factura-001",
"createdAt": "2026-05-25T20:00:00.000Z"
}
{
"id": "8e39f393-...",
"status": "AWAITING_APPROVAL",
"approvalId": "appr_...",
"threshold": 2,
"expiresAt": "2026-05-26T20:00:00.000Z",
"amount": 100000,
"rail": "BREB"
}
Status lifecycle
| Status | Significado |
|---|---|
PENDING | Reservado en wallet, esperando confirmación del rail |
AWAITING_APPROVAL | Multi-sig activo (threshold≥2), espera firmas |
EXECUTING | En ejecución (multi-sig quorum alcanzado) |
COMPLETED | Confirmado, irreversible |
FAILED | Falló, fondos devueltos al wallet |
EXPIRED | TTL 24h agotado sin quorum (multi-sig) |
GET /wallets/transactions/:id o esperá webhooks salientes (próximamente).
Idempotencia
El camporeference actúa como idempotency key dentro de 60s. Reenviá la misma request con el mismo reference para safely retry tras 5xx.
Defensa SARLAFT
targetDocumentes obligatorio para BREB (no se persiste null en la transacción)- Mouv valida el documento del cliente contra blacklist AML antes de dispatchar
- Counterparty limits (tope diario/mensual por tercero) se verifican antes del send
- Transactions quedan persistidas con
apiKeyIdpara audit trail