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:

Authentication: All requests require a Bearer token in the Authorization header.

Project scoping: All requests require your project ID, passed via either:

  • X-Project-Id header, 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

FieldTypeDescription
organization_idstring (UUID)Your organization ID (provided during onboarding)
project_idstring (UUID)Your project ID (provided during onboarding)
audience_namestringA name for your audience
typestringMust be "intents"
segmentation_typestringMust be one of: "Audience", "Persona", "Account"
filterobjectMust contain at least one rule with fieldName: "INTENT"

Optional Fields

FieldTypeDefaultDescription
audience_descriptionstring""Description of the audience
selectstring"*"Which columns to include in results
unloadstring"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 where fieldName is INTENT, intent, topic, or topic_id
  • Without this, you get: "topic_id or INTENT field with topic IDs is mandatory for intents audience"
  • project_id in 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

StatusMeaningWhat To Do
PendingQueued for processingPoll again in 10 seconds
SyncingProcessing in progressPoll again in 10 seconds
CompletedAudience is readyProceed to sample or download
FailedAn error occurredCheck 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

ParameterTypeDefaultDescription
limitinteger200Number of rows to return
project_idstring--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 limit parameter 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 partition
  • preview.json -- preview data for that partition
  • One or more .parquet data 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.

StatusMeaningWhat To Do
readyFiles are availableDownload from output_links
unloadingFiles are being preparedPoll again in 3 seconds
donePreparation finishingPoll again in 3 seconds
failedPreparation failedRetry 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"]
  }
}
ValueMeaning
highStrong intent signal
mediumModerate intent signal
lowWeak 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

OperatorValue TypeDescription
inarray of stringsMatches any of the values
not inarray of stringsExcludes these values
is / equalsstring or arrayField exactly equals value
not equalsstringField does not equal value
containsstringField contains the text
not containsstringField does not contain the text
startswithstringField starts with the text
endswithstringField 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
>=stringGreater than or equal to
<=stringLess than or equal to
>stringGreater than
<stringLess 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 the name, value, or label field)

Listing Audiences

Request

GET /api/v1/audiences?project_id=YOUR_PROJECT_ID&type=intents&page=1&page_size=20

Query Parameters

ParameterTypeDefaultDescription
project_idstring--Your project ID (required)
typestring--Filter by type: intents, elixir, events
statusstring--Filter by status: Completed, Failed, etc.
pageinteger1Page number
page_sizeinteger20Results per page
sort_bystring--Sort column: audience_name, status, created_at
sort_orderstring--ASC or DESC
namestring--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:

FieldDescription
dataArray of audience objects
pageCurrent page number
page_sizeNumber of results per page
totalTotal number of matching audiences
total_pagesTotal 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

ActionMethodEndpointResponse
UpdatePUT/api/v1/audiences/{id}?project_id=...200 with updated audience
ClonePOST/api/v1/audiences/{id}/clone?project_id=...201 with new audience
DeleteDELETE/api/v1/audiences/{id}?project_id=...204 No Content

Errors

All error responses return a JSON object with an error field:

HTTP StatusExample 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_id is required on all endpoints. Omitting it returns a 400 error.


Next Steps