Platform API · Product API · Audience
Counting and retrieval
Which endpoint answers which question about the audience: the exact count of a filter, a quick search, a cursor traverse of a large result set, a single contact by id or identifier, and what the subscription plan lets each of them return.
Once a filter selects the right people, there are four different things you might want back, and they are four different endpoints with four different costs and permissions. Picking the wrong one is the usual cause of a 403 you did not expect or a page-two that never arrives.
Which endpoint for which question
| The question | Endpoint | What comes back |
|---|---|---|
| How many match this filter? | POST /audience/count | A single exact total, no contact rows |
| Show me a first page | POST /audience/search | Up to 50 contacts, from the beginning |
| Give me all of them | POST /audience/scroll | Up to 100 per page, cursor-paginated |
| All of them, inside a segment | POST /audience/segment/{uid}/scroll | Same, restricted to a segment |
| This one person | GET /audience/{audienceId} and the identifier lookups | One contact |
| A breakdown, not rows | POST /audience/aggregations | Aggregation results only |
Counting
POST /project/{project}/audience/count takes the audience query filter and returns only the total. It is the endpoint whose number you may act on: exact, uncapped and live, with no sampling anywhere near it.
The exact number of contacts matching a filter.
curl -X POST "$BASE/audience/count" \
-H "Authorization: Bearer $INSTASENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "filterCompliance": { "sms": "no-opt-out" } }'Four things worth knowing:
- An empty body counts the whole audience.
limitandoffsetare ignored. - It carries no contact data, which is why it stays available under the
anonymizeddata policy mode, where/audience/searchis disabled. For restricted credentials it is the supported way to answer "how many contacts match this". - To count who can actually receive, pass
filterCompliance. Without it the total is the raw audience, not a sending figure. The consent and reach rules are the same ones a campaign estimate applies. See Counting who can receive. - It is the endpoint that settles any number a probe suggested. Probes report shape and may be sampled; this is the size.
Where a count drops: the ladder
A total on its own does not say why it is small. Add "ladder": true at the top level of the body and the same call also returns four counts, each one a subset of the one before, so you can see at which step the contacts fall away:
curl -X POST "$BASE/audience/count" \
-H "Authorization: Bearer $INSTASENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "ladder": true, "filterCompliance": { "sms": "no-opt-out" } }'{
"metadata": {
"totalHits": 452,
"ladder": {
"audience": 1200,
"matched": 1200,
"reachable": 610,
"consented": 452
},
"unknownSegments": []
}
}| Rung | Who it counts |
|---|---|
audience | Every contact in the project. |
matched | The contacts your filter selects: the conditions in root plus the scoping keys (countries, data sources, required attributes). No reach and no consent yet. |
reachable | Those of matched the channel can reach: a valid mobile number and, for rcs and whatsapp, a device not known to lack support. |
consented | Those of reachable the consent policy in filterCompliance allows. Always equal to totalHits. |
consented is the number of contacts who would actually receive the message. Quote it as the reach of a send; matched alone overstates it. The gaps between rungs tell you what to fix: a big drop from matched to reachable is missing or unusable phone numbers, a big drop from reachable to consented is the consent policy at work. Without filterCompliance (or the explicit consent and reach keys it expands to) there is no reach or consent to apply, so matched, reachable and consented come back equal.
unknownSegments lists any segment uid in root that matches no segment in the project. Such a condition selects nobody, so a zero with an entry here is a typo in the filter, not an empty audience.
Searching and scrolling
Both take the same filter. They differ in how much they will give you and what it costs.
A first page of matching contacts, up to 50.
/audience/search uses offset/limit pagination, but the offset is always forced to 0: it is built for a quick look from the beginning, not for walking a result set. Its ceiling is 50 contacts per request and it needs PROJECT_AUDIENCE_READ.
A cursor traverse of the whole result set, 100 contacts at a time.
/audience/scroll is the one for large traverses. It returns a cursor in the response metadata that you pass back to get the next page, up to 100 contacts per request. The cursor is a base64 string holding the internal query state and expires after one minute of inactivity, so a traverse has to keep moving: a job that fetches a page, spends five minutes processing it and comes back will find the cursor gone.
It needs PROJECT_AUDIENCE_LIST, which is gated by the subscription plan. That is the usual reason a call that works for one organization is refused for another with the same code.
Retrieving one contact
When you already know who you are looking for, four direct lookups skip the filter entirely.
By audience contact id.
By the _user_id your systems use.
By phone number. URL-encode the leading plus as %2B.
By email address.
The id these return is the one every other per-contact call takes, including the contact's events and direct messaging.
Aggregations
POST /audience/aggregations runs your aggregations over the filtered audience and returns results only, with no contact rows and the limit pinned to zero. It needs PROJECT_AGGREGATIONS, which is not generally available and is granted manually by Instasent.
If what you want is a distribution over an attribute rather than a bespoke aggregation, /audience/coverage gives you one with the ordinary read scope, at the cost of being a probe: shape, possibly sampled, never a size.
What the plan lets you see
Two gates decide the fields on a returned contact, and both have to be open: the scopes on your token and the subscription plan of the organization.
| Level | Scope | Fields returned |
|---|---|---|
| Default | PROJECT_AUDIENCE_READ | Full name and user id only |
| Basic | PROJECT_AUDIENCE_DATA_BASIC | Phone, email, country, name, boolean fields |
| Full | PROJECT_AUDIENCE_DATA_FULL | Full contact data including PII |
What's next
- Query filter: the filter these endpoints take, including cursor mechanics and aggregation shapes.
- Segments: scrolling a saved segment, and reading its cached size.
- Probes: check the filter is selecting on something real before you count it.
Last updated