Analytics reports

Query exact aggregated results and manage reports shared with a store.

Use reports to read aggregated sales, product, acquisition, traffic and journey results or manage report definitions shared with a store. The API base is https://api-store.tringify.com/api/2025-01. Authenticate with a store API token or an installed app credential. Every request is scoped to the credential's store; do not send a store ID or a staff user ID.

Permissions and merchant control#

Reads and query execution require read_reports. Creating, updating or deleting a saved report requires write_reports, together with its read scope. The permission applies to aggregate reporting; it does not grant access to individual customer or order records. Request additional resource permissions only when your integration needs those records.

Merchants can select report permissions when creating or updating a store API token. Apps declare the scopes in the Developer Portal and follow the release and installation approval flow for a changed permission request. Existing credentials do not acquire report access automatically.

API-created reports are always shared with the store team. Staff who can edit reports can change or delete them after the creating token is revoked or the app is uninstalled. API credentials cannot read a staff member's personal reports or inherit the creator's personal favorites. Personal visibility and favorites are managed in Store Admin or the mobile app.

Endpoints#

Method and path

Scope

Behavior

GET /reports/catalog

read_reports

Supported datasets, fields, editable query presets, descriptions and limits.

POST /reports/query

read_reports

Execute the supplied query. Body: query, optional page and limit.

GET /reports

read_reports

List shared definitions. Query: search, page, limit.

POST /reports

write_reports

Create a shared definition. Body: name and query.

GET /reports/{id}

read_reports

Read a shared definition.

PUT /reports/{id}

write_reports

Replace name and query, supplying the current revision.

DELETE /reports/{id}?revision=1

write_reports

Delete the saved definition at its current revision.

POST /reports/{id}/run

read_reports

Run the current saved query. Body: optional page and limit; use {} for defaults.

POST /reports/exports

read_reports

Queue a complete CSV export. Body: query. Returns HTTP 202 and a job.

GET /reports/exports

read_reports

List this credential owner’s jobs. Query: page (1–10000), limit (1–50; default 20).

GET /reports/exports/{jobId}

read_reports

Read job state, query, snapshot metadata, row count and expiry.

GET /reports/exports/{jobId}/download

read_reports

Get a short-lived download URL for a completed, unexpired job.

Start from a preset#

The catalog includes a presets array. Each entry has an id, label, description, and complete query. Copy its query into a query, saved-report or export request, adjusting supported fields and filters as needed. Most presets start with the last 30 days; view_to_purchase_journey starts with the last 7 days. All presets initially include every sales channel. Reading or opening a preset does not create a saved report, export, or schedule. A saved query remains independent of later preset changes. Use the catalog returned to your integration rather than treating the preset list as fixed.

GET /reports/catalog: presets json
{
  "presets": [
    {
      "id": "order_operations",
      "label": "Order operations",
      "description": "Current cancellations and full or partial refunds for orders created in the selected period.",
      "query": {
        "version": 1,
        "dataset": "order_operations",
        "measures": [
          "orders",
          "cancelled_orders",
          "cancellation_rate",
          "refunded_orders",
          "partially_refunded_orders"
        ],
        "dimensions": [
          "day"
        ],
        "filter": {
          "range": "30d"
        },
        "sort": {
          "field": "day",
          "direction": "asc"
        },
        "view": "table"
      }
    },
    {
      "id": "payment_outcomes",
      "label": "Payment outcomes",
      "description": "Current outcomes of payment records created in the selected period, including split tenders and retries.",
      "query": {
        "version": 1,
        "dataset": "payment_operations",
        "measures": [
          "payment_records",
          "payment_orders"
        ],
        "dimensions": [
          "provider",
          "payment_status"
        ],
        "filter": {
          "range": "30d"
        },
        "sort": {
          "field": "payment_records",
          "direction": "desc"
        },
        "view": "table"
      }
    },
    {
      "id": "refund_outcomes",
      "label": "Refund outcomes",
      "description": "Current outcomes of refund requests, with known completed amounts and amount coverage.",
      "query": {
        "version": 1,
        "dataset": "refund_operations",
        "measures": [
          "refund_records",
          "completed_refunds",
          "pending_refunds",
          "failed_refunds",
          "unknown_refunds",
          "completed_refund_amount",
          "refund_amount_coverage"
        ],
        "dimensions": [
          "method"
        ],
        "filter": {
          "range": "30d"
        },
        "sort": {
          "field": "refund_records",
          "direction": "desc"
        },
        "view": "table"
      }
    },
    {
      "id": "fulfillment_outcomes",
      "label": "Fulfilment outcomes",
      "description": "Current shipment outcomes and tracking-number coverage for fulfilments created in the selected period.",
      "query": {
        "version": 1,
        "dataset": "fulfillment_operations",
        "measures": [
          "fulfillment_records",
          "fulfillment_orders",
          "pending_fulfillments",
          "in_transit_fulfillments",
          "delivered_fulfillments",
          "returning_fulfillments",
          "returned_fulfillments",
          "failed_fulfillments",
          "cancelled_fulfillments",
          "tracking_coverage"
        ],
        "dimensions": [
          "fulfillment_status"
        ],
        "filter": {
          "range": "30d"
        },
        "sort": {
          "field": "fulfillment_records",
          "direction": "desc"
        },
        "view": "table"
      }
    },
    {
      "id": "sales_over_time",
      "label": "Sales over time",
      "description": "Daily net sales, total sales and orders.",
      "query": {
        "version": 1,
        "dataset": "sales",
        "measures": [
          "net",
          "total",
          "orders"
        ],
        "dimensions": [
          "day"
        ],
        "filter": {
          "range": "30d"
        },
        "sort": {
          "field": "day",
          "direction": "asc"
        },
        "view": "table"
      }
    },
    {
      "id": "product_economics",
      "label": "Product economics",
      "description": "Net sales, known product costs and covered margin, with cost coverage visible.",
      "query": {
        "version": 1,
        "dataset": "products",
        "measures": [
          "units",
          "net",
          "cogs",
          "margin",
          "cost_coverage"
        ],
        "dimensions": [
          "product"
        ],
        "filter": {
          "range": "30d"
        },
        "sort": {
          "field": "net",
          "direction": "desc"
        },
        "view": "table"
      }
    },
    {
      "id": "frequently_bought_together",
      "label": "Frequently bought together",
      "description": "Product pairs present in at least five qualifying orders.",
      "query": {
        "version": 1,
        "dataset": "product_pairs",
        "measures": [
          "pair_orders"
        ],
        "dimensions": [
          "product_a",
          "product_b"
        ],
        "filter": {
          "range": "30d"
        },
        "sort": {
          "field": "pair_orders",
          "direction": "desc"
        },
        "view": "table"
      }
    },
    {
      "id": "repeat_purchases",
      "label": "Repeat purchases and replenishment",
      "description": "Repeat-customer rate and time between product purchases for identified customers.",
      "query": {
        "version": 1,
        "dataset": "repeat_purchases",
        "measures": [
          "customers",
          "repeat_customers",
          "repeat_rate",
          "repeat_cycles",
          "median_days_between_orders"
        ],
        "dimensions": [
          "product"
        ],
        "filter": {
          "range": "30d"
        },
        "sort": {
          "field": "repeat_customers",
          "direction": "desc"
        },
        "view": "table"
      }
    },
    {
      "id": "traffic_by_source",
      "label": "Traffic by source",
      "description": "Observed sessions and events grouped by referrer.",
      "query": {
        "version": 1,
        "dataset": "traffic",
        "measures": [
          "sessions",
          "events"
        ],
        "dimensions": [
          "referrer"
        ],
        "filter": {
          "range": "30d"
        },
        "sort": {
          "field": "sessions",
          "direction": "desc"
        },
        "view": "table"
      }
    },
    {
      "id": "campaign_conversion",
      "label": "Campaign conversion",
      "description": "Sessions, carts, checkouts and purchases by recorded entry source and campaign.",
      "query": {
        "version": 1,
        "dataset": "campaigns",
        "measures": [
          "sessions",
          "cart_sessions",
          "checkout_sessions",
          "purchase_sessions",
          "purchase_rate",
          "source_coverage"
        ],
        "dimensions": [
          "source",
          "medium",
          "campaign"
        ],
        "filter": {
          "range": "30d"
        },
        "sort": {
          "field": "sessions",
          "direction": "desc"
        },
        "view": "table"
      }
    },
    {
      "id": "acquisition_quality",
      "label": "Acquisition quality",
      "description": "Orders, sales and attribution coverage by recorded campaign details.",
      "query": {
        "version": 1,
        "dataset": "acquisition",
        "measures": [
          "orders",
          "total",
          "attributed_orders",
          "unattributed_orders",
          "attribution_coverage"
        ],
        "dimensions": [
          "source",
          "medium",
          "campaign"
        ],
        "filter": {
          "range": "30d"
        },
        "sort": {
          "field": "total",
          "direction": "desc"
        },
        "view": "table",
        "attribution_model": "last_touch"
      }
    },
    {
      "id": "view_to_purchase_journey",
      "label": "Product view to purchase",
      "description": "Sessions completing product view, cart, checkout and purchase in order within 30 minutes.",
      "query": {
        "version": 1,
        "dataset": "journeys",
        "measures": [
          "sessions",
          "step_rate",
          "overall_rate",
          "linkage_coverage"
        ],
        "dimensions": [
          "step"
        ],
        "filter": {
          "range": "7d"
        },
        "sort": {
          "field": "step",
          "direction": "asc"
        },
        "view": "table",
        "journey": {
          "steps": [
            "product_viewed",
            "cart_add",
            "begin_checkout",
            "purchase"
          ],
          "window_minutes": 30
        }
      }
    }
  ]
}

Product economics selects units, net sales, cost of goods, covered margin and cost coverage by product, sorted by net sales. Costs and margin cover only remaining units with a known cost snapshot. A zero recorded cost is known; a missing cost is unknown. Coverage is a unit share, not a revenue share. Covered margin does not deduct payment fees, fulfilment expenses, advertising or other operating costs, and is not contribution profit. All financial measures remain in the store base currency.

Run a report#

POST /reports/query json
{
  "limit": 25,
  "page": 1,
  "query": {
    "version": 1,
    "dataset": "sales",
    "measures": [
      "orders",
      "net"
    ],
    "dimensions": [
      "day"
    ],
    "filter": {
      "range": "30d"
    },
    "sort": {
      "field": "day",
      "direction": "asc"
    },
    "view": "table"
  }
}

Successful responses use {"success":true,"data":...}. Creating a definition returns HTTP 201; queueing an export returns HTTP 202; other successful operations return HTTP 200. Query data contains the executed query, currency, timezone, from, to_exclusive, generated_at, columns, rows, total, page and limit. Dates and timestamps use ISO formats. from is inclusive and to_exclusive is exclusive.

Operational outcomes#

Datasets order_operations, payment_operations, refund_operations and fulfillment_operations describe current outcomes of records created in the requested period. Each dataset filters by its own record creation time, so payment, refund and fulfilment rows can belong to older orders. All exclude test orders and include cancelled and archived orders. The sales-channel filter uses the channel recorded with the order. Days use the store timezone.

These are current-outcome cohorts, not historical status snapshots or counts of status transitions during the period. Later cancellations, payment updates and refund settlements can revise earlier periods. Comparisons with previous_period or previous_year evaluate both cohorts using current outcomes. Order operations includes unpaid orders, so its order count differs from recognized sales.

Payment records retain their own grain: retries and split tenders can create several records per order. payment_orders is distinct within each row and must not be added across rows to calculate unique orders. payment_status is pending, authorized, captured, failed, refunded, partially_refunded or unknown. Refunded payments are not also counted as currently captured. payment_failure_share divides failed records by all records; it is not a checkout failure rate. Provider and method values are recorded identifiers, not localized labels.

refund_status is completed, pending, failed or unknown. Completion requires confirmed provider refund or gift-card settlement and completed order effects; store-credit refunds additionally require confirmation that credit was issued. Manual refunds require completed order effects. Unconfirmed historical store-credit refunds remain unknown. Each partial refund is a separate record. Free-text reasons, notes, customer data and provider payloads are not report fields.

completed_refund_amount sums only known non-negative base-currency amounts of completed refunds, including refunded charges. It is null if no completed amount is known. refund_amount_coverage is the number of completed records with a known amount divided by all completed records; a saved zero is known. Coverage is null when no refunds are complete. This request-date total differs from sales measures that attribute refunds to the original order creation date. Monetary values use the same currency precision and canonical decimal strings as other reports.

Fulfilment operations retain fulfilment-record grain: partial fulfilments count separately and fulfillment_orders is distinct only within each returned row. Current statuses are the canonical fulfilment states. in_transit_fulfillments includes in_transit, out_for_delivery and delivery_failed; failed_fulfillments includes failed, lost, damaged and destroyed. tracking_coverage divides records with a non-empty tracking number by all fulfilment records.

Fulfilment operations do not expose transit or delivery duration. Manual status changes record projection time rather than an immutable carrier event time, so combining them would produce misleading performance metrics. Carrier identifiers are returned as recorded strings and can be blank.

Operational reports support the existing saved definitions, permissions, comparisons, stable pagination and CSV export contract. Missing earlier groups compare integer counts with zero; unknown refund amounts and ratios remain null. API outcomes remain canonical identifiers; clients can translate their labels.

Ordered journeys#

POST /reports/query: ordered journey json
{
  "limit": 25,
  "page": 1,
  "query": {
    "version": 1,
    "dataset": "journeys",
    "measures": [
      "sessions",
      "step_rate",
      "overall_rate",
      "linkage_coverage"
    ],
    "dimensions": [
      "step"
    ],
    "filter": {
      "range": "7d"
    },
    "sort": {
      "field": "step",
      "direction": "asc"
    },
    "view": "table",
    "journey": {
      "steps": [
        "product_viewed",
        "cart_add",
        "begin_checkout",
        "purchase"
      ],
      "window_minutes": 30
    }
  }
}

Use dataset journeys with journey.steps and journey.window_minutes. Steps must contain 2–8 supported event IDs in their required order. Repeated event types are allowed; purchase may appear only as the final step. The window must be an integer from 1 to 1440 minutes. Strings, fractional minutes, unknown event IDs and journey configuration on another dataset are rejected.

Event ID

Event

Retained days

session_started

Session started

30

page_view

Page viewed

30

product_viewed

Product viewed

30

search

Search

30

cart_add

Added to cart

400

wishlist_add

Added to wishlist

400

begin_checkout

Checkout started

400

customer_login

Customer signed in

30

customer_register

Customer registered

30

purchase

Purchase

400

The journeys dataset in GET /reports/catalog includes journey_options: events with id, label and raw_retention_days, min_steps, max_steps, min_window_minutes and max_window_minutes. Require the single breakdown step, whose canonical value is a one-based integer string. Match that index to the query steps for its event label. Table display accepts multiple measures; a bar chart accepts one. Line charts and comparison periods are not supported.

A session enters once at its earliest first-step event at or after from and before to_exclusive. Each subsequent step must occur strictly after the preceding matched step, at or before entry plus window_minutes, and before to_exclusive. A later repeated entry does not restart the window. Equal timestamps do not establish sequence. Sessions entering near to_exclusive may not have had their full completion window, so recent periods can show incomplete journeys.

Matching requires the same storefront, sales channel and nonempty session identifier, with analytics consent true on every matched event. Sessions are not stitched across devices or storefronts. Test and identified automated events are excluded. Purchase counts the recorded sale event, independent of a later cancellation or refund; these completion counts are not current order counts or sales revenue.

sessions counts entries reaching a step. step_rate divides that count by the preceding step count, while overall_rate divides by entries. The first step returns 1 when entries exist; a zero denominator returns null. recorded_events counts all permitted occurrences of the step event in the period, including events without a linkable session or analytics consent. linked_events counts occurrences with a nonempty session and analytics consent; linkage_coverage is linked_events / recorded_events, or null with no recorded events. Event counts are not distinct session counts, and repeated steps can show the same event coverage. Results contain aggregates, not session IDs or customer identities.

The earliest report instant must still be retained when the query or export is processed. The limit is the shortest raw_retention_days among selected steps. Browsing observations retain 30 days, so a journey containing one rejects 90d and older custom dates. Commerce-only steps retain 400 days; custom selections remain capped at 366 calendar days. Source expiry produces an invalid-input response instead of zero conversions. Queued exports whose source expires fail with REPORT_SOURCE_EXPIRED and provide no partial file; choose recent dates and queue another export.

Saved definitions and queued exports preserve the complete journey configuration. CSV exports append report_journey_steps as a JSON array and report_journey_window_minutes. Keep these with the one-based step column and snapshot metadata when interpreting an export.

Acquisition and attribution coverage#

POST /reports/query: acquisition json
{
  "limit": 25,
  "page": 1,
  "query": {
    "version": 1,
    "dataset": "acquisition",
    "measures": [
      "orders",
      "total",
      "attributed_orders",
      "unattributed_orders",
      "attribution_coverage"
    ],
    "dimensions": [
      "source",
      "medium",
      "campaign"
    ],
    "filter": {
      "range": "30d"
    },
    "sort": {
      "field": "total",
      "direction": "desc"
    },
    "view": "table",
    "attribution_model": "last_touch"
  }
}

Campaign performance#

Use dataset campaigns for consented active sessions grouped by their first recorded entry source. Each scoped session is counted once per selected period. Sessions are not unique people and are not joined across stores, storefronts, channels or devices. Entry sources remain attached when a session continues on a later day.

Measures include sessions, product_sessions, cart_sessions, checkout_sessions, purchase_sessions, cart_rate, checkout_rate, purchase_rate and source_coverage. Stage counts describe sessions with each activity during the period, without requiring an ordered sequence. Multiple purchases in one session count once, and later refunds or cancellations do not erase purchase events. Use acquisition for recognized financial amounts and journeys for ordered steps.

Campaign breakdowns include source, medium, campaign, campaign_id, term, content, source_platform, creative_format, marketing_tactic, referrer, landing_page, day and channel. Day is the session's first activity within the selected period in the store timezone. Source uses the entry campaign tag or external referrer; unavailable and historical origins are blank. Source coverage is the share of sessions with a named campaign or referral source. Campaign fields depend on the permissions in effect at capture.

Campaign queries support saved definitions, comparisons, CSV exports and staff schedules. Compared session counts use zero for missing prior rows; rates remain unavailable without a denominator. There is no campaign revenue, ad spend, ROAS or causal lift measure in this dataset.

Dataset acquisition uses the same qualifying orders, creation-date filters and base-currency total sales as sales reports. Select attribution_model as first_touch or last_touch; omission defaults to last_touch. Query results return the effective model. An explicit null, empty string, unknown value or non-string model is rejected with HTTP 400. Other datasets reject this field.

Each model uses its recorded qualifying touch. If that touch is missing, timestamped acquisition history supplies the earliest or latest qualifying touch. If only one touch is known, both models use it. A recorded UTM field, referrer, click identifier or campaign metadata is an acquisition signal. A session ID or landing page alone is not. Missing or malformed history timestamps are ignored. Switching models changes source allocation, not the qualifying order set or total revenue.

Dimensions source, medium and campaign contain the chosen touch's recorded utm_source, utm_medium and utm_campaign. Missing values are empty strings. They are not inferred from click identifiers, and an empty source is not classified as direct traffic. An order can have another acquisition signal despite empty UTM fields. Use attributed_orders, unattributed_orders, attributed_total, unattributed_total and attribution_coverage to distinguish that coverage. Coverage is attributed orders divided by qualifying orders, rounded to at most six decimal places; it is null when there are no qualifying orders.

Both comparison periods use the same selected model. A missing earlier group has zero additive counts and sales, while its coverage remains null. CSV exports always include report_attribution_model for this dataset. Saved definitions and export queries preserve the model; staff schedules reuse the saved choice. Results are aggregates, without individual touch histories or customer identities. They do not measure advertising spend, ROAS or causal campaign lift.

Compare periods#

Set the optional query field comparison to previous_period or previous_year for sales, product and acquisition reports, or operational outcome reports. Omit it when no comparison is required. Explicit null, an empty string, unknown values, and comparisons on traffic reports are rejected.

POST /reports/query response data json
{
  "columns": [],
  "comparison": {
    "from": "2026-07-15T00:00:00-04:00",
    "mode": "previous_period",
    "to_exclusive": "2026-08-13T09:00:00-04:00"
  },
  "currency": "USD",
  "from": "2026-08-14T00:00:00-04:00",
  "generated_at": "2026-09-12T13:00:00Z",
  "limit": 25,
  "page": 1,
  "query": {
    "version": 1,
    "dataset": "sales",
    "measures": [
      "orders",
      "net"
    ],
    "dimensions": [
      "day"
    ],
    "filter": {
      "range": "30d"
    },
    "sort": {
      "field": "day",
      "direction": "asc"
    },
    "view": "table",
    "comparison": "previous_period"
  },
  "rows": [
    {
      "comparison": {
        "change": {
          "net": "25.50",
          "orders": "1"
        },
        "change_rate": {
          "net": "0.255000",
          "orders": "0.500000"
        },
        "values": {
          "net": "100.00",
          "orders": "2"
        }
      },
      "values": {
        "day": "2026-09-01",
        "net": "125.50",
        "orders": "3"
      }
    }
  ],
  "timezone": "America/New_York",
  "to_exclusive": "2026-09-12T09:00:00-04:00",
  "total": 1
}

Comparison windows use the store timezone and local calendar dates. previous_period shifts both resolved boundaries backward by the number of inclusive local dates in the selection, preserving their local wall-clock times. previous_year uses the corresponding local dates one year earlier; February 29 maps to February 28 when the earlier year is not a leap year. Daily rows use those dates directly. Weekly and monthly rows align by their position within the current and earlier windows.

The current period controls rows, total, sorting and pagination. A group found only in the earlier period is not returned. Each current row adds comparison.values, comparison.change, and comparison.change_rate; the top-level comparison contains mode, from, and to_exclusive. Pages are still independent queries, so use an export when both periods must come from one consistent snapshot.

For additive measures such as orders, units and money totals, a current group with no earlier activity has an earlier value of zero. Values that cannot be derived without observations, including average order value, cost, margin and cost coverage, remain null. If the current value is null and the earlier value is known, the earlier value is retained while change and change rate are null. Change is current minus earlier. Change rate is (current - earlier) / abs(earlier), returned with six decimal places; it is null when either value is unavailable or the earlier value is zero. Money values and changes keep the currency precision and their sign.

Frequently bought together#

Use dataset product_pairs with measure pair_orders, both product_a and product_b dimensions, and view table. Sort by any selected field. The product identifiers are an unordered pair: product_a is the lower numeric product ID, and product_b the higher. Rows include labels.product_a and labels.product_b from the order-item titles. All variants of one product are combined before pairs are counted.

POST /reports/query: product pairs json
{
  "limit": 25,
  "page": 1,
  "query": {
    "version": 1,
    "dataset": "product_pairs",
    "measures": [
      "pair_orders"
    ],
    "dimensions": [
      "product_a",
      "product_b"
    ],
    "filter": {
      "range": "30d"
    },
    "sort": {
      "field": "pair_orders",
      "direction": "desc"
    },
    "view": "table"
  }
}

Each pair is counted once per qualifying order, independent of line quantity and variant count. Paid or cash-on-delivery orders qualify, including imports. Test, cancelled and fully refunded orders are excluded. Each product must retain at least one unit after completed refunds. Gift-card products and custom items are excluded. The selected order-creation window and sales channel apply before counting. Only pairs present in at least 5 orders are returned; total counts qualifying pair rows, not orders. An absent pair is not evidence of zero orders.

Product-pair reports reject comparison periods with HTTP 400: a suppressed earlier count must not be presented as zero. Both product dimensions are required; charts and other breakdowns are rejected. Pagination, saved definitions and complete exports use the same pair rules. CSV adds product_a_name and product_b_name in the selected dimension order. Results contain aggregate product relationships, not customer identities, recommendation lift or an audience definition.

Repeat purchases and replenishment#

Use dataset repeat_purchases with the product dimension and table view. Available measures are customers, repeat_customers, repeat_rate, repeat_cycles, average_days_between_orders, and median_days_between_orders. Variants are combined under their product ID and rows include labels.product.

POST /reports/query: repeat purchases json
{
  "limit": 25,
  "page": 1,
  "query": {
    "version": 1,
    "dataset": "repeat_purchases",
    "measures": [
      "customers",
      "repeat_customers",
      "repeat_rate",
      "repeat_cycles",
      "median_days_between_orders"
    ],
    "dimensions": [
      "product"
    ],
    "filter": {
      "range": "30d"
    },
    "sort": {
      "field": "repeat_customers",
      "direction": "desc"
    },
    "view": "table"
  }
}

Only recognized, non-test and non-cancelled orders linked to a customer ID are included. Guest orders are excluded. A repeat cycle is each qualifying product purchase after that customer's first qualifying purchase inside the selected order-creation window. Time-between-purchase measures therefore describe consecutive purchases inside that window, not a customer's lifetime purchase history. Products with fewer than 5 distinct identified buyers are suppressed.

Repeat-purchase reports reject comparison periods, charts and breakdowns other than product. An absent product can mean that it did not meet the minimum sample; it does not prove zero purchases. These aggregate rows do not expose customer identities or create an audience.

Exact amounts and missing values#

Each row has a values object keyed by the selected field IDs. Money, integer and ratio values are decimal strings. Money uses a decimal point, no grouping or currency symbol, and the currency's full decimal precision: for example INR 1234.50, JPY 1234, or KWD 9.590. Keep these values as decimals in calculations. Store Admin's General display preferences do not change the API values.

Financial measures use the store base currency. A currency breakdown groups orders by their order currency but does not change the currency of the measures. null means unavailable; it is not zero. In product reports, a recorded zero cost is known, while an item without a cost snapshot contributes no known cost or covered margin. cost_coverage is a ratio, not a percent string. Product rows can include labels.product alongside the product identifier.

Query rules and limits#

Field

Accepted values and rules

version

  1. Unknown versions are rejected.

dataset

sales, products, product_pairs, repeat_purchases, acquisition, campaigns, traffic, journeys, order_operations, payment_operations, refund_operations or fulfillment_operations. Read the catalog for compatible fields.

journey

Required only for journeys: steps is an array of 2–8 event IDs; window_minutes is an integer from 1–1440. Read datasets[].journey_options for events, retention and limits.

attribution_model

Acquisition only: first_touch or last_touch. Omission defaults to last_touch; explicit null, empty, unknown and non-string values are rejected.

measures

1–10 distinct measure IDs from the selected dataset.

dimensions

0–3 distinct breakdown IDs. Traffic requires exactly one. Choose at most one of day, week and month.

filter.range

today, yesterday, 7d, 30d, 90d or custom.

filter.from / filter.to

Required only for custom, as YYYY-MM-DD. Inclusive start and end dates, in order, covering at most 366 calendar days. The start cannot be in the future. The actual query end is capped at the current time.

filter.channel_id

Optional sales-channel UUID. Omitting it includes all channels. Channel filtering does not change the authenticated store.

comparison

Optional previous_period or previous_year for sales, products, acquisition, campaigns and operational outcomes. Traffic, product-pair, repeat-purchase and journey comparisons are not supported.

sort

field must be a selected measure or breakdown; direction must be asc or desc.

view

table, line or bar. Charts require one measure. Bar requires one breakdown; line requires exactly one day, week or month breakdown. The API still returns rows.

page / limit

Page starts at 1, defaults to 1 and cannot exceed 100000. Limit defaults to 25; allowed range 1–250.

Request body

At most 32768 bytes. Unknown fields, malformed JSON and extra JSON values are rejected.

Time, pagination and reconciliation#

The store timezone defines calendar boundaries. Today starts at local midnight. Yesterday covers the previous complete local day. The 7d, 30d and 90d presets include today and end at the time of the request. Relative ranges are reevaluated on every run. Weeks start on Monday.

Each page reports the full matching row count in total. Continue requesting pages until all rows have been read. Pages are separate queries, not a frozen export: new events, orders, refunds or a moving relative date range can change later results. Custom dates keep the calendar range fixed but do not freeze the underlying data. Use a report export job when you need a complete result from one consistent snapshot.

Sales reports exclude test and cancelled orders. Refunds affect the original order period. Merchandise refunds reduce net sales, while a shipping-only refund affects total sales without reducing merchandise net sales. Tax charged and shipping charged describe the amounts recorded on the recognized orders; they are not presented as net tax or shipping receipts. Traffic sessions are distinct within each row, so adding rows can count the same session more than once.

Gift-card purchases are issuance value, not sales revenue. Their allocated completed refunds are excluded from recognized revenue as well. Merchandise paid for with a gift card remains included. Orders containing only gift cards still contribute to the order count. Pending and failed refunds do not reduce revenue. Refunds without returned items affect total sales but cannot be attributed to merchandise returns. Cumulative recognized refund amounts are settled per order at its currency precision using ties-to-even rounding before revenue is aggregated.

Complete CSV exports#

POST /reports/exports json
{
  "query": {
    "version": 1,
    "dataset": "sales",
    "measures": [
      "orders",
      "net"
    ],
    "dimensions": [
      "day"
    ],
    "filter": {
      "range": "30d"
    },
    "sort": {
      "field": "day",
      "direction": "asc"
    },
    "view": "table"
  }
}

Read the returned job ID with GET /reports/exports/{jobId}. Typical states are pending, processing, completed and failed. Wait a few seconds between status requests and increase the interval while a job remains pending. Only request the download after completion. A saved report can be exported by first reading its query and passing that query to the export endpoint; later changes to the saved definition do not change the queued query.

An export contains all matching rows, up to 100000, rather than just the current preview page. A larger result fails with REPORT_EXPORT_TOO_LARGE; reduce its range or choose a coarser breakdown. One active report export is allowed per store across staff and API credentials. A competing request fails with an export-in-progress error. Export history defaults to page 1, limit 20, and returns jobs, total, page and limit.

The query period, currency and timezone are fixed when the job is accepted. The data is read from a consistent snapshot when processing starts, recorded as metadata.generated_at. A retried worker can produce a later snapshot but keeps the accepted period. Read metadata.from and metadata.to_exclusive for the evaluated boundaries. CSV columns use canonical decimal values and include currency, timezone and snapshot metadata; display preferences do not change them.

For a compared export, the accepted job also freezes metadata.comparison_from and metadata.comparison_to_exclusive. The CSV reads the current and earlier periods in the same consistent snapshot, preserves the current row order, adds {measure}_comparison, {measure}_change, and {measure}_change_rate, and records comparison_mode plus both earlier boundaries. When comparison is omitted, the existing CSV columns are unchanged.

Jobs belong to the API token or app installation that created them, not to the staff member who granted access. A different token, another app installation, and staff export history cannot read that job. Credentials for the same app installation share its jobs; reinstalling creates a different owner. Revocation, uninstallation or loss of read_reports prevents further API access. Existing signed links remain usable until their short expiry, so treat them as bearer links and do not publish them.

Completed files are available for 24 hours after completion. Status includes expires_at; after that time it includes REPORT_EXPORT_EXPIRED and no download is available. Download responses contain download_url and expires_at. Links last at most five minutes and never outlive the file’s availability. Downloading an unfinished job returns HTTP 409. Missing, inaccessible or expired files return HTTP 404. Failed jobs report REPORT_EXPORT_FAILED, REPORT_EXPORT_TOO_LARGE or REPORT_SOURCE_EXPIRED; they do not provide partial CSV files. API-created exports do not send staff notifications.

Before retrying an export start after an uncertain response, list this credential’s recent jobs and compare their query, creation time and evaluated metadata. A successful response is not a delivery notification. There is no export webhook or scheduled delivery in this API; check the job status.

Report schedules and threshold notifications belong to individual staff members in Store Admin and the mobile app. They are not Store API resources and an app cannot choose a staff recipient or inherit staff notification preferences. An integration that needs an alert can run its permitted report query on its own schedule, compare canonical decimal values itself, and deliver through channels it is separately authorized to use.

Save, update and delete#

POST /reports json
{
  "name": "Sales by day",
  "query": {
    "version": 1,
    "dataset": "sales",
    "measures": [
      "orders",
      "net"
    ],
    "dimensions": [
      "day"
    ],
    "filter": {
      "range": "30d"
    },
    "sort": {
      "field": "day",
      "direction": "asc"
    },
    "view": "table"
  }
}

A saved definition contains id, name, query, revision, created_at and updated_at. Names contain 1–80 characters after trimming; the same credential cannot reuse a name without regard to letter case. A store can keep up to 100 active reports, including personal reports created by staff. The list search is a literal, case-insensitive match on the name, with at most 80 characters.

Saving stores the choices, not a frozen set of results. For an update, send the complete name and query plus the current revision. For deletion, supply revision in the URL query. If another writer changed the definition, HTTP 409 prevents an overwrite. Read the current report and reconcile your change before retrying. Deleted reports are no longer returned; deletion does not remove orders, customers or events.

Errors and retries#

HTTP status

Meaning

Next step

400

Invalid query, body, pagination, name or revision; or the saved report limit was reached.

Correct the request using the error message and catalog.

401

Missing, expired or invalid credential context.

Use a current credential.

403

Required report scope is missing.

Obtain the merchant's explicit permission through the token or app grant flow.

404

The report or export does not exist, is not visible to this credential, or its file has expired.

Check the report ID and its shared visibility.

409

The supplied revision is stale, or an export download is not ready.

Reload and reconcile changes; do not blindly overwrite.

429

Request rate or simultaneous report capacity was exceeded.

Honor Retry-After. Reduce concurrent report queries.

503

Report data is temporarily unavailable or the query could not complete.

Retry with backoff or reduce the requested time range.

Errors use {"success":false,"error":{"code":"...","message":"..."}}, with details or public parameters when applicable. Read operations can be retried. Before retrying a create after an uncertain response, search for the saved definition and confirm whether it was created.

Sales fields#

Field

Kind

Type

Definition

orders

Measure

integer

Recognized, non-cancelled orders; excludes test orders.

gross

Measure

money

Merchandise before discounts and completed merchandise refunds; excludes gift-card purchases.

discounts

Measure

money

Discounts on merchandise in recognized orders; excludes gift-card purchases.

returns

Measure

money

Completed refunds allocated to merchandise.

net

Measure

money

Merchandise after discounts and merchandise refunds.

tax

Measure

money

Tax recorded on recognized orders.

shipping

Measure

money

Shipping recorded on recognized orders.

total

Measure

money

Recognized revenue after completed refunds, including charges; excludes gift-card purchases and their allocated refunds. Merchandise paid for with gift cards is included.

aov

Measure

money

Total sales divided by recognized orders.

day

Breakdown

date

The order creation date in the store timezone.

week

Breakdown

date

Monday of the order creation week in the store timezone.

month

Breakdown

date

The order creation month in the store timezone.

country

Breakdown

string

Country from the shipping address saved with the order; empty if unavailable.

channel

Breakdown

string

The sales channel recorded with the order.

currency

Breakdown

string

The currency used by the order. Measures remain in the store base currency.

Products fields#

Field

Kind

Type

Definition

units

Measure

integer

Sold units less refunded units; excludes gift cards.

gross

Measure

money

Item values before discounts and merchandise refunds.

discounts

Measure

money

Discounts allocated to these items.

returns

Measure

money

Completed merchandise refunds allocated to these items.

net

Measure

money

Item values after discounts and merchandise refunds.

cogs

Measure

money

Cost snapshots for remaining units with a known cost; unavailable when no cost is known.

margin

Measure

money

Net sales less costs for items with a known cost; unavailable when no cost is known.

cost_coverage

Measure

ratio

Share of remaining units with a known cost. An explicit zero cost is known.

product

Breakdown

entity

The product saved with the order item.

day

Breakdown

date

The order creation date in the store timezone.

country

Breakdown

string

Country saved with the order's shipping address.

Frequently bought together fields#

Field

Kind

Type

Definition

pair_orders

Measure

integer

Distinct qualifying orders containing both products. Each unordered pair counts once per order, regardless of quantities or variants. Only pairs present in at least five orders are shown.

product_a

Breakdown

entity

The lower product ID in the unordered pair. Includes all variants of that product.

product_b

Breakdown

entity

The higher product ID in the unordered pair. Includes all variants of that product.

Repeat purchases and replenishment fields#

Field

Kind

Type

Definition

customers

Measure

integer

Distinct identified customers who bought the product in the selected period. Guest orders without a customer ID are excluded.

repeat_customers

Measure

integer

Distinct identified customers with at least two qualifying orders for the product in the selected period.

repeat_rate

Measure

ratio

Repeat customers divided by identified customers for the product.

repeat_cycles

Measure

integer

Qualifying purchases after a customer's first purchase of the product in the selected period.

average_days_between_orders

Measure

decimal

Average elapsed days between consecutive qualifying purchases of the product.

median_days_between_orders

Measure

decimal

Median elapsed days between consecutive qualifying purchases of the product.

product

Breakdown

entity

The product saved with the order item. All variants are combined.

Acquisition fields#

Field

Kind

Type

Definition

orders

Measure

integer

Recognized, non-cancelled orders; excludes test orders.

total

Measure

money

Recognized revenue after completed refunds, including charges; excludes gift-card purchases and their allocated refunds.

aov

Measure

money

Total sales divided by recognized orders.

attributed_orders

Measure

integer

Orders with a recorded campaign or referral signal in the selected attribution model.

unattributed_orders

Measure

integer

Orders without a recorded acquisition signal. A session or landing page alone is not attribution.

attributed_total

Measure

money

Total sales from orders with a recorded acquisition signal.

unattributed_total

Measure

money

Total sales from orders without a recorded acquisition signal.

attribution_coverage

Measure

ratio

Attributed orders divided by all qualifying orders; unavailable when no orders qualify.

source

Breakdown

string

Recorded utm_source for the selected touch; blank when unavailable. It is not inferred from click identifiers.

medium

Breakdown

string

Recorded utm_medium for the selected touch; blank when unavailable.

campaign

Breakdown

string

Recorded utm_campaign for the selected touch; blank when unavailable.

campaign_id

Breakdown

string

Recorded utm_id for the selected attribution touch; blank when unavailable.

term

Breakdown

string

Recorded utm_term for the selected attribution touch; blank when unavailable.

content

Breakdown

string

Recorded utm_content for the selected attribution touch; blank when unavailable.

source_platform

Breakdown

string

Recorded utm_source_platform for the selected attribution touch; blank when unavailable.

creative_format

Breakdown

string

Recorded utm_creative_format for the selected attribution touch; blank when unavailable.

marketing_tactic

Breakdown

string

Recorded utm_marketing_tactic for the selected attribution touch; blank when unavailable.

day

Breakdown

date

The order creation date in the store timezone.

country

Breakdown

string

Country saved with the order's shipping address; blank when unavailable.

channel

Breakdown

string

The sales channel recorded with the order.

Campaign performance fields#

Field

Kind

Type

Definition

sessions

Measure

integer

Distinct consented sessions with activity in the selected period; not unique people.

product_sessions

Measure

integer

Sessions with at least one product view in the period.

cart_sessions

Measure

integer

Sessions adding a product to the cart in the period.

checkout_sessions

Measure

integer

Sessions starting checkout in the period.

purchase_sessions

Measure

integer

Sessions with a recorded purchase in the period. Multiple purchases count once; subsequent refunds do not erase the event.

cart_rate

Measure

ratio

Cart sessions divided by active sessions.

checkout_rate

Measure

ratio

Checkout sessions divided by active sessions.

purchase_rate

Measure

ratio

Purchasing sessions divided by active sessions. This is observed session conversion, not orders divided by visitors.

source_coverage

Measure

ratio

Share of active sessions with a recorded campaign or external referral source.

source

Breakdown

string

Recorded session-entry campaign source or external referring source; blank for direct or unavailable.

medium

Breakdown

string

Recorded session-entry campaign medium or referral category.

campaign

Breakdown

string

Recorded session-entry campaign name.

campaign_id

Breakdown

string

Recorded utm_id.

term

Breakdown

string

Recorded utm_term.

content

Breakdown

string

Recorded utm_content.

source_platform

Breakdown

string

Recorded utm_source_platform.

creative_format

Breakdown

string

Recorded utm_creative_format.

marketing_tactic

Breakdown

string

Recorded utm_marketing_tactic.

referrer

Breakdown

string

External referring hostname; store-owned hosts are excluded.

landing_page

Breakdown

string

First consented observed landing path.

day

Breakdown

date

First activity in the selected period, in the store timezone. Each session belongs to one day.

channel

Breakdown

string

The session's sales channel.

Traffic fields#

Field

Kind

Type

Definition

events

Measure

integer

Recorded events for the selected breakdown; repeated events are included.

sessions

Measure

integer

Distinct observed sessions for each breakdown. A session may belong to several rows.

page

Breakdown

string

Visited page path.

search

Breakdown

string

Recorded search terms.

search_zero

Breakdown

string

Search terms with no results.

country

Breakdown

string

Observed country.

city

Breakdown

string

Observed city.

referrer

Breakdown

string

Recorded referring source.

Ordered journeys fields#

Field

Kind

Type

Definition

sessions

Measure

integer

Consented sessions completing this and every preceding step in order, within the selected time window from their first entry.

step_rate

Measure

ratio

Sessions reaching this step divided by sessions reaching the preceding step. Unavailable when none reached the preceding step.

overall_rate

Measure

ratio

Sessions reaching this step divided by sessions entering the journey. Unavailable when no sessions entered.

recorded_events

Measure

integer

All recorded non-test human or commerce events of this step's type in the selected period, including repeated and unlinked events.

linked_events

Measure

integer

Recorded events of this type carrying a session ID and analytics consent. These are events, not distinct sessions or completed steps.

linkage_coverage

Measure

ratio

Events with a session ID and analytics consent divided by recorded events of this type. Unavailable when no events were recorded.

step

Breakdown

integer

One-based position in the configured journey. Read query.journey.steps for its event type.

Order operations fields#

Field

Kind

Type

Definition

orders

Measure

integer

All non-test orders created in the period, including unpaid and cancelled orders. Archived orders remain included.

cancelled_orders

Measure

integer

Orders from the selected creation period that are currently cancelled.

cancellation_rate

Measure

ratio

Currently cancelled orders divided by all non-test orders created in the period.

refunded_orders

Measure

integer

Orders from the selected creation period whose current financial status is refunded.

partially_refunded_orders

Measure

integer

Orders from the selected creation period whose current financial status is partially refunded.

day

Breakdown

date

The order creation date. In the store timezone.

week

Breakdown

date

Monday of the record creation week in the store timezone.

month

Breakdown

date

The record creation month in the store timezone.

country

Breakdown

string

Country saved with the order; blank when unavailable.

channel

Breakdown

string

The sales channel recorded with the order.

cancellation_status

Breakdown

string

Current cancellation state: cancelled or not_cancelled. This is independent of the merchant's workflow status.

Payment outcomes fields#

Field

Kind

Type

Definition

payment_records

Measure

integer

Payment records created in the period for non-test orders. Split tenders and retries can create several records per order. Includes cancelled orders; not a count of checkout attempts.

payment_orders

Measure

integer

Distinct orders represented by these payment records. An order can appear in several breakdown rows.

captured_payments

Measure

integer

Records whose current status is captured. Records subsequently refunded belong to their current refund status instead.

failed_payments

Measure

integer

Records whose current status is failed.

pending_payments

Measure

integer

Records whose current status is pending or authorized.

refunded_payments

Measure

integer

Records whose current status is refunded or partially_refunded.

unknown_payments

Measure

integer

Records with a missing or unrecognized current payment status.

payment_failure_share

Measure

ratio

Currently failed payment records divided by all payment records created in the period. This is not a checkout failure rate.

day

Breakdown

date

The payment record creation date. In the store timezone.

week

Breakdown

date

Monday of the record creation week in the store timezone.

month

Breakdown

date

The record creation month in the store timezone.

country

Breakdown

string

Country saved with the order; blank when unavailable.

channel

Breakdown

string

The sales channel recorded with the order.

payment_status

Breakdown

string

Current recorded payment status; unrecognized or missing values are unknown.

provider

Breakdown

string

Recorded provider identifier; blank when unavailable.

method

Breakdown

string

Recorded payment method identifier.

Refund outcomes fields#

Field

Kind

Type

Definition

refund_records

Measure

integer

Refund records created in the period for non-test orders, including cancelled orders. Multiple partial refunds count separately.

completed_refunds

Measure

integer

Refund requests whose settlement and order effects are complete.

pending_refunds

Measure

integer

Refund requests awaiting settlement or completion of their order effects.

failed_refunds

Measure

integer

Refund requests whose recorded settlement failed.

unknown_refunds

Measure

integer

Refund requests without a recognized settlement outcome.

completed_refund_amount

Measure

money

Sum of saved base-currency amounts for completed refunds with known non-negative amounts. Includes merchandise and other charges. Unavailable if no completed amount is known; read amount coverage alongside it.

refund_amount_coverage

Measure

ratio

Completed refund requests with a known non-negative base-currency amount divided by all completed requests. A saved zero is known; unavailable when no refunds are complete.

day

Breakdown

date

The refund request creation date. In the store timezone.

week

Breakdown

date

Monday of the record creation week in the store timezone.

month

Breakdown

date

The record creation month in the store timezone.

country

Breakdown

string

Country saved with the order; blank when unavailable.

channel

Breakdown

string

The sales channel recorded with the order.

refund_status

Breakdown

string

Current completion outcome: completed, pending, failed or unknown.

method

Breakdown

string

Recorded refund method; missing or unrecognized methods are unknown.

Fulfilment outcomes fields#

Field

Kind

Type

Definition

fulfillment_records

Measure

integer

Fulfilment records created in the period for non-test orders. Partial fulfilments count separately; cancelled orders remain included.

fulfillment_orders

Measure

integer

Distinct orders represented by these fulfilment records. An order can appear in several breakdown rows.

pending_fulfillments

Measure

integer

Fulfilments whose current status is pending.

in_transit_fulfillments

Measure

integer

Fulfilments currently in transit, out for delivery, or awaiting another attempt after a failed delivery attempt.

delivered_fulfillments

Measure

integer

Fulfilments whose current status is delivered.

returning_fulfillments

Measure

integer

Fulfilments currently returning to the sender.

returned_fulfillments

Measure

integer

Fulfilments returned to the sender.

failed_fulfillments

Measure

integer

Fulfilments currently failed, lost, damaged, or destroyed.

cancelled_fulfillments

Measure

integer

Fulfilments whose current status is cancelled.

tracking_coverage

Measure

ratio

Fulfilments with a non-empty tracking number divided by all fulfilment records.

day

Breakdown

date

The fulfilment record creation date. In the store timezone.

week

Breakdown

date

Monday of the record creation week in the store timezone.

month

Breakdown

date

The record creation month in the store timezone.

country

Breakdown

string

Country saved with the order; blank when unavailable.

channel

Breakdown

string

The sales channel recorded with the order.

fulfillment_status

Breakdown

string

Current canonical fulfilment status.

carrier

Breakdown

string

Carrier saved with the fulfilment; blank when unavailable.