List marketing contacts
The store’s marketing contacts: one row per resolvable person, with the per-channel consent state that decides whether they may be mailed. THE FILTERS ARE WHAT THIS ROUTE IS FOR. ?email_consent=subscribed is the set you may mail today, which is the question an ESP reconciliation actually asks; ?q= is a substring match over email, phone and both names for a support lookup. Combine them freely. FOUR CONSENT STATES, AND never IS NOT unsubscribed. never means this person was never asked, unsubscribed means they were and said no, and pending is a double opt-in nobody confirmed. Only subscribed is permission to send; collapsing the other three into one is how a platform mails someone who refused. ERASED CONTACTS STAY IN THE LIST rather than disappearing, with erased true and every personal field null. That is deliberate: if the row vanished, every system syncing from this one would keep the copy this platform just destroyed. Treat erased true as a delete on your side. TOTAL SPEND IS NOT PUBLISHED. The stored figure sums minor units across whatever currency each order was placed in and this record carries no currency code, so it is a number you could not interpret. Segment on spend through the segments family instead, where the comparison is evaluated server-side.
Authorizations
A secret API key. Publishable keys cannot reach this API. A key may carry an expiry, and an expired key is refused exactly like an unknown one, with a 401 that names no reason; check the key's expires_at in the dashboard rather than inferring it from a response. When a merchant rolls a key's secret they choose a grace window of up to 3 days, and for its duration BOTH the new secret and the one it replaced authenticate, so an integration moves over on its own deploy schedule instead of at the instant the button is pressed. Move before the window closes: after it, the old secret is refused. Nothing else about this contract moves with a roll. The key keeps its id and its scopes, so the only thing an integration updates is the credential itself.
Query Parameters
Case-insensitive substring match over email, phone_e164, first_name and last_name. % and _ match themselves rather than acting as wildcards, so a search for a literal underscore in a local part finds it and a search for "%" is not an unfiltered export.
Filter by the CURRENT email consent state. subscribed is the set you may mail; the other three are not, and they are separate facts rather than shades of the same one. An unrecognised value is a 400, because a client told "no contacts" by a typo concludes the store has an empty list.
subscribed, pending, unsubscribed, never The same filter for sms. Consent is per channel, so an email unsubscribe leaves this untouched.
subscribed, pending, unsubscribed, never The same filter for push.
subscribed, pending, unsubscribed, never Rows per page. Out of range is a 400 rather than a silent clamp, so a client asking for more than 100 learns it did not get it.
1 <= x <= 100The next_cursor from the previous page. Opaque: decode nothing from it and construct nothing by hand, since its encoding is not part of this contract. Omit it to read the first page.
