Webhook event reference

Field-by-field reference for webhook payloads: core vs enrichment fields, bucket semantics, the routing rule, and the PII posture.

Webhook event reference

This page is the field contract for webhook payloads. For subscription management, signature verification, delivery semantics, and per-event JSON examples, see Webhooks.

Every payload has two layers:

  • Core — the envelope plus data.subject_ref, data.account_ref, and the moment, lifecycle, commerce, and attribution objects. Stable within an apiVersion (currently 2026-07). Code against these.
  • Enrichment — the data.enrichment object, derived from the intent graph. Every field is optional and degrades to "unknown" or absent. Never let a receiver depend on one.

The routing rule

Enrichment and moment parameters are routing and segmentation inputs. They must never appear in copy a customer reads.

These fields exist so your automation can pick the right sequence, timing, and owner — not so your emails can narrate them back to the user.

  • Good: the subject hit a seat cap, so your automation routes them into the seats sequence — whose copy you wrote for people who need more seats.
  • Bad: pasting wall_key or a bucket name into a sentence a customer reads (“You hit seats.limit and your conversion likelihood is high, so…”).

The good version uses the field to choose the message. The bad version leaks internal machinery into the message, reads as surveillance, and breaks the moment it degrades to "unknown". If a value can be "unknown", it was never safe to put in a sentence.


Envelope fields (core)

FieldTypeNullableDescription
apiVersionstringnoEnvelope version, currently "2026-07". Breaking changes ship under a new version.
eventstringnoEvent type — one of the 19 in the table below.
webhookIdstringnoevt_<uuid>. Stable across retries; deduplicate on it.
timestampstring (ISO 8601)noWhen the moment occurred — not when the delivery was attempted.

data — subject fields (core)

FieldTypeNullableDescription
data.subject_refstringnoPseudonymous reference to the end user (e.g. u_8f3a...), minted by your SDK integration. Resolvable only by you.
data.account_refstringyesPseudonymous reference to the account/organization (acct_...), or null when there is no account context.

data.moment (core)

Always present. Describes where in the flow the moment happened. Every field is nullable — events outside a wall context (for example trial.started) carry mostly nulls here.

FieldTypeNullableDescription
wall_event_idstringyesIdentifier of the underlying wall event, when the moment originated at a wall.
wall_keystringyesWhich wall — your configured key, e.g. seats.limit, exports.monthly.
actionstringyesWhat the orchestration did at the moment, e.g. upgrade_offer, guidance, fallback_offer, admin_request, sales_route.
trigger_classstringyesThe class of trigger, e.g. free_tier_limit, trial_gate, usage_wall, feature_gate.
moment_typeenumyespre_gate, at_gate, or post_value.
reason_codestringyesMachine-readable reason for the moment, e.g. quota_exhausted, offer_declined.
agent_environmentstringyesThe agent host where the moment happened, when known.

data.lifecycle (core)

Always present. The subject’s subscription lifecycle at the time of the moment.

FieldTypeNullableDescription
stateenumnofree, trial, active, converted, or unknown. Degrades to "unknown" rather than blocking delivery.
trial_ends_atstring (ISO 8601)yesTrial end date; null outside a trial.
trial_days_remainingnumberyesWhole days remaining; null outside a trial.
usage_remaining_bucketenumnonone, low, some, or unknown. See bucket semantics.

data.commerce (core — conversion.* events only)

Present only on conversion.trial_converted, conversion.upgrade_accepted, and conversion.entitlement_resumed. Absent — not null — on every other event. Individual fields may be null when not applicable to the transaction.

FieldTypeNullableDescription
plan_keystringyesThe plan involved in the conversion, e.g. growth_monthly.
amount_centsnumberyesTransaction amount in minor units.
currencystringyesISO 4217 currency code, lowercase, e.g. usd.
branchstringyesWhich conversion path produced it, e.g. acquisition (free/trial to paid) vs expansion (paid to bigger).
railstringyesHow the conversion completed, e.g. in_thread.

data.enrichment (every field optional)

Derived from the intent graph. Any field can be "unknown", null, or absent on any delivery — enrichment never delays or blocks delivery.

FieldTypeValuesDescription
intent_stateenumresearching, deciding, purchasing, converted, churned, unknownWhere the subject sits in their journey.
conversion_likelihoodenumlow, medium, high, unknownBucketed likelihood score. See bucket semantics.
journey_momentumenumadvancing, stalled, retreating, unknownDirection of travel across recent interactions.
journey_depthnumber03How deep into the journey the subject is.
is_returningbooleantrue / falseWhether the subject has been seen before.
ai_providerstringThe AI provider behind the agent, when known.

data.attribution (core)

FieldTypeNullableDescription
paramsstringnoReady-made query string to append to campaign links, e.g. utm_source=inception_moment&utm_campaign=trial.expiring.

Bucket semantics

Enrichment ships buckets rather than raw scores — buckets are stable to route on, and they make the degradation behavior explicit.

conversion_likelihood buckets an internal 0–100 score:

BucketScore
lowbelow 35
medium35 to below 70
high70 and above
unknownnot enough signal to score

usage_remaining_bucket describes headroom on the subject’s current entitlements:

BucketMeaning
noneat or over the limit
lowclose to the limit
somecomfortable headroom
unknownusage signal unavailable

Degradation. Every enrichment field degrades to "unknown" (or is absent) rather than blocking or delaying delivery. A delivery never waits on the intent graph. Treat "unknown" as its own routing branch — usually “take the default path” — not as an error.


Per-event reference

All 19 events carry the full core envelope. The table below shows what varies: whether the moment object is meaningfully populated, whether commerce is present, and the fields most receivers route on.

Eventmoment populatedcommerceFields to watch
moment.wall_hityesabsentwall_key, trigger_class, moment_type, conversion_likelihood
moment.upgrade_offeredyesabsentwall_key, action
moment.guidance_offeredyesabsentwall_key, moment_type (typically pre_gate)
moment.free_tier_reachedyesabsentwall_key, usage_remaining_bucket (typically none)
moment.post_value_offeredyesabsentmoment_type (post_value), journey_momentum
moment.upgrade_abandonedyesabsentwall_key, reason_code, journey_momentum
moment.fallback_acceptedyesabsentwall_key, action
moment.admin_upgrade_requestedyesabsentaccount_ref, wall_key
moment.sales_route_capturedyesabsentaccount_ref, conversion_likelihood
moment.blocker_reportedyesabsentwall_key, reason_code
trial.startedmostly nullabsentlifecycle.trial_ends_at, trial_days_remaining
trial.activatedmostly nullabsentlifecycle.trial_days_remaining, journey_depth
trial.expiringmostly nullabsenttrial_days_remaining, usage_remaining_bucket, intent_state
trial.expiredmostly nullabsentlifecycle.state, trial_ends_at
conversion.trial_convertedmostly nullpresentcommerce.plan_key, branch, amount_cents
conversion.upgrade_acceptedmostly nullpresentcommerce.plan_key, branch, account_ref
conversion.entitlement_resumedmostly nullpresentcommerce.plan_key
value.deliveredpartialabsentmoment_type (post_value), journey_momentum
subject.activation_reachedmostly nullabsentlifecycle.state, journey_depth

“Mostly null” means the moment object is present (core is stable) but its nullable fields typically carry nulls, because the event did not originate at a wall. Write receivers accordingly: check for null on every moment field, on every event.

Per-event JSON examples with realistic values are in the event catalog.


PII posture

Webhook payloads contain no emails and no names — ever. There is no field for them in any event, and none will be added within this apiVersion.

The subject_ref contract:

  • Refs are minted by your SDK integration (your getSubjectRef), not by Inception. Inception stores and forwards the ref as an opaque string.
  • Refs are stable per user, so they work as join keys in your warehouse and as custom properties in your email platform or CRM.
  • Only you can resolve a ref back to a person. A leaked payload identifies no one to anyone who is not already holding your user database.

account_ref follows the same contract at the account/organization level.

Practical implication: any workflow that ends in an email being sent must pass through something you control — a receiver or a pre-synced ref-to-contact mapping — to translate the ref. The standard patterns are in Trigger email campaigns from Revenue Moments.