Intent Audiences API
Overview
The Audiences API lets you create targeted audiences based on intent signals. You define which topics you care about, and the platform finds contacts actively researching those topics.
flowchart LR
A["Find Topics\n(Taxonomy API)"] --> B[Create Audience]
B --> C[Poll Status]
C --> D{Status?}
D -->|Pending / Processing| C
D -->|Completed| E[Preview Sample]
E --> F[Download Full Results]
style A fill:#3b82f6,color:#fff
style F fill:#22c55e,color:#fff
stateDiagram-v2
[*] --> Pending: Create audience
Pending --> Processing: System picks up job
Processing --> Completed: Results ready
Processing --> Failed: Error occurred
Completed --> [*]: Download results
Failed --> [*]: Check error, retry
Base URL: https://apiv3.delivr.ai
Prerequisites:
- JWT token and organization ID (Authentication)
- A project ID (Account Setup)
Authentication: All requests require a Bearer token in the Authorization header.
Project scoping: All requests require your project ID, passed via either:
X-Project-Idheader, OR?project_id=query parameter
Both methods work on all endpoints.
Authorization: Bearer YOUR_API_TOKEN
X-Project-Id: YOUR_PROJECT_ID
Content-Type: application/json
Step 0: Get Available Topics
Before creating an audience, you need topic IDs. Browse the catalog using the Taxonomy API.
Quick Example
curl "https://apiv2.delivr.ai/taxonomy/topics?limit=10&search=cloud+computing" \
-H "Authorization: Bearer YOUR_API_TOKEN"Example Response (200 OK)
{
"response": {
"topics": [
{
"topic_id": "4eyes_115481",
"category_name": "Business",
"subcategory_name": "Controls & Standards",
"name": "Cloud Computing",
"status": "active",
"topic_type": "B2B"
}
]
}
}Use the topic_id values (e.g. "4eyes_115481") in your audience filter's INTENT rule. See the Taxonomy API for filtering by category, subcategory, and type.
Step 1: Create an Audience
Request
POST /api/v1/audiences?project_id=YOUR_PROJECT_ID
{
"organization_id": "YOUR_ORGANIZATION_ID",
"project_id": "YOUR_PROJECT_ID",
"audience_name": "AI Research Intent",
"type": "intents",
"segmentation_type": "Audience",
"filter": {
"condition": "and",
"rules": [
{
"fieldName": "INTENT",
"conditionRules": {
"operator": "in",
"value": ["artificial_intelligence", "machine_learning"]
}
}
]
}
}Required Fields
| Field | Type | Description |
|---|---|---|
organization_id | string (UUID) | Your organization ID (provided during onboarding) |
project_id | string (UUID) | Your project ID (provided during onboarding) |
audience_name | string | A name for your audience |
type | string | Must be "intents" |
segmentation_type | string | Must be one of: "Audience", "Persona", "Account" |
filter | object | Must contain at least one rule with fieldName: "INTENT" |
Optional Fields
| Field | Type | Default | Description |
|---|---|---|---|
audience_description | string | "" | Description of the audience |
select | string | "*" | Which columns to include in results |
unload | string | "preview" | "preview" for sample only, "unload" for full export |
Example Response (201 Created)
{
"id": 8268,
"organization_id": "YOUR_ORGANIZATION_ID",
"project_id": "YOUR_PROJECT_ID",
"audience_name": "AI Research Intent",
"audience_description": "",
"segmentation_type": "Audience",
"status": "Pending",
"type": "intents",
"unload": "preview",
"filter": { "..." },
"sql_filter_statement": {
"where": "topic_id in ('artificial_intelligence', 'machine_learning')"
},
"select": "*",
"size": null,
"account_count": null,
"date_updated_size": null,
"output_path": null,
"date_updated_path": null,
"renew_time": null,
"error": null,
"task_id": null,
"created_at": "2026-02-01T10:00:00Z",
"updated_at": "2026-02-01T10:00:00Z"
}Save the id from the response -- you need it for all subsequent requests.
Validation Rules
type: "intents"requires at least one rule wherefieldNameisINTENT,intent,topic, ortopic_id- Without this, you get:
"topic_id or INTENT field with topic IDs is mandatory for intents audience" project_idin the body must match the project ID from your auth context
Step 2: Check Audience Status
After creating, the platform processes your audience in the background. Poll until status is "Completed".
Request
GET /api/v1/audiences/{id}?project_id=YOUR_PROJECT_ID
Example Response (200 OK)
{
"id": 4769,
"organization_id": "YOUR_ORGANIZATION_ID",
"project_id": "YOUR_PROJECT_ID",
"audience_name": "AI Research Intent",
"audience_description": "",
"segmentation_type": "Audience",
"status": "Completed",
"type": "intents",
"unload": "preview",
"filter": { "..." },
"sql_filter_statement": { "..." },
"select": "*",
"size": 1000,
"account_count": null,
"date_updated_size": "2026-01-31T09:19:44.934716Z",
"output_path": "gs://...",
"date_updated_path": "2026-01-31T09:19:44.934716Z",
"renew_time": null,
"error": null,
"task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"created_at": "2026-01-12T12:09:49.187774Z",
"updated_at": "2026-01-31T09:19:44.937174Z"
}Status Values
| Status | Meaning | What To Do |
|---|---|---|
Pending | Queued for processing | Poll again in 10 seconds |
Syncing | Processing in progress | Poll again in 10 seconds |
Completed | Audience is ready | Proceed to sample or download |
Failed | An error occurred | Check the error field |
Typical processing time is 20-40 seconds for most audiences.
Step 3: Preview Sample Data
Once status is "Completed", preview a sample of the results.
Request
GET /api/v1/audiences/{id}/sample?limit=5&project_id=YOUR_PROJECT_ID
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 200 | Number of rows to return |
project_id | string | -- | Your project ID |
Example Response (200 OK)
{
"rows": [
{
"first_name": "jane",
"last_name": "smith",
"job_title": "product analyst",
"department": "operations",
"seniority_level": "staff",
"company_name": "acme corp",
"company_domain": "acmecorp.com",
"company_industry": "insurance",
"company_employee_count_range": "1001 to 5000",
"company_revenue_range": "1 billion and over",
"company_city": "new york",
"company_state": "new york",
"company_country": "united states",
"current_business_email": "[email protected]",
"current_business_email_validation_status": "valid",
"linkedin_url": "https://linkedin.com/in/jane-smith-12345678",
"score": "high",
"topic_id": "4eyes_110486",
"topic_name": "15Five",
"category": "Business",
"subcategory": "Brands",
"ts": "2026-01-30T00:00:00",
"...": "111 total fields per row"
}
]
}Each row contains ~111 fields per contact, including:
- Contact info: name, email, phone, address, LinkedIn
- Company info: name, domain, industry, size, revenue, location
- Demographics: age range, gender, income, education, net worth
- Intent fields (added by processing):
score,topic_id,topic_name,category,subcategory,ts - Identity hashes: SHA256, SHA1, MD5 HEMs (hashed email)
Use the schema endpoint to see the full list of available fields.
Note: The sample endpoint returns up to 200 rows. The
limitparameter is accepted but does not currently reduce the result set.
Step 4: Download the Full Audience
The download endpoint prepares files and returns signed URLs. If files are not yet prepared, it automatically triggers preparation and returns a status you can poll.
Request
GET /api/v1/audiences/{id}/download?project_id=YOUR_PROJECT_ID
Response When Ready (200 OK)
{
"status": "ready",
"output_links": {
"day=20260130/prefix=4eyes_110/score=high": [
"https://signed-s3-url/count.json?...",
"https://signed-s3-url/part-0.parquet?..."
],
"day=20260130/prefix=4eyes_500/score=high": [
"https://signed-s3-url/count.json?...",
"https://signed-s3-url/part-0.parquet?..."
]
}
}The output_links keys are partitioned by day, topic prefix, and score. Each partition contains:
count.json-- record count for that partitionpreview.json-- preview data for that partition- One or more
.parquetdata files with the actual audience data (e.g.part-0.parquet,part-1.parquet)
Some partitions may only have count.json (when no matching data was found for that topic/score combination).
Signed URLs are valid for 24 hours.
Response When Not Ready (200 OK)
{
"status": "unloading"
}Download Status Values
The typical progression is: unloading -> done -> ready.
| Status | Meaning | What To Do |
|---|---|---|
ready | Files are available | Download from output_links |
unloading | Files are being prepared | Poll again in 3 seconds |
done | Preparation finishing | Poll again in 3 seconds |
failed | Preparation failed | Retry or contact support |
Stop polling after 3 minutes and contact support if still not ready.
Downloading the Files
Files are in Parquet format. See Reading Parquet Files for how to convert them to CSV or open in Excel.
Filter the URLs to find .parquet files (skip count.json unless you need record counts):
import requests
response = requests.get(
"https://apiv3.delivr.ai/api/v1/audiences/AUDIENCE_ID/download",
params={"project_id": "YOUR_PROJECT_ID"},
headers={"Authorization": "Bearer YOUR_API_TOKEN"},
)
data = response.json()
if data["status"] == "ready":
for partition, urls in data["output_links"].items():
for url in urls:
if url.split("?")[0].endswith(".parquet"):
# Download parquet file
r = requests.get(url)
filename = partition.replace("/", "_") + ".parquet"
with open(filename, "wb") as f:
f.write(r.content)Available Fields (Schema)
To see all available fields and their data types:
GET /api/v1/audiences/schema?project_id=YOUR_PROJECT_ID
Example Response (200 OK)
{
"fields": [
{ "name": "address_id", "data_type": "Utf8View", "nullable": true },
{ "name": "age_range", "data_type": "Utf8View", "nullable": true },
{ "name": "business_emails", "data_type": "Utf8View", "nullable": true },
{ "name": "company_address", "data_type": "Utf8View", "nullable": true },
{ "name": "company_city", "data_type": "Utf8View", "nullable": true },
{ "name": "company_country", "data_type": "Utf8View", "nullable": true },
{ "name": "company_domain", "data_type": "Utf8View", "nullable": true },
{ "name": "company_name", "data_type": "Utf8View", "nullable": true },
{ "name": "company_size", "data_type": "Utf8View", "nullable": true },
{ "name": "first_name", "data_type": "Utf8View", "nullable": true },
{ "name": "job_title", "data_type": "Utf8View", "nullable": true },
{ "name": "last_name", "data_type": "Utf8View", "nullable": true },
{ "name": "score", "data_type": "Utf8View", "nullable": true },
{ "name": "topic_id", "data_type": "Utf8View", "nullable": true },
{ "name": "topic_name", "data_type": "Utf8View", "nullable": true }
]
}Use the name values from this response as fieldName in your filter rules.
Note: This is a partial list. The full schema contains additional fields. Call the endpoint to see all available fields.
Filter Reference
The filter field is a tree of rules joined by "and" or "or".
Structure
{
"condition": "and",
"rules": [ ... ]
}Topics (required for intents)
{
"fieldName": "INTENT",
"conditionRules": {
"operator": "in",
"value": ["topic_id_1", "topic_id_2"]
}
}Contact your account team for available topic IDs. Maximum 10 topics per audience.
Signal Strength (optional)
If omitted, all strengths are included.
{
"fieldName": "score",
"conditionRules": {
"operator": "in",
"value": ["high", "medium"]
}
}| Value | Meaning |
|---|---|
high | Strong intent signal |
medium | Moderate intent signal |
low | Weak intent signal (broadest reach) |
Field Filters (optional)
Use any field name from the schema endpoint:
{
"fieldName": "company_size",
"conditionRules": {
"operator": "in",
"value": ["1000-5000", "5000+"]
}
}Available Operators
| Operator | Value Type | Description |
|---|---|---|
in | array of strings | Matches any of the values |
not in | array of strings | Excludes these values |
is / equals | string or array | Field exactly equals value |
not equals | string | Field does not equal value |
contains | string | Field contains the text |
not contains | string | Field does not contain the text |
startswith | string | Field starts with the text |
endswith | string | Field ends with the text |
is not blank | (none) | Field has a value |
is blank | (none) | Field is empty or null |
is not null / notnull | (none) | Field is not null |
is null / isnull | (none) | Field is null |
>= | string | Greater than or equal to |
<= | string | Less than or equal to |
> | string | Greater than |
< | string | Less than |
Values can be provided as:
- A plain string:
"value": "some text" - An array of strings:
"value": ["val1", "val2"] - An array of objects:
"value": [{"name": "val1"}, {"name": "val2"}](backend extracts thename,value, orlabelfield)
Listing Audiences
Request
GET /api/v1/audiences?project_id=YOUR_PROJECT_ID&type=intents&page=1&page_size=20
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
project_id | string | -- | Your project ID (required) |
type | string | -- | Filter by type: intents, elixir, events |
status | string | -- | Filter by status: Completed, Failed, etc. |
page | integer | 1 | Page number |
page_size | integer | 20 | Results per page |
sort_by | string | -- | Sort column: audience_name, status, created_at |
sort_order | string | -- | ASC or DESC |
name | string | -- | Search by audience name |
Example Response (200 OK)
{
"data": [
{
"id": 4879,
"organization_id": "YOUR_ORGANIZATION_ID",
"project_id": "YOUR_PROJECT_ID",
"audience_name": "Automated Customer Service Need",
"audience_description": "Business owners interested in automating customer service",
"segmentation_type": "Audience",
"status": "Completed",
"type": "intents",
"size": 4899,
"created_at": "2026-01-28T18:52:02.850618Z",
"updated_at": "2026-02-01T00:02:35.076531Z"
}
],
"page": 1,
"page_size": 20,
"total": 15,
"total_pages": 1
}Pagination
The response includes pagination metadata:
| Field | Description |
|---|---|
data | Array of audience objects |
page | Current page number |
page_size | Number of results per page |
total | Total number of matching audiences |
total_pages | Total number of pages |
Complete Example
1. Create
curl -X POST "https://apiv3.delivr.ai/api/v1/audiences?project_id=YOUR_PROJECT_ID" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"organization_id": "YOUR_ORGANIZATION_ID",
"project_id": "YOUR_PROJECT_ID",
"audience_name": "Enterprise Cloud Computing Intent",
"audience_description": "Large companies researching cloud infrastructure",
"type": "intents",
"segmentation_type": "Audience",
"filter": {
"condition": "and",
"rules": [
{
"fieldName": "INTENT",
"conditionRules": {
"operator": "in",
"value": ["cloud_computing", "cloud_infrastructure"]
}
},
{
"fieldName": "score",
"conditionRules": {
"operator": "in",
"value": ["high", "medium"]
}
},
{
"fieldName": "company_size",
"conditionRules": {
"operator": "in",
"value": ["1000-5000", "5000+"]
}
}
]
}
}'2. Poll Status (repeat until "Completed")
curl "https://apiv3.delivr.ai/api/v1/audiences/AUDIENCE_ID?project_id=YOUR_PROJECT_ID" \
-H "Authorization: Bearer YOUR_API_TOKEN"3. Preview Sample
curl "https://apiv3.delivr.ai/api/v1/audiences/AUDIENCE_ID/sample?limit=5&project_id=YOUR_PROJECT_ID" \
-H "Authorization: Bearer YOUR_API_TOKEN"4. Download
# Poll until status is "ready"
curl "https://apiv3.delivr.ai/api/v1/audiences/AUDIENCE_ID/download?project_id=YOUR_PROJECT_ID" \
-H "Authorization: Bearer YOUR_API_TOKEN"
# Download parquet files from the signed URLs in output_links
curl -o audience_data.parquet "SIGNED_URL_FROM_RESPONSE"Other Operations
| Action | Method | Endpoint | Response |
|---|---|---|---|
| Update | PUT | /api/v1/audiences/{id}?project_id=... | 200 with updated audience |
| Clone | POST | /api/v1/audiences/{id}/clone?project_id=... | 201 with new audience |
| Delete | DELETE | /api/v1/audiences/{id}?project_id=... | 204 No Content |
Errors
All error responses return a JSON object with an error field:
| HTTP Status | Example error Message |
|---|---|
| 400 | "project_id is required" |
| 400 | "topic_id or INTENT field with topic IDs is mandatory for intents audience" |
| 400 | "failed to transform filter: ..." |
| 401 | "invalid or expired token: ..." |
| 404 | "Audience not found" |
| 500 | "Failed to retrieve audience" |
Note:
project_idis required on all endpoints. Omitting it returns a 400 error.
Next Steps
- Taxonomy API -- Browse the full topic catalog (19,500+ topics)
- On-Domain Events API -- Query pixel visitor events instead of intent audiences
- High-Intent Visitors Runbook -- Example: daily lead list from pricing page visitors
Updated 1 day ago