Webhooks
Receive signed HTTP notifications when bookings, payments and catalogue items change.
Webhooks let Localoy tell your server when something happens — a customer books, a payment settles, a
catalogue item changes — instead of your server asking. Each notification is an HTTPS POST with a JSON
body, signed so you can prove it came from Localoy.
Set up an endpoint#
In the Partner Portal, open Open Network → Webhooks and add an endpoint:
| Setting | Detail |
|---|---|
| URL | Where Localoy sends events. See the requirements below. |
| Environment | SANDBOX or PRODUCTION. An endpoint receives only its environment's events. |
| Events | The event types to send it. |
Each endpoint gets its own signing secret, starting whsec_. You can reveal it again and rotate it
from the portal. Rotation takes effect immediately — see
Rotating the secret.
You can have up to 10 endpoints. The same URL cannot be added twice in one environment.
URL requirements#
Localoy checks the URL when you save it and before every delivery:
- It must use
https. - It must not contain a username, password or
#fragment, and must be at most 2,048 characters. - It must resolve only to public IP addresses — not private, loopback, link-local or similar ranges.
- It must not use port 22, 23, 25, 445, 3306, 5432, 6379, 9200, 11211 or 27017.
Receive an event#
POST /webhooks/localoy HTTP/1.1
Host: api.example.com
Content-Type: application/json
User-Agent: Localoy-Webhooks/1.0
X-Localoy-Signature: t=1790410530,v1=5b1f0c9e…
X-Localoy-Event-Id: evt_mfz3k2a1Xq9vT0bLm3Rk
X-Localoy-Event-Type: booking.created
X-Localoy-Delivery-Attempt: 1
X-Localoy-Webhook-Id: cm6wh00k0000000000000001
X-Localoy-Delivery-Id: cm6d3l1v3ry00000000000001
{"id":"evt_mfz3k2a1Xq9vT0bLm3Rk","event":"booking.created","occurredAt":"2026-09-26T08:15:30.123Z",…}Your endpoint should:
- Verify the signature against the raw body.
- Skip the event if you have already processed its
X-Localoy-Event-Id. - Answer with any
2xxstatus within 10 seconds, then do slow work in the background.
- Localoy → Your endpoint: POST event + X-Localoy-Signature
- Your endpoint → Your endpoint: Verify signature and timestamp
- Your endpoint → Your endpoint: Seen this event ID? Then skip
- Your endpoint → Your job queue: Enqueue the event
- Your endpoint → Localoy: 200 OK — within 10 s
- Your job queue → Your job queue: Process: update your records
| Header | Meaning |
|---|---|
X-Localoy-Signature | t={unix seconds},v1={hex HMAC-SHA256}. |
X-Localoy-Event-Id | The event's ID. The same on every retry and replay — use it to de-duplicate. |
X-Localoy-Event-Type | The event type, such as booking.created. |
X-Localoy-Delivery-Attempt | 1 on the first try, then 2, 3… on retries. |
X-Localoy-Webhook-Id | Which of your endpoints this is. |
X-Localoy-Delivery-Id | This delivery. A replay from the portal gets a new delivery ID but keeps the event ID. |
Test your endpoint#
Press Test next to an endpoint in the portal. Localoy sends a signed ping event to it, whatever
events it subscribes to — even while it is disabled.
{
"id": "evt_mfz3k9c4Lw2pY7aHn0Qe",
"event": "ping",
"occurredAt": "2026-09-26T08:15:30.123Z",
"environment": "sandbox",
"partnerId": "cm1partnerid000000000000001",
"data": {
"message": "This is a test event from Localoy. Your receiver is reachable and this signature was produced by your endpoint's current signing secret.",
"endpointId": "cm6wh00k0000000000000001"
}
}