Cómo hacer una transferencia a una llave
En esta guía, aprenderás cómo iniciar una intent de dispersión a través de Bre-B usando Kamin Ledger. Una vez configurado tu entorno, el proceso consta de dos pasos simples, la resolución de la llave y la creación de la intent. Es importante tener en cuenta que las transacciones en Bre-B son de cuenta a cuenta, las llaves son un alias de facil recordación las cuales tienen asociadas una cuenta bancaria y la información de la identidad del dueño de la llave
Requisitos previos
Antes de comenzar:
- Has resuleto una llave de Bre-B, la llave puede ser tipo:
Documento de identidadNúmero de celularCorre electrónicoAlfanúmerica
- Puedes usar alguan de estas llaves de prueba
- Tienes un par de llaves válidas para firmar las transacciones.
- Has leído la guía de Primeros pasos y tienes configurados tu Wallet, Dominio y Autenticación.
Flujo
Objetivo
Envía fondos a un destinatario usando Bre-B mediante la resolución de la llave.
Paso 1: Obtener la dirección de destino
Para resolver una llave en Bre-B debes usar el flujo de Resolución de Llaves. Esta resolucíon devolver la informacion del destinatario, la cual contiene tanto la informacion de la cuenta, como la información de la identidad del dueño de la llave, por ejemplo:
Tenemos la llave @kaminTestKey
GET <baseURL>/v2/anchors/{@kaminTestKey};Respuesta:
{
"data": {
"handle": "wcDHYmSJP8uJF5dVGXBEKNA3e5hBm1eQEn",
"wallet": "breb",
"target": "signer:wcDHYmSJP8uJF5dVGXBEKNA3e5hBm1eQEn@breb",
"schema": "breb",
"custom": {
"bankId": "901830825",
"status": "ACTIVE",
"firstName": "Alphanum",
"lastName": "Key",
"keyType": "ALPHANUM",
"keyValue": "@kaminTestKey",
"idType": "CC",
"idValue": "1088432333",
"bankAccountType": "SVGS",
"bankAccountNumber": "000202020"
},
"access": [
{...}
]
},
"hash": "52bf5317248ca9d59d71c7d023803be40a9ae4168c8c3cf979423187f21ec548",
"meta": {
"proofs": [...]
}
}De la respuesta se obtiene todo lo necesario para validar los datos del destinatario y para generar la transfrencia de fondos, en este caso, el campo data.target contiene la información de la cuenta destino,
la cual debe ser usada en el campo target del Intent. Por otro lado toda la data del usuario esta contenida en el objeto data.custom y puede ser usada para validar los datos del destinatario.
Es importante no hacer ningun tipo de validacion sobre este campo
data.target ya que puede cambiar en el futuro.
Una vez obtenido el destino, se puede proceder a crear el intent de dispersión.
Paso 2: Crear el intent de dispersión
Puedes usar el SDK del ledger, la CLI o código para enviar una intent de transferencia de dinero. El ejemplo proporcionado primero resuelve el destino usando Get Anchor, luego procede a crear la intent SEND.
El origen es de donde se debitarán los fondos, en este caso, tu billetera, y el destino es la cuenta del usuario en registrado en Bre-B.
Definición de campos
| Nombre | Tipo | Descripción |
|---|---|---|
| handle* | String (64) | Identificador unico del intent, usado para garantizar idempotencia |
| source.handle* | String (64) | Billetera origen de la transferencia. En una intent SEND, el origen es tu billetera |
| target.handle* | String (64) | Billetera destino. En una intent SEND, el destino es el el data.target obtenido en la resolución de la llave |
| amount* | integer | Monto de la transferencia |
| symbol.handle* | String (16) | Moneda. Por defecto bcop |
| custom.received* | String (255) | String de una fecha en formato ISO 8601 que representa el instante en que se genero la solicitud |
Ejemplo de solicitud
Hashea, firma y envía al endpoint Create Intent. Consulta Hashing y firmado de solicitudes para detalles.
POST https://<ledger-url>/api/v2/intentsAccept: application/json, text/plain, */*
Content-Type: application/json
x-ledger: <ledger-handle>{
"data": {
"handle": "<unique-intent-id>",
"claims": [
{
"action": "transfer",
"source": { "handle": "<source-wallet-handle>" },
"target": { "handle": "<target-breb-key-handle>" },
"symbol": { "handle": "bcop" },
"amount": <amount-in-cents>
}
],
"schema": "transfer",
"access": [
{ "action": "any", "signer": { "public": "<public-key>" } }
],
"custom": {
"received": "<iso-8601-timestamp>"
}
},
"hash": "<sha256-hash-of-data>",
"meta": {
"proofs": [
{
"method": "ed25519-v2",
"public": "<public-key>",
"digest": "<digest-del-proof>",
"result": "<signature-of-digest>",
"custom": { "moment": "<iso-8601-timestamp>" }
}
]
}
}Todas las solicitudes de mutación (como POST) deben ser firmadas con tu llave privada.
El monto enviado fue COP 1000 debido al factor de 100 que tiene el símbolo bcop
Cuerpo de la respuesta:
{
"hash": "559a7324f3f5f01a9ce23e1f1e8a6f06c68ccd4c510ecc3a025deafee781d85c",
"data": {
"handle": "cvS7ioG5k9U65GosbwDsy",
"claims": [
{
"action": "transfer",
"amount": 100000,
"source": {
"handle": "kamin.one"
},
"symbol": {
"handle": "bcop"
},
"target": {
"handle": "signer:wbX9V3UnXie7zz6wSpKkZHUrdjA31rowcp@brebe"
}
}
],
"schema": "transfer",
"custom": {
"received": "2025-10-10T11:59:22.241-05:00"
},
"access": [
{
"action": "any",
"signer": {
"public": "Oh3xliLHnYelAZbQyTEZv5jo3JNrsBiea+/6X6AxUK0="
}
}
]
},
"luid": "$int.-0XJXjBbpzYN67lwM",
"meta": {
"proofs": [
{
"custom": {
"moment": "2025-06-17T19:09:33.299Z",
"status": "created"
},
"digest": "804c90a2b9c053976040791c7efdd7ee0b59fe1463091db68c99aa67e4912227",
"method": "ed25519-v2",
"public": "Oh3xliLHnYelAZbQyTEZv5jo3JNrsBiea+/6X6AxUK0=",
"result": "d5KZ647Gqkv85H6pqe132Hy2jprDKIWEhCjgrJTXr393Ku9OxI8yrmzfzO8YstiF5JrJOUNCXiZGQ1DDy8YMDA=="
},
{
"custom": {
"moment": "2025-06-17T19:09:33.878Z",
"status": "pending"
},
"digest": "3bf7894bf40967ef7c677b04118a9b7d34557c7152c84ac9fe752e4ff0038456",
"method": "ed25519-v2",
"public": "aSRs/3ni0v/zcLSQetGDAy1DunN9VcBPoeUK+UyzOJA=",
"result": "Fb15jWB2PQ6Z+QgDDXZoWwsG3H4WodMRxvNW6lldEfi56Vd11QRCHcNwt8D1QSOE7zuEkcVC4XISFX9/vw5ADQ=="
},
{
"custom": {
"luid": "$int.-0XJXjBbpzYN67lwM",
"moment": "2025-06-17T19:09:33.898Z",
"status": "pending"
},
"digest": "31c0ba4d36ce86f89c095830b4282d000f63a0a0b9641f0e1b290c89b733a831",
"method": "ed25519-v2",
"public": "aSRs/3ni0v/zcLSQetGDAy1DunN9VcBPoeUK+UyzOJA=",
"result": "4tfeYwp/d26g2MwBhPDoPOjZ6HD4dMrZyAighIfZvn3j/FfRWuTk/jDYgft4yPZnW1FqgcMsalhSLGt+VgdKBw=="
}
],
"status": "pending",
"thread": "-0XJXjh6_AjFUGHNz",
"moment": "2025-06-17T19:09:33.877Z",
"owners": ["Oh3xliLHnYelAZbQyTEZv5jo3JNrsBiea+/6X6AxUK0="]
}
}Al recibir el 200 OK en la creación del intent este procedera a ser procesado por el nodo de Bre-B y tendrá un máximo de 20 segundos para quedar en un estado final desde la solicitud
de la creación, la fecha del campo received
Verificación de la Transacción
- Revisa el campo
meta.statusen la respuesta o posteriormente con una solicitudGETa/intents/{handle}.
Consulta la guía Cómo obtener el estado de un intent. - El estado cambiará a
completedcuando la transferencia sea exitosa, o arejectedsi ocurre algún error. Puedes escuchar los cambios a través de un webhook.
Revisa la guía Cómo registrar y escuchar efectos de estado de un intent para más información. - Consulta el Ciclo de vida de un intent para detalles sobre cada estado.
Validación de la información del destino
Después de que el intent alcanza su estado de completado, la información del destino se almacena como una proof dentro del intent.
Esto permite que el negocio realice verificaciones o validaciones futuras en sus procesos internos.
La información queda almacenada y puede ser consultada en cualquier momento, ya sea a través del webhook o realizando una
llamada GET al intent.
{
"custom": {
"moment": "2026-01-27T15:15:29.023Z",
"snapshot": {
"idType": "CC",
"idValue": "1088432333",
"bankName": "bancoRojo",
"lastName": "Key",
"firstName": "Alphanum"
}
},
"digest": "4163df852128ab47e39f5d4504ded8dfdcdf39f3985073e3eaaddd6a0591ef39",
"method": "ed25519-v2",
"public": "oNlpTnHtyTNkpdWxZ2a0twcUmziYgGCNUEqHNEQXsA0=",
"result": "MEMIDv4DMw9D4ewsufftEHyhxGdWtEISWc5PUbljmYKxt4Z/X1jevcL8bEj6eYMB4AWYuU3S8SaGLGYDXHg1Bw=="
},
{
"custom": {
"moment": "2026-01-24T13:32:21.763Z",
"status": "committed"
}, {...}
},
{
"custom": {
"moment": "2026-01-24T13:32:22.213Z",
"status": "completed"
}, {...}
}Esta proof aparece antes de la proof con estado completed y antes de la proof final committed.
Actualmente, el campo bankName no devuelve el nombre correcto del banco
debido a una limitación del nodo. Estamos trabajando con el equipo del nodo
para resolverlo. En la mayoría de los casos, el valor se devolverá como
BanRep.
¿Qué sigue?
Una vez que tu transferencia ha sido enviada, puedes:
- Monitorear el estado de la intent para confirmar su entrega
- Notificar al usuario cuando el pago se haya completado o fallado
- Registrar o conciliar la transacción en tu sistema interno
Historial de cambios
- Corregido• Se corrigieron enlaces que llevaban a la versión en español
- Agregado• Se agregó el ejemplo de la solicitud HTTP cruda (endpoint, headers y cuerpo JSON) junto a los ejemplos en TypeScript, SDK y CLI.
- Cambiado• Se actualizó el símbolo del rail BREB de `cop` a `bcop`.
- Agregado• Se agrego la sección de Validación de la información del destino
- Corregido• Se le agregó .handle a los campos source, target y symbol en la tabla de definición de campos
- Agregado• Versión inicial