Quorum Data API
Store-visit measurement and location data for agencies and their advertisers. Send Quorum your advertisers and store lists, then read back each store's status, its visit records, and the numbers on your published Quorum reports.
Base URL: https://api.quorum.live Auth: Bearer token Swagger UI · ReDoc · openapi.json
Authentication
Send your token in the Authorization header on every request:
Authorization: Bearer <your-token>
Three routes need no token: the health check (GET /v1/health, also served at /health), GET /v1/library/categories and POST /v1/library/audience-intel.
- A missing or unknown token gets
401. - A token can have an expiry date. After it, the token gets
401with"API token expired". Ask Quorum for a new one. - A token can be read-only. A read-only token can call every GET route it is allowed, but
POST /v1/intake/*returns403with a message saying the token is read-only. - Tokens are bound to one agency and stored as SHA-256 hashes, so Quorum cannot show you a token again. Keep it in a secrets manager.
Two kinds of advertiser id
| Id | Where it comes from | Which routes take it |
|---|---|---|
| Your DSP advertiser id | Your own id (for MNTN, the ${aid} pixel macro). The same value you send as client_advertiser_id to intake. | /v1/advertisers/{advertiser_id}/locations, .../locations/{segment_md5}/visits, /report, /reports, and every /v1/intake/* route. |
| Quorum advertiser id | Listed by GET /v1/advertisers, and returned as quorum_advertiser_id by GET /v1/intake/advertisers once mapped. | Every other advertiser_id: the roll-ups (/summary, /campaigns, ...), /visitor-geography, /nearby-competitors, /v1/performance/*, /v1/segments/* and /v1/partner-feed/*. /locations, /visits, /report and /reports also accept a Quorum id your agency owns. |
If you have no DSP mapping with Quorum (for example your DSP ids are on a platform Quorum has not crosswalked), use the Quorum ids from GET /v1/advertisers everywhere. When an id is both one of your DSP ids and a Quorum id, the DSP reading wins.
One DSP id can map to more than one Quorum account (for example one per market). /locations then returns the union of their locations, and /visits serves any location configured on any of them.
Quick start
curl https://api.quorum.live/v1/health
# {"status":"ok","snowflake":"connected"}
curl https://api.quorum.live/v1/advertisers \ -H "Authorization: Bearer <token>"
curl "https://api.quorum.live/v1/advertisers/12345/locations?location_type=POI" \ -H "Authorization: Bearer <token>"
Access and scope
A token issued to anyone outside Quorum is a partner token. Partner tokens follow the rules below. Internal Quorum tokens are not affected.
1. You read only your own agency's advertisers
- On the advertiser roll-ups (
/v1/advertisers/{advertiser_id}/config,/tab-availability,/summary,/timeseries,/campaigns,/lineitems,/lift,/store-visits/brands), an advertiser that is not your agency's gets403with"Advertiser N is not in your agency."Ownership is checked against both of Quorum's advertiser registries. An id that both registries assign to different agencies is refused until Quorum resolves it. - Routes that take your DSP id (
/locations,/visits,/report,/reports) resolve it inside your agency only, or accept a Quorum id your agency owns. Any other id gets404. - Routes that filter by your agency (
/v1/performance/*,/v1/segments/catalog,/v1/advertisers/{advertiser_id}/segments,/v1/partner-feed/*,/visitor-geography,/nearby-competitors) return an empty list or404for an advertiser that is not yours. - A token can also be limited to a list of advertisers. Any other
advertiser_idgets403. - If Quorum cannot check ownership at that moment, you get
503, never data. Retry.
2. No device- or household-level routes
These routes return a 403 to partner tokens. The message points to the Quorum MCP at https://mcp.quorum.live/mcp, which answers the same questions as k-anonymous aggregates:
| Route | Why |
|---|---|
| POST /v1/resolve | Returns a household and its devices. |
| GET /v1/household/{household_id}/geo | Household-level. |
| GET /v1/household/{household_id}/footprint | Household-level. |
| GET /v1/household/{household_id}/visits | Household-level. |
| GET /v1/household/{household_id}/publishers | Household-level. |
| GET /v1/segments/{segment_md5}/visits | Device-level rows. |
| GET /v1/segments/{segment_md5}/visitor-geography | Small-area geography with no privacy floor. |
| GET /v1/locations/{segment_md5}/visitor-geography | Small-area geography with no privacy floor. |
| GET /v1/advertisers/{advertiser_id}/segments/{segment_md5}/households | Household list. |
| GET /v1/performance/households | One row per household. |
3. Writes need a write-enabled token
POST /v1/intake/* (advertisers, locations, disconnect, reconnect) returns 403 for a read-only token. The qurum_ag_id (or agency_id) in an intake body must equal your token's agency, or the request gets 403.
4. Disconnected advertisers
After you disconnect an advertiser (POST /v1/intake/advertisers/{client_advertiser_id}/disconnect), every read of it returns 410, by your id or by its Quorum advertiser id. Nothing is deleted and capture continues; reconnecting restores everything, including the disconnected period.
Status codes
Errors come back as JSON with a detail field that says what went wrong.
| Code | Meaning | What to do |
|---|---|---|
| 200 | Success. An empty list is a real answer (nothing matched), not a reason to retry. | Use it. |
| 202 | Your advertiser is recognised but Quorum has not finished mapping it (PENDING). | Back off and retry later. |
| 400 | Bad input the route checks itself, such as a reversed or too-wide date window on the partner feed, or a duplicate id in one intake request. | Fix the request. |
| 401 | Missing header, unknown token, or expired token. | Check the token; ask Quorum for a new one if it expired. |
| 403 | The token is not allowed this request: a partner token on a device- or household-level route, an advertiser outside your agency or outside the token's advertiser list, a read-only token on POST /v1/intake/*, or an intake body whose agency does not match the token. | Do not retry. Read detail. |
| 404 | Not found for your agency: an unknown advertiser id, a segment_md5 not configured for the advertiser, a missing ZIP, or no published report. | Permanent for that input. For an unknown advertiser, POST it to /v1/intake/advertisers first. |
| 410 | Your agency disconnected this advertiser. | Do not retry. Reconnect it to restore access; nothing was deleted. |
| 422 | Invalid parameter or body (FastAPI validation), or an advertiser Quorum has marked IGNORED/DEACTIVATED. | Fix the request. An ignored advertiser is permanent. |
| 429 | Per-IP rate limit, only on the library routes that state one (audience-intel: 3 per minute; cross-shop and cross-shop-dma: 10 per minute). | Slow down. |
| 500 | Unexpected server error. | Contact api@quorum.live. |
| 503 | Quorum cannot verify tokens or advertiser ownership right now, or a report payload is not servable yet. | Retry shortly. |
What changed (2026-11-10, API 2.1.0)
- Partner scope. Partner tokens read only their own agency's advertisers, and the device- and household-level routes are refused with
403. See Access and scope. - Token expiry and read-only tokens. An expired token gets
401; a read-only token gets403onPOST /v1/intake/*. - Published report numbers. New
GET /v1/advertisers/{advertiser_id}/reportand/reports. - Store status read-back. New
GET /v1/intake/locations. - Disconnect / reconnect. New
POST /v1/intake/advertisers/{client_advertiser_id}/disconnect,/reconnectandGET .../connection; reads for a disconnected advertiser return410. - Quorum ids on /locations and /visits. A partner token may now pass a Quorum advertiser id its agency owns, not only a DSP id. Useful when your DSP ids are not crosswalked.
- Intake is add-only. Re-posting a store returns the same
location_id, withcreatedandstatusper row./locationsnow echoes yourclient_location_nameandlocation_id. - Stores move to pending_draw once their advertiser is mapped and they have a usable address.
- One DSP id, several Quorum accounts.
/locationsand/visitsserve the union. - /visits date window. Dates are UTC days. New opt-in
end_exclusive=truefor a[date_from, date_to)window; without itdate_tois inclusive. - /locations fields.
maid_count_60dis deprecated and always null; use the newdevice_days_60d.lat,lon,address,cityandstateare filled, and a stored text'null'comes back as a JSON null. - /v1/health works as an alias of
/health. - Removed: the library's free-text question route (
ask). Ask open-ended questions through the Quorum MCP.
Every advertiser configured for your agency, with names. The advertiser_id it returns is a Quorum advertiser id; use it on the roll-ups, /v1/performance/*, /v1/segments/* and /v1/partner-feed/*. No parameters.
| Field | Type | Description |
|---|---|---|
| agency_id | integer | Your agency id. |
| agency_name | string|null | Agency name. |
| advertiser_id | integer | Quorum advertiser id. |
| advertiser_name | string|null | Advertiser name. |
curl "https://api.quorum.live/v1/advertisers" \ -H "Authorization: Bearer <token>"
The numbers on your published Quorum report, as data. They come from the same build as the report page, so every figure reconciles with the page. Schema quorum.retail_report.v1.
advertiser_id is your own DSP advertiser id, or a Quorum advertiser id your agency owns. You only ever see reports registered to your agency. A DSP id that is pending, disconnected or ignored answers 202, 410 or 422 as on /locations.
Query parameters
| Parameter | Type | Description |
|---|---|---|
| report_id | string | Pick one report when the advertiser has several (see /reports). |
| period | string | Report period, YYYYMM. |
| version | integer ≥ 1 | A specific published version. Default: the latest. |
What is in the payload
headline,daily,weekly,campaigns,publishers,creatives,stores,zips,time_to_visit, plusdefinitions,windows(withmatureandmatures_on),attribution_days,kminandcoverage_multiplier. Sections the page does not show are[].- Visit: one household visiting any of the locations on one calendar day, deduplicated, attributed within
attribution_daysof an ad exposure.visit_rate= visits / impressions. *_detfields are measured (deterministic) households.*_est=*_det×coverage_multiplier.- The row-level tables carry the measured
visits_det. The page shows those cells grossed up, so page value = round(visits_det × coverage_multiplier). Each row'svisit_rateis the page's own rate. - Cells under the reporting floor (k ≥ 3) are
nullwithsuppressed: true(or awithheld_reason). The page withholds them too. - Rates are fractions (0.00096, not 0.096%). Dates are the report's local dates,
YYYY-MM-DD. publicationis added by the API:report_id,version,period,quorum_advertiser_ids,published_at,builder_sha,mature,matures_on, andother_report_idswhen the advertiser has more than one report.- While
matureis false, visits can still attribute and the figures can only go up.
404 when there is no published report for the advertiser (and filters). 503 if the stored payload is not in a servable format.
curl "https://api.quorum.live/v1/advertisers/12345/report" \ -H "Authorization: Bearer <token>"
Every published version of every report for the advertiser, newest first, without the numbers. Optional period (YYYYMM). Response: {"advertiser_id": ..., "reports": [ {report_id, version, period, quorum_advertiser_ids, published_at, builder_sha, mature, matures_on} ]}.
curl "https://api.quorum.live/v1/advertisers/12345/reports?period=202610" \ -H "Authorization: Bearer <token>"
The advertiser's capability flags. advertiser_id is a Quorum advertiser id; partner tokens get 403 for an advertiser outside their agency. The same applies to every roll-up below, and each of them takes date_from / date_to (YYYY-MM-DD, default the last 30 days).
| Field | Type | Description |
|---|---|---|
| advertiser_id | integer | Quorum advertiser id. |
| display_name | string|null | Advertiser name. |
| has_store | boolean | Store-visit reporting is configured (report types 1, 4 or 6). |
| has_web | boolean | Web-visit reporting is configured (report types 2 or 5). |
| report_type_ids | string|null | Comma-separated report type ids. |
| attribution_window | integer | Days from exposure to visit that count. Default 28. |
| config_status | string | ACTIVE, IMPRESSIONS_ONLY or NOT_CONFIGURED. |
curl "https://api.quorum.live/v1/advertisers/1234/config" -H "Authorization: Bearer <token>"
Which report tabs have data in a date range (date_from, date_to, default the last 30 days). Use it before drawing a report UI.
| Field | Description |
|---|---|
| impressions | The publisher table has rows in range. |
| store_visits / web_visits | From the config flags, not a data check. |
| publisher / geo / creative / traffic / household | The matching performance table has rows in range. |
| lift | has_store and impressions are both true. |
| advertiser_id, config_status | As on /config. |
curl "https://api.quorum.live/v1/advertisers/1234/tab-availability?date_from=2026-10-01&date_to=2026-10-31" \ -H "Authorization: Bearer <token>"
Headline metrics over date_from..date_to. Impressions and reach come from the publisher performance table; visits from the household attribution tables, scaled by a coverage multiplier.
The roll-ups (/summary, /timeseries, /campaigns, /lineitems, /lift) use a different method from your published report and will not match it. To reproduce the numbers on your report page, use /report.
| Field | Description |
|---|---|
| impressions / device_reach / household_reach | From the publisher table. |
| store_panel_reach / web_panel_reach | Measured households that saw an ad and then visited. |
| store_visits / web_visits | panel reach × multiplier. |
| store_visit_rate / web_visit_rate | Visits / impressions. |
| multiplier / multiplier_grain / multiplier_significant | Coverage multiplier and the grain it came from (line item, campaign, advertiser, or a global default). |
| hh_resolution_rate | Share of impressions that resolved to a household. |
| platform_count / campaign_count / lineitem_count | Counts in range. |
| has_store / has_web | Config flags. |
| start_date / end_date / data_start / data_end | Requested window and the dates that actually had data. |
curl "https://api.quorum.live/v1/advertisers/1234/summary?date_from=2026-10-01&date_to=2026-10-31" \ -H "Authorization: Bearer <token>"
One row per day: log_date, impressions, device_reach, household_reach, store_visits, store_visit_rate, web_visits, web_visit_rate. Visits are multiplier-scaled. Params: date_from, date_to.
curl "https://api.quorum.live/v1/advertisers/1234/timeseries?date_from=2026-10-01&date_to=2026-10-31" \ -H "Authorization: Bearer <token>"
One row per insertion order: io_id, io_name, impressions, device_reach, household_reach, store_panel_reach, store_visits, store_visit_rate, web_panel_reach, web_visits, web_visit_rate, multiplier, first_date, last_date. Params: date_from, date_to.
curl "https://api.quorum.live/v1/advertisers/1234/campaigns?date_from=2026-10-01&date_to=2026-10-31" \ -H "Authorization: Bearer <token>"
One row per line item, with the same fields as /campaigns plus li_id and li_name. Params: date_from, date_to, and optional io_id to limit to one campaign.
curl "https://api.quorum.live/v1/advertisers/1234/lineitems?date_from=2026-10-01&io_id=IO-456" \ -H "Authorization: Bearer <token>"
Visit rate of exposed households against non-exposed visitors. Params: date_from, date_to.
| Field | Description |
|---|---|
| exposed_hh | Households with at least one impression. |
| exposed_store_visitors / exposed_store_visit_rate | Exposed households that visited, and their share. |
| exposed_web_visitors / exposed_web_visit_rate | The same for web visits. |
| control_store_visitors / control_store_visit_rate | Baseline from non-exposed visitors. |
| lift_pct | (exposed rate − control rate) / control rate × 100. |
| confidence | Simple 0–99 score from the exposed sample size. |
| has_store / has_web | Config flags. |
curl "https://api.quorum.live/v1/advertisers/1234/lift?date_from=2026-10-01&date_to=2026-10-31" \ -H "Authorization: Bearer <token>"
Store visits by brand and category. Response: advertiser_id, total_visits, unique_households, and brands[] with brand, category, visits (measured, not scaled), unique_households, avg_days_to_visit. Params: date_from, date_to.
curl "https://api.quorum.live/v1/advertisers/1234/store-visits/brands?date_from=2026-10-01&date_to=2026-10-31" \ -H "Authorization: Bearer <token>"
Locations and visits
These routes give you the stores Quorum tracks for an advertiser and the visits it observes there.
| Route | What it answers |
|---|---|
| GET .../locations | Which locations are tracked, with metadata, coordinates and 60-day activity. Takes your DSP id or an owned Quorum id. |
| GET .../locations/{segment_md5}/visits | Every device observation at one location, paginated for bulk export. Takes your DSP id or an owned Quorum id. |
| GET .../locations/{segment_md5}/visitor-geography | Where a location's visitors live, by census block. Takes the Quorum id. |
| GET .../locations/{segment_md5}/nearby-competitors | Nearby locations in a category. Takes the Quorum id. |
Typical workflow
POST your advertiser to
/v1/intake/advertisersand your stores to/v1/intake/locations.Poll
GET /v1/intake/locationsuntil stores areactive; each active store lists itssegment_md5s.Call
/locationsto see every tracked location (yours carry yourclient_location_name).Pull
/visitspersegment_md5for a date window.
Polling
/locations and /visits resolve your id first (DSP id, then a Quorum id your agency owns). 200 (even with an empty list) means mapped; 202 means mapped soon, retry; 404 unknown for your agency; 410 disconnected; 422 ignored. Only 202 is a retry signal.
Household ids
The household_id on visit records is, for partner tokens, a stable 32-character HMAC of the household: the same household always gets the same value, so you can deduplicate and match on it, but it cannot be turned back into a location. The finest geography returned is the census block.
Every location configured for the advertiser, both POIs (stores, venues) and Attractions (zones), whether or not visits have been seen. advertiser_id is your own DSP advertiser id, or a Quorum advertiser id your agency owns. Locations with no visits in 60 days are included unless you set min_households.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| location_type | string | — | POI or ATTRACTION. Omit for both. |
| brand | string | — | Case-insensitive exact brand match. |
| min_households | integer | 0 | Minimum 60-day household count. 1 drops locations with no traffic. |
| limit | integer | 5000 | Max rows, up to 50,000. |
Response fields
| Field | Type | Description |
|---|---|---|
| segment_md5 | string | Quorum's id for the location. Use it on /visits. |
| location_type | string | POI or ATTRACTION. |
| name / brand / category | string|null | Quorum's name for the location, its brand and category. |
| client_location_name | string|null | Your own label for the store, exactly as you sent it to POST /v1/intake/locations. Null for locations you did not submit, or not yet drawn. One label can sit on several segment_md5s. |
| location_id | integer|null | The intake location_id for that label (informational). |
| lat / lon | float|null | Location coordinates. |
| address / city / state / zip_code | string|null | Address. |
| dma_name / region | string|null | DMA and region. |
| visits_30d | integer|null | Measured visits in the last 30 days (not scaled). |
| household_count_60d | integer | Distinct households seen in the last 60 days. 0 if none. |
| device_days_60d | integer | Device-days in the last 60 days (a device seen on two days counts twice). |
| maid_count_60d | null | Deprecated, always null. Use device_days_60d. |
Text fields never carry the string "null": a missing value is a JSON null.
curl "https://api.quorum.live/v1/advertisers/12345/locations?location_type=POI&min_households=1" \ -H "Authorization: Bearer <token>"
Raw visit records for one location: one row per device observation, with household resolution and IP enrichment. advertiser_id is your own DSP advertiser id, or a Quorum advertiser id your agency owns. 404 if the segment_md5 is not configured for the advertiser.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| date_from | date | 60 days before date_to | First UTC day of the window, always inclusive (YYYY-MM-DD). |
| date_to | date | today (UTC) | Last UTC day. Inclusive unless end_exclusive=true. |
| end_exclusive | boolean | false | false: window is [date_from, date_to]. true: window is [date_from, date_to), so if each pull starts where the last one ended, no day is returned twice. |
| limit | integer | 100,000 | Rows per page, up to 1,000,000. |
| offset | integer | 0 | Row offset. Add limit to get the next page. |
Response fields
| Field | Type | Description |
|---|---|---|
| segment_md5 | string | The location. |
| segment_name | string|null | Quorum's name for the location. |
| maid | string|null | Mobile advertising id seen at the location. |
| household_id | string|null | Stable 32-character opaque key for partner tokens (see Household ids). Null if the device did not resolve. |
| visit_date | date | UTC calendar day of the visit. |
| visit_timestamp | datetime|null | Time of the observation, in UTC (no offset in the string). |
| capture_ip | string|null | IP seen at capture (the device's, not the household's). |
| hh_primary_ip | string|null | Best household IPv4: the most-observed IP for this device in the last 30 days. |
| ip_last_seen | date|null | Last time hh_primary_ip was seen. |
| ip_observation_count | integer|null | How often that IP was seen for this device. Higher is more reliable. |
| capture_census_block | string|null | Census block of the location. |
| hh_census_block | string|null | Home census block of the household. |
| capture_lat / capture_lon | float|null | Coordinates of the observation, when available. |
Order and paging: rows are sorted by visit_date descending, then maid ascending. The most recent 1–3 days are still filling in.
curl "https://api.quorum.live/v1/advertisers/12345/locations/abc123def456.../visits?date_from=2026-10-01&date_to=2026-11-01&end_exclusive=true&limit=100000&offset=0" \ -H "Authorization: Bearer <token>"
Where a location's visitors live, from a pre-built table over a rolling 90-day window. No date parameters. advertiser_id here is the Quorum advertiser id (from GET /v1/advertisers), and the location must be configured for it in your agency, otherwise 404.
| Field | Type | Description |
|---|---|---|
| segment_md5 | string | The location. |
| window_start / window_end | date|null | The window actually used. |
| total_devices_at_location | integer | Distinct devices seen at the location in the window. |
| census_blocks[] | array | Home census blocks, highest visitor index first. Each: census_block_id, zip_code, device_count, cblock_population, cblock_households, cblock_visitor_index (1.5 = 50% more visitors than its population share predicts), zip_visitor_index. |
curl "https://api.quorum.live/v1/advertisers/1234/locations/abc123def456.../visitor-geography" \ -H "Authorization: Bearer <token>"
Library locations in a category near an anchor location, nearest first. The advertiser's own locations are left out. advertiser_id is the Quorum advertiser id; the anchor must be configured for it in your agency and have coordinates, otherwise 404.
| Parameter | Type | Default | Description |
|---|---|---|---|
| category_pattern | string (required) | — | Category to match. A bare word matches any category containing it; * or % are wildcards (restaur*, *QSR*). |
| radius_miles | float | by category | 0.1–100. If omitted: auto/dealer 25, hotel 15, home improvement/furniture 10, gym/fitness 8, restaurant 5, grocery/pharmacy/cafe 3, gas 2, anything else 5. |
| limit | integer | 200 | Up to 2,000. |
Fields: segment_md5, name, brand, category, distance_miles, lat, lon, address, city, state, dma_name, visits_30d, household_count_60d.
curl "https://api.quorum.live/v1/advertisers/1234/locations/abc123def456.../nearby-competitors?category_pattern=restaurant&radius_miles=3" \ -H "Authorization: Bearer <token>"
Add or update your advertisers, keyed on your own client_advertiser_id. A new id opens a PENDING mapping that Quorum completes; nothing is ever deleted. The same id twice in one request is a 400.
| Field | Type | Required | Description |
|---|---|---|---|
| qurum_ag_id | integer | Yes | Your agency id; must equal your token's agency (403 otherwise). Also accepted as agency_id. |
| records[] | array (1–10,000) | Yes | Each: client_advertiser_id (integer, required), client_advertiser_name (required), website, status. |
| records[].status | string | No | ACTIVE or RETIRED (= disconnected). Omit to leave the stored status unchanged; a new advertiser starts ACTIVE. |
Response: accepted, new_client_advertiser_ids.
curl -X POST https://api.quorum.live/v1/intake/advertisers \
-H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
-d '{"qurum_ag_id": 1234, "records": [{"client_advertiser_id": 12345, "client_advertiser_name": "Example Brand", "website": "example.com"}]}'
Your advertisers and their Quorum mapping. Optional client_advertiser_id filter. Fields: client_advertiser_id, client_advertiser_name, website, status, quorum_advertiser_id (null until mapped), mapping_status (PENDING | MAPPED | IGNORED), mapped_at, location_count, status_updated_at.
curl "https://api.quorum.live/v1/intake/advertisers?client_advertiser_id=12345" \ -H "Authorization: Bearer <token>"
From the next request on, every route that reads this advertiser returns 410, whether you call it with your own advertiser id or the Quorum advertiser id: /locations, /visits, /report, /performance/*, /summary and the rest. Nothing is deleted, capture keeps running, and the Quorum advertiser, your stores and their locations are kept. Optional body {"reason": "..."} (kept in Quorum's audit log). Idempotent: repeating it returns 200 with changed: false.
Serves the advertiser again, with its full history, including visits captured while it was disconnected. Same optional body. Idempotent.
The current state. All three return client_advertiser_id, agency_id, status (ACTIVE | RETIRED), connected, status_updated_at, and on POST changed. 404 if the id is unknown to your agency; 403 on the POSTs for a read-only token.
curl -X POST https://api.quorum.live/v1/intake/advertisers/12345/disconnect \
-H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
-d '{"reason": "campaign paused"}'
curl https://api.quorum.live/v1/intake/advertisers/12345/connection \
-H "Authorization: Bearer <token>"
Send your stores. Add-only: send the full list or just the new stores. Stores already on file are kept, new ones are added, and a store you leave out is never deleted.
- Your
location_nameis stored exactly as sent. It is the label Quorum gives back everywhere (GET /v1/intake/locations, andclient_location_nameon/locations). - A store row is identified by
client_advertiser_id+location_name+address+city+state+zip_code. Re-posting the same row returns the samelocation_idwithcreated: false. - A store moves from
submittedtopending_drawonce its advertiser is mapped and it has a street address plus a ZIP or city and state. Quorum then draws its footprint and it becomesactive.
| Field | Type | Required | Description |
|---|---|---|---|
| qurum_ag_id | integer | Yes | Your agency id (or agency_id); must equal your token's agency. |
| records[] | array (1–10,000) | Yes | One per store. |
| records[].client_advertiser_id | integer | Yes | Your advertiser id. |
| records[].location_name | string | Yes | Your store label. |
| records[].address / city / state / zip_code | string | No | Street address. state is two letters; a 1–4 digit ZIP is zero-padded to 5. |
| records[].store_url | string | No | Store page URL. |
Response
| Field | Description |
|---|---|
| accepted | Records in the request. |
| inserted / already_present | New rows, and rows that were already on file. |
| new_client_advertiser_ids | Advertisers seen for the first time. |
| locations[] | One per record, in request order: client_advertiser_id, location_name, location_id, created, status (submitted | pending_draw | active). |
curl -X POST https://api.quorum.live/v1/intake/locations \
-H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
-d '{"qurum_ag_id": 1234, "records": [{"client_advertiser_id": 12345, "location_name": "Example Brand #12", "address": "123 Main St", "city": "Dallas", "state": "TX", "zip_code": "75201"}]}'
The stores you have posted, one row per store, with their status.
| Status | Meaning |
|---|---|
| submitted | Received. Waiting for the advertiser to be mapped, or for a usable address. |
| pending | Queued for Quorum to draw the footprint (the POST echo calls this pending_draw). No visits yet. |
| active | Footprint drawn; segment_md5s lists the location ids. A new footprint back-fills about 85 days of visits on its first nightly run. |
Query parameters
| Parameter | Type | Description |
|---|---|---|
| client_advertiser_id | integer | Only this advertiser (your id). |
| status | string | submitted, pending or active. |
| location_name | string | Exact, case-sensitive label match. |
| after_location_id | integer | Paging cursor: the previous page's next_after_location_id. Omit for the first page. |
| limit | integer | Page size, 1–5000. Default 1000. |
Response: agency_id, status_counts (submitted, pending, active, for the same filters ignoring status and paging), returned, next_after_location_id (null on the last page), and locations[] with location_id, client_advertiser_id, location_name, address, city, state, zip_code, store_url, status, segment_md5s, submitted_at, last_submitted_at, status_updated_at (UTC). No geometry is returned.
curl "https://api.quorum.live/v1/intake/locations?client_advertiser_id=12345&status=active" \ -H "Authorization: Bearer <token>"
Daily exposure and visit counts for your agency, one row per day × advertiser (or campaign) × metric set. JSON by default, CSV with format=csv or Accept: text/csv.
| Parameter | Type | Description |
|---|---|---|
| date_from / date_to | date (required) | Inclusive window, at most 31 days. A wider or reversed window is a 400. |
| grain | string | advertiser (default) or campaign. |
| advertiser_id | integer | Quorum advertiser id. Omit for all of your agency's advertisers. |
| metric_set | string | Comma-separated subset of EXPOSURE, VISITS_STORE, VISITS_WEB. Default: all three. |
| format | string | json or csv. |
Row fields: activity_date, agency_id, advertiser_id, advertiser_name, campaign_id, campaign_name, metric_set, impressions, hh_resolved_impressions, det_count, est_count, suppressed, multiplier, multiplier_grain, multiplier_significant, config_status, unique_households_last_touch, source_table, generated_at.
det_countis measured households, never scaled.est_count= det_count × multiplier, and is null when the multiplier is not statistically significant.- A row whose det_count is above 0 but under the privacy floor (currently 50 households) has
det_countandest_countnull andsuppressed: true. A 0 always means a verified zero.
curl "https://api.quorum.live/v1/partner-feed/daily?date_from=2026-10-01&date_to=2026-10-31&grain=campaign&format=csv" \ -H "Authorization: Bearer <token>"
Window totals from the feed for one advertiser, beside its hosted report, so you can tell whether they should match. Params: advertiser_id (Quorum id), date_from, date_to (all required; 31 days max).
Response: advertiser_id, window, feed_total (impressions, det_household_reach, est_household_reach), hosted_report (report_id, report_type, refreshed_at, note, or null), match, match_reason.
curl "https://api.quorum.live/v1/partner-feed/reconcile?advertiser_id=1234&date_from=2026-10-01&date_to=2026-10-31" \ -H "Authorization: Bearer <token>"
Performance tables
Daily performance rows for one Quorum advertiser, filtered to your agency (an advertiser outside it returns an empty list). Shared parameters: advertiser_id (required), date_from (default 30 days ago), date_to (default today), io_id, li_id, limit.
Fields on every row: log_date, io_id, io_name, li_id, li_name, advertiser_id, platform_name, impressions, device_reach, household_reach, visitors, visit_rate, panel_reach, multiplier, web_visitors, total_page_views, web_visit_rate.
| Route | Extra fields | Notes |
|---|---|---|
| GET /v1/performance/publishers | publisher, supply_vendor, publisher_code, site_id, publisher_id, supply_type_id | limit default 5000, max 50,000. |
| GET /v1/performance/geo | dma, zip, census_block_id | Extra filter dma (code or name). limit default 5000, max 50,000. |
| GET /v1/performance/traffic | url, url_type | limit default 5000, max 50,000. |
| GET /v1/performance/creative | creative_id, creative_name, creative_size | limit default 5000, max 50,000. |
| GET /v1/performance/households | household_id, census_block_id | Internal tokens only |
curl "https://api.quorum.live/v1/performance/publishers?advertiser_id=1234&date_from=2026-10-01&io_id=IO-456" \ -H "Authorization: Bearer <token>"
Segments
Location segments configured for a Quorum advertiser in your agency.
Params: advertiser_id (required), limit (default 1000, max 10,000). Fields: agency_id, quorum_advertiser_id, location_type, segment_md5, name, brand, category, entity_type, dma_name.
curl "https://api.quorum.live/v1/segments/catalog?advertiser_id=1234" -H "Authorization: Bearer <token>"
30-day counts per segment, ending 5 days ago for data lag. Params: advertiser_id (required), limit (default 1000). Fields: segment_md5, segment_visitors_30d (distinct households), active_days, total_device_visits.
curl "https://api.quorum.live/v1/segments/stats?advertiser_id=1234" -H "Authorization: Bearer <token>"
POI segments with household visit stats over date_from..date_to (default the last 90 days). Filters: brand, category, min_households, limit (default 5000, max 50,000). Fields: segment_md5, name, brand, category, entity_type, dma_name, lat, lon, household_count, device_count, first_visit, last_visit.
curl "https://api.quorum.live/v1/advertisers/1234/segments?min_households=1" -H "Authorization: Bearer <token>"
Reference data
zip_code, city, state, state_name, county, dma_code, dma_name, population, population_density, latitude, longitude. 404 if unknown.
curl https://api.quorum.live/v1/zips/10001 -H "Authorization: Bearer <token>"
For a 15-digit FIPS block: census_block_id, zip_code, city, state, state_name, state_fips, county_fips, tract_fips, dma_code, dma_name, zip_population. 404 if unknown.
Library metadata for any segment_md5: segment_name, brand, category, dma_name, zip_code, region, visits_30d, source_agency_id, source_advertiser_id. 404 if not in the library.
Location library
Aggregate data on Quorum's reference library of tracked US locations (brands, categories, DMAs). Open-ended questions go to the Quorum MCP at https://mcp.quorum.live/mcp; the library's free-text question route has been removed.
| Route | Auth | What it does |
|---|---|---|
| GET /v1/library/categories | Public | Top categories by location count and 30-day visits. Param limit (default 25, max 100). |
| POST /v1/library/audience-intel | Public | Audience bundle for a brand: footprint, top DMAs and locations, cross-shopping, cohorts, media affinity. Body {"brand": "..."}. 3 requests per minute per IP. |
| GET /v1/library/search | Bearer | Find locations. At least one of category, brand, dma, zip_code; plus sort_by (visits_30d or name) and limit (max 100). |
| GET /v1/library/stats | Bearer | Library-wide totals. |
| GET /v1/library/brands | Bearer | Brand search for pickers: q, category, limit. |
| GET /v1/library/cross-shop | Bearer | Where a brand's visitors also go (sampled). brand (required), dma, limit (max 30), sample_size. 10 per minute per IP. |
| GET /v1/library/cross-shop-dma | Bearer | Cross-shopping for one brand in one DMA: brand, dma, limit (max 30). 10 per minute per IP. |
| POST /v1/library/audience-report | Bearer | A written audience report for a brand. Body {"brand": "..."}. |
| POST /v1/library/personas | Bearer | Persona mix of the households that visit a brand. Body {"brand": "..."}. |
| POST /v1/library/activate | Bearer | Ask Quorum's team to activate a brand audience on your DSP. Body needs brand and email; optional dsp, seat_id, devices, markets, category. |
curl "https://api.quorum.live/v1/library/categories?limit=10"
Audience intelligence reports
The published brand audience-intelligence reports: {"reports": [...], "count": N}.
One report as JSON: master, headline_stats, dma_distribution, category_affinity, cross_shopping, competitive_set, narratives. 404 for an unknown slug.
These are brand-level reports, not your campaign reports; for those see /report.
Internal tokens only
Partner tokens get 403 on every route on this page, with a pointer to the Quorum MCP (https://mcp.quorum.live/mcp). They are listed so the API surface is complete.
| Route | What it returns (internal tokens) |
|---|---|
| POST /v1/resolve | Body {"input_type": "ipv4" | "maid" | "latlong", "value": "...", "max_distance_m": 30}. Returns household_id, centroid_distance_m, maid_count, maids[] (maid, primary_ip, census_block_id, state). |
| GET /v1/household/{household_id}/geo | census_block_id, zip_code, dma_code, dma_name, state, maid_count. |
| GET /v1/household/{household_id}/visits | Segment visits for one advertiser (advertiser_id required; date_from, date_to as a half-open UTC window; limit). |
| GET /v1/household/{household_id}/footprint | Every library location the household visited (date_from, date_to, limit). |
| GET /v1/household/{household_id}/publishers | Publisher exposure by day. |
| GET /v1/segments/{segment_md5}/visits | Per-device visits, one row per device per day. |
| GET /v1/segments/{segment_md5}/visitor-geography | Visitors' home ZIPs and DMAs. |
| GET /v1/locations/{segment_md5}/visitor-geography | Library visitor geography by census block and ZIP. |
| GET /v1/advertisers/{advertiser_id}/segments/{segment_md5}/households | Households that visited a segment. |
| GET /v1/performance/households | One attribution row per household. |
Data freshness
| Data | Freshness |
|---|---|
| Visit records (/visits) | Loaded nightly. The most recent 1–3 days are still filling in. |
| New store footprints | Back-fill about 85 days of visits on their first nightly run. |
| Published reports (/report) | As of each published version; mature turns true once the attribution window has closed. |
| Rolling 30-day segment counts | Window ends 5 days ago. |
| Geographic reference data | Static, refreshed periodically. |