Descubrimiento de llaves
Encuentra la llave Bre-B de un beneficiario a partir de su identidad y cuenta bancaria antes de enviar dinero.
Usa el descubrimiento de llaves cuando conoces la identidad del beneficiario y su cuenta destino, pero no su llave Bre-B exacta. Mono prueba un conjunto acotado de llaves derivadas de los datos enviados y solo devuelve una llave utilizable cuando confirma la misma persona, banco y cuenta.
Si ya conoces la llave exacta, llama a Resolver llave. Discovery sirve para encontrar una llave desde los datos del beneficiario, no para listar todas las llaves que posee una persona.
Pruebas en sandbox
Usa los sufijos determinísticos de documento 101–104 para probar los resultados exacto,
alternativo, vacío cacheado y no disponible. Consulta descubrimiento de llaves en
sandbox.
Antes de empezar
- Autentícate con OAuth 2.0 client credentials.
- Confirma que Mono haya habilitado el descubrimiento de llaves para tu tenant.
- Usa
target_discoveriesparaPOST /api/v1/targets/discover. - Usa
target_discoveriesotarget_discoveries:readonlypara los GET del catálogo bancario. - Ten el
tenant_account_idque originará la transferencia saliente. Debe pertenecer al tenant autenticado.
Consulta Autenticación de Bre-B Participant para el flujo de tokens.
1. Selecciona el código bancario canónico
Discovery recibe un código ACH colombiano de tres dígitos en
account.bank_code. No derives ese código por tu cuenta desde el nombre del
banco. Primero busca en el catálogo:
GET /api/v1/banks?q=bancolombia&limit=5Un código ACH, nombre canónico o alias exacto produce un match confiable y
ninguna sugerencia:
{
"catalog_version": 1,
"match": {
"ach_code": "007",
"name": "BANCOLOMBIA"
},
"data": []
}Una búsqueda parcial o aproximada produce sugerencias:
GET /api/v1/banks?q=davi&limit=5{
"catalog_version": 1,
"match": null,
"data": [
{ "ach_code": "051", "name": "DAVIVIENDA" },
{ "ach_code": "551", "name": "DAVIPLATA" }
]
}Solo un match no nulo se puede seleccionar automáticamente. Cada elemento de
data es una sugerencia —incluso si solo hay uno—, así que muéstrale las
opciones al pagador y usa el ach_code que seleccione. Una búsqueda sin
resultados también devuelve 200, con match: null y data: [].
También puedes listar el catálogo completo o consultar un código exacto. Ver Listar bancos y Consultar banco.
2. Descubre la llave
Envía los datos que ya conoces del beneficiario. Los nombres, celular y correo son pistas opcionales; la identidad, banco y cuenta son obligatorios.
POST /api/v1/targets/discover
Content-Type: application/json
Authorization: Bearer <access_token>{
"tenant_account_id": "bbtacc_5tgliBmzjZ6mpQPRbQjfKj",
"person": {
"document_type": "CC",
"document_number": "1192793827",
"first_name": "Diego",
"middle_name": null,
"first_surname": "Sánchez",
"second_surname": null,
"phone": "+573104838791",
"email": "diego@example.com"
},
"account": {
"bank_code": "013",
"number": "0013123456789",
"type": "savings_account"
}
}Consulta Descubrir llave para ver todos los campos y enums.
3. Maneja el resultado
Los dos resultados normales devuelven 200. Revisa state; no trates todo
200 como una llave descubierta.
state | Significado |
|---|---|
discovered | target y resolution_id están presentes. La llave coincide con la persona, banco y cuenta solicitados. |
not_discovered | target y resolution_id son null. state_reason es no_exact_target; esto no significa que la persona no tenga otra llave. |
Llave exacta encontrada
{
"state": "discovered",
"state_reason": null,
"attempts_count": 2,
"resolution_id": "bbtgr_5tgliBmzjZ6mpQPRbQjfKj",
"target": {
"id": "bbtgt_5tgliBmzjZ6mpQPRbQjfKj",
"key_type": "identification",
"key_value": "1192793827",
"resolution_type": "plain_key",
"spbvi": "CRB",
"participant_nit": "860003020",
"creditor": {
"type": "natural",
"document_type": "CC",
"document_number": "1192793827",
"full_name": "Diego Sánchez"
},
"creditor_account": {
"type": "savings_account",
"number": "0013123456789",
"currency_code": "COP"
},
"transaction_amount": null,
"payment_id": null
},
"same_person_keys": [
{
"key_type": "alphanumeric",
"key_value": "@BBVA3104838791",
"bank_code": "007",
"participant_nit": "890903938",
"creditor_account": {
"type": "savings_account",
"number_last_four": "4321",
"currency_code": "COP"
},
"resolution_required": true
}
]
}La llave resuelta es fresca y de un solo uso: pasa su target.id a una sola
transferencia saliente. Llamar discovery otra vez crea otra resolución de la
llave en lugar de devolver una guardada en cache.
No se encontró una llave exacta
{
"state": "not_discovered",
"state_reason": "no_exact_target",
"attempts_count": 4,
"resolution_id": null,
"target": null,
"same_person_keys": [
{
"key_type": "email",
"key_value": "diego@example.com",
"bank_code": "007",
"participant_nit": "890903938",
"creditor_account": {
"type": "savings_account",
"number_last_four": "4321",
"currency_code": "COP"
},
"resolution_required": true
}
]
}same_person_keys siempre está presente y puede ser []. Contiene máximo
cinco llaves confirmadas para la misma identidad y nunca datos de otra persona.
No es exhaustivo: las candidatas solo provienen de los datos del request y
discovery se detiene en la primera llave exacta. Por eso una respuesta
discovered solo incluye llaves de la misma persona observadas antes de esa
primera llave exacta.
Un elemento de same_person_keys es una llave alternativa, pero todavía no
puede usarse para transferir. Antes de usarlo:
- Deja que el pagador elija la alternativa.
- Llama a Resolver llave
con su
key_valuepara obtener una llave fresca y utilizable. - Confirma que el
participant_nity la terminación decreditor_account.numberde la llave recién resuelta todavía coincidan con elparticipant_nitynumber_last_fourde la alternativa. - Pide confirmación antes de enviar dinero.
La resolución adicional es obligatoria porque una alternativa no queda reservada y después podría apuntar a otro destino.
Comportamiento del cache
Mono puede cachear por máximo una hora únicamente resultados not_discovered
con same_person_keys vacío. En ese cache hit, attempts_count es 0. Los
resultados que contienen una llave exacta o una alternativa no se sirven desde cache,
por lo que sus datos del directorio e IDs provienen del request actual.
Envía la transferencia saliente
Cuando el pagador confirme al beneficiario resuelto, crea la transferencia
saliente con el target.id de la llave:
{
"tenant_account_id": "bbtacc_5tgliBmzjZ6mpQPRbQjfKj",
"description": "Pago a beneficiario confirmado",
"transfers": [
{
"target_id": "bbtgt_5tgliBmzjZ6mpQPRbQjfKj",
"amount": { "amount": 12000000, "currency": "COP" },
"external_id": "transferencia-confirmada-1"
}
]
}Consulta Crear transferencias
salientes
para el request completo. Cada target.id solo puede financiar una transferencia;
haz otro discovery o resolución para otro pago.
Cuando discovery crea una llave exacta, aplican los webhooks existentes
target_resolution_created
y
target_resolution_resolved.
Los resultados not_discovered y las alternativas no emiten webhooks de
resolución. Los consumidores deben deduplicar esos webhooks por resolution_id;
la entrega es asíncrona, por lo que un evento target_resolution_created puede
traer state=resolved y el orden no está garantizado. Trata el state y
updated_at más recientes como autoridad.
Errores y reintentos
| Estado | Cuándo ocurre | Qué hacer |
|---|---|---|
400 | El documento o número de cuenta no se puede comparar de forma segura. | Corrige los datos; no reintentes sin cambios. |
401 | Falta el token, es inválido o expiró. | Obtén un token válido y reintenta. |
403 | La credencial no tiene el scope requerido o discovery no está habilitado para el tenant. | Solicita el scope o contacta a Mono para habilitar el descubrimiento de llaves. |
404 | La cuenta tenant no existe o no pertenece al tenant. | Verifica tenant_account_id. Un lookup de banco exacto desconocido también devuelve bank_not_found. |
422 | El payload es inválido o bank_code no es aceptado (unknown_bank). | Corrige el request o selecciona un banco del catálogo público. |
429 | Se superó el límite de discovery por cliente o tenant (rate_limit_exceeded). | Espera el intervalo Retry-After antes de reintentar. |
503 | El directorio Bre-B no está disponible temporalmente. | Reintenta después de Retry-After, cuando esté presente, con backoff acotado. |
500 | Ocurrió un error inesperado del servidor. | Reintenta de forma segura; contacta a soporte con el id de la respuesta si persiste. |
Una búsqueda válida sin llave exacta no es un error HTTP: devuelve 200 con
state=not_discovered.
Referencia relacionada
Siguientes pasos
- Descubrimiento de llaves en sandbox — prueba los escenarios determinísticos
101–104antes de salir a producción. - Flujo de transferencia saliente — paga la llave que acabas de descubrir.
- Autenticación de Bre-B Participant — los scopes y el flujo de tokens que requiere discovery.