Reference

Event catalog.

Every event onpack emits, with the exact payload your endpoint will receive. Subscribe to any combination when you register an endpoint.

scan.processed

The headline event. Fires for every production scan with the full outcome of what happened — the scan itself, who it's tied to, and which promotion was evaluated (if any), with its result.

Fires when: a shopper scans a production QR and the scan flow resolves. Also fires when a previously-anonymous scan is retroactively credited to a new signup within 15 minutes — the payload carries retroactive_credit: true in that case. Silent on within-window dedupes.

Eligibility outcomes you'll see in eligibility[].outcome:

OutcomeMeaning
wonEntered and won a reward. reward is populated.
lostEntered but didn't draw a reward. reward is null.
bundle_in_progressCollect-all bundle — this scan counted, more SKUs needed.
needs_termsLive promotion with unaccepted T&Cs — scanner must accept to enter.
not_signed_inA live promotion applied, but the scanner wasn't signed in to enter.
JSON
{
  "id": "4b0e…c912",
  "event": "scan.processed",
  "occurred_at": "2026-04-23T15:04:12Z",
  "brand": { "id": 1, "slug": "milka", "name": "Milka", "prefix": "MK" },
  "data": {
    "scan": {
      "id": 184293,
      "unit": { "id": 9102, "code": "MK-CHO-260412-7HGQ2" },
      "sku":  { "id": 31, "name": "Milka Alpine Milk 100g", "prefix": "MK-CHO" },
      "batch_id": 22,
      "country": "DE", "city": "Berlin",
      "device_type": "mobile",
      "scanned_at": "2026-04-23T15:04:12Z",
      "retroactive_credit": false
    },
    "collector": { "id": 55821, "identified": true },
    "points_awarded": 10,
    "eligibility": [
      {
        "activation": { "id": 8, "name": "Spring Instant Win", "activation_type": "instant_win" },
        "outcome": "won",
        "entry_id": 71284,
        "reward": { "id": 44, "name": "5€ voucher", "reward_type": "coupon", "tier": "standard", "face_value": 5.0 },
        "bundle_progress": null
      }
    ]
  }
}

activation.entered

Fires for every production promotion entry — wins and losses. Use this when you want honest funnel data, not just the winners.

JSON
{
  "event": "activation.entered",
  "occurred_at": "2026-04-23T15:04:12Z",
  "brand": { "id": 1, "slug": "milka", "name": "Milka", "prefix": "MK" },
  "data": {
    "activation_entry": { "id": 71284, "outcome": "lost" },
    "activation":       { "id": 8, "name": "Spring Instant Win", "activation_type": "instant_win" },
    "reward":           null,
    "consumer":         { "id": 55821 },
    "scan":             { "id": 184293 },
    "unit":             { "id": 9102, "code": "MK-CHO-260412-7HGQ2" },
    "sku":              { "id": 31, "name": "Milka Alpine Milk 100g", "prefix": "MK-CHO" }
  }
}

activation.win

Convenience event — strict subset of activation.entered that only fires on wins. Same payload shape. Subscribe to this if you want a simpler "someone won something" trigger without filtering on the consumer side.

reward.redeemed

Fires when a collector redeems a reward at point-of-fulfilment. Includes the redemption status, reward details, consumer id, and any onpack fees involved.

batch.generated

Fires when a batch of unit codes finishes generating — codes are now printable. batch.export_ready fires shortly after with checksum and row count when the downloadable file is available.

webhook.test

A synthetic event triggered by the Send Test button in the dashboard. Useful for verifying signature handling before subscribing to real traffic.

Subscribing

Webhook endpoints are registered from Settings → Developers → Webhooks in your brand dashboard. Each endpoint subscribes to a specific set of events — you can opt into all, some, or one.