JSON objects
Full example payloads for Incentive Engine advance, CustomerFacts, per-surface context, emit/done, and outcomes.
Example JSON for the objects apps pass into (and receive from) the Incentive Engine. Values match the sample shopper used in Customer facts and Facts by surface.
Client vs server
Client advance may only send trigger, context, sessionId, and optional renderTarget. organizationId, customer, marketId, and extraFacts are server-derived and must not be accepted from the client.
Thank You vs Post-purchase triggers
order_editing.post_purchase = Thank You page. order_editing.checkout_post_purchase_viewed = Post-purchase interstitial (no context.order).
Conditions evaluate against { customer, context } (see Evaluation scope). Cart prices are in minor units (cents).
Client advance (Thank You)
What a storefront / extension sends to the app’s incentive tRPC advance mutation.
{
"trigger": "order_editing.post_purchase",
"context": {
"orderId": "gid://shopify/Order/5678901234"
},
"sessionId": "gid://shopify/Order/5678901234",
"renderTarget": "purchase.thank-you.block.render"
}Server AdvanceInput (enriched)
What the engine receives after the app resolves org, customer, market, and (for Thank You) live order rollup into extraFacts.
{
"organizationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"trigger": "order_editing.post_purchase",
"context": {
"orderId": "gid://shopify/Order/5678901234"
},
"customer": {
"id": "gid://shopify/Customer/9988776655"
},
"sessionId": "oe:gid://shopify/Order/5678901234",
"marketId": "gid://shopify/Market/1",
"renderTarget": "purchase.thank-you.block.render",
"extraFacts": {
"order": {
"id": "gid://shopify/Order/5678901234",
"name": "#1042",
"order_number": 1042,
"email": "alex@shop.com",
"financial_status": "paid",
"fulfillment_status": "unfulfilled",
"total_price": "89.00",
"subtotal_price": "75.00",
"total_discount": "10.00",
"total_tax": "14.00",
"currency": "EUR",
"edited": false,
"created_at": "2026-08-15T09:12:00.000Z",
"line_items": [
{
"id": "gid://shopify/LineItem/1",
"product_id": "gid://shopify/Product/123",
"variant_id": "gid://shopify/ProductVariant/456",
"sku": "TEE-BLK-M",
"title": "Classic Tee",
"variant_title": "Black / M",
"quantity": 2,
"price": "29.00",
"total_discount": "5.00",
"currency": "EUR"
}
]
}
}
}extraFacts is merged into context before evaluation (e.g. context.order).
Evaluation scope
What the condition builder / evaluator sees after facts load and context merge.
{
"customer": {
"organization_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"customer_id": "gid://shopify/Customer/9988776655",
"profile": {
"email": "alex@shop.com",
"first_name": "Alex",
"last_name": "Müller",
"display_name": "Alex Müller",
"phone": "+49 170 1234567",
"locale": "de",
"tags": ["VIP", "newsletter"],
"total_orders": 12,
"total_spent": "348.50",
"currency": "EUR",
"created_at": "2024-01-10T08:00:00.000Z",
"updated_at": "2026-08-15T09:12:00.000Z"
},
"orders": [
{
"id": "gid://shopify/Order/5678901234",
"name": "#1042",
"order_number": 1042,
"email": "alex@shop.com",
"financial_status": "paid",
"fulfillment_status": "unfulfilled",
"total_price": "89.00",
"subtotal_price": "75.00",
"total_discount": "10.00",
"total_tax": "14.00",
"currency": "EUR",
"edited": false,
"created_at": "2026-08-15T09:12:00.000Z",
"line_items": [
{
"id": "gid://shopify/LineItem/1",
"product_id": "gid://shopify/Product/123",
"variant_id": "gid://shopify/ProductVariant/456",
"sku": "TEE-BLK-M",
"title": "Classic Tee",
"variant_title": "Black / M",
"quantity": 2,
"price": "29.00",
"total_discount": "5.00",
"currency": "EUR"
}
]
}
],
"subscriptions": [
{
"id": "gid://shopify/SubscriptionContract/111",
"status": "ACTIVE",
"currency_code": "EUR",
"next_billing_date": "2026-09-01T00:00:00.000Z",
"billing_interval": "MONTH",
"billing_interval_count": 1,
"delivery_price": "4.90",
"lines_count": 1,
"origin_order_id": "gid://shopify/Order/111000",
"last_payment_status": "SUCCEEDED",
"created_at": "2025-06-01T10:00:00.000Z",
"days_until_next_billing": 5,
"lines": [
{
"id": "gid://shopify/SubscriptionLine/1",
"product_id": "gid://shopify/Product/789",
"variant_id": "gid://shopify/ProductVariant/790",
"selling_plan_id": "gid://shopify/SellingPlan/99",
"selling_plan_name": "Deliver every month",
"sku": "COFFEE-1KG",
"title": "House Blend",
"variant_title": "1 kg",
"quantity": 1,
"current_price": "24.00",
"currency_code": "EUR"
}
]
}
]
},
"context": {
"orderId": "gid://shopify/Order/5678901234",
"order": {
"id": "gid://shopify/Order/5678901234",
"name": "#1042",
"order_number": 1042,
"email": "alex@shop.com",
"financial_status": "paid",
"fulfillment_status": "unfulfilled",
"total_price": "89.00",
"subtotal_price": "75.00",
"total_discount": "10.00",
"total_tax": "14.00",
"currency": "EUR",
"edited": false,
"created_at": "2026-08-15T09:12:00.000Z",
"line_items": [
{
"id": "gid://shopify/LineItem/1",
"product_id": "gid://shopify/Product/123",
"variant_id": "gid://shopify/ProductVariant/456",
"sku": "TEE-BLK-M",
"title": "Classic Tee",
"variant_title": "Black / M",
"quantity": 2,
"price": "29.00",
"total_discount": "5.00",
"currency": "EUR"
}
]
}
}
}Anonymous / missing replica row → customer is null.
CustomerFacts
Standalone row from data_plane.customer_facts (same object nested under customer in the scope above). Money fields are Postgres numeric strings.
{
"organization_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"customer_id": "gid://shopify/Customer/9988776655",
"profile": {
"email": "alex@shop.com",
"first_name": "Alex",
"last_name": "Müller",
"display_name": "Alex Müller",
"phone": "+49 170 1234567",
"locale": "de",
"tags": ["VIP", "newsletter"],
"total_orders": 12,
"total_spent": "348.50",
"currency": "EUR",
"created_at": "2024-01-10T08:00:00.000Z",
"updated_at": "2026-08-15T09:12:00.000Z"
},
"orders": [
{
"id": "gid://shopify/Order/5678901234",
"name": "#1042",
"order_number": 1042,
"email": "alex@shop.com",
"financial_status": "paid",
"fulfillment_status": "unfulfilled",
"total_price": "89.00",
"subtotal_price": "75.00",
"total_discount": "10.00",
"total_tax": "14.00",
"currency": "EUR",
"edited": false,
"created_at": "2026-08-15T09:12:00.000Z",
"line_items": [
{
"id": "gid://shopify/LineItem/1",
"product_id": "gid://shopify/Product/123",
"variant_id": "gid://shopify/ProductVariant/456",
"sku": "TEE-BLK-M",
"title": "Classic Tee",
"variant_title": "Black / M",
"quantity": 2,
"price": "29.00",
"total_discount": "5.00",
"currency": "EUR"
}
]
}
],
"subscriptions": [
{
"id": "gid://shopify/SubscriptionContract/111",
"status": "ACTIVE",
"currency_code": "EUR",
"next_billing_date": "2026-09-01T00:00:00.000Z",
"billing_interval": "MONTH",
"billing_interval_count": 1,
"delivery_price": "4.90",
"lines_count": 1,
"origin_order_id": "gid://shopify/Order/111000",
"last_payment_status": "SUCCEEDED",
"created_at": "2025-06-01T10:00:00.000Z",
"days_until_next_billing": 5,
"lines": [
{
"id": "gid://shopify/SubscriptionLine/1",
"product_id": "gid://shopify/Product/789",
"variant_id": "gid://shopify/ProductVariant/790",
"selling_plan_id": "gid://shopify/SellingPlan/99",
"selling_plan_name": "Deliver every month",
"sku": "COFFEE-1KG",
"title": "House Blend",
"variant_title": "1 kg",
"quantity": 1,
"current_price": "24.00",
"currency_code": "EUR"
}
]
}
]
}days_until_next_billing is derived at read time, not stored.
Thank You context (merged)
After extraFacts.order merge for trigger order_editing.post_purchase.
{
"orderId": "gid://shopify/Order/5678901234",
"order": {
"id": "gid://shopify/Order/5678901234",
"name": "#1042",
"order_number": 1042,
"email": "alex@shop.com",
"financial_status": "paid",
"fulfillment_status": "unfulfilled",
"total_price": "89.00",
"subtotal_price": "75.00",
"total_discount": "10.00",
"total_tax": "14.00",
"currency": "EUR",
"edited": false,
"created_at": "2026-08-15T09:12:00.000Z",
"line_items": [
{
"id": "gid://shopify/LineItem/1",
"product_id": "gid://shopify/Product/123",
"variant_id": "gid://shopify/ProductVariant/456",
"sku": "TEE-BLK-M",
"title": "Classic Tee",
"variant_title": "Black / M",
"quantity": 2,
"price": "29.00",
"total_discount": "5.00",
"currency": "EUR"
}
]
}
}Post-purchase interstitial context
Trigger order_editing.checkout_post_purchase_viewed. No order object.
{
"checkoutToken": "abc123checkout",
"productIds": [
"gid://shopify/Product/123",
"gid://shopify/Product/124"
],
"subtotal": 72.5,
"currency": "EUR",
"itemCount": 3,
"countryCode": "DE"
}checkoutToken and productIds are in the trigger schema but not in the condition picker.
Cancel context
Trigger subscriptions.cancel_intent.
{
"subscriptionContractId": "gid://shopify/SubscriptionContract/111",
"reason": "too_expensive",
"subReason": "found_cheaper",
"otherReason": null
}Picker exposes reason / subReason only; subscriptionContractId and free-text otherReason are schema/payload fields.
Account upsell context (merged)
Trigger subscriptions.upsell_viewed. Client sends subscriptionContractId; server merges contract from the replica.
{
"subscriptionContractId": "gid://shopify/SubscriptionContract/111",
"contract": {
"id": "gid://shopify/SubscriptionContract/111",
"status": "ACTIVE",
"currency_code": "EUR",
"next_billing_date": "2026-09-01T00:00:00.000Z",
"billing_interval": "MONTH",
"billing_interval_count": 1,
"delivery_price": "4.90",
"lines_count": 1,
"origin_order_id": "gid://shopify/Order/111000",
"last_payment_status": "SUCCEEDED",
"created_at": "2025-06-01T10:00:00.000Z",
"days_until_next_billing": 5,
"lines": [
{
"id": "gid://shopify/SubscriptionLine/1",
"product_id": "gid://shopify/Product/789",
"variant_id": "gid://shopify/ProductVariant/790",
"selling_plan_id": "gid://shopify/SellingPlan/99",
"selling_plan_name": "Deliver every month",
"sku": "COFFEE-1KG",
"title": "House Blend",
"variant_title": "1 kg",
"quantity": 1,
"current_price": "24.00",
"currency_code": "EUR"
}
]
}
}Order-status nudge context (merged)
Trigger subscriptions.order_status_viewed.
{
"orderId": "gid://shopify/Order/5678901234",
"order": {
"id": "gid://shopify/Order/5678901234",
"name": "#1042",
"order_number": 1042,
"email": "alex@shop.com",
"financial_status": "paid",
"fulfillment_status": "unfulfilled",
"total_price": "89.00",
"subtotal_price": "75.00",
"total_discount": "10.00",
"total_tax": "14.00",
"currency": "EUR",
"edited": false,
"created_at": "2026-08-15T09:12:00.000Z",
"line_items": [
{
"id": "gid://shopify/LineItem/1",
"product_id": "gid://shopify/Product/123",
"variant_id": "gid://shopify/ProductVariant/456",
"sku": "TEE-BLK-M",
"title": "Classic Tee",
"variant_title": "Black / M",
"quantity": 2,
"price": "29.00",
"total_discount": "5.00",
"currency": "EUR"
}
]
}
}Cart context
Trigger cart.cart_viewed. Prices are minor units.
{
"cartToken": "abc123cart",
"cart": {
"token": "abc123cart",
"note": "Leave at door",
"currency": "EUR",
"item_count": 4,
"total_price": 4999,
"original_total_price": 5999,
"items_subtotal_price": 5500,
"total_discount": 1000,
"total_weight": 1200,
"requires_shipping": true,
"items": [
{
"product_id": 1234567890,
"variant_id": 9876543210,
"quantity": 2,
"sku": "TEE-BLK-M",
"vendor": "memberr",
"product_type": "Apparel",
"handle": "classic-tee",
"product_title": "Classic Tee",
"variant_title": "Black / M",
"title": "Classic Tee - Black / M",
"price": 2900,
"original_price": 2900,
"final_price": 2610,
"line_price": 5800,
"original_line_price": 5800,
"final_line_price": 5220,
"total_discount": 580,
"gift_card": false,
"requires_shipping": true,
"selling_plan_allocation": null
}
],
"cart_level_discount_applications": [
{
"type": "discount_code",
"title": "SUMMER10",
"value": "10.0",
"value_type": "percentage",
"total_allocated_amount": 1000
}
]
}
}AdvanceResult emit
Engine found a matching offer and paused for accept/decline.
{
"kind": "emit",
"grantId": "grant_01JABCDEFGHJKMNPQRSTVWXYZ",
"offerNodeId": "offer_upsell_1",
"flowVersionId": "fv_01JFLOWVERSION000000000001",
"incentive": {
"kind": "upsell_offer",
"surface": "checkout_ui",
"selection": {
"type": "single",
"product": "gid://shopify/Product/555",
"variants": [],
"discount": {
"type": "percent",
"percent": 15
}
},
"showProductsAlreadyInCart": false,
"copy": {
"headline": {
"de": "Vervollständige deine Bestellung",
"en": "Complete your order"
},
"body": {
"de": "Füge Electrolytes hinzu, solange sie noch vorrätig sind.",
"en": "Add electrolytes while we still have stock."
},
"cta": {
"de": "Zur Bestellung hinzufügen",
"en": "Add to order"
}
}
}
}Apps may wrap this with surface UI (ui / flowUi) before returning to the extension.
AdvanceResult done
No offer to show (flow ended, no match, or caps exhausted).
{
"kind": "done"
}Client recordOutcome
After the customer accepts or declines an emitted offer.
{
"grantId": "grant_01JABCDEFGHJKMNPQRSTVWXYZ",
"outcome": "accepted"
}Use "declined" when they dismiss. Redemption is a separate client call with { "grantId": "…" } when the surface records fulfillment of the grant.