The envelope
Every event delivery is wrapped in the same envelope. The data object varies by event; everything else stays constant.
{
"id": "9c5a1f3b-7d2e-4a8c-b9f1-3e5d8b1c2a4d",
"event": "donation.paid",
"created_at": "2026-05-15T10:23:46+05:30",
"webhook_id": 42,
"data": "<event-specific payload - see below>"
}
Request headers
Verifying the signature
Re-compute hash_hmac('sha256', $rawJsonBody, $yourWebhookSecret) and constant-time-compare against X-Donateazy-Signature. Reject the request if they don't match.
// PHP example
$raw = file_get_contents('php://input');
$expected = hash_hmac('sha256', $raw, $WEBHOOK_SECRET);
if (! hash_equals($expected, $_SERVER['HTTP_X_DONATEAZY_SIGNATURE'] ?? '')) {
http_response_code(401); exit;
}
$payload = json_decode($raw, true);
Delivery semantics
Timeout
Your endpoint has 10 seconds to respond with a 2xx status code. Anything else is treated as a failure.
Retry-with-backoff
Up to 5 attempts at intervals of 60s, 5min, 15min, 1hr, 2hr. Total retry window: ~3.5 hours.
Idempotency
Use the X-Donateazy-Delivery UUID as your idempotency key. A retried delivery has the same UUID; a re-fired event has a new one.
Failure cap
After 10 consecutive failures the webhook is auto-disabled. Re-enable from the dashboard or via API.
Order
Events for the same resource are delivered in commit order, but cross-resource ordering is not guaranteed. Treat each event as a fact, not a sequence.
Private IPs
Webhook URLs resolving to RFC1918 / link-local addresses are rejected at delivery time for SSRF safety.
Event reference
All 20 events your endpoint can subscribe to. Each `data` block below is what fills the envelope's `data` field for that event.
donation.created
Deep-dive page →
#permalink
When a new donation is recorded.
A donor initiates a donation (UPI, card, net-banking). Fires BEFORE payment confirmation.
Sample data payload
{
"donation_id": 12345,
"ngo_id": 7,
"donor": {
"id": 482,
"name": "Vandana Kapoor",
"email": "vandana@example.com",
"phone": "+919876543210",
"pan": "ABCDE1234F"
},
"amount": 5000,
"currency": "INR",
"campaign_id": 18,
"status": "pending",
"payment_method": "upi",
"created_at": "2026-05-15T10:23:14+05:30"
}
donation.paid
Deep-dive page →
#permalink
When a donation payment is confirmed.
Payment gateway confirms the donation succeeded. This is the safe event to credit your downstream ledger.
Sample data payload
{
"donation_id": 12345,
"ngo_id": 7,
"donor": {
"id": 482,
"name": "Vandana Kapoor",
"email": "vandana@example.com"
},
"amount": 5000,
"currency": "INR",
"payment_method": "upi",
"gateway": "razorpay",
"gateway_payment_id": "pay_NXxYzAbCd1234",
"paid_at": "2026-05-15T10:23:46+05:30",
"status": "paid"
}
donation.refunded
Deep-dive page →
#permalink
When a donation is refunded.
A previously-paid donation is refunded (full or partial) via the payment gateway.
Sample data payload
{
"donation_id": 12345,
"ngo_id": 7,
"original_amount": 5000,
"refund_amount": 5000,
"currency": "INR",
"gateway_refund_id": "rfnd_NYxYzAbCd5678",
"reason": "duplicate_payment",
"refunded_at": "2026-05-16T09:11:02+05:30"
}
donor.created
Deep-dive page →
#permalink
When a new donor is added.
A new donor record is created in your NGO's database - either via a donation, manual entry, or CSV import.
Sample data payload
{
"donor_id": 482,
"ngo_id": 7,
"name": "Vandana Kapoor",
"email": "vandana@example.com",
"phone": "+919876543210",
"pan": "ABCDE1234F",
"source": "donation_flow",
"created_at": "2026-05-15T10:23:14+05:30"
}
donor.updated
Deep-dive page →
#permalink
When donor information is updated.
A donor's record is updated. The `changes` array names the fields that changed; `before` and `after` capture the diff.
Sample data payload
{
"donor_id": 482,
"ngo_id": 7,
"changes": [
"email",
"phone"
],
"before": {
"email": "old@example.com",
"phone": "+919999988888"
},
"after": {
"email": "vandana@example.com",
"phone": "+919876543210"
},
"updated_at": "2026-05-16T11:02:18+05:30"
}
donor.merged
Deep-dive page →
#permalink
When duplicate donors are merged.
Two donor records are merged (manual de-duplication or auto-merge). The `kept_donor_id` is the surviving record; `merged_donor_id` was the duplicate.
Sample data payload
{
"kept_donor_id": 482,
"merged_donor_id": 491,
"ngo_id": 7,
"donations_transferred": 3,
"merged_at": "2026-05-16T15:44:00+05:30",
"merged_by_user_id": 12
}
receipt.generated
Deep-dive page →
#permalink
When a tax receipt is generated.
An 80G tax receipt is generated for a paid donation. Includes the public verify-receipt URL.
Sample data payload
{
"receipt_id": 9821,
"donation_id": 12345,
"ngo_id": 7,
"donor_id": 482,
"receipt_no": "DZ/2026-27/00921",
"amount": 5000,
"fy_label": "2026-27",
"generated_at": "2026-05-15T10:23:55+05:30",
"verify_url": "https://www.donateazy.in/verify-receipt?no=DZ%2F2026-27%2F00921",
"pdf_url": "https://www.donateazy.in/receipts/9821/download"
}
campaign.created
Deep-dive page →
#permalink
When a new campaign is created.
A new fundraising campaign is created.
Sample data payload
{
"campaign_id": 18,
"ngo_id": 7,
"title": "Monsoon Relief 2026",
"goal_amount": 1000000,
"currency": "INR",
"starts_at": "2026-06-01T00:00:00+05:30",
"ends_at": "2026-08-31T23:59:59+05:30",
"public_url": "https://www.donateazy.in/c/monsoon-relief-2026",
"created_at": "2026-05-15T09:00:00+05:30"
}
campaign.completed
Deep-dive page →
#permalink
When a campaign reaches its goal or end date.
A campaign reaches its goal OR its end date passes. The `reason` field disambiguates.
Sample data payload
{
"campaign_id": 18,
"ngo_id": 7,
"title": "Monsoon Relief 2026",
"reason": "goal_reached",
"goal_amount": 1000000,
"raised_amount": 1024500,
"donor_count": 187,
"completed_at": "2026-08-12T14:32:11+05:30"
}
grant.created
Deep-dive page →
#permalink
When a new grant is recorded.
A new grant (foundation, government, CSR) is recorded in the grant pipeline. Pro and above.
Sample data payload
{
"grant_id": 33,
"ngo_id": 7,
"funder_name": "Tata Trusts",
"sanction_reference": "TT/2026-27/EDU/045",
"sanction_amount": 2500000,
"currency": "INR",
"sanctioned_at": "2026-05-10T00:00:00+05:30",
"programme": "Girl Child Education",
"tranches": 4,
"created_at": "2026-05-15T11:00:00+05:30"
}
grant.disbursement
Deep-dive page →
#permalink
When a grant disbursement is recorded.
A grant tranche is disbursed to a beneficiary or programme.
Sample data payload
{
"disbursement_id": 1142,
"grant_id": 33,
"ngo_id": 7,
"tranche_number": 2,
"amount": 625000,
"currency": "INR",
"disbursed_at": "2026-08-01T11:30:00+05:30",
"beneficiary_id": null,
"pfms_uid": "PFMS/2026/3812",
"utilisation_certificate_url": "https://www.donateazy.in/grants/33/uc-2"
}
payment_link.used
Deep-dive page →
#permalink
When a donation is made via a payment link.
A donation is made via a payment-link (embedded in WhatsApp / email / a website). Triggered AFTER `donation.paid` for the same donation.
Sample data payload
{
"payment_link_id": 88,
"donation_id": 12345,
"ngo_id": 7,
"donor_id": 482,
"amount": 5000,
"currency": "INR",
"campaign_id": 18,
"source_url": "https://www.donateazy.in/p/monsoon-relief",
"used_at": "2026-05-15T10:24:01+05:30"
}
service_order.created
Deep-dive page →
#permalink
When an NGO places a service-marketplace order (Darpan / 12A / 80G / FCRA / bookkeeping etc.).
Sample payload documentation pending. The envelope shape is documented above.
service_order.assigned
Deep-dive page →
#permalink
When an admin assigns a provider to a service order.
Sample payload documentation pending. The envelope shape is documented above.
service_order.in_progress
Deep-dive page →
#permalink
When the assigned provider starts work on a service order.
Sample payload documentation pending. The envelope shape is documented above.
service_order.awaiting_govt
Deep-dive page →
#permalink
When the service order is waiting on a government portal (IT / MHA / MCA).
Sample payload documentation pending. The envelope shape is documented above.
service_order.delivered
Deep-dive page →
#permalink
When the provider uploads the final deliverable.
Sample payload documentation pending. The envelope shape is documented above.
service_order.completed
Deep-dive page →
#permalink
When the NGO acknowledges delivery (lifecycle terminal).
Sample payload documentation pending. The envelope shape is documented above.
service_order.cancelled
Deep-dive page →
#permalink
When a service order is cancelled before delivery.
Sample payload documentation pending. The envelope shape is documented above.
service_order.refunded
Deep-dive page →
#permalink
When a service order is refunded.
Sample payload documentation pending. The envelope shape is documented above.