Instant-Win Integration#
This guide describes how an external partner integrates an instant-win promotion with Evolu through the headless Integrators API.
Model: who decides the win?#
Evolu's instant-prize mechanic can run in two modes:
| Mode | Who decides the winner | This guide |
|---|---|---|
WINDOW | Evolu draws via time-gated prize windows. | — |
INTEGRATOR_DECLARED | The integrator decides wins externally and registers them in Evolu via the API. | ✅ |
In INTEGRATOR_DECLARED mode the partner runs the entire instant-win logic on their side. Evolu is a compliance ledger: it records each entry, the declared win, the prize, and the lifecycle webhooks — but it never decides who wins.
Prerequisites#
Before integrating, the campaign operator must, in Evolu Studio:
- Set the instant-prize mechanic to integrator-declared mode.
- Register the prizes in the campaign's prize pool. Every win you register references a prize by its
prize_definition_id— prizes must exist beforehand. - Enable the campaign for the API channel and issue you an API key (live + test).
The happy path#
The integrator creates an entry with the win included in the payload, then waits for Evolu's webhooks as the entry is processed and evaluated.
Step 1 — Create the entry with the win#
POST /v1/entries with the participant enrollment, LGPD consent, the fiscal evidence, and an instant_win block carrying the outcome you decided:
{ "enrollment": { "...": "..." }, "consent": { "...": "..." }, "evidence": { "...": "..." }, "instant_win": { "won": true, "prize_definition_id": "0190559e-cc00-7a00-bc00-1a2b3c4d5e6f" }}For a participant who did not win, send "instant_win": { "won": false }. Evolu replies 202 Accepted with an entry_id; the entry is PENDING and processed asynchronously. The declared win is held and confirmed later, during evaluation.
To discover valid prize_definition_id values, call GET /v1/prizes — it lists the campaign's pool (scoped to your key's mode) with each prize's remaining current_stock.
Step 2 — React to the webhooks#
Evolu delivers lifecycle webhooks (HMAC-signed) to your configured endpoint:
| Event | When | Meaning |
|---|---|---|
entry.received | Immediately, for accepted entries | The entry is being processed. |
entry.completed | After the entry phase | The entry is APPROVED or REJECTED. |
entry.evaluated | After the evaluation phase (only if approved) | Carries the confirmed instant-win outcome. |
Outcomes#
What you receive depends on whether the entry survives processing and whether you declared a win.
A win only stands if the entry is approved
If the entry is rejected during processing (e.g. an invalid fiscal key, fraud), the declared win is voided and you only receive entry.completed with status: REJECTED — there is no entry.evaluated.
The entry.evaluated payload#
For an approved entry, entry.evaluated echoes the win back so your system can reconcile:
{ "event_type": "entry.evaluated", "data": { "entry_id": "01905a3b-7c8d-7f00-a1b2-c3d4e5f6a7b8", "enrollment_id": "0190559e-aa00-7a00-bc00-1a2b3c4d5e6f", "mechanics": [ { "mechanic_type": "instant_prize", "status": "APPROVED", "outcome": { "won": true, "prize_definition_id": "0190559e-cc00-7a00-bc00-1a2b3c4d5e6f", "prize_name": "R$ 50 Voucher", "award_status": "AWARDED" } } ] }}For a declared loss, status is REJECTED and outcome is { "won": false }.
The award lifecycle#
Corrections: revoke & reassign#
Both correction endpoints are synchronous — they return 200 with the new state and do not emit a webhook (you initiated the change, so you already know the result).
Revoke#
POST /v1/entries/{entry_id}/instant-prize/revoke — marks the award revoked and returns its unit to the prize pool. Use it when a win must be cancelled (e.g. fraud found after the fact).
Reassign#
POST /v1/entries/{entry_id}/instant-prize/reassign — atomically revokes a win and re-registers it:
- Same entry, different prize — omit
target_entry_id; only the prize changes. - Move to another entry — set
target_entry_id. The target entry must belong to the same campaign and have finished processing (beAPPROVED).
Endpoint reference#
| Endpoint | Purpose |
|---|---|
GET /v1/prizes | List the campaign's prize pool + remaining stock. |
POST /v1/entries | Create the entry, with the win in the instant_win block. |
POST /v1/entries/{entry_id}/instant-prize/revoke | Revoke a win. |
POST /v1/entries/{entry_id}/instant-prize/reassign | Move a win to another entry / prize. |
All endpoints require the Authorization: Bearer <api_key> header. The full request and response schemas are in the Instant Prize and Entries references.
Rules & edge cases#
- The win is part of the entry. It is declared in the
instant_winblock ofPOST /v1/entries— recorded atomically with the entry, so there is no submit-timing race. There is no separate "submit win" endpoint. - Prizes are pre-registered.
prize_definition_idmust reference a prize already in the campaign's pool (seeGET /v1/prizes). Unknown prizes are rejected with422. - Test vs live. The API key's mode (test/live) is the entry's mode. A test-mode key can only act on test-mode entries — and sees only test-mode prizes.
- Prize stock.
GET /v1/prizesreportscurrent_stock. A confirmed win decrements it; a revoke or reassign returns the unit. Evolu records the integrator's decision — it does not block a win when the pool is empty, socurrent_stockmay reach zero. - Losses are optional but supported.
"instant_win": { "won": false }produces anentry.evaluatedwithinstant_prizeREJECTED— useful for explicit confirmation of non-winning entries. Omitinstant_winentirely and the entry simply has noinstant_prizemechanic inentry.evaluated.