Webhook Events#
This page documents the envelope shared by every webhook and the data payload of each event type. For delivery, signing, and retry behaviour see the Webhooks guide.
Event envelope#
Every webhook body is an envelope wrapping an event-specific data object:
event_idstringStable unique id of the event. Mirrors the X-Evolu-Event-Id header — deduplicate on it.
event_typestringThe event type — entry.received, entry.completed, or entry.evaluated.
campaign_idstring<uuid>The campaign the event belongs to.
created_atstring<date-time>ISO 8601 timestamp of when the event was generated.
livemodebooleantrue for production data, false for entries created with a test-mode key.
api_versionstringThe webhook schema version, e.g. 2026-04-30.
requestobjectCorrelation context — { "idempotency_key": "..." }, echoing the key from the original entry submission.
dataobjectThe event-specific payload — documented per event below.
entry.received
Dispatched immediately after an entry is accepted for asynchronous processing — a delivery confirmation ("pong"). An entry rejected at submission is not processed asynchronously (its rejection is returned synchronously in the 202 response), so it does not receive an entry.received event.
{ "event_id": "evt_entry_received_01905a3b7c8d7f00a1b2c3d4e5f6a7b8", "event_type": "entry.received", "campaign_id": "0190559e-1f00-7a00-bc00-1a2b3c4d5e6f", "created_at": "2026-04-30T14:30:01Z", "livemode": true, "api_version": "2026-04-30", "request": { "idempotency_key": "550e8400-e29b-41d4-a716-446655440000" }, "data": { "entry_id": "01905a3b-7c8d-7f00-a1b2-c3d4e5f6a7b8", "enrollment_id": "0190559e-aa00-7a00-bc00-1a2b3c4d5e6f", "status": "PENDING" }}data.entry_idstring<uuid>The accepted entry.
data.enrollment_idstring<uuid>The participant's campaign enrollment.
data.statusstringThe entry status at acceptance time — typically PENDING.
entry.completed
Dispatched once fiscal validation and fraud checks finish. The entry has reached a terminal processing state.
{ "event_type": "entry.completed", "data": { "entry_id": "01905a3b-7c8d-7f00-a1b2-c3d4e5f6a7b8", "enrollment_id": "0190559e-aa00-7a00-bc00-1a2b3c4d5e6f", "status": "REJECTED", "reason_code": "NOT_ELIGIBLE" }}data.statusstringAPPROVED or REJECTED.
data.reason_codestring | nullA machine-readable rejection reason when status is REJECTED; null otherwise.
entry.evaluated
Dispatched after the campaign's mechanics are evaluated. Carries one item per evaluated mechanic, with its proposed outcome.
{ "event_type": "entry.evaluated", "data": { "entry_id": "01905a3b-7c8d-7f00-a1b2-c3d4e5f6a7b8", "enrollment_id": "0190559e-aa00-7a00-bc00-1a2b3c4d5e6f", "mechanics": [ { "mechanic_id": "0190559e-cc00-7a00-bc00-1a2b3c4d5e6f", "mechanic_type": "lucky_numbers", "status": "APPROVED", "reason_code": null, "outcome": { "quantity": 2, "series_count": 10, "numbers": [ { "series": "0", "order_number": "12345" }, { "series": "1", "order_number": "67890" } ] } } ] }}The lucky_numbers outcome above is from a campaign in automatic generation mode — Evolu generated the numbers and ships them in outcome.numbers. A manual-mode campaign omits numbers and you generate them yourself:
{ "mechanic_type": "lucky_numbers", "status": "APPROVED", "outcome": { "quantity": 5, "series_count": 10 }}data.mechanicsarrayOne entry per evaluated mechanic.
data.mechanics[].mechanic_typestringThe mechanic type. API-channel entries are evaluated against lucky_numbers and instant_prize.
data.mechanics[].statusstringAPPROVED or REJECTED for that mechanic.
data.mechanics[].outcomeobjectThe proposed outcome, specific to the mechanic.
lucky_numbers— always carries{ "quantity": N, "series_count": S }: how many lucky numbers the participant qualified for, and the campaign's series range (validseriesvalues are0toS - 1). In automatic generation mode it additionally carriesnumbers— the numbers Evolu generated (see below). In manual modenumbersis absent and you generate them yourself.instant_prize— for a win,{ "won": true, "prize_definition_id": "…", "prize_name": "…", "award_status": "AWARDED" }; for a declared loss,{ "won": false }. This echoes the win you registered, confirmed once the entry passed processing.
data.mechanics[].outcome.numbersarrayAutomatic generation mode only. The lucky numbers Evolu generated and assigned to the participant, ordered by (series, order_number). Empty when none were assigned (e.g. the mechanic was rejected). Each item is { "series": "0", "order_number": "12345" } — the series (a non-negative integer string, 0 to series_count - 1) and the order_number (a 5-digit string). These are the participant's official numbers; there is nothing to submit back.
Lucky numbers — automatic vs. manual generation
The lucky-numbers outcome depends on the campaign's generation mode:
- Automatic — Evolu generates the numbers during evaluation and delivers them in
outcome.numbers. Persist them; there is nothing to submit back. - Manual — Evolu computes the qualified
quantitybut does not generate the numbers. Useoutcome.quantityandoutcome.series_countto generate them, then submit them via the Lucky Numbers endpoint.