Paging Audience Records
Read a built audience as JSON pages instead of downloading files
Overview
GET /api/v1/audiences/{id}/records returns a built audience as JSON, one page at a time. Each result is one row with the same columns the download files carry. Dates render as YYYY-MM-DD, timestamps as RFC 3339 UTC, and missing values as null.
The audience must be built first. Call GET /api/v1/audiences/{id}/download and poll until its status is ready. Until then, records returns 409 with "error": "not_ready". A status of expired there means the build's output aged out; calling the download endpoint rebuilds it.
Paging Loop
Follow next_cursor until a response has none. page_size (1-5000, default 1000) is a maximum, so a page can hold fewer rows and still have more after it: loop on the cursor, not the row count. Send Accept-Encoding: gzip to get compressed responses.
import time
import requests
url = "https://api.delivr.ai/api/v1/audiences/AUDIENCE_ID/records"
headers = {
"X-Api-Key": "YOUR_API_KEY",
"X-Api-Secret": "YOUR_API_SECRET",
"Accept-Encoding": "gzip",
}
params = {"project_id": "YOUR_PROJECT_ID", "page_size": 5000}
records = []
while True:
r = requests.get(url, params=params, headers=headers)
if r.status_code == 503:
time.sleep(int(r.headers.get("Retry-After", 5)))
continue
r.raise_for_status()
page = r.json()
records.extend(page["results"])
if "next_cursor" not in page:
break
params["cursor"] = page["next_cursor"]A response looks like this (count is the build's total rows, omitted when unknown):
{
"audience_id": "123",
"count": 4221397,
"results": [{"first_name": "Ana", "job_title": "VP Marketing", "perc_score": 92}],
"next_cursor": "..."
}Errors
| Status | Meaning |
|---|---|
| 400 | Invalid page_size, an unknown query parameter, or an invalid cursor. |
| 402 | The organization cannot be charged, as with the download endpoint. |
| 404 | Audience not found. |
409 not_ready | Not built yet. Call the download endpoint and poll until ready. |
409 cursor_stale | The audience was rebuilt after the cursor was issued. Restart without a cursor. |
| 422 | This audience cannot be served as records. Use the download endpoint. |
429 platform_cap_exceeded | Usage limit reached, as with the download endpoint. |
503 busy | Wait the number of seconds in Retry-After, then retry. Other 503s: retry with backoff. |
Billing
Records are billed per record returned, at the audience's meter (Predictive Signals audiences bill at the Predictive Signals rate).
- A record read again on the same UTC day is not charged again.
- In one day, paging a build never costs more than downloading it.
- If the build's file download was already charged, paging that build is free.
- A page that fails partway is not charged.
Test API keys get deterministic sample data, marked with the response header X-Delivr-Mode: test, and are never billed.
Updated about 1 hour ago
