Webhooks
Beta: You can register webhooks today. Loby starts sending webhook events soon. The format on these pages won't change, so you can build and test your endpoint now.
A webhook is a URL on your server that Loby sends an HTTPS POST to when something changes in your museum, for example when a membership is created. Each request carries one webhook event as JSON, signed so you can check that it comes from Loby.
A webhook event is the notification itself. It has nothing to do with the Event object, which is an exhibition or a program.
How it works
- Create a webhook with Create Webhook: your URL and the event types you want.
- Store the
secretfrom the response. It is only shown this once. - When something changes, Loby sends a webhook event to every enabled webhook that lists its type. Changes from every source count: online checkout, the till, the back office and your own API calls.
- Verify the signature, answer with a
2xxstatus, then do your work.
curl https://api.loby.io/v1/webhooks \ -H "Authorization: Bearer $LOBY_API_KEY" \ -H "content-type: application/json" \ -d '{ "url": "https://example.com/loby/webhooks", "eventTypes": ["membership.created", "membership.updated", "membership.deleted"] }'
The webhook event
{ "id": "5f0c3a8e-6d2b-4c1e-9a7f-2b8d4e6f1a3c", "type": "membership.created", "createdAt": "2026-11-03T10:15:42.123Z", "testMode": false, "data": { "object": { "id": "bd4a0997-39db-41d9-883a-cdfa83e2101f", "createdAt": "2026-11-03T10:15:41.870Z", "updatedAt": "2026-11-03T10:15:41.870Z", "validFrom": "2026-11-03", "validTo": "2027-11-03", "active": true, "autoRenew": true, "autoRenewed": false, "previousMembershipId": null, "renewal": false, "customerId": "8f14e45f-ceea-467a-9b5e-1d3c2a4b6e7f", "secondaryCustomerId": null, "order": { "id": "f0a52c7e-9e04-4bb4-bd38-1bb88e1dd0e4", "salesChannelType": "WEB" }, "extensions": [], "membershipType": { "id": "0c1de555-6f74-4a83-91b0-0f6594306ac1", "title": "Yearly", "cycle": "YEARLY", "price": 54000, "origin": "WEB" } } } }
| Property | Type | Description |
|---|---|---|
id | string (UUIDv4) | Unique identifier of the webhook event. The same as the webhook-id header, and the same on every retry |
type | string | The event type |
createdAt | string | Timestamp when the change happened |
testMode | boolean | Whether the change happened in test mode |
data.object | object | The object that changed, as the API returns it. For membership.* event types it is a Membership |
Headers
| Header | Description |
|---|---|
webhook-id | The webhook event's id |
webhook-timestamp | When this attempt was sent, in seconds since the Unix epoch |
webhook-signature | The signature of this attempt. See Verifying Signatures |
content-type | application/json |
Responding
Answer with a 2xx status within 10 seconds, before any slow work: put the webhook event on a queue and process it from there. Loby ignores the response body.
Any other answer is a failed delivery: a 3xx (redirects are not followed), 4xx or 5xx status, a timeout, or a connection or TLS error.
Retries
A failed delivery is sent again with the same webhook-id and body, and a new webhook-timestamp and signature:
| Attempt | Wait after the attempt before |
|---|---|
| 1 | None |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 6 hours |
| 7 | 12 hours |
| 8 | 24 hours |
| 9 | 24 hours |
When the 9th attempt fails, about 3 days after the first, Loby gives up on that webhook event for that webhook. To catch up after a longer outage, read what you missed with the API, for example with List Memberships.
Duplicates and order
- The same webhook event can arrive more than once. Use
webhook-idto skip the ones you have already handled. - Webhook events don't arrive in the order the changes happened. When you need the current state, fetch it, for example with Get Membership.
Test mode
A webhook has the mode of the API key that created it. A webhook created with a test mode key receives only test mode webhook events (testMode: true), and only test mode keys see it. To try the whole flow, create a webhook with a test mode key and sell a membership while the back office or the checkout runs in test mode.
Turning off and deleting
- Set
enabledtofalsewith Update Webhook to stop new webhook events. Nothing is kept for later while a webhook is off. - Delete Webhook stops it for good, including retries that are still waiting.
- A webhook belongs to your museum, not to the API key that created it: deleting the key doesn't stop the webhook.
Changing the secret
Create a new webhook with the same URL and event types, let your endpoint accept both secrets, then delete the old webhook. While both exist, every webhook event arrives twice with the same webhook-id, so you skip the second one.