Skip to main content

Webhooks Overview

Webhooks send real-time notifications to your server when events occur (e.g., a transaction is confirmed, a token is deployed). Instead of polling the API, your server receives a POST request the moment something happens.

How It Works

1. Register a webhook endpoint → POST /v1/webhook_endpoints
2. Subscribe to event types (e.g., "token.deployed", "transaction.confirmed")
3. Urblock sends POST requests with signed JSON payloads to your endpoint
4. Your server responds with 2xx to acknowledge receipt
5. Failed deliveries are retried with exponential backoff

Payload Format

Every webhook delivery sends a JSON body with this structure:

{
"object": "event",
"id": "evt_abc123",
"type": "transaction.confirmed",
"data": {
"object": "transaction",
"id": "tx_abc123",
"type": "mint",
"status": "confirmed",
"tx_hash": "0xabc...",
"token_id": "tok_abc123",
"created": 1709740800
},
"created": 1709740860
}

Delivery Headers

Each delivery includes these headers:

HeaderDescription
X-Urblock-EventEvent type (e.g., transaction.confirmed)
X-Urblock-DeliveryUnique delivery ID (whd_...)
X-Urblock-SignatureHMAC-SHA256 signature for verification
Content-TypeAlways application/json

Signature Verification

Every delivery is signed with your webhook secret using HMAC-SHA256. The signature format is:

X-Urblock-Signature: t=1709740860,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd

Verification Steps

  1. Extract t (timestamp) and v1 (signature) from the header
  2. Build the payload: {timestamp}.{raw_body}
  3. Compute HMAC-SHA256 with your webhook secret
  4. Compare using constant-time comparison

Node.js Verification Example

import crypto from "crypto";

function verifySignature(rawBody: string, signatureHeader: string, secret: string): boolean {
const [tPart, v1Part] = signatureHeader.split(",");
const timestamp = tPart.split("=")[1];
const receivedHmac = v1Part.split("=")[1];

const payload = `${timestamp}.${rawBody}`;
const expectedHmac = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");

return crypto.timingSafeEqual(
Buffer.from(receivedHmac, "hex"),
Buffer.from(expectedHmac, "hex")
);
}
Timestamp Tolerance

Check that the timestamp is within 5 minutes of the current time to prevent replay attacks:

const tolerance = 5 * 60; // 5 minutes
const age = Math.floor(Date.now() / 1000) - parseInt(timestamp);
if (age > tolerance) throw new Error("Webhook too old");

Retry Policy

Failed deliveries (non-2xx response or timeout) are retried with exponential backoff:

AttemptDelayTotal wait
1Immediate0s
230s30s
32 min2.5 min
48 min10.5 min
532 min42.5 min

After 5 failed attempts, the delivery is marked as failed. You can manually retry failed deliveries via the Webhooks API.

Event Types

Event TypeDescription
token.deployedToken contract confirmed on-chain
token.deploy_failedToken deployment failed
transaction.submittedTransaction sent to blockchain
transaction.confirmedTransaction confirmed in a block
transaction.failedTransaction reverted or timed out
identity.registeredT-REX identity registered
compliance.module_boundCompliance module bound to token
governance.proposal_createdNew governance proposal
governance.proposal_executedProposal executed via timelock
vesting.deployedVesting contract deployed
vault.deployedVault contract deployed
multisig.deployedMultisig wallet deployed
tba.createdToken Bound Account created
batch.completedBatch operation completed

Best Practices

  1. Always verify signatures — never trust unverified payloads
  2. Respond quickly — return 200 OK before doing heavy processing; queue work for later
  3. Handle duplicates — use the id field (event ID) to deduplicate in your handler
  4. Use HTTPS — webhook URLs must use HTTPS
  5. Monitor failures — check the delivery dashboard for failed webhooks
  6. Process idempotently — your handler should be safe to call multiple times with the same event

Next Steps