Saltar al contenido principal

Introducción

Generalmente, cuando realiza una solicitud a un endpoint de API, espera obtener una respuesta casi inmediata. Sin embargo, algunas solicitudes pueden tardar mucho tiempo en procesarse, lo que puede generar errores de tiempo de espera. Para evitar un error de tiempo de espera, se devuelve una respuesta pendiente. Dado que sus registros deben actualizarse con el estado final de la solicitud, necesita:
  1. Realizar una solicitud de actualización (comúnmente conocido como polling) o,
  2. Escuchar eventos mediante el uso de una URL de webhook.
Consejo útil
Recomendamos que utilice webhooks para proporcionar valor a sus clientes en lugar de usar callbacks o polling. Con los callbacks, no tenemos control sobre lo que sucede del lado del cliente. Tampoco usted. Los callbacks pueden fallar si la conexión de red del dispositivo del cliente falla o es débil, o si el dispositivo se apaga después de una transacción.

Polling vs Webhooks

El polling requiere realizar una solicitud GET a intervalos regulares para obtener el estado final de una solicitud. Por ejemplo, cuando emite una dirección a un cliente para depósitos, sigue realizando solicitudes de transacciones vinculadas a la dirección hasta que encuentre una. Con webhooks, el servidor de recursos, Blockradar en este caso, envía actualizaciones a su servidor cuando cambia el estado de su solicitud. El cambio en el estado de una solicitud se conoce como evento. Normalmente escuchará estos eventos en un endpoint POST llamado su URL de webhook. La siguiente tabla destaca algunas diferencias entre polling y webhooks:
PollingWebhooks
Modo de actualizaciónManualAutomático
Limitación de tasaNo
Impactado por escaladoNo

Crear una URL de webhook

Una URL de webhook es simplemente un endpoint POST al que un servidor de recursos envía actualizaciones. La URL necesita analizar una solicitud JSON y devolver un 200 OK:
// Usando Express
app.post("/my/webhook/url", function(req, res) {
    // Recuperar el cuerpo de la solicitud
    const event = req.body;
    // Hacer algo con el evento
    res.send(200);
});
Cuando su URL de webhook recibe un evento, necesita analizar y reconocer el evento. Reconocer un evento significa devolver un 200 OK en el encabezado HTTP. Sin un 200 OK en el encabezado de respuesta, seguiremos enviando eventos durante las próximas 2 horas y 35 minutos:
  • Intentaremos enviar webhooks 5 veces con un retraso creciente entre cada intento, comenzando con 5 minutos y aumentando exponencialmente hasta 80 minutos. La duración total de estos 5 intentos abarcará aproximadamente 2 horas y 35 minutos.
Evite tareas de larga duración
Si tiene tareas de larga duración en su función de webhook, debe reconocer el evento antes de ejecutar las tareas de larga duración. Las tareas de larga duración conducirán a un tiempo de espera de solicitud y una respuesta de error automática de su servidor. Sin una respuesta 200 OK, reintentamos como se describe en el párrafo anterior.

Probar Webhooks localmente

Durante el desarrollo, puede configurar su URL de webhook en su entorno de billetera maestra de PRUEBA a una dirección local, como http://localhost o 127.0.0.1. Para exponer su servidor local a Internet con fines de prueba, considere usar una herramienta como ngrok o webhook.site. Estas herramientas le permiten ver cómo se ve la carga útil del webhook y simular eventos de webhook localmente antes de implementar su aplicación en un entorno en vivo. Con estas herramientas, puede asegurarse de que su integración de webhook funcione correctamente y manejar cualquier problema en un entorno local controlado antes de pasar a producción.

Reenviar Webhook de Transacción

En caso de que por alguna razón no reciba el webhook de transacción y el tiempo de espera haya transcurrido, hemos proporcionado una API que puede usar para reenviar un webhook de transacción
¡Úselo con precaución!
Como esto puede llevar a procesar transacciones ya completadas, asegúrese de tener una validación adecuada al usar este endpoint.
curl --request POST \
  --url https://api.blockradar.co/v1/wallets/{walletId}/transactions/webhooks/resend \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: <api-key>' \
  --data '{
  "id": "TRANSACTION_ID"
}'

Verificar el origen del evento

Dado que su URL de webhook está disponible públicamente, necesita verificar que los eventos provengan de Blockradar y no de un actor malicioso. Hay dos formas de asegurar que los eventos a su URL de webhook provengan de Blockradar:
  1. Validación de firma (recomendado)

Validación de firma

Los eventos enviados desde Blockradar llevan el encabezado x-blockradar-signature. El valor de este encabezado es una firma HMAC SHA512 de la carga útil del evento firmada usando su clave secreta. La verificación de la firma del encabezado debe realizarse antes de procesar el evento:
const crypto = require('crypto');
const apiKey = process.env.WALLET_API_KEY;
// Usando Express
app.post("/my/webhook/url", function(req, res) {
    //validar evento
    const hash = crypto.createHmac('sha512', apiKey).update(JSON.stringify(req.body)).digest('hex');
    if (hash == req.headers['x-blockradar-signature']) {
    // Recuperar el cuerpo de la solicitud
    const event = req.body;
    // Hacer algo con el evento  
    }
    res.send(200);
});

Lista de verificación para poner en producción

Ahora que ha creado exitosamente su URL de webhook, aquí hay algunas formas de asegurar que obtenga una experiencia agradable:
  • Agregue la URL de webhook en sus billeteras maestras en el panel de Blockradar
  • Asegúrese de que su URL de webhook esté disponible públicamente (las URLs de localhost no pueden recibir eventos)
  • Si usa .htaccess, recuerde agregar el / al final de la URL
  • Pruebe su webhook para asegurarse de que está recibiendo el cuerpo JSON y devolviendo una respuesta HTTP 200 OK
  • Si su función de webhook tiene tareas de larga duración, primero debe reconocer la recepción del webhook devolviendo un 200 OK antes de proceder con las tareas de larga duración
  • Si no obtenemos una respuesta HTTP 200 OK de sus webhooks, lo marcamos como un intento fallido
  • Intentaremos enviar webhooks 5 veces con un retraso creciente entre cada intento, comenzando con 5 minutos y aumentando exponencialmente hasta 80 minutos. La duración total de estos 5 intentos abarcará aproximadamente 2 horas y 35 minutos.

Tipos de eventos

Estos son los eventos que actualmente generamos. Agregaremos más a esta lista a medida que integremos más acciones en el futuro.

Ejemplos de Eventos

A continuación se muestran ejemplos de cargas útiles de webhook para algunos de los eventos más comunes:
{
    "event": "deposit.success",
    "data": {
        "id": "6d2f9646-cae4-48a5-8bfe-1f9379868d4f",
        "reference": "LSk5RLfSrR",
        "senderAddress": "0x2455eC6700092991Ce0782365A89d5Cd89c8Fa22",
        "recipientAddress": "0xe1037B45b48390285e5067424053fa35c478296b",
        "amount": "10.0",
        "amountPaid": "10.0",
        "fee": null,
        "currency": "USD",
        "blockNumber": 6928760,
        "blockHash": "0x5f2e0ed782752b9559e7a3d89c0fb9f6706e4866e74ba7a434cf933bb3f02a2b",
        "hash": "0x94c733496df59c15e5a489f20374096bba31166a8e149ceea4d410e3e5821357",
        "confirmations": 6,
        "confirmed": true,
        "gasPrice": "1201381238",
        "gasUsed": "62159",
        "gasFee": "0.000074676656372842",
        "status": "SUCCESS",
        "type": "DEPOSIT",
        "note": null,
        "amlScreening": {
            "provider": "ofac",
            "status": "success",
            "message": "Address is not sanctioned"
        },
        "assetSwept": null,
        "assetSweptAt": null,
        "assetSweptGasFee": null,
        "assetSweptHash": null,
        "assetSweptSenderAddress": null,
        "assetSweptRecipientAddress": null,
        "assetSweptAmount": null,
        "reason": null,
        "network": "testnet",
        "chainId": 11155111,
        "metadata": {
            "user_id": 1
        },
        "createdAt": "2024-10-23T11:19:58.451Z",
        "updatedAt": "2024-10-23T11:19:58.451Z",
        "asset": {
            "id": "fe04a28c-c615-4e41-8eda-f84c862864f5",
            "name": "USDC Coin",
            "symbol": "USDC",
            "decimals": 6,
            "address": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
            "standard": "ERC20",
            "isActive": true,
            "logoUrl": "https://res.cloudinary.com/blockradar/image/upload/v1716800083/crypto-assets/usd-coin-usdc-logo_fs9mhv.png",
            "network": "testnet",
            "createdAt": "2024-05-14T11:53:33.682Z",
            "updatedAt": "2024-06-14T22:32:12.589Z"
        },
        "address": {
            "id": "0a69c48a-6c6f-422c-bd6a-70de3306a3ac",
            "address": "0xe1037B45b48390285e5067424053fa35c478296b",
            "name": "Customer 1",
            "isActive": true,
            "type": "INTERNAL",
            "derivationPath": "m/44'/60'/0'/0/87",
            "metadata": {
                "user_id": 1
            },
            "configurations": {
                "aml": {
                    "status": "success",
                    "message": "Address is not sanctioned",
                    "provider": "ofac"
                },
                "showPrivateKey": false,
                "disableAutoSweep": false,
                "enableGaslessWithdraw": false
            },
            "network": "testnet",
            "createdAt": "2024-10-23T11:13:40.446Z",
            "updatedAt": "2024-10-23T11:13:40.446Z"
        },
        "blockchain": {
            "id": "85ffc132-3972-4c9e-99a5-5cf0ccb688bf",
            "name": "ethereum",
            "symbol": "eth",
            "slug": "ethereum",
            "derivationPath": "m/44'/60'/0'/0",
            "isEvmCompatible": true,
            "logoUrl": "https://res.cloudinary.com/blockradar/image/upload/v1716800081/crypto-assets/ethereum-eth-logo_idraq2.png",
            "isActive": true,
            "tokenStandard": "ERC20",
            "createdAt": "2024-05-14T11:53:33.095Z",
            "updatedAt": "2024-06-14T22:32:11.983Z"
        },
        "wallet": {
            "id": "d236a191-c1d4-423c-a439-54ce6542ca41",
            "name": "Ethereum Master Wallet",
            "description": "This is ethereum testnet master wallet",
            "address": "0x947514e4B803e312C312da0F1B41fEDdbe15ae7a",
            "derivationPath": "m/44'/60'/0'/0/0",
            "isActive": true,
            "status": "ACTIVE",
            "network": "testnet",
            "createdAt": "2024-08-22T09:48:56.322Z",
            "updatedAt": "2024-10-23T10:52:34.332Z",
            "business": {
                "id": "4b96c271-35eb-45e8-b558-6a53f95df601",
                "name": "Test One Inc",
                "sector": "Fintech",
                "status": "ACTIVE",
                "createdAt": "2024-08-22T09:28:37.522Z",
                "updatedAt": "2024-08-22T09:28:37.522Z"
            }
        },
        "beneficiary": null
    }
}

Lista Completa de Eventos

EventoDescripción
deposit.successSe activa cuando una transacción de depósito se recibe y confirma exitosamente en la blockchain.
deposit.processingSe activa cuando una transacción de depósito se está procesando.
deposit.failedSe activa cuando una transacción de depósito no se procesa o confirma.
deposit.cancelledSe activa cuando una transacción de depósito se cancela antes de completarse.
deposit.swept.successSe activa cuando los fondos de un depósito se barren (transfieren) exitosamente a la billetera maestra.
deposit.swept.failedSe activa cuando el proceso de barrido automático falla al transferir fondos a la billetera maestra.
withdraw.successSe activa cuando una transacción de retiro se ejecuta y confirma exitosamente en la blockchain.
withdraw.failedSe activa cuando una transacción de retiro falla al ejecutarse. Esto puede ocurrir debido a fondos insuficientes, congestión de red u otros problemas relacionados con blockchain.
withdraw.cancelledSe activa cuando una transacción de retiro se cancela antes de completarse.
gateway-deposit.successSe activa cuando un depósito de USDC al contrato de Gateway Wallet se finaliza exitosamente y se acredita al saldo unificado de Gateway.
gateway-deposit.failedSe activa cuando un depósito de USDC al contrato de Gateway Wallet falla o es rechazado.
gateway-deposit.cancelledSe activa cuando una transacción de depósito gateway se cancela antes de completarse.
gateway-withdraw.successSe activa cuando USDC se acuña y retira exitosamente en la cadena de destino a través del contrato Gateway Minter.
gateway-withdraw.failedSe activa cuando una transacción de retiro (acuñación) vía Gateway falla al ejecutarse, lo que puede ocurrir debido a saldo unificado insuficiente, firma inválida o problemas de blockchain.
gateway-withdraw.cancelledSe activa cuando una transacción de retiro gateway se cancela antes de completarse.
signed.successSe activa cuando una transacción firmada se ejecuta exitosamente, sin embargo, la transacción no se transmite en la blockchain.
signed.failedSe activa cuando una transacción firmada falla al ejecutarse. Esto puede ocurrir debido a congestión de red u otros problemas relacionados con blockchain.
signed.cancelledSe activa cuando una transacción firmada se cancela antes de completarse.
swap.successSe activa cuando una transacción de intercambio se ejecuta exitosamente y los activos se intercambian.
swap.failedSe activa cuando una transacción de intercambio falla al ejecutarse. Esto puede ocurrir debido a fondos insuficientes, congestión de red o errores del contrato de intercambio.
swap.cancelledSe activa cuando una transacción de intercambio se cancela antes de completarse.
custom-smart-contract.successSe activa cuando una transacción de contrato inteligente personalizado se ejecuta exitosamente. Esto indica que la interacción del contrato se completó exitosamente en la blockchain.
custom-smart-contract.failedSe activa cuando una transacción de contrato inteligente personalizado falla al ejecutarse. Esto puede ocurrir debido a varias razones como fondos insuficientes, congestión de red o errores del contrato inteligente.
custom-smart-contract.cancelledSe activa cuando una transacción de contrato inteligente personalizado se cancela antes de completarse.
staking.successSe activa cuando una transacción de staking se ejecuta exitosamente y los activos se hacen stake.
staking.failedSe activa cuando una transacción de staking falla al ejecutarse. Esto puede ocurrir debido a fondos insuficientes, congestión de red o errores del contrato de staking.
staking.cancelledSe activa cuando una transacción de staking se cancela antes de completarse.
unstaking.successSe activa cuando una transacción de unstaking se ejecuta exitosamente y los activos se retiran del stake.
unstaking.failedSe activa cuando una transacción de unstaking falla al ejecutarse. Esto puede ocurrir debido a saldo en stake insuficiente, congestión de red o errores del contrato de staking.
unstaking.cancelledSe activa cuando una transacción de unstaking se cancela antes de completarse.
unstaking.withdraw.successSe activa cuando los activos retirados del stake se retiran exitosamente a la dirección del usuario.
unstaking.withdraw.failedSe activa cuando el retiro de activos retirados del stake falla al ejecutarse. Esto puede ocurrir debido a saldo insuficiente, congestión de red u otros problemas relacionados con blockchain.
unstaking.withdraw.cancelledSe activa cuando una transacción de retiro de unstaking se cancela antes de completarse.
restaking.successSe activa cuando una transacción de re-staking se ejecuta exitosamente y los activos se vuelven a hacer stake.
restaking.failedSe activa cuando una transacción de re-staking falla al ejecutarse. Esto puede ocurrir debido a fondos insuficientes, congestión de red o errores del contrato de staking.
restaking.cancelledSe activa cuando una transacción de re-staking se cancela antes de completarse.
auto-settlement.successSe activa cuando una transacción de liquidación automática se ejecuta exitosamente y la liquidación se completa.
auto-settlement.failedSe activa cuando una transacción de liquidación automática falla al ejecutarse. Esto puede ocurrir debido a fondos insuficientes, congestión de red o errores del contrato de liquidación.
auto-settlement.cancelledSe activa cuando una transacción de liquidación automática se cancela antes de completarse.
salvage.successSe activa cuando una operación de salvamento se ejecuta exitosamente y los activos se recuperan.
salvage.failedSe activa cuando una operación de salvamento falla al ejecutarse. Esto puede ocurrir debido a fondos insuficientes, congestión de red o errores del contrato de salvamento.
salvage.cancelledSe activa cuando una operación de salvamento se cancela antes de completarse.

Tipos y Estados de Transacciones

Tipos de Transacciones

Los siguientes tipos de transacciones se utilizan en las cargas útiles de webhook:
TipoDescripción
DEPOSITUna transacción de depósito donde los fondos se reciben en una dirección de billetera
WITHDRAWUna transacción de retiro donde los fondos se envían desde una billetera a una dirección externa
SIGNEDUna transacción firmada donde la transacción solo se firma y no se transmite a la red
GATEWAY_DEPOSITUna transacción de depósito donde los fondos se reciben en una dirección de billetera gateway
GATEWAY_WITHDRAWUna transacción de retiro donde los fondos se envían desde una billetera gateway a una dirección externa
SALVAGEUna operación de salvamento para recuperar fondos bloqueados o perdidos
AUTO_SETTLEMENTUna transacción de liquidación automática
AUTO_FUNDINGUna transacción de financiación automática que acuña y mueve stablecoins
STAKINGUna transacción de staking donde los activos se hacen stake
UNSTAKINGUna transacción de unstaking donde los activos en stake se retiran
RESTAKINGUna transacción de re-staking donde los activos se vuelven a hacer stake
UNSTAKING_WITHDRAWUn retiro de activos retirados del stake
CUSTOM_SMART_CONTRACTUna interacción de contrato inteligente personalizado
SWAPUna transacción de intercambio donde un activo se intercambia por otro

Estados de Transacciones

Los siguientes estados indican el estado actual de una transacción:
EstadoDescripción
PENDINGLa transacción se está procesando pero aún no se confirma
PROCESSINGLa transacción se está procesando actualmente
SUCCESSLa transacción se ha ejecutado y confirmado exitosamente
FAILEDLa transacción falló al ejecutarse o fue rechazada
INCOMPLETELa transacción está incompleta y puede requerir pasos adicionales
CANCELLEDLa transacción se canceló antes de completarse
Estos tipos y estados de transacciones se utilizan en los campos type y status de las cargas útiles de webhook para ayudarlo a comprender qué tipo de transacción ocurrió y su estado actual.
¡Feliz codificación! ❤️