Lelemon
  • Get started
  • Use cases
  • Guides
  • API basics
  • Webhooks
  • SDK, CLI and MCP
  • API reference
  • Changelog
  • v1 (legacy)
Receive eventsVerify signaturesEvent catalog
powered by Zudoku
Webhooks

Receive events

You will

Register an endpoint, answer fast and handle retries.

You need

  • A key with webhooks:write
  • A public https URL that answers 2xx

1. Register an endpoint

enabledEvents takes types from the event catalog, or "*" for all. The response includes secret, shown only once. scope is self for the events of this organization or customers for the events of its subaccounts. An organization can have up to 16 endpoints, enabled or not, because every event goes to each one that listens to it. The next one answers 422 webhook_endpoint_limit: delete one you no longer use, or add event types to one that already exists.

2. Test it

POST /v2/webhook-endpoints/{id}/test sends a signed webhook_endpoint.test event to that endpoint only.

3. Answer fast

Respond 2xx as soon as you have stored the event, and do the work afterwards. Any other answer, or no answer, is retried.

Each event is an envelope:

customerId is present when the event belongs to a subaccount. The data shape depends on type.

Eventobject, 7 fields
  • objectenumrequired

    event

  • idstringrequired

    Example evt_3PqA0x8bVw1TqS9mYp3RkL

  • typestringrequired

    The event type, such as case.escalated. See GET /v2/event-types.

  • createdAtstring (date-time)required
  • organizationIdstringrequired

    Example org_7Hc2LmQ0x8bVw1TqS9mYp3

  • customerIdstringoptional

    The subaccount the event belongs to, when there is one.

    Example sub_7Hc2LmQ0x8bVw1TqS9mYp3

  • dataobjectrequired

    The shape depends on `type`. See GET /v2/event-types.

Retries

LelemonYour endpointPOST event evt_...Lelemon-Signature: t=...,v1=...1Verify v1 on the raw bodyand t within 5 minutes2503, not a 2xx3Wait 5 s, then 5 min, 30 min, 2 h, 5 h, 10 h4POST the same evt_...new Lelemon-Delivery-Id5200stored first, worked on later6After attempt 12: exhausted72 h with no success: endpoint disabled7
Answer 2xx fast. Anything else, or no answer, is retried with growing waits, and the same event id comes back every time.
  1. Lelemon sends the event with Lelemon-Signature and a Lelemon-Delivery-Id. The v1 value is an HMAC-SHA256 of t, a dot and the raw body.
  2. Your endpoint checks the signature against the raw body and rejects a t more than 5 minutes from its clock.
  3. Any answer that is not 2xx, or no answer, counts as a failure.
  4. Lelemon waits and tries again, up to 12 attempts in all.
  5. The event id stays the same on every attempt and the Lelemon-Delivery-Id changes. Deduplicate by the evt_ id.
  6. Your endpoint stores the event, answers 2xx and does the work afterwards. The delivery is done.
  7. After the last attempt the delivery is exhausted. An endpoint with no successful delivery for 72 hours becomes disabled and Lelemon sends an email.
AttemptWait before it
25 seconds
35 minutes
430 minutes
52 hours
65 hours
7 to 1210 hours each

After the last attempt the delivery is exhausted. If an endpoint has no successful delivery for 72 hours, it becomes disabled and Lelemon sends an email.

Events can arrive twice and out of order. Deduplicate by the evt_ id and compare createdAt. Each attempt carries a Lelemon-Delivery-Id header, a whd_ id that changes per attempt while the event id stays the same. It is the id of that attempt in GET /v2/webhook-endpoints/{id}/deliveries, so you can match what you received with what Lelemon recorded.

Inspect and replay

  • GET /v2/webhook-endpoints/{id}/deliveries lists the attempts of an endpoint.
  • POST /v2/events/{id}/resend sends an event again, to one endpoint with endpointId or to every subscribed endpoint.

Events and their delivery attempts are kept for 30 days. After that, an event can no longer be resent (404) and its attempts leave the list. An event that is still being retried or was resent within the last 30 days stays until that window passes.

Local development

Local URLs are rejected unless the API runs with NODE_ENV=development or test and LELEMON_ALLOW_LOCAL_WEBHOOKS=true. Then localhost, 127.0.0.1 and ::1 are accepted. No other private range is. Elsewhere, expose your machine with a tunnel.

Verify signatures
On this page
  • 1. Register an endpoint
  • 2. Test it
  • 3. Answer fast
  • Retries
  • Inspect and replay
  • Local development
curl https://api.lelemon.cl/v2/webhook-endpoints \ -H "Authorization: Bearer $LELEMON_API_KEY" \ -H "Idempotency-Key: webhook-main" \ --json '{ "url": "https://example.com/lelemon", "enabledEvents": ["message.created", "case.control_changed", "case.escalated"] }'
{ "object": "event", "id": "evt_...", "type": "message.created", "createdAt": "2026-10-29T14:10:42.000Z", "organizationId": "org_...", "customerId": "sub_...", "data": {} }