Webhooks
Receive events as they happen and verify their signature.
Webhooks POST a JSON event to your URL when something happens to your company's trees. Create endpoints in the Platform dashboard at Settings > Webhooks or through the API (webhooks:manage).
These are the outgoing webhooks of the Platform to your systems. The Platform itself receives its data from the WoodYouCare Foundation; every Foundation event that touches your company becomes one of the events below.
Events
The events follow the lifecycle of an allocation. Every payload is documented under Webhook events in the reference.
| Type | Sent when |
|---|---|
allocation.created | Trees were pledged to your company (the Foundation registered a donation) |
allocation.planted | The planting behind an allocation was done; the dossier has a date, polygon and species |
allocation.monitored | A first monitoring measurement was recorded for the planting of an allocation |
allocation.updated | The number of trees of an allocation changed, for example after a refund; data.previous holds the old value |
planting.updated | The proof dossier of a planting was extended: photos, species, notes or another monitoring measurement |
verification.published | A verification statement was published for a project of yours |
recipient.created | A recipient was created through the API, in the dashboard, by a gift code or by the Foundation |
recipient.claimed | A person claimed one of your gift codes and became a recipient |
certificate.created | A certificate was generated or regenerated |
Payload
{
"id": "whevt_01K...",
"object": "event",
"type": "allocation.planted",
"created": "2026-10-01T12:00:00Z",
"livemode": true,
"data": {
"object": { "id": "alloc_01K...", "object": "allocation", "status": "planted", "trees": 250 }
}
}data.object is the same object the matching GET endpoint returns. Personal data of recipients is only included when the endpoint was set up to receive it.
Verify the signature
Every request carries a WoodYouCare-Signature header:
WoodYouCare-Signature: t=1790000000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bdCompute an HMAC-SHA256 of {t}.{raw request body} with your endpoint's signing secret and compare it with v1. Reject requests where t is more than five minutes old.
import crypto from 'node:crypto';
export function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(',').map((part) => part.split('=')));
const expected = crypto.createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex');
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
return fresh && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}Delivery
- Answer with any 2xx status within 10 seconds. Do the real work afterwards, for example on a queue.
- Failed deliveries are retried for about a day with increasing delays.
- An endpoint that keeps failing for three days is switched off; its owners get an email.
- The same event can arrive more than once. Store
idand skip events you already processed. - Redirects are not followed, and endpoints must be public HTTPS URLs.
- Missed something?
GET /v2/eventslists the last 30 days with delivery status, andPOST /v2/events/{id}/redeliversends one again.