Event reference
Every event type, which webhooks and functions receive it, and the fields in its data.
Webhook subscriptions and platform event functions choose from the same event types. Copy names exactly as written here: a misspelt custom event saves without complaint and never fires.
How to read the event tables
Each family table has a Webhooks and a Functions column. Each cell says what that subscription picker offers and whether the event arrives:
| In the column | What it means |
|---|---|
| A bold label, such as Won | The picker lists it under that label, and it is sent |
| Custom event | It is sent, but the picker doesn't list it: add it with Add custom |
| Never sent | The picker lists it, but the platform never sends it. Leave it out |
| Refused | A subscription that names it won't save |
| Never fires | It saves as a custom event, but never reaches a function |
Functions add their own trigger rules: see How platform events are delivered.
A delivered request
Here, Lindenhall's CRM receives a reward.won.v1 event. The headers are explained in About webhooks.
POST /omnilab/events HTTP/1.1
Host: crm.lindenhall.example
Content-Type: application/json
User-Agent: OmniLab-Webhook/1.0
webhook-id: msg_6abe2823c1e5b2a9d4f81c3e:callbacks/3bb6d5ca-a587-4a81-84e0-7e200394b9c5
webhook-timestamp: 1790847012
webhook-signature: v1,LXEWQrcmsEQBYnyp+6wy9chTD7GQPMTbAiWHF5IaSIE=The body is a CloudEvents document: the event's identity at the top, its details in data. It is formatted here for reading. The real body is one line of compact JSON, and the signature covers those exact bytes.
{
"specversion": "1.0",
"id": "6abe2823c1e5b2a9d4f81c3e",
"type": "reward.won.v1",
"subject": "d96c390f-5753-441c-baa3-0689a8c83716",
"time": "2026-10-01T09:30:11.482Z",
"datacontenttype": "application/json",
"tenantid": "tenants/1e3f8137-9ea4-4d99-a7be-023d88c4f8c1",
"data": {
"contact": {
"contact_id": "contacts/922eb227-f65a-4998-b116-a53edaf0d325",
"unique_visitor_id": "e1bcce15-7972-4afc-bd6d-871ca666b7d0",
"external_contact_id": "LH-0042817"
},
"tenant_context": {
"subdomain": "lindenhall"
},
"group_context": {
"group_id": "groups/6946c01f-8542-471c-9e2f-dac2661027c6",
"unique_key": "lindenhall-riverside"
},
"interaction": {
"interaction_id": "interactions/6cc002c6-2be1-412c-ac0d-c5d16a8c7cc6",
"interaction_display_name": "Autumn Prize Draw",
"interaction_public_key": "autumn-prize-draw"
},
"web_context": {
"utm": { "source": "instagram", "medium": "social" },
"user_agent": {
"os": "iOS",
"device": "iPhone",
"is_mobile": true,
"is_desktop": false,
"is_tablet": false,
"is_bot": false
}
},
"reward_id": "d96c390f-5753-441c-baa3-0689a8c83716",
"internal_reward_id": "rewards/42101441-81cd-45c9-bca0-993039133359",
"reward_display_name": "£10 food court voucher",
"reward_winning_method": "FIRST_COME_FIRST_SERVE",
"coupon_code_id": "coupons/3bb6d5ca-a587-4a81-84e0-7e200394b9c5",
"coupon_code_value": "LH10-7QK2"
}
}A few top-level attributes that only identify the sender are left out above. Empty fields are often omitted. Read every field as optional, and ignore the ones you don't use.
A function receives the same type, id, time, source and data, without the headers: see PlatformEvent.
Fields most events share
Besides its own fields, data carries context blocks:
| Block | Fields | Carried by |
|---|---|---|
contact | contact_id, unique_visitor_id, external_contact_id, custom_fields | Every event. contact_id is empty for an anonymous visitor. Booking, ticket, check-in and submission events fill contact_id only. Smart Link events fill unique_visitor_id only. |
tenant_context | subdomain | Every event |
group_context | group_id, and unique_key on campaign events | Every event |
interaction | interaction_id, interaction_display_name, interaction_public_key, interaction_snapshot_id, session_id, visit_id | Campaign events: the touchpoint, reward, contact and other families |
web_context | utm (campaign, source, medium, term, content), user_agent (os, device, raw, is_mobile, is_desktop, is_tablet, is_bot), referrer, query_params | Campaign events. Smart Link events carry utm, user_agent, referrer, url and an ip_address whose last part is zeroed. |
No block carries the contact's email or name. A function reads them with OmniLab.Contact.get(data.contact.contact_id).
How filters match
A webhook subscription filter compares one value in the event with the value you enter, exactly.
| Filter key | Matches when | Value format |
|---|---|---|
group_id | data.group_context.group_id equals the value. A parent organisation's ID doesn't match its children's events. | groups/<id>, as in a delivery you've received |
tenant_id | The top-level tenantid equals the value. Every event of your account carries the same one, so this filter narrows nothing. | tenantid from a delivery you've received |
interaction_id | No event matches it today. Campaign events nest the campaign in data.interaction, where the filter doesn't look. Booking events don't carry it. | Leave this filter out |
To receive one campaign only, filter in your receiver on data.interaction.interaction_public_key. Function subscriptions have their own filter keys: see Narrow a subscription with filters.
Touchpoint events
| Event type | When it fires | Webhooks | Functions |
|---|---|---|---|
touchpoint.page_visit.v1 | A touchpoint page is viewed | Page visit | Refused |
touchpoint.started.v1 | A touchpoint session starts | Started | Started |
touchpoint.participated.v1 | A participant enters the experience | Participated | Participated |
touchpoint.participation_form_filled.v1 | A participation form is submitted | Participation form filled | Participation form filled |
touchpoint.completed.v1 | A touchpoint session completes | Completed | Completed |
touchpoint.terms_accepted.v1 | Terms or consent are accepted | Terms accepted | Terms accepted |
cta.clicked.v1 | A configured call-to-action button is selected | CTA clicked | CTA clicked |
| Event type | Adds to data |
|---|---|
touchpoint.page_visit.v1, touchpoint.started.v1, touchpoint.participated.v1, touchpoint.completed.v1 | touchpoint_id, touchpoint_title, touchpoint_type, interactive_totem_type, instant_game_type, event_id |
touchpoint.participation_form_filled.v1 | The fields above, plus form_level, form_frequency, form_schema_id, and submitted_data: one field_id, field_label, field_type and value per answer |
touchpoint.terms_accepted.v1 | term_and_condition_text, terms_and_conditions_accepted_at, terms_and_conditions_uri, opt_in_level, collectible_id, collectible_title |
cta.clicked.v1 | cta_label, cta_url |
Reward events
| Event type | When it fires | Webhooks | Functions |
|---|---|---|---|
reward.eligible.v1 | A participant becomes eligible for a reward | Eligible | Eligible |
reward.won.v1 | A participant wins a reward | Won | Won |
reward.lost.v1 | A participant doesn't win a reward | Lost | Lost |
reward.redeemed.v1 | A won reward is redeemed | Redeemed | Redeemed |
reward.temporary_won.v1 | A temporary win is recorded | Temporary won | Temporary won |
reward.temporary_lost.v1 | A temporary loss is recorded | Temporary lost | Temporary lost |
reward.temporary_blocked.v1 | A temporary reward state is blocked | Temporary blocked | Temporary blocked |
reward.expired.v1 | Never: the picker label Expired has no event behind it | Never sent | Never sent |
| Event type | Adds to data |
|---|---|
| Every reward event | reward_id, internal_reward_id, reward_display_name, reward_winning_method |
reward.won.v1, reward.temporary_won.v1 | The reward fields, plus coupon_code_id, coupon_code_value and reward_time_id |
reward.redeemed.v1 | The reward fields, plus coupon_code_id and coupon_code_value |
Contact and other events
Both pickers list these under Contact and Other.
| Event type | When it fires | Webhooks | Functions |
|---|---|---|---|
contact.created.v1 | A new contact is created | Created | Created |
contact.identified.v1 | An anonymous visitor is linked to a known contact | Identified | Identified |
contact.authenticated.v1 | A contact signs in | Authenticated | Authenticated |
notification.sent.v1 | A notification is sent to a participant | Notification sent | Notification sent |
feedback.submitted.v1 | Feedback or a satisfaction rating is submitted | Feedback submitted | Feedback submitted |
question.answered.v1 | A question or quiz answer is submitted | Question answered | Question answered |
| Event type | Adds to data |
|---|---|
contact.created.v1 | contact_id, touchpoint_id, touchpoint_title, touchpoint_type, event_id, game_id |
contact.identified.v1, contact.authenticated.v1 | The contact.created.v1 fields, plus identification_type (SIGN_UP or LOGIN) and identification_timestamp |
notification.sent.v1 | notification_event_type, notification_by_type, touchpoint_id, touchpoint_title |
feedback.submitted.v1 | rating, comment |
question.answered.v1 | question, question_answer |
Booking, ticket and attendance events
The webhook picker lists these under Booking & Ticket and Participation.
| Event type | When it fires | Webhooks | Functions |
|---|---|---|---|
booking.created.v1 | A booking is created | Booking created | Custom event |
booking.deleted.v1 | A booking is deleted | Booking deleted | Custom event |
ticket.confirmed.v1 | A ticket is confirmed | Ticket confirmed | Custom event |
ticket.canceled.v1 | A confirmed ticket is cancelled | Ticket canceled | Custom event |
ticket.waitlisted.v1 | A participant joins the waitlist | Ticket waitlisted | Custom event |
ticket.deleted.v1 | A ticket is deleted | Ticket deleted | Custom event |
participation.checked_in.v1 | A participant is checked in to an activity | Checked in | Custom event |
participation.deleted.v1 | A participation record is deleted | Custom event | Custom event |
In these events, event_id and event_name name the bookable activity, not the platform event.
| Event type | Adds to data |
|---|---|
booking.created.v1 | booking_id, event_id, event_name, tickets_number, reserver_id, host_id, ticket_type_id, ticket_type_display_name, slot_start_date, slot_end_date, booked_at |
ticket.confirmed.v1, ticket.canceled.v1, ticket.waitlisted.v1 | ticket_id, booking_id, event_id, event_name, host_id, ticket_type_id, ticket_type_display_name, slot_start_date, slot_end_date, then ticket_confirmed_at, ticket_canceled_at or ticket_waitlisted_at |
participation.checked_in.v1 | participation_id, ticket_id, event_id, event_name, ticket_type_id, ticket_type_display_name, check_in_method (SELF or SCAN), slot_start_date, slot_end_date, check_in_time |
booking.deleted.v1 | booking_id, event_id, reserver_id, deleted_at, deletion_user |
ticket.deleted.v1 | ticket_id, booking_id, event_id, contact_id, deleted_at, deletion_user |
participation.deleted.v1 | participation_id, ticket_id, event_id, contact_id, deleted_at, deletion_user |
{
"booking_id": "2394d604-afcc-4f7f-98c1-ef3676c20d6b",
"event_id": "8f1c2a47-3b9e-4d6a-9c05-71e2b4d8a913",
"event_name": "VIP styling session",
"tickets_number": 2,
"reserver_id": "contacts/922eb227-f65a-4998-b116-a53edaf0d325",
"host_id": "host_K7m2Qx9",
"ticket_type_id": "ticket_5d0e9b3c-6f1a-4c2e-8a7d-2b9f4e6c1a08",
"ticket_type_display_name": "VIP",
"slot_start_date": "2026-05-03T14:00:00Z",
"slot_end_date": "2026-05-03T14:30:00Z",
"booked_at": "2026-04-26T09:15:00Z"
}Receipt submission events
| Event type | When it fires | Webhooks | Functions |
|---|---|---|---|
submission.created.v1 | A receipt submission is created | Custom event | Custom event |
submission.status_changed.v1 | A submission changes validation or review status | Custom event | Custom event |
submission.amended.v1 | A submission is amended | Custom event | Custom event |
submission.replaced.v1 | One submission replaces another | Custom event | Custom event |
| Event type | Adds to data |
|---|---|
| Every submission event | submission_id, session_id, game_id, player_id, game_name |
submission.created.v1 | validation_mode, merchant_name, amount, currency, receipt_date, duplicate_reference_id, is_resubmission, original_submission_id, submitted_at |
submission.status_changed.v1 | previous_status, new_status, trigger_source (ocr, policy_auto or operator_action), reason, changed_at |
submission.amended.v1 | amended_fields, merchant_name, amount, currency, amended_at |
submission.replaced.v1 | new_submission_id, replaced_at |
Smart Link events
| Event type | When it fires | Webhooks | Functions |
|---|---|---|---|
smartlink.redirected.v1 | A Smart Link redirects a visitor | Custom event | Never fires |
It adds smart_link_id, slug, title, destination_url, redirection_status, variant_id, variant_name and variant_variables to data. It identifies the visitor, never a contact, so it can't trigger a function.
Event group types
The webhook picker's Event group lists six types the platform never sends. A subscription to them saves, but nothing arrives, so leave them out:
event.created.v1,event.deleted.v1andevent.type.updated.v1event.availability.updated.v1,event.slot.reached_capacity.v1andevent.fully_booked.v1
Choosing events for analytics
Feeding a warehouse or a BI tool? Teams most often subscribe a webhook to these:
touchpoint.page_visit.v1touchpoint.participated.v1touchpoint.completed.v1reward.won.v1reward.redeemed.v1smartlink.redirected.v1
Subscribe only to what the destination reads. A filtered subscription costs nothing, while an unwanted delivery still costs you a request.