Skip to main content
Omneo fires webhooks when events occur in the platform, a transaction is created, a profile is updated, a tier is achieved. Configure a webhook endpoint to receive these events and react in your own system.

What is a webhook?

An Omneo webhook is an HTTP POST from Omneo to a URL you provide. The request body is the Event Context for the triggering event, a richer payload than the standard API response, including aggregations, flattened tags, and related objects.

Configuring a webhook

Webhooks are configured in Omneo CX Manager under Settings > Webhooks, or via the Webhooks API. Each webhook subscribes one URL to one trigger event.
FieldRequiredDescription
Trigger typeYesThe event that fires the webhook, for example profile.updated
URLYesThe endpoint Omneo POSTs to. Each trigger and URL combination must be unique
NamespaceYesIdentifies the integration that owns the webhook. Events caused by the API token matching this namespace are not delivered back to it, which prevents update loops
QueueNoDelivery priority: high, default, or low. Invalid values fall back to low
ConditionNoA JSON Logic rule evaluated against the event context. The webhook only fires when the rule returns true. See Conditions
Extra data templateNoA Twig template that adds fields to the payload before delivery. See Extra data template
Webhooks deliver the raw event context for a trigger. If you need a custom-shaped payload fired from a Reaction, use a Target instead. See Webhooks vs Targets for when to use each.

Webhook events

EventFires when
profile.createdA new profile is created
profile.updatedA profile is updated
transaction.createdA transaction is recorded
transaction.updatedA transaction is updated
benefit.issuedA benefit is issued to a profile
benefit.redeemedA benefit is redeemed
reward.issuedA reward is issued
reward.redeemedA reward is redeemed
points.awardedPoints are awarded
tier.achievedA profile achieves a new tier
achievement.progressedAn achievement is incremented

Conditions

A Condition is a JSON Logic rule attached to a webhook. Before Omneo queues a delivery, it evaluates the condition against the Event Context for the triggering event. The webhook is only sent when the condition returns true. Conditions run before delivery, so they reduce traffic at the source. Use them instead of receiving every event and discarding the ones you do not need in your own endpoint. Conditions fail closed. If a condition returns false, or evaluation throws an error (for example a malformed rule), the webhook is not sent. The same JSON Logic syntax used in Reaction filters applies here. The { "var": "field" } expression reads a value from the event context, using dot notation for nested fields.

Filtering by event source

Every event context includes a requested_by object describing the API token that caused the event:
{
  "requested_by": {
    "id": 42,
    "user_id": 42,
    "token": "pos-sync",
    "host": "[tenant].api.omneo.io"
  }
}
The token field is the name of the API token that made the request. Use it to skip events caused by a specific integration. For example, to stop a webhook firing for updates made by a token named pos-sync:
{ "!==": [{ "var": "requested_by.token" }, "pos-sync"] }
Or to only deliver events caused by your e-commerce integration:
{ "===": [{ "var": "requested_by.token" }, "shopify-integration"] }
requested_by can be null for events generated by internal platform processes rather than an API request. Provide a default value when comparing so the rule still evaluates:
{ "!==": [{ "var": ["requested_by.token", ""] }, "pos-sync"] }
The webhook namespace already excludes one source automatically: events caused by the API token whose name matches the namespace are never delivered to that webhook. Use a condition when you need to filter sources other than your own.

Filtering by profile data

Any field in the event context can drive a condition. For profile events, profile fields sit at the root of the context. Only fire when the profile is in the gold tier:
{ "===": [{ "var": "tier_handle" }, "gold"] }
Only fire for profiles tagged vip with more than $1,000 spend in the last 12 months:
{
  "and": [
    { "in": ["vip", { "var": "flattened_tags" }] },
    { ">": [{ "var": "aggregations.spend_12m" }, 1000] }
  ]
}
Only fire when email marketing consent is on:
{ "===": [{ "var": "attributes.comms.email_promo" }, true] }
For transaction events, the profile is nested under profile, so the paths become profile.tier_handle, profile.flattened_tags, and so on. See Event Contexts for the fields available per event type.

Extended operators

Webhook conditions support all standard JSON Logic operators plus Omneo extensions. The most useful for filtering:
OperatorArgumentsReturns true when
not_in[value, array]The value is not in the array. On a string, checks the substring is absent
non_empty_array[array]The array has at least one element
array_length[array, operator, number]The array length satisfies the comparison, for example [{"var": "items"}, ">=", 2]
array_has_key_value[key, value, data]Any object in the data, searched recursively, has the key with exactly that value
number_equal[left, right]Both values are numerically equal, tolerating string-formatted numbers
date_filter[value, operator, num, unit]The date compares true against now plus the offset. Operator is a comparison such as lt or gte, unit is days, weeks, months, or years
compare_dates[value, compareValue, operator, num, unit]The first date compares true against the second date plus the offset
String helpers to_lower and to_upper normalise values before comparison, for example matching an email domain case-insensitively. For the complete list including date and value helpers, see Extended operators.

Extra data template

An Extra data template is a Twig template attached to a webhook. When the webhook fires, Omneo renders the template with the full event context as variables, parses the output as JSON, and merges the resulting fields into the top level of the payload before delivery. Use it to enrich the payload with computed or static fields so the receiving system does not need to derive them:
{
  "source_system": "omneo",
  "full_name": "{{ first_name }} {{ last_name }}",
  "is_vip": {{ tier_handle == 'gold' ? 'true' : 'false' }},
  "spend_12m": {{ aggregations.spend_12m|default(0) }}
}
For a profile.updated event, the delivered payload is the profile event context plus these four extra fields at the root.

Template rules

  • The rendered output must be a valid JSON object. Anything else, including a bare value or malformed JSON, aborts the delivery.
  • Extra fields merge at the top level of the payload. A template key that matches an existing context key overrides it.
  • All event context fields are available as Twig variables, with the same paths as conditions: tier_handle, aggregations.spend_12m, profile.email on transaction events, and so on.
  • Quote string values in the template output. Leave numbers and booleans unquoted.
  • Omneo strips newlines from the rendered output before parsing, so do not rely on multi-line string values.
  • Use the default filter for fields that can be absent, for example {{ aggregations.spend_12m|default(0) }}, so a missing value does not produce invalid JSON.
If the template fails to render or produces invalid JSON, the webhook is not sent at all. Test templates against a real event context before relying on them in production.

Example: routing hints for a comms platform

A template can precompute routing decisions so the receiver stays simple:
{
  "list_id": "{{ tier_handle == 'gold' or tier_handle == 'platinum' ? 'vip-list' : 'standard-list' }}",
  "consent": {
    "email": {{ attributes.comms.email_promo ? 'true' : 'false' }},
    "sms": {{ attributes.comms.sms_promo ? 'true' : 'false' }}
  }
}

Delivery behaviour

  • Profile webhooks (profile.created, profile.updated) are not dispatched for incomplete profiles (is_completed is 0) or for profiles with a system profile type.
  • Webhooks are never delivered back to the integration that caused the event when the requester’s API token name matches the webhook namespace.
  • Deliveries are queued by priority (high, then default, then low).
  • The condition is evaluated before the delivery is queued. The extra data template is rendered at send time.
  • Each event is delivered once. Omneo does not retry failed deliveries, so reconcile against the API to catch events your endpoint missed, for example by polling Browse transactions with an updated_at filter.

Processing a webhook

Your endpoint should:
  1. Respond with 200 OK quickly, process asynchronously if needed
  2. Validate the payload structure matches your expected event context
  3. Identify the profile via the id field in the context
  4. Take the appropriate action in your system

Example: Transaction webhook context

{
  "id": "txn-uuid",
  "profile_id": "profile-uuid",
  "total": 149.95,
  "transacted_at": "2025-06-15 14:32:00",
  "profile": {
    "id": "profile-uuid",
    "first_name": "Jane",
    "last_name": "Smith",
    "email": "jane@example.com",
    "tier_handle": "gold",
    "aggregations": {
      "spend_12m": 2450.00,
      "shop_count": 14
    }
  }
}