Webhooks
Send every new enquiry and show-round booking from Toddly to Zapier, Make or your own system as a signed POST. Part of Pro.
Last updated 14 November 2026
A webhook sends each event to an address you choose, the moment it happens, so a new enquiry can land in your spreadsheet, CRM or nursery management system without anyone copying it across.
Events
| Type | When |
|---|---|
enquiry.created |
A parent sends an enquiry, visit request or callback request |
visit.booked |
A show-round is booked: by the parent into one of your times, or by you from the enquiry page |
visit.moved |
The parent moves their show-round to another time |
visit.cancelled |
The show-round is cancelled, by the parent or by you |
test |
You press “Send test event” |
Set it up
- In your dashboard open Settings, then Webhook.
- Paste the https address your tool gives you and press Save.
- Copy the signing secret we show you. It is shown once only; you can make a new one at any time.
- Press Send test event. The last delivery and its result show under the address.
Only public https addresses are accepted: no IP addresses, no ports other than 443, nothing on a private network. Redirects are not followed.
Zapier
- Create a Zap and choose Webhooks by Zapier as the trigger, with the event Catch Hook.
- Copy the webhook URL Zapier shows and paste it into Toddly under Settings, Webhook.
- Press Send test event in Toddly, then Test trigger in Zapier. Zapier now knows the fields: map
data.enquiry.parent_name,data.enquiry.parent_emailand the rest into your next step.
Make
- Create a scenario and add the Webhooks module Custom webhook. Press Add and copy the address Make creates.
- Paste it into Toddly under Settings, Webhook.
- Press Send test event in Toddly while Make is listening, so it learns the data structure.
What we send
Each event is a POST with a JSON body:
{
"id": "evt_6f1c9a0d2b7e4c3a8f5e1d20",
"type": "enquiry.created",
"created": 1789466400,
"nursery_id": "eng-ey490982",
"data": {
"enquiry": {
"id": 1234,
"type": "visit",
"child_age_months": 20,
"start": "2027-01",
"days": ["mon", "wed"],
"message": "Could we look round on a Tuesday morning?",
"parent_name": "Sam Jones",
"parent_email": "[email protected]",
"parent_phone": "+447700900123",
"visit_at": "2026-11-17T10:00:00Z",
"link": "https://toddly.co.uk/dash/eng-ey490982/enquiries/1234"
},
"visit": {
"id": 56,
"starts_at": "2026-11-17T10:00:00Z",
"status": "booked"
}
}
}
visitis there onvisit.*events;visit.movedaddsprevious_starts_at.startis a month (2027-01),asapornot_sure. Times carry their UK offset. A field the parent left out is left out or empty, never a guess.idis the same on every retry of one event: use it to ignore a repeat.
The body holds the same details as your enquiry email. Your nursery is the controller of them once they reach you, and the tools you send them to work for you.
Check the signature
Every request has a header:
X-Webhook-Signature: t=1789466400,v1=5f2b…
v1 is the HMAC-SHA256 of the text t, a full stop and the raw request body, keyed with your signing secret, in hex. Recompute it, compare in constant time, and refuse a t more than five minutes old.
const crypto = require("crypto");
function verified(header, rawBody, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const want = crypto.createHmac("sha256", secret).update(parts.t + "." + rawBody).digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
return fresh && want.length === parts.v1.length &&
crypto.timingSafeEqual(Buffer.from(want), Buffer.from(parts.v1));
}
import hashlib, hmac, time
def verified(header: str, raw_body: bytes, secret: str) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
want = hmac.new(secret.encode(), parts["t"].encode() + b"." + raw_body, hashlib.sha256).hexdigest()
fresh = abs(time.time() - int(parts["t"])) < 300
return fresh and hmac.compare_digest(want, parts["v1"])
Zapier’s and Make’s catch hooks do not check signatures; the address they give you is long and unguessable, so keep it private.
Delivery
- Answer with any
2xxstatus within 5 seconds. We do not read your response body. - Anything else, a redirect or no answer is a failure. We try again after 1, 4, 16, 64 and 256 minutes, six tries in all.
- After 20 failed deliveries in a row the webhook switches off and your team gets an email. Fix the address and send a test event to switch it back on.
Frequently asked questions
Which plan has webhooks?
Pro, and the 14-day Pro trial. On Free nothing is sent.
Do I still get enquiry emails?
Yes. The webhook is an extra copy for your other tools. Enquiries still reach you by email and in your dashboard.
What happens if my endpoint is down?
We try again over about six hours. After 20 failed deliveries in a row we switch the webhook off and email your team; a successful test event switches it back on.