API reference
Event and webhook payloads
Every internal event is a JSON document validated against packages/contracts/events/<name>.v1.json (JSON Schema 2020-12) and published on NATS JetStream with the subject shown. Nats-Msg-Id carries the event id so redelivery is de-duplicated. The webhook envelope below wraps any of these for delivery to your own HTTP endpoints.
click
Subject: dt.click.created.v1. Schema: click.v1.json.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | ULID |
tenant_id | string | yes | |
ts | string (date-time) | yes | |
schema_version | integer | yes | |
click_id | string | yes | |
entities | object | yes | |
entities.offer_id | string | ||
entities.partner_id | string | ||
entities.advertiser_id | string | ||
entities.landing_page_id | string | ||
entities.creative_id | string | ||
entities.smartlink_id | string | ||
entities.offer_group_id | string | ||
entities.goal_id | string | ||
entities.tracking_domain_id | string | ||
entities.app_id | string | ||
params | object | sub1..sub15, p1..p15 aliases resolved to sub*, source, sub_source, creative, campaign_ext, adgroup, label, adv1..adv10, utm_*, platform click ids, custom | |
ip | string | ||
geo | object | ||
geo.country | string | ||
geo.region | string | ||
geo.city | string | ||
geo.postal | string | ||
geo.dma | string | ||
geo.isp | string | ||
geo.carrier | string | ||
geo.asn | string | ||
geo.connection_type | string | ||
device | object | ||
device.device_type | string | ||
device.brand | string | ||
device.model | string | ||
device.os | string | ||
device.os_version | string | ||
device.browser | string | ||
device.browser_version | string | ||
device.language | string | ||
device.user_agent | string | ||
flags | object | ||
flags.is_proxy | boolean | ||
flags.is_vpn | boolean | ||
flags.is_datacenter | boolean | ||
flags.is_tor | boolean | ||
flags.is_bot | boolean | ||
flags.is_unique | boolean | ||
flags.is_duplicate | boolean | ||
flags.is_invalid | boolean | ||
flags.is_test | boolean | ||
money | object | ||
money.payout | string | ||
money.revenue | string | ||
money.sale_amount | string | ||
money.cost | string | ||
money.currency | string | ||
money.fx_rate | string | ||
money.cost_currency | string | WP-80: currency of the cost the partner passed (cost_currency=); empty = currency | |
decision | object | ||
decision.redirect_mode | string | ||
decision.destination_url | string | ||
decision.invalid_reason | string: traffic_filter, traffic_control, already_converted, offer_expired, geotargeting, caps, caps_degraded, fraud, blocked_partner, bot, duplicate, offer_inactive, partner_inactive, other | ||
decision.fail_traffic_target_id | string | ||
decision.cap_state | string | ||
decision.matched_rule_ids | array of string | ||
fraud | object | ||
fraud.score | integer | ||
fraud.reasons | array of string | ||
fraud.rule_ids | array of string | ||
fraud.dry_run | boolean | every evaluation that scored the click came from a dry-run pack (log only): the score changes neither the click nor its conversions | |
link_style | string: native, numeric, trackier, everflow, tune, affise, cake, app, unilink | ||
referer | string | ||
click_domain | string | ||
session_id | string | ||
fingerprint_hash | string | ||
consent | object | ||
latency_ms | integer | ||
edge_region | string | ||
raw_query | string | ||
cost_status | string: accepted, not_permitted, invalid | WP-80: the click passed cost=: accepted (partner allowed to pass media cost), not_permitted (recorded, cost ignored) or invalid (not a non-negative amount) |
Minimal example:
{
"id": "01JABCDEF0123456789XYZ",
"tenant_id": "01JABCDEF0123456789XYZ",
"ts": "2026-01-15T10:30:00Z",
"schema_version": 1,
"click_id": "01JABCDEF0123456789XYZ",
"entities": {
"offer_id": "01JABCDEF0123456789XYZ",
"partner_id": "01JABCDEF0123456789XYZ",
"advertiser_id": "01JABCDEF0123456789XYZ",
"landing_page_id": "01JABCDEF0123456789XYZ",
"creative_id": "01JABCDEF0123456789XYZ",
"smartlink_id": "01JABCDEF0123456789XYZ",
"offer_group_id": "01JABCDEF0123456789XYZ",
"goal_id": "01JABCDEF0123456789XYZ",
"tracking_domain_id": "01JABCDEF0123456789XYZ",
"app_id": "01JABCDEF0123456789XYZ"
}
}
config_changed
Subject: dt.config.changed.v1. Schema: config_changed.v1.json.
NATS subject dt.config.changed.v1; edge reloads snapshot for tenant when version > held version
| Field | Type | Required | Description |
|---|---|---|---|
tenant_id | string | yes | |
version | integer | yes | |
changed_at | string (date-time) | yes | |
entity_type | string | ||
entity_id | string |
Minimal example:
{
"tenant_id": "01JABCDEF0123456789XYZ",
"version": 1,
"changed_at": "2026-01-15T10:30:00Z"
}
config_snapshot
Subject: HTTP snapshot document (not a subject). Schema: config_snapshot.v1.json.
Full per-tenant hot-path config pushed to edge-redirect/ingest; built by control-plane from Postgres rows (docs/04).
| Field | Type | Required | Description |
|---|---|---|---|
tenant_id | string | yes | |
version | integer | yes | |
generated_at | string (date-time) | yes | |
tenant | object | yes | |
tracking_domains | array of object | yes | |
advertisers | array of object | yes | |
partners | array of object | yes | |
partner_tiers | array of object | ||
offers | array of object | yes | |
traffic_controls | array of object | ||
lists | array of object | ||
postbacks | array of object | ||
fraud_rules | array of object | ||
smartlinks | array of object | WP-13 smartlinks with member offers (snapshot.Smartlink) | |
scoped_controls | array of object | WP-14 tenant-wide rule sets with scope_kind offer|geo (evaluated by the edge hook only) | |
caps | array of object | WP-14 caps not attached to an offer (partner, advertiser, goal, smartlink, tenant); snapshot.Cap | |
dayparts | array of object | WP-14 day-parting schedules (snapshot.Daypart) |
Minimal example:
{
"tenant_id": "01JABCDEF0123456789XYZ",
"version": 1,
"generated_at": "2026-01-15T10:30:00Z",
"tenant": {},
"tracking_domains": [
{}
],
"advertisers": [
{}
],
"partners": [
{}
],
"offers": [
{}
]
}
conversion_created
Subject: dt.conversion.created.v1. Schema: conversion_created.v1.json.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | ULID |
tenant_id | string | yes | |
ts | string (date-time) | yes | |
schema_version | integer | yes | |
conversion_id | string | yes | |
click_id | string | ||
impression_id | string | ||
txn_id | string | ||
order_id | string | ||
conversion_type | string: base, goal, event, upsell, rebill, refund, chargeback, adjustment | ||
goal_key | string | ||
entities | object | yes | |
entities.offer_id | string | ||
entities.partner_id | string | ||
entities.advertiser_id | string | ||
entities.landing_page_id | string | ||
entities.creative_id | string | ||
entities.smartlink_id | string | ||
entities.offer_group_id | string | ||
entities.goal_id | string | ||
entities.tracking_domain_id | string | ||
entities.app_id | string | ||
params | object | sub1..sub15, p1..p15 aliases resolved to sub*, source, sub_source, creative, campaign_ext, adgroup, label, adv1..adv10, utm_*, platform click ids, custom | |
click_ts | string (date-time) | ||
ctit_seconds | integer | ||
status | string: pending, approved, rejected, cancelled, extended, flagged, scrubbed | yes | |
status_reason | string | ||
status_source | string | ||
is_hidden_from_partner | boolean | ||
money | object | yes | |
money.payout | string | ||
money.revenue | string | ||
money.sale_amount | string | ||
money.cost | string | ||
money.currency | string | ||
money.fx_rate | string | ||
money.payout_tenant_ccy | string | WP-76: payout in the tenant's default currency at the rate in force on the conversion's UTC date (absent: no rate) | |
money.revenue_tenant_ccy | string | WP-76: revenue in the tenant's default currency (as payout_tenant_ccy) | |
payout_entry_id | string | ||
method | string: postback, pixel, iframe, js, sdk, s2s, coupon, manual, import | yes | |
attribution | object | ||
attribution.model | string | ||
attribution.touch | string: click, impression, coupon, probabilistic, skan, referrer, none | ||
attribution.confidence | number | ||
attribution.is_organic | boolean | ||
attribution.match | string | WP-80: the matching method (click_id, cookie, fingerprint, email, coupon, device, probabilistic, impression, txn_reuse) | |
ip | string | ||
click_ip | string | ||
geo | object | ||
geo.country | string | ||
geo.region | string | ||
geo.city | string | ||
geo.postal | string | ||
geo.dma | string | ||
geo.isp | string | ||
geo.carrier | string | ||
geo.asn | string | ||
geo.connection_type | string | ||
device | object | ||
device.device_type | string | ||
device.brand | string | ||
device.model | string | ||
device.os | string | ||
device.os_version | string | ||
device.browser | string | ||
device.browser_version | string | ||
device.language | string | ||
device.user_agent | string | ||
user_id | string | ||
email_hash | string | ||
coupon_code | string | ||
fraud | object | ||
raw_request | string | ||
is_test | boolean | ||
hold | object | WP-80: timed hold set by a conversion rule (status extended until release_at, then the hold scheduler sets then) | |
hold.rule_set_id | string | ||
hold.minutes | integer | ||
hold.release_at | string (date-time) | ||
hold.then | string: approved, rejected | ||
items | array of object | WP-80: SKU lines as priced; payout / revenue of the conversion are their sum when priced per SKU |
Minimal example:
{
"id": "01JABCDEF0123456789XYZ",
"tenant_id": "01JABCDEF0123456789XYZ",
"ts": "2026-01-15T10:30:00Z",
"schema_version": 1,
"conversion_id": "01JABCDEF0123456789XYZ",
"entities": {
"offer_id": "01JABCDEF0123456789XYZ",
"partner_id": "01JABCDEF0123456789XYZ",
"advertiser_id": "01JABCDEF0123456789XYZ",
"landing_page_id": "01JABCDEF0123456789XYZ",
"creative_id": "01JABCDEF0123456789XYZ",
"smartlink_id": "01JABCDEF0123456789XYZ",
"offer_group_id": "01JABCDEF0123456789XYZ",
"goal_id": "01JABCDEF0123456789XYZ",
"tracking_domain_id": "01JABCDEF0123456789XYZ",
"app_id": "01JABCDEF0123456789XYZ"
},
"status": "pending",
"money": {
"payout": "string",
"revenue": "string",
"sale_amount": "string",
"cost": "string",
"currency": "string",
"fx_rate": "string",
"payout_tenant_ccy": "string",
"revenue_tenant_ccy": "string"
},
"method": "postback"
}
conversion_status_changed
Subject: dt.conversion.status_changed.v1. Schema: conversion_status_changed.v1.json.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | ULID |
tenant_id | string | yes | |
ts | string (date-time) | yes | |
schema_version | integer | yes | |
conversion_id | string | yes | |
entities | object | ||
entities.offer_id | string | ||
entities.partner_id | string | ||
entities.advertiser_id | string | ||
entities.landing_page_id | string | ||
entities.creative_id | string | ||
entities.smartlink_id | string | ||
entities.offer_group_id | string | ||
entities.goal_id | string | ||
entities.tracking_domain_id | string | ||
entities.app_id | string | ||
from_status | string | yes | |
to_status | string | yes | |
reason | string | ||
actor_type | string | ||
actor_id | string | ||
payout_delta | string | ||
revenue_delta | string | ||
currency | string | ||
effective_at | string (date-time) | yes | original conversion time: the reporting period this change restates (equals conversion_ts); ts is when the change happened |
version | integer | yes | |
conversion_ts | string (date-time) | original conversion time (reporting period of the restatement) | |
click_id | string | ||
click_ts | string (date-time) | ||
money | object | absolute amounts after the change | |
money.payout | string | ||
money.revenue | string | ||
money.sale_amount | string | ||
money.currency | string | ||
money.payout_tenant_ccy | string | WP-76: payout in the tenant's default currency at the rate in force on the conversion's UTC date (absent: no rate) | |
money.revenue_tenant_ccy | string | WP-76: revenue in the tenant's default currency (as payout_tenant_ccy) | |
dims | object | denormalised dimensions so writers need no lookup | |
status_source | string |
Minimal example:
{
"id": "01JABCDEF0123456789XYZ",
"tenant_id": "01JABCDEF0123456789XYZ",
"ts": "2026-01-15T10:30:00Z",
"schema_version": 1,
"conversion_id": "01JABCDEF0123456789XYZ",
"from_status": "string",
"to_status": "string",
"effective_at": "2026-01-15T10:30:00Z",
"version": 1
}
impression
Subject: dt.impression.created.v1. Schema: impression.v1.json.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | ULID |
tenant_id | string | yes | |
ts | string (date-time) | yes | |
schema_version | integer | yes | |
impression_id | string | yes | |
entities | object | yes | |
entities.offer_id | string | ||
entities.partner_id | string | ||
entities.advertiser_id | string | ||
entities.landing_page_id | string | ||
entities.creative_id | string | ||
entities.smartlink_id | string | ||
entities.offer_group_id | string | ||
entities.goal_id | string | ||
entities.tracking_domain_id | string | ||
entities.app_id | string | ||
params | object | sub1..sub15, p1..p15 aliases resolved to sub*, source, sub_source, creative, campaign_ext, adgroup, label, adv1..adv10, utm_*, platform click ids, custom | |
ip | string | ||
geo | object | ||
geo.country | string | ||
geo.region | string | ||
geo.city | string | ||
geo.postal | string | ||
geo.dma | string | ||
geo.isp | string | ||
geo.carrier | string | ||
geo.asn | string | ||
geo.connection_type | string | ||
device | object | ||
device.device_type | string | ||
device.brand | string | ||
device.model | string | ||
device.os | string | ||
device.os_version | string | ||
device.browser | string | ||
device.browser_version | string | ||
device.language | string | ||
device.user_agent | string | ||
flags | object | ||
flags.is_proxy | boolean | ||
flags.is_vpn | boolean | ||
flags.is_datacenter | boolean | ||
flags.is_tor | boolean | ||
flags.is_bot | boolean | ||
flags.is_unique | boolean | ||
flags.is_duplicate | boolean | ||
flags.is_invalid | boolean | ||
flags.is_test | boolean | ||
is_viewable | boolean | ||
referer | string | ||
raw_query | string |
Minimal example:
{
"id": "01JABCDEF0123456789XYZ",
"tenant_id": "01JABCDEF0123456789XYZ",
"ts": "2026-01-15T10:30:00Z",
"schema_version": 1,
"impression_id": "01JABCDEF0123456789XYZ",
"entities": {
"offer_id": "01JABCDEF0123456789XYZ",
"partner_id": "01JABCDEF0123456789XYZ",
"advertiser_id": "01JABCDEF0123456789XYZ",
"landing_page_id": "01JABCDEF0123456789XYZ",
"creative_id": "01JABCDEF0123456789XYZ",
"smartlink_id": "01JABCDEF0123456789XYZ",
"offer_group_id": "01JABCDEF0123456789XYZ",
"goal_id": "01JABCDEF0123456789XYZ",
"tracking_domain_id": "01JABCDEF0123456789XYZ",
"app_id": "01JABCDEF0123456789XYZ"
}
}
mobile_event
Subject: dt.mobile.event.v1, dt.mobile.ad_revenue.v1. Schema: mobile_event.v1.json.
dt.mobile.event.v1 and dt.mobile.ad_revenue.v1 (event_name ad_revenue; network/ad_unit/placement/ad_type in params)
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | |
schema_version | integer | yes | |
tenant_id | string | yes | |
ts | string (date-time) | yes | |
event_id | string | yes | |
event_name | string | yes | |
app_id | string | yes | |
device_id | string | ||
install_id | string | ||
install_ts | string (date-time) | ||
days_since_install | integer | ||
session_id | string | ||
partner_id | string | ||
offer_id | string | ||
click_id | string | ||
is_attributed | boolean | ||
is_reengagement | boolean | ||
is_first | boolean | ||
revenue | string | yes | 6-dp decimal |
currency | string | yes | |
params | object | ||
partner_params | object | ||
device_ids | object | ||
customer_user_id | string | ||
platform | string | ||
os_version | string | ||
app_version | string | ||
sdk_version | string | ||
environment | string | ||
country | string | ||
ip | string | ||
validation_status | string | ||
consent | object | ||
third_party_sharing | boolean |
Minimal example:
{
"id": "01JABCDEF0123456789XYZ",
"schema_version": 1,
"tenant_id": "01JABCDEF0123456789XYZ",
"ts": "2026-01-15T10:30:00Z",
"event_id": "01JABCDEF0123456789XYZ",
"event_name": "string",
"app_id": "01JABCDEF0123456789XYZ",
"revenue": "string",
"currency": "string"
}
mobile_install
Subject: dt.mobile.install.v1. Schema: mobile_install.v1.json.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | |
schema_version | integer | yes | |
tenant_id | string | yes | |
ts | string (date-time) | yes | |
install_id | string | yes | |
app_id | string | yes | |
device_id | string | yes | |
kind | string: install, reinstall, reattribution, reengagement | yes | |
match_type | string: referrer, device_id, click_id, deep_link, san, preload, probabilistic, organic | yes | |
confidence | number | ||
partner_id | string | ||
offer_id | string | ||
advertiser_id | string | ||
click_id | string | ||
click_ts | string (date-time) | ||
san_network | string | ||
attribution_window | string | ||
is_organic | boolean | ||
is_reinstall | boolean | ||
is_reattribution | boolean | ||
is_reengagement | boolean | ||
first_install_ts | string (date-time) | ||
platform | string | ||
os_version | string | ||
app_version | string | ||
sdk_version | string | ||
environment | string: production, sandbox | ||
country | string | ||
ip | string | ||
att_status | string | ||
customer_user_id | string | ||
device_ids | object | ||
params | object | ||
consent | object | ||
third_party_sharing | boolean | ||
rejected | array of string |
Minimal example:
{
"id": "01JABCDEF0123456789XYZ",
"schema_version": 1,
"tenant_id": "01JABCDEF0123456789XYZ",
"ts": "2026-01-15T10:30:00Z",
"install_id": "01JABCDEF0123456789XYZ",
"app_id": "01JABCDEF0123456789XYZ",
"device_id": "01JABCDEF0123456789XYZ",
"kind": "install",
"match_type": "referrer"
}
mobile_session
Subject: dt.mobile.session.v1. Schema: mobile_session.v1.json.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | |
schema_version | integer | yes | |
tenant_id | string | yes | |
ts | string (date-time) | yes | |
session_id | string | yes | |
app_id | string | yes | |
device_id | string | yes | |
install_id | string | ||
install_ts | string (date-time) | ||
days_since_install | integer | ||
partner_id | string | ||
offer_id | string | ||
is_organic | boolean | ||
is_reengagement | boolean | ||
platform | string | ||
os_version | string | ||
app_version | string | ||
sdk_version | string | ||
environment | string | ||
country | string | ||
ip | string |
Minimal example:
{
"id": "01JABCDEF0123456789XYZ",
"schema_version": 1,
"tenant_id": "01JABCDEF0123456789XYZ",
"ts": "2026-01-15T10:30:00Z",
"session_id": "01JABCDEF0123456789XYZ",
"app_id": "01JABCDEF0123456789XYZ",
"device_id": "01JABCDEF0123456789XYZ"
}
mobile_skan_postback
Subject: dt.mobile.skan_postback.v1. Schema: mobile_skan_postback.v1.json.
WP-27: a received SKAdNetwork / AdAttributionKit postback after verification and conversion-value decode. events / revenue_estimate are empty for unverified postbacks.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | |
schema_version | integer | yes | |
tenant_id | string | yes | |
ts | string (date-time) | yes | |
app_id | string | yes | |
kind | string: skan, aak | yes | |
version | string | ||
ad_network_id | string | yes | |
transaction_id | string | yes | |
postback_sequence_index | integer | yes | |
source_identifier | string | ||
source_app_id | string | ||
source_domain | string | ||
fidelity_type | integer | ||
did_win | boolean | ||
redownload | boolean | ||
conversion_type | string | ||
fine_cv | integer | ||
coarse_cv | string: ``, low, medium, high | ||
country_code | string | ||
verified | boolean | yes | |
partner_id | string | ||
offer_id | string | ||
campaign | string | ||
schema_id | string | ||
events | array of string | yes | |
revenue_estimate | string | yes | |
currency | string | yes |
Minimal example:
{
"id": "01JABCDEF0123456789XYZ",
"schema_version": 1,
"tenant_id": "01JABCDEF0123456789XYZ",
"ts": "2026-01-15T10:30:00Z",
"app_id": "01JABCDEF0123456789XYZ",
"kind": "skan",
"ad_network_id": "01JABCDEF0123456789XYZ",
"transaction_id": "01JABCDEF0123456789XYZ",
"postback_sequence_index": 1,
"verified": false,
"events": [
"string"
],
"revenue_estimate": "string",
"currency": "string"
}
mobile_uninstall
Subject: dt.mobile.uninstall.v1. Schema: mobile_uninstall.v1.json.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | |
schema_version | integer | yes | |
tenant_id | string | yes | |
ts | string (date-time) | yes | |
app_id | string | yes | |
device_id | string | yes | |
install_id | string | ||
install_ts | string (date-time) | ||
partner_id | string | ||
offer_id | string | ||
is_organic | boolean | ||
platform | string | ||
source | string |
Minimal example:
{
"id": "01JABCDEF0123456789XYZ",
"schema_version": 1,
"tenant_id": "01JABCDEF0123456789XYZ",
"ts": "2026-01-15T10:30:00Z",
"app_id": "01JABCDEF0123456789XYZ",
"device_id": "01JABCDEF0123456789XYZ"
}
postback_result
Subject: dt.postback.result.v1. Schema: postback_result.v1.json.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | ULID |
tenant_id | string | yes | |
ts | string (date-time) | yes | |
schema_version | integer | yes | |
postback_id | string | yes | |
conversion_id | string | yes | |
partner_id | string | ||
url_resolved | string | ||
method | string | ||
request_headers | object | ||
request_body | string | ||
response_code | integer | ||
response_body | string | ||
latency_ms | integer | ||
attempt | integer | yes | |
error | string | ||
final | boolean | ||
next_retry_at | string (date-time) |
Minimal example:
{
"id": "01JABCDEF0123456789XYZ",
"tenant_id": "01JABCDEF0123456789XYZ",
"ts": "2026-01-15T10:30:00Z",
"schema_version": 1,
"postback_id": "01JABCDEF0123456789XYZ",
"conversion_id": "01JABCDEF0123456789XYZ",
"attempt": 1
}
webhook_envelope
Subject: External webhook delivery (HTTP POST). Schema: webhook_envelope.v1.json.
Delivered by HTTP POST to your webhook URL. Headers sent: X-Metrixed-Signature (t=<unix>,v1=<hex HMAC-SHA256 of t + "." + body>), X-Metrixed-Event, X-Metrixed-Delivery (attempt number) and, on manual replays, X-Metrixed-Replay. See webhooks.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | |
tenant_id | string | yes | |
event | string | yes | e.g. offer.updated, partner.created, partner_application.approved, conversion.created, conversion.status_changed, click.created, postback.failed, cap.reached, fraud.flagged, invoice.created, payout.executed |
created_at | string (date-time) | yes | |
api_version | string | ||
data | object | yes | |
previous | object |
Minimal example:
{
"id": "01JABCDEF0123456789XYZ",
"tenant_id": "01JABCDEF0123456789XYZ",
"event": "string",
"created_at": "2026-01-15T10:30:00Z",
"data": {}
}