Audience Query Payload & API Specification
This document defines the formal JSON specification for executable audience definitions evaluated by analytics-query-engine, alongside the complete REST API contract.
1. Executable Audience Query Schema
All audience evaluation, validation, and preview endpoints accept a root query object with the following structure:
{
"query": {
"entity": "Customer",
"dimensions": ["Customer.country", "Orders.purchaseCount"],
"metrics": ["Customer.count"],
"time": [
{
"member": "metrics.timestamp",
"range": ["2026-07-01", "2026-07-15"]
}
],
"filters": {
"match": "ALL",
"conditions": [
{
"member": "Customer.country",
"operator": "equals",
"values": ["India"]
},
{
"member": "commerceDetails.count",
"operator": "greaterThanOrEqual",
"values": ["1"],
"window": "31d"
},
{
"not": {
"member": "Orders.refundAmount",
"operator": "greaterThan",
"values": ["100"]
}
}
]
}
}
}
Top-Level Query Attributes
| Field | Type | Required | Description |
|---|---|---|---|
entity | string | Yes | Primary entity evaluated. Must be set to "Customer". |
dimensions | string[] | No | Selected returnable attributes for preview rows (e.g., ["Customer.email", "Orders.purchaseCount"]). |
metrics | string[] | Yes | Aggregation metric evaluated. Must include ["Customer.count"]. |
time | object[] | Yes | Global evaluation lookback window. Must target "metrics.timestamp". Range can be ISO dates (["2026-01-01", "2026-03-31"]) or relative presets (["last 30 days"]). Maximum span is 365 days. |
filters | object | Yes | The root rule group. Note: Must use filters, not where. |
2. Filter Group & Condition Syntax
Root & Nested Groups (match: "ALL" / "ANY")
Groups contain a match property and a conditions array:
- AND Logic: Set
"match": "ALL"— all enclosed conditions or subgroups must be satisfied. - OR Logic: Set
"match": "ANY"— at least one condition or subgroup must be satisfied.
{
"match": "ALL",
"conditions": [
{
"member": "Customer.lifecycleStage",
"operator": "equals",
"values": ["lead"]
},
{
"match": "ANY",
"conditions": [
{
"member": "touchpoint.source",
"operator": "equals",
"values": ["Google"],
"window": "30d"
},
{
"member": "touchpoint.source",
"operator": "equals",
"values": ["LinkedIn"],
"window": "30d"
}
]
}
]
}
Exclusion Logic (not)
To exclude users matching a specific condition or group, wrap the definition in a "not" object:
{
"not": {
"member": "events.eventType",
"operator": "equals",
"values": ["purchase"],
"window": "30d"
}
}
3. Operator Reference Matrix
The supported operators depend on the catalog field type:
| Operator | Field Types | Values Required | Description | Example Payload Snippet |
|---|---|---|---|---|
equals | string, number, boolean | Exactly 1 | Exact match equality. | {"operator": "equals", "values": ["active"]} |
notEquals | string, number, boolean | Exactly 1 | Inequality comparison. | {"operator": "notEquals", "values": ["churned"]} |
in | string, number | 1 or more | Value matches any in the list. | {"operator": "in", "values": ["India", "UAE", "UK"]} |
notIn | string, number | 1 or more | Value does not match any in list. | {"operator": "notIn", "values": ["internal", "test"]} |
greaterThan | number, money, time | Exactly 1 | Numeric/time greater than. | {"operator": "greaterThan", "values": ["100"]} |
greaterThanOrEqual | number, money, time | Exactly 1 | Numeric/time greater than or equal. | {"operator": "greaterThanOrEqual", "values": ["1"]} |
lessThan | number, money, time | Exactly 1 | Numeric/time less than. | {"operator": "lessThan", "values": ["50"]} |
lessThanOrEqual | number, money, time | Exactly 1 | Numeric/time less than or equal. | {"operator": "lessThanOrEqual", "values": ["5"]} |
between | number, money, time | Exactly 2 | Value lies inclusively within range. | {"operator": "between", "values": ["10", "50"]} |
isSet | All types | 0 (empty []) | Attribute is not null/empty. | {"operator": "isSet", "values": []} |
isNotSet | All types | 0 (empty []) | Attribute is null or missing. | {"operator": "isNotSet", "values": []} |
4. Time Windows & Lookback Intervals
Any field marked requiresTimeWindow: true in the catalog must specify a window property.
Supported window formats:
- Interval Notation:
"7d","14d","30d","90d","180d","365d". - Relative Semantic Presets:
"last 7 days""last 30 days""from 7 days ago to now""from now to 2 weeks from now"
5. Analytics Query Engine REST Endpoints
All endpoints use base URL http://<analytics-query-engine-host> and share the same response envelope:
{
"code": 200,
"success": true,
"message": "",
"data": [
{
"...": "typed response object"
}
]
}
Endpoints Matrix
| Route | Method | Purpose | Key Headers |
|---|---|---|---|
/api/v2/analytics/audiences/audience-fields | GET | Fetch field catalog & operators. | Client-ID, Workspace-ID |
/api/v2/analytics/audiences/field-values | POST | Autocomplete dropdown values for a field. | Client-ID, Workspace-ID |
/api/v2/analytics/audiences/validate | POST | Check query syntax and rule validity. | Client-ID, Workspace-ID |
/api/v2/analytics/audiences/preview | POST | Calculate reach and return sample rows. | Client-ID, Workspace-ID, X-Audience-PII-Access (optional) |
/api/v2/analytics/audiences/{audienceId}/evaluate | POST | Run live evaluation for a saved audience. | Client-ID, Workspace-ID, X-Audience-PII-Access (optional) |
/api/v2/analytics/audiences/{audienceId}/insight | POST | Compute statistical overlap & drivers. | Client-ID, Workspace-ID |
6. Sample Request & Response Payloads
Validate Audience Query (POST /api/v2/analytics/audiences/validate)
Request
curl --location 'http://localhost:8080/api/v2/analytics/audiences/validate' \
--header 'Authorization: Bearer <JWT_TOKEN>' \
--header 'Content-Type: application/json' \
--header 'Client-ID: 34507' \
--header 'Workspace-ID: 34509' \
--data '{
"query": {
"entity": "Customer",
"metrics": ["Customer.count"],
"time": [{"member": "metrics.timestamp", "range": ["last 30 days"]}],
"filters": {
"match": "ALL",
"conditions": [
{
"member": "Customer.country",
"operator": "equals",
"values": ["India"]
}
]
}
}
}'
Valid Response (data[0])
{
"valid": true,
"warnings": [],
"errors": []
}
Invalid Response (data[0])
{
"valid": false,
"warnings": [],
"errors": [
{
"code": "missing_filters",
"field": "query.filters",
"message": "Audience requests must include query.filters."
}
]
}
Preview Audience (POST /api/v2/analytics/audiences/preview)
Request (Include Rows & PII Clearance)
curl --location 'http://localhost:8080/api/v2/analytics/audiences/preview?limit=10&offset=0&includeRows=true' \
--header 'Authorization: Bearer <JWT_TOKEN>' \
--header 'Content-Type: application/json' \
--header 'Client-ID: 34507' \
--header 'Workspace-ID: 34509' \
--header 'X-Audience-PII-Access: true' \
--data '{
"query": {
"entity": "Customer",
"dimensions": ["Customer.email", "Customer.country", "Orders.purchaseCount"],
"metrics": ["Customer.count"],
"time": [{"member": "metrics.timestamp", "range": ["last 30 days"]}],
"filters": {
"match": "ALL",
"conditions": [
{
"member": "Customer.country",
"operator": "equals",
"values": ["India"]
}
]
}
}
}'
Response (data[0])
{
"summary": {
"estimatedCount": 1420,
"totalCount": 10500,
"impactSteps": [
{
"step": 1,
"name": "Country equals India",
"count": 1420
}
]
},
"rows": [
{
"Customer.country": "India",
"Orders.purchaseCount": 3
}
],
"pagination": {
"totalRows": 1420,
"limit": 10,
"offset": 0
}
}