Developer reference · Webhooks API v1

20 real-time events. Signed. Idempotent. Retried.

Subscribe any HTTPS endpoint to Donateazy events. Every delivery is HMAC-SHA256-signed, includes a UUID delivery ID for idempotency, and is retried with exponential backoff on failure. This page is the source of truth - when a new event is added to the platform, it appears here automatically.

Webhook configuration lives in your NGO dashboard under System · Webhooks. Pro plan and above.

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

Header Value
Content-Type application/json
User-Agent Donateazy-Webhook/1.0
X-Donateazy-Event donation.paid (the event name)
X-Donateazy-Signature HMAC-SHA256 hex of the raw JSON body, keyed by your webhook secret
X-Donateazy-Delivery UUID of this delivery - use for idempotency

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"
}
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.

Wire up your first webhook in 5 minutes.

Configure subscriptions in your dashboard. Pro plan and above.

See pricing
Chat with us