Webhooks
Webhooks let you receive real-time notifications when events occur in your Crowd.Credit account. Instead of polling the API, webhooks push event data to your server.
Setting Up a Webhook
Create a Subscription
curl -X POST https://api.crowd.credit/api/v1/webhooks \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhooks/crowd-credit",
"events": ["deposit.created", "payment.received", "credit.tier_changed"],
"secret": "your_webhook_secret"
}'
Event Types
| Event | Description |
|---|---|
deposit.created | New deposit confirmed on-chain |
deposit.withdrawn | Deposit withdrawal completed |
payment.received | Credit payment received |
payment.due | Payment due date approaching |
payment.overdue | Payment is past due |
credit.tier_changed | Graduation tier changed |
credit.line_updated | Credit line amount changed |
credit.frozen | Credit line frozen |
yield.distributed | Yield distribution credited |
score.updated | CrowdProof score updated |
account.frozen | Account frozen |
Webhook Payload
All webhook deliveries include a JSON payload:
{
"id": "evt_abc123",
"type": "deposit.created",
"timestamp": "2026-03-07T12:00:00Z",
"data": {
"depositId": "dep_xyz789",
"token": "USDC",
"amount": "10000.00",
"transactionHash": "0x..."
}
}
Verifying Signatures
Every webhook delivery includes an HMAC-SHA256 signature in the X-Webhook-Signature header. Always verify this signature to ensure the payload is authentic.
import crypto from 'crypto';
function verifyWebhookSignature(
payload: string,
signature: string,
secret: string
): boolean {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
Retry Policy
Failed webhook deliveries are retried with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 12 hours |
After 6 failed attempts, the webhook subscription is marked as inactive. You can reactivate it from the dashboard.