# Payload Reference

The payload has the same shape for every event and every platform.

Keys marked always sent arrive on every event — when they do not apply they come empty (`""`, `0`, `[]`, `{}`, `null`) rather than missing, so you can read them without existence checks. The only exception is the order lines, where a few keys may be absent entirely; those are marked in place.

## Complete Reference[​](#Complete-Reference "Direct link to Complete Reference")

**event** object always sent

info

What happened, when, and what it was worth.

**name** string

info

What happened. A standard DATA Reshape event name — `checkout_completed`, `product_viewed`, `lead_created`, `order_canceled` and so on. The full vocabulary is the [Events Reference](/events.md).

```
name: "checkout_completed"
```

Two things to settle before you switch on this field

**You receive only the events enabled for your account, not all of them.** Which ones are delivered is configured per account. An event you never see is not necessarily missing — it may simply not be enabled. Agree the list with us rather than inferring it from traffic.

**The name can be customised.** By default it is the standard name above, but it can be mapped to a name of your choosing, agreed at setup — useful when your system already has its own vocabulary. If a custom name was agreed, that is what arrives.

So: switch on `event.name`, but write the switch against the list you agreed, and let an unrecognised name fall through to a default branch instead of throwing. The list can grow.

**id** string

info

Id from the source platform — order number, lead id. `""` when there is none.

```
id: "13195238211910"
```

**unique\_id** string

info

Unique id of this instance, and the recommended idempotency key. Present on orders and leads, `""` elsewhere.

When the platform provides no id, we send a generated one, unique per page load — it does not guarantee deduplication. Use `deduplication_id` in that case.

```
unique_id: "13195238211910"
```

**deduplication\_id** string

info

Present on **every** event, so it is the idempotency key for those without a `unique_id`.

It is derived: on orders and leads it contains `unique_id`, so the two are not independent — do not treat them as separate keys. Elsewhere it is built from the event time and the page load, so it is stable for the same event resent, and different between two visits.

```
deduplication_id: "idx13195238211910"
```

tip

Both identifiers are **opaque**: compare them, do not parse them. The format may change.

**timestamp** int

info

When the event happened, ms Unix UTC.

```
timestamp: 1786202400000
```

**value** number

info

Total value including tax, in `currency`. Includes shipping and other components as the shop declares them. `0` on events without a value.

```
value: 164.99
```

**currency** string

info

ISO 4217, three letters.

```
currency: "RON"
```

**exchange\_rate** number

info

Rate declared by the platform when the order currency differs from the base one. `1` otherwise.

```
exchange_rate: 1
```

**reason** string | null

info

Why the event happened — a cancellation or disqualification reason. Webhook routes only; `null` elsewhere.

```
reason: "out_of_stock"
```

**properties** object

info

The shop's own attributes, exactly as the source sends them. See [properties](#properties).

```
properties: { gift_wrap: ["yes"] }
```

**context** object always sent

info

The page, the device and the route the event arrived on.

**url** string

info

The page where the event happened.

```
url: "https://shop.example/checkout"
```

**referrer\_url** string

info

The referring page. `""` on direct access, or when the referrer is not relevant for attribution.

```
referrer_url: "https://www.google.com/"
```

**landing\_url** string

info

First page of the current visit, with its campaign parameters.

```
landing_url: "https://shop.example/lp?utm_source=facebook"
```

**timestamp** int

info

Page load time, ms Unix UTC. Shared by every event from the same load, unlike `event.timestamp`.

```
timestamp: 1786202390000
```

**last\_ad\_source** string

info

The most recent paid source. `""` when there is none.

```
last_ad_source: "facebook"
```

**integration** string

info

The route the data arrived on: `browser`, `webhook <platform>`, or both joined by `|` when the same event was seen on both and merged.

```
integration: "browser|webhook merchantpro"
```

**data\_source** string

info

Business origin: `website`, `admin`, `phone`, `app`, or a label of the shop's own.

```
data_source: "website"
```

**script\_id** string

info

Identifier of the shop configuration, 8 characters.

```
script_id: "YOURSCR1"
```

**page\_type** string

info

Page type: `home`, `product`, `category`, `checkout`.

```
page_type: "checkout"
```

**has\_adblocker** int

info

`1` if an ad blocker was detected, `0` otherwise.

```
has_adblocker: 0
```

**nav\_type** string

info

How the visitor got to this page.

| value          | meaning                                                  |
| -------------- | -------------------------------------------------------- |
| `navigate`     | a normal navigation — a link, or the address typed       |
| `reload`       | the page was reloaded                                    |
| `back_forward` | the browser's back or forward button                     |
| `prerender`    | the page was preloaded by the browser before being shown |
| `other`        | a navigation type the browser reports but we do not name |
| `unavailable`  | the browser did not report one                           |
| `error`        | the browser API failed when we asked                     |

The first four are the [Performance API navigation types](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming/type), reported as the browser names them.

```
nav_type: "navigate"
```

**screen** string

info

Screen resolution, `"width x height"`.

```
screen: "360x780"
```

**user\_agent** string

info

The raw browser User-Agent.

```
user_agent: "Mozilla/5.0 (Linux; Android 14) Chrome/151.0.0.0 Mobile"
```

**device\_type** string

info

`mobile`, `desktop`, `tablet`, `unknown`.

```
device_type: "mobile"
```

**browser\_name** string

info

Browser parsed from the User-Agent. `other` when it cannot be determined.

```
browser_name: "chrome"
```

**browser\_version** string

info

Browser version. `""` when it cannot be determined.

```
browser_version: "151.0.0.0"
```

**operating\_system** string

info

Operating system parsed from the User-Agent.

```
operating_system: "android"
```

**operating\_system\_version** string

info

Operating system version.

```
operating_system_version: "14"
```

**browser\_app** string

info

The app the page opened in, when that is certain — `facebook`, `instagram`. `no_app` otherwise.

```
browser_app: "no_app"
```

**browser\_language** string

info

Browser language.

```
browser_language: "ro-RO"
```

**visitor\_ip\_address** string

info

The visitor IP address.

```
visitor_ip_address: "86.122.24.187"
```

**visitor\_ip\_country** string

info

Country derived from the IP, ISO 3166-1 alpha-2. Describes **where the request came from**, which can differ from the address on the order in `user.country`.

```
visitor_ip_country: "RO"
```

**visitor\_ip\_city** string

info

City derived from the IP.

```
visitor_ip_city: "Brașov"
```

**visitor\_ip\_region** string

info

Region derived from the IP. Code or name, depending on the source.

```
visitor_ip_region: "BV"
```

**visitor\_ip\_postal\_code** string

info

Postal code derived from the IP. An approximation of the area, **not** the customer address.

```
visitor_ip_postal_code: "500001"
```

**products** array

info

Order lines, in a unified shape — the same keys whatever platform the shop runs. Present on events that have them.

**products\[0]** object

**id** string

info

Id of the variant sold.

```
id: "SKU-1024-BLACK"
```

**parent\_id** string

info

Id of the parent product. `= id` when there are no variants.

```
parent_id: "1024"
```

**name** string

info

Variant name.

```
name: "Urban backpack 20L black"
```

**parent\_name** string

info

Parent product name. `= name` when missing.

```
parent_name: "Urban backpack 20L"
```

**sku** string

info

Stock code.

```
sku: "SKU-1024-BLACK"
```

**parent\_sku** string

info

Parent stock code. `= sku` when missing.

```
parent_sku: "SKU-1024"
```

**ean** string

info

Standard product code. `""` when missing.

```
ean: "5901234123457"
```

**gtin** string

info

Standard product code. `""` when missing.

```
gtin: "5901234123457"
```

**mpn** string

info

Manufacturer part number. `""` when missing.

```
mpn: "NM-1024-BK"
```

**brand** string

info

Brand.

```
brand: "Nomad"
```

**type** string

info

Product type, as the shop declares it.

```
type: "simple"
```

**category** string

info

Main category.

```
category: "backpacks"
```

**categories** array

info

Every category, as `{name}` objects.

```
categories: [{ name: "backpacks" }, { name: "accessories" }]
```

**quantity** int

info

Units on the line. Minimum `1`.

```
quantity: 2
```

**price** number

info

**Final** unit price, with tax, after the product discount.

```
price: 82.5
```

tip

`price × quantity` is the line value, already net. Discounts in `coupons` below are **already subtracted from `price`** — do not subtract them again.

**price\_without\_tax** number

info

The same final unit price, excluding tax.

```
price_without_tax: 69.33
```

**price\_base** number

info

**List** unit price, with tax, before the product discount. `= price` when there is no discount; the difference `price_base − price` is the discount per unit.

```
price_base: 87.5
```

**price\_base\_without\_tax** number

info

List unit price, excluding tax.

```
price_base_without_tax: 73.53
```

**coupons** array

info

Discounts applied **to this line**. `value` is the line total, not per unit. **Key absent** when there are none.

These are distinct from the order-level `coupons` container: those apply across the whole order, are not reflected in product prices, and *are* subtracted from the aggregate value.

```
coupons: [{ name: "PROMO5", value: 10, type: "fixed", tax_included: true, tax_percent: 19 }]
```

Worked example

List price `87.5`, a `10` coupon across the whole line (`5` per unit at `quantity: 2`), final price `82.5`. Line value = `82.5 × 2 = 165` — exactly what `values.products_value_with_tax` shows.

**currency** string

info

Line currency.

```
currency: "RON"
```

**exchange\_rate** number

info

Line exchange rate. `1` by default.

```
exchange_rate: 1
```

**tax\_percent** number

info

Tax rate applied to the line.

```
tax_percent: 19
```

**tax\_included** bool

info

Whether the prices above include tax.

```
tax_included: true
```

**url** string

info

Address of the variant. **Key absent** when the address is invalid.

```
url: "https://shop.example/backpack-black"
```

**parent\_url** string

info

Address of the parent product. **Key absent** when the address is invalid.

```
parent_url: "https://shop.example/backpack"
```

**image** string

info

Main image. **Key absent** when no valid address exists.

```
image: "https://shop.example/img/1024.jpg"
```

**images** array

info

Every image. **Key absent** when no valid address exists.

```
images: ["https://shop.example/img/1024.jpg"]
```

**stock\_status** string

info

Stock state, as the shop declares it.

```
stock_status: "1"
```

**stock\_exists** bool

info

Availability, derived from `stock_status`.

```
stock_exists: true
```

**stock\_location** string

info

Warehouse, when the shop declares it.

```
stock_location: "main-warehouse"
```

**created\_at** int

info

When the product was added to the catalogue, ms Unix UTC. `0` when missing.

```
created_at: 1690000000000
```

**properties** object

info

The shop's own attributes for this line. **Key absent** when empty. See [properties](#properties).

```
properties: { variant: ["black / M"] }
```

caution

Keys marked **key absent** really are missing from the object in the situations described — unlike `event`, `user`, `attribution`, `context`, `consent` and `values`, where every key always arrives.

**shipping** array

info

Shipping methods on the order. Present only on events that have them.

**shipping\[0]** object

**id** string

info

Shipping method id.

```
id: "courier"
```

**name** string

info

Shipping method name.

```
name: "Express courier"
```

**type** string

info

Method type, as the shop declares it.

```
type: "courier"
```

**currency** string

info

Currency of the shipping cost.

```
currency: "RON"
```

**value** number

info

Shipping cost, including tax.

```
value: 19.99
```

**value\_without\_tax** number

info

Shipping cost, excluding tax.

```
value_without_tax: 16.8
```

**exchange\_rate** number

info

Exchange rate for this line. `1` by default.

```
exchange_rate: 1
```

**payments** array

info

Payment methods on the order. Present only on events that have them.

**payments\[0]** object

**id** string

info

Payment method id.

```
id: "card"
```

**name** string

info

Payment method name.

```
name: "Card"
```

**type** string

info

Method type: `card`, `cash`, `transfer`, as the shop declares it.

```
type: "card"
```

**value** number

info

Amount paid with this method.

```
value: 164.99
```

**coupons** array

info

Order-level discounts. Product-level ones are in `products[].coupons`. Present only on events that have them.

**coupons\[0]** object

**id** string

info

Coupon id or code.

```
id: "SUMMER10"
```

**name** string

info

Coupon name, as shown to the customer.

```
name: "SUMMER10"
```

**type** string

info

`percent` or `fixed`, as the shop declares it.

```
type: "percent"
```

**value** number

info

Discount value, including tax.

```
value: 20
```

**value\_without\_tax** number

info

Discount value, excluding tax.

```
value_without_tax: 16.81
```

**user** object always sent

info

Who the visitor is, as far as we know. Personal values leave only as SHA-256 fingerprints of the normalised value — plain values never leave our system.

**id** string

info

Customer id in the shop platform. `""` for orders without an account.

```
id: "7"
```

**emails\_sha256** array

info

Email fingerprints, at most 5. Normalisation before hashing: lowercase.

**The order is guaranteed** — most recently discovered first. If you want a visitor's current address, it is the first in the list.

```
emails_sha256: ["34d338…206f", "9b7f21…41ac"]
```

tip

All four fingerprint keys are **always arrays**, even where only one value can exist today. The type never changes, so you can iterate without checks. An empty list means we do not have the value.

**phones\_sha256** array

info

Phone fingerprints, same rules and same ordering. Normalisation before hashing: E.164 format.

```
phones_sha256: ["9f2a41…7b3c"]
```

**first\_name\_sha256** array

info

Fingerprint of the first name. Normalisation: lowercase, trimmed, punctuation and inner spaces removed, diacritics and digits kept — `Ștefan-Ion` becomes `ștefanion`.

```
first_name_sha256: ["aa34d338…9e206"]
```

**last\_name\_sha256** array

info

Fingerprint of the last name, same normalisation as the first name.

```
last_name_sha256: ["cc91f2a4…e4d3c"]
```

**country** string

info

Country from the order address, ISO 3166-1 alpha-2, lowercase. May differ from `context.visitor_ip_country`, which is derived from the IP.

```
country: "ro"
```

**region** string

info

County or region from the address. Free text, no fixed vocabulary.

```
region: "BV"
```

**city** string

info

City from the address. Free text.

```
city: "Brașov"
```

**created\_at** int | null

info

When the account was created, ms Unix UTC. `null` for orders without an account.

```
created_at: 1690000000000
```

**first\_seen** int

info

Earliest known interaction with the shop, ms Unix UTC.

It may **decrease** over time for the same visitor, as we learn about earlier interactions. When aggregating, take the minimum.

```
first_seen: 1785164079095
```

**properties** object

info

The shop's own attributes about this customer. See [properties](#properties).

```
properties: { account_status: ["active"] }
```

**cookies** object

info

A `{ name: value }` object with the cookies available from the visitor's browser on the shop domain.

Some cookies are not available for security reasons — they are neither collected nor altered. Cookies can also be excluded on request.

```
cookies: { _fbp: "fb.1.1785929520000.916422363983203244", _ga: "GA1.1.8296324256672419.1785542401" }
```

**consent** object always sent

info

What the visitor agreed to. When they have not chosen, the values reflect the shop's default setting.

**analytics** int

info

`1` granted, `0` not granted.

```
analytics: 1
```

**marketing** int

info

`1` granted, `0` not granted.

```
marketing: 0
```

**id** string

info

Id of the consent decision, when the consent platform provides one. `""` otherwise.

```
id: "a1b2c3d4-…"
```

**attribution** object always sent

info

Where the visitor came from. The two lists are different readings of the same data: `channels` covers every channel, `paid_sources` only the paid platforms. Every entry carries the days we saw it, so you can apply whatever window your own model uses.

**channels** array

info

The channels the visitor arrived through, **in order of first touch**. Each channel appears once, however many times it was touched, with the span over which it was seen.

Order is information, not decoration: two visits with the same channels in a different order arrive as different lists. To compare *which* channels were touched, sort both lists first; to compare the *journey*, compare them as they are.

```
channels: [
  { channel: "paid",       first_day: "2026-08-23", last_day: "2026-09-09", days_seen: 4 },
  { channel: "newsletter", first_day: "2026-09-03", last_day: "2026-09-03", days_seen: 1 }
]
```

| field       | meaning                                                                                  |
| ----------- | ---------------------------------------------------------------------------------------- |
| `channel`   | one of the values below                                                                  |
| `first_day` | the first day we have a record of this channel bringing the visitor, `YYYY-MM-DD` in UTC |
| `last_day`  | the last day it brought them; equal to `first_day` for a single touch                    |
| `days_seen` | how many **distinct days** it brought them, `first_day` and `last_day` included          |

Days, not moments

`first_day` and `last_day` are **days**, deliberately. They are exact as days and cannot be narrowed to an hour, so do not build "hours since last touch" logic on them.

`days_seen` counts days the same way: two visits from the same channel on the same day count once. It measures how persistent a source was, not traffic volume, and it is never a click count.

The day is the **UTC** day, like every timestamp we send. For a shop east of UTC this means a late-night visit can be dated one day earlier than the shop's own reports show it — a visit at 01:00 in Bucharest is `2026-09-11` here and the 12th there. Convert to your timezone if you compare the two.

Nothing is cut by a window

Every channel we still have a record of is listed, with its own days, so you apply whatever window your model uses.

Cutting the lists made the payload contradict itself: a channel and the platform that started it would report different histories, or a returning visitor would arrive with a first touch dated to their return. With the days on every entry there is nothing to cut for.

`first_day` is the first day we have, not the first day it happened

We do not keep the journey forever. For a visitor who has been coming back for a long time, `first_day` is where our record begins, not where the relationship did.

| value         | what it covers                                                                                                                                                         |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `paid`        | advertising bought on a platform: Google, Meta, TikTok, Bing, X, Snapchat, Pinterest, LinkedIn, OpenAI, Biano, Favi                                                    |
| `retargeting` | remarketing platforms — Criteo, RTB House                                                                                                                              |
| `affiliate`   | affiliate networks, paid on commission — 2Performant, Profitshare, Awin, Admitad, TradeDoubler, CJ, Impact, Rakuten, Webgains, Flip                                    |
| `ai`          | AI assistants, organic — ChatGPT, Perplexity, Gemini, Claude, Copilot, DeepSeek, Grok, You.com, Poe, Mistral, Meta AI, Phind. An ad inside ChatGPT is `paid`, not `ai` |
| `newsletter`  | your own email                                                                                                                                                         |
| `organic`     | a search engine, with no ad click on it — **Google, Bing, Yahoo, Yandex, DuckDuckGo, Baidu, Ecosia, Startpage, Qwant, Seznam**                                         |
| `social`      | a social network, with no advertising — Facebook, Instagram, TikTok, X, Snapchat, Pinterest, LinkedIn, Reddit, YouTube                                                 |
| `others`      | another site sent the visitor — any domain not named above                                                                                                             |

`others` is ordinary referral traffic, not an error

It is where a plain domain lands: a blog, a marketplace, a price comparison site, a partner's page. There is no separate `referral` value — a domain we do not map specially is simply `others`.

That also covers a search engine or a social network outside the lists above, because all we can tell is that some site sent the visitor. If a market you sell in leans on an engine or a network we are missing, tell us and we add it — until then that traffic is real, and it sits in `others`.

tip

`paid` means **advertising**, not "everything that cost money": `retargeting` and `affiliate` are paid too, but appear separately because they are budgeted separately. For the paid total, take the union of the three.

info

**An empty list** — no source was identified: the visitor arrived directly, typed address or bookmark, or the signal was lost. There is no `direct` value; the absence is the answer.

info

**Which platform, not just which channel.** Named platforms arrive only for paid traffic, in `paid_sources`. For `organic`, `social`, `others` and `newsletter` you get the channel alone — not the search engine, the social network or the referring site.

That is deliberate: platform names matter for budget attribution, which is a paid concern. Everywhere else the channel is the useful unit, and sending the full source taxonomy would tie your integration to our internal classification. If you need the specific source, tell us — it is a configuration question, not a limitation of the format.

caution

The list may grow. Treat an unknown value as a new channel, not as an error.

**paid\_sources** array

info

Platform names rather than channel names, ordered by first touch like `channels`. `[]` means no paid source is on record for this visitor.

```
paid_sources: [
  { source: "google",      type: "ads",         first_day: "2026-08-23", last_day: "2026-09-09", days_seen: 4 },
  { source: "2performant", type: "affiliate",   first_day: "2026-09-07", last_day: "2026-09-07", days_seen: 1 },
  { source: "criteo",      type: "retargeting", first_day: "2026-09-10", last_day: "2026-09-10", days_seen: 1 }
]
```

| field       | meaning                                                                                   |
| ----------- | ----------------------------------------------------------------------------------------- |
| `source`    | the platform name                                                                         |
| `type`      | `ads`, `affiliate`, `retargeting`, or `other`                                             |
| `first_day` | the first day we have a record of this platform bringing the visitor, `YYYY-MM-DD` in UTC |
| `last_day`  | the last day it brought them                                                              |
| `days_seen` | how many **distinct days** it brought them, `first_day` and `last_day` included           |

`days_seen` does not add up across the two lists

A channel's `days_seen` is its own distinct days, not the sum of its platforms'. Google and Meta both bringing the visitor on the same day is one day for the channel `paid` and one day for each of them — so the platforms can add up to more than the channel. That is what "distinct days" means, not a discrepancy.

Like `channels`, this list is not cut — every paid platform we still have a record of is here, with its own days.

Read `type` before you sum anything

This list is everything acquired for money, which is not the same as everything you bought as advertising. An affiliate network is billed on a sale, a retargeting DSP from a separate budget, and search ads per click — grouping them under one total answers no real question. `type` is what lets you separate them.

**values** object always sent

info

Order totals, in `event.currency`, at most four decimals. The event value itself is in `event.value`.

**products\_count** int

info

Distinct product lines.

```
products_count: 1
```

**products\_total\_quantity** int

info

Units in total, across every line.

```
products_total_quantity: 2
```

**products\_value\_with\_tax** number

info

Sum of the lines — unit price × quantity — including tax.

```
products_value_with_tax: 165
```

**products\_value\_without\_tax** number

info

The same sum, excluding tax.

```
products_value_without_tax: 138.66
```

**shipping\_count** int

info

Shipping methods on the order.

```
shipping_count: 1
```

**shipping\_value\_with\_tax** number

info

Shipping cost, including tax.

```
shipping_value_with_tax: 19.99
```

**shipping\_value\_without\_tax** number

info

Shipping cost, excluding tax.

```
shipping_value_without_tax: 16.8
```

**coupons\_count** int

info

Order-level discounts applied. Product-level discounts are already reflected in product prices and are not counted here.

```
coupons_count: 1
```

**coupons\_value\_with\_tax** number

info

Value of the order-level discounts, including tax.

```
coupons_value_with_tax: 20
```

**coupons\_value\_without\_tax** number

info

Value of the order-level discounts, excluding tax.

```
coupons_value_without_tax: 16.81
```

**payments\_count** int

info

Payment methods used.

```
payments_count: 1
```

**payments\_total\_value** number

info

Sum of the payments.

```
payments_total_value: 164.99
```

tip

The net is `products_value_without_tax + shipping_value_without_tax - coupons_value_without_tax`.

**queries** array

info

Marketing parameters from the addresses visited: `utm_campaign`, `utm_source`, `utm_medium`, `utm_content`, `utm_term`, and the click identifiers of the active advertising platforms — `fbclid`, `gclid`, `ttclid` and so on, once configured for the shop.

One entry **per parameter**, with the last value seen — not a history of every value. The list includes parameters from earlier visits, not only the current one.

How far back this list goes

Unlike the attribution lists, this one **is** cut — a click id kept forever would grow without bound. The window is **at least 30 days**, and wider when the shop's attribution window is wider than that. It is measured against `event.timestamp`, so a webhook that arrives late carries the same list it would have carried at the time of the event.

You do not need the exact number to use the data: every entry carries its own `added_at`, so what is in the list tells you what was in the window.

**queries\[0]** object

**name** string

info

Parameter name.

```
name: "utm_source"
```

**value** string

info

Parameter value.

```
value: "facebook"
```

**added\_at** int

info

When we last saw this value, ms Unix UTC.

```
added_at: 1785929520000
```

## properties[​](#properties "Direct link to properties")

`event.properties`, `user.properties` and `products[].properties` are **free-form**: the content is exactly what the source — the shop or its platform — sends. We do not add keys, translate them, filter them by meaning, or interpret them.

The only thing we do is bring them to a predictable shape, so they do not differ from platform to platform:

| in                        | out                                                     |
| ------------------------- | ------------------------------------------------------- |
| `"Color Variant"`         | `"color_variant"` — keys become `snake_case`            |
| `"black"`                 | `["black"]` — values are always arrays                  |
| `42`, `true`              | `["42"]`, `["true"]` — numbers and booleans become text |
| `["red", "red", "blue"]`  | `["red", "blue"]` — duplicates removed                  |
| `""`, `null`, `undefined` | *ignored*                                               |
| `{ "nested": "obj" }`     | *ignored* — if it is the only value, the key disappears |

So the keys and values are the source's; the shape is ours. A key reaches you only if it has at least one value left after the cleanup — you will never receive an empty array.

caution

There is no fixed key list here and there cannot be: every shop sends something different. Nothing in this container is guaranteed — a key may appear or disappear without notice, because the decision is the shop's, not ours. Read it as data, not as something you can build a schema on.

## Time windows[​](#Time-windows "Direct link to Time windows")

Three containers carry history; everything else describes the current event.

| container                  | how far back                                                |
| -------------------------- | ----------------------------------------------------------- |
| `attribution.channels`     | everything we still have, each entry dated                  |
| `attribution.paid_sources` | the same, it is the same data read differently              |
| `queries`                  | at least 30 days, wider if the shop's attribution window is |

The two attribution lists are not cut: they carry their days per entry, so you apply the window your model needs. `queries` is cut, because a click id kept without a window would grow without bound, and it is measured against `event.timestamp`, not delivery time — a webhook that arrives late produces the same payload it would have produced at the time of the event.

One limit applies to all three: we do not keep a visitor's history forever, so the oldest day you can see is bounded by how long we hold it, not by any window.

## Full example[​](#Full-example "Direct link to Full example")

A single `checkout_completed`, with every container populated.

```
{
  "event": {
    "name": "checkout_completed",
    "id": "13195238211910",
    "unique_id": "13195238211910",
    "deduplication_id": "idx13195238211910",
    "timestamp": 1786202400000,
    "value": 164.99,
    "currency": "RON",
    "exchange_rate": 1,
    "reason": null,
    "properties": {}
  },
  "context": {
    "url": "https://shop.example/checkout",
    "referrer_url": "",
    "landing_url": "https://shop.example/lp?utm_source=facebook",
    "timestamp": 1786202390000,
    "last_ad_source": "facebook",
    "integration": "browser|webhook merchantpro",
    "data_source": "website",
    "script_id": "YOURSCR1",
    "page_type": "checkout",
    "has_adblocker": 0,
    "nav_type": "navigate",
    "screen": "360x780",
    "user_agent": "Mozilla/5.0 (Linux; Android 14) Chrome/151.0.0.0 Mobile",
    "device_type": "mobile",
    "browser_name": "chrome",
    "browser_version": "151.0.0.0",
    "operating_system": "android",
    "operating_system_version": "14",
    "browser_app": "no_app",
    "browser_language": "ro-RO",
    "visitor_ip_address": "86.122.24.187",
    "visitor_ip_country": "RO",
    "visitor_ip_city": "Brașov",
    "visitor_ip_region": "BV",
    "visitor_ip_postal_code": "500001"
  },
  "products": [
    {
      "id": "SKU-1024-BLACK",
      "quantity": 2,
      "price": 82.5,
      "price_base": 87.5
    }
  ],
  "shipping": [
    {
      "id": "courier",
      "value": 19.99
    }
  ],
  "payments": [
    {
      "id": "card",
      "type": "card",
      "value": 164.99
    }
  ],
  "coupons": [
    {
      "id": "SUMMER10",
      "type": "percent",
      "value": 20
    }
  ],
  "user": {
    "id": "7",
    "first_name_sha256": [
      "aa34d338…9e206"
    ],
    "last_name_sha256": [
      "cc91f2a4…e4d3c"
    ],
    "emails_sha256": [
      "34d338…206f"
    ],
    "phones_sha256": [
      "9f2a41…7b3c"
    ],
    "country": "ro",
    "region": "BV",
    "city": "Brașov",
    "created_at": 1690000000000,
    "first_seen": 1785164079095,
    "properties": {
      "account_status": [
        "active"
      ]
    }
  },
  "cookies": {
    "_fbp": "fb.1.1785929520000.916422363983203244"
  },
  "consent": {
    "analytics": 1,
    "marketing": 0,
    "id": ""
  },
  "attribution": {
    "channels": [
      { "channel": "paid", "first_day": "2026-08-23", "last_day": "2026-09-11", "days_seen": 6 },
      { "channel": "newsletter", "first_day": "2026-09-03", "last_day": "2026-09-03", "days_seen": 1 },
      { "channel": "organic", "first_day": "2026-09-06", "last_day": "2026-09-08", "days_seen": 2 },
      { "channel": "retargeting", "first_day": "2026-09-10", "last_day": "2026-09-10", "days_seen": 1 },
      { "channel": "affiliate", "first_day": "2026-09-11", "last_day": "2026-09-11", "days_seen": 1 }
    ],
    "paid_sources": [
      { "source": "facebook", "type": "ads", "first_day": "2026-08-23", "last_day": "2026-09-09", "days_seen": 4 },
      { "source": "google", "type": "ads", "first_day": "2026-08-30", "last_day": "2026-09-11", "days_seen": 3 },
      { "source": "criteo", "type": "retargeting", "first_day": "2026-09-10", "last_day": "2026-09-10", "days_seen": 1 },
      { "source": "2performant", "type": "affiliate", "first_day": "2026-09-11", "last_day": "2026-09-11", "days_seen": 1 }
    ]
  },
  "values": {
    "products_count": 1,
    "products_total_quantity": 2,
    "products_value_with_tax": 165,
    "products_value_without_tax": 138.66,
    "shipping_count": 1,
    "shipping_value_with_tax": 19.99,
    "shipping_value_without_tax": 16.8,
    "coupons_count": 1,
    "coupons_value_with_tax": 20,
    "coupons_value_without_tax": 16.81,
    "payments_count": 1,
    "payments_total_value": 164.99
  },
  "queries": [
    {
      "name": "utm_source",
      "value": "facebook",
      "added_at": 1785929520000
    }
  ]
}
```
