Skip to main content
GET
Get traffic geography

Authorizations

Authorization
string
header
required

Bearer token authentication

Query Parameters

period
string

Named reporting period (default last_30_days). Supported names: today, last_7_days, last_30_days, last_90_days, last_12_months, this_month, last_month. An unsupported name returns 422.

Response

Success

Store-traffic geography for a period — the resolved window, the days of it geography could answer, the ranked country breakdown with the revenue delivered to each country, and a nested city breakdown carrying its own capture window, wrapped in the standard API response envelope.

period
object
required
effective_window
object | null
required

The days of the requested period that geography could answer — the requested window intersected with the days this store has carried placed visits. Every count in the payload is taken over this window rather than the requested one.

Null when the two do not meet, which means the period lies entirely before this store began carrying placed visits. Null arrives with an empty countries list and zeroed totals, and is deliberately distinct from an answerable window whose counts are all zero — that means nobody came. Do not coerce one into the other.

revenue_window
object
required

The days the revenue figures cover — the whole requested period, on the order's own clock. An order falls inside it by created_at, over the half-open UTC range [starts_on 00:00, (ends_on + 1) 00:00), the same predicate every conversion figure on this tab applies.

Never null, unlike effective_window, and it covers a different and longer span. Orders have carried a delivery country for years, while visit geography only reaches capture_start and can never be backfilled — an IP that was never recorded cannot be recovered. So on a period reaching back past capture, a country row shows revenue for the whole window beside visitors for only part of it. Neither number is wrong; each is right over its own span. Do not render the two columns as one measurement — say which days each covers, rather than leaving a reader to infer the gap from a suspiciously low visitor count. The gap closes as capture accrues and never inverts: revenue always covers at least as much of the window as visitors do.

capture_start
string<date> | null
required

The day this store first carried a placed visit (YYYY-MM-DD, UTC), or null when it never has. Reported whether or not the requested period overlaps it, so a client can say when geography began rather than presenting an empty period as an absence of traffic.

countries
object[]
required

Countries ranked by resolved visitors, capped at ten and optionally ending in a single "(other)" row folding the tail.

This is a partition, not an attribution split: each visitor resolves to exactly one country — the country of their most recent placed visit in the window — so the rows are disjoint and Σ(visitors) + unplaced_visitors == total_visitors holds exactly.

A row's visitors and revenue answer two different questions and are not a numerator and a denominator: visitors counts people an IP placed in this country, revenue sums orders whose delivery address is here. Never divide one by the other into a conversion rate — the two populations are not the same people and the quotient means nothing. They also cover different spans; see revenue_window.

cities
object
required

The city breakdown, nested rather than listed beside the countries because it answers a different set of days. City capture began after country capture, so this object carries its own capture_start, its own effective_window, and its own total_visitors.

cities.total_visitors will usually differ from the top-level total_visitors, because each counts the visitors of its own window. Both are correct. Divide city shares by cities.total_visitors and never by the top-level one.

total_visitors
integer
required

Total distinct bot-free visitors over the effective window, placed and unplaced together. The denominator every share divides by.

unplaced_visitors
integer
required

Visitors with no placed visit in the effective window — counted, not dropped, so the country breakdown provably sums to the whole.

Shares are against total_visitors and are deliberately not renormalised, so Σ(shares) is the placed fraction rather than 1. The gap is this number, and it is meant to stay visible.

accounted_revenue
string
required

The revenue the country rows add up to over revenue_window, as a decimal string in the platform base currency — so a merchant totting the column up arrives at this number. The folded "(other)" row is included, exactly as it is in the column.

paid_revenue
string
required

Every purchased order's revenue over the same revenue_window, whatever country it was delivered to or whether it named one at all, as a decimal string in the platform base currency — the whole of the population the country column is cut from.

Paired with accounted_revenue this is what makes the rows auditable: two checkable numbers rather than one computed percentage, so the client owns the phrasing. The identity is exact — accounted_revenue plus the revenue of purchased orders carrying no delivery country equals paid_revenue — and the two do not usually diverge, so a gap between them is worth looking into rather than the ordinary state of things.

Read it as the population's total, not as store revenue. It covers storefront purchases and excludes imported orders, which are a material share of platform revenue, so neither this number nor the column beneath it is a merchant's whole book.

status
integer
required

The HTTP status code echoed in the response envelope.

meta
object
required