Overview
When you anchor a record with Anchora, it takes 30-60 seconds to be confirmed on the Polygon blockchain. Instead of polling for status, configure webhooks to receive instant notifications when:
- anchor.confirmed - Record successfully anchored to blockchain
- anchor.failed - Anchoring failed (rare, usually network issues)
- record.updated - Mutable fields were updated
- record.deleted - Record was soft or hard deleted
Configuring Webhooks
You can configure webhooks in two ways: globally via your dashboard, or per-request using the webhookUrl parameter.
Per-Request Webhook
curl -X POST https://api.anchora.co.in/v1/anchor/encrypted \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "data": { "name": "Alice Smith", "certificateId": "CERT-2024-001" }, "encryptionKey": "your-32-character-encryption-key!!", "webhookUrl": "https://your-app.com/webhooks/anchora" }'
Webhook Payload
When an event occurs, Anchora sends a POST request to your webhook URL with the following payload:
{
"event": "anchor.confirmed",
"timestamp": "2024-01-31T10:30:00Z",
"data": {
"recordId": "507f1f77bcf86cd799439011",
"hash": "a1b2c3d4e5f6...64chars",
"txHash": "0x3f8a9c2e1b4d7f6a...",
"blockNumber": 45678901,
"status": "ANCHORED"
},
"signature": "sha256=abc123..."
}
Multi-Chain Headers NEW
Webhooks now carry chain provenance headers so receivers can branch on chain type without re-querying the API. Old EVM-only receivers continue to work — the new headers are additive.
X-Anchora-Event: ANCHORED X-Anchora-Hash: <full hash> X-Anchora-Package: SEPARATED | IN_PLACE | MANAGED X-Anchora-Chain: evm | fabric // NEW X-Anchora-Network: polygon-amoy | fabric-byo | ... // NEW X-Anchora-Retry-Attempt: 0..5
Fabric body example
For Fabric records, note: blockNumber is explicit null (fabric-gateway doesn't expose block heights), transactionHash is the raw Fabric txID (no 0x prefix), and batchId is a string.
{
"type": "ANCHORED",
"hash": "63e33ef9...",
"recordId": "507f1f77bcf86cd799439012",
"chainType": "fabric",
"networkId": "fabric-byo",
"blockNumber": null,
"transactionHash": "95cfed3ad9d5c49a...",
"batchId": "7",
"anchoredAt": "2026-05-12T11:21:10.736Z",
"merkleProof": ["0x70bdd5..."],
"metadata": {}
}
Hybrid body example
A Hybrid record's webhook carries BOTH chain anchors in a single delivery — primary fields at top level, secondary inside dualAnchor.
{
"type": "ANCHORED",
"hash": "e90e818fbf...",
"chainType": "fabric",
"networkId": "fabric-byo",
"batchId": "4",
"transactionHash": "aea1e2167553e7e3...",
"blockNumber": null,
"merkleProof": [],
"dualAnchor": {
"chainType": "evm",
"networkId": "polygon-amoy",
"batchId": 114,
"blockNumber": 38228377,
"transactionHash": "0x6bc51454f711...",
"merkleProof": [],
"anchoredAt": "..."
}
}
See Multi-Chain Anchoring for the complete payload reference, or Hybrid Mode Guide for end-to-end setup.
Verifying Webhook Signatures
All webhook requests include a signature header to verify authenticity. Always verify signatures before processing webhooks.
const crypto = require('crypto'); function verifyWebhook(payload, signature, secret) { const expectedSignature = 'sha256=' + crypto.createHmac('sha256', secret) .update(payload) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expectedSignature) ); } // In your webhook handler app.post('/webhooks/anchora', (req, res) => { const signature = req.headers['x-webhook-signature']; const isValid = verifyWebhook( JSON.stringify(req.body), signature, process.env.WEBHOOK_SECRET ); if (!isValid) { return res.status(401).json({ error: 'Invalid signature' }); } // Process the webhook console.log('Received event:', req.body.event); res.status(200).json({ received: true }); });
Retry Policy
If your endpoint returns a non-2xx response, Anchora will retry the webhook with exponential backoff:
| Attempt | Delay | Total Time |
|---|---|---|
| 1st retry | 1 minute | 1 minute |
| 2nd retry | 5 minutes | 6 minutes |
| 3rd retry | 30 minutes | 36 minutes |
| 4th retry | 2 hours | ~2.5 hours |
| 5th retry (final) | 24 hours | ~26.5 hours |
Best Practices
- Respond quickly: Return a 200 response immediately, then process async
- Handle duplicates: Use the
recordIdto deduplicate events - Verify signatures: Always validate the
x-webhook-signatureheader - Use HTTPS: Webhook URLs must use HTTPS in production
- Log everything: Keep logs of received webhooks for debugging