List contacts
GET /contacts
Newest first.
| Parameter | Default | Notes |
|---|---|---|
limit | 50 | Clamped to 1–200. |
after | — | The keyset cursor: the last id from the previous page. |
query | — | Matches the address or either name, case-insensitively, as a substring. |
segment_id | — | Only the contacts in that segment — a list you picked or a rule, whichever it is. |
rules | — | Ad hoc conditions, the same JSON a rule segment stores. |
{
"data": [
{ "id": "8412", "email": "alice@example.com", "first_name": "Alice",
"properties": { "plan": "pro" }, "unsubscribed": false,
"created_at": 1735689600 }
],
"next": "8412"
}
Pass next back as after to continue, and stop when data comes back empty —
a full page followed by nothing is an ordinary end.
Topic answers are not included. They cost a query per topic, which a page of fifty must not pay; retrieving one contact returns them.
Asking a question about the list
rules is the segment predicate, so you can ask the API what the dashboard’s
filters ask:
{ "match_": "all", "conditions": [
{ "field": "property", "key": "plan", "op": "is", "value": "pro" },
{ "field": "engagement", "what": "opened", "op": "not_within_days", "days": 90 }
]}
URL-encoded as the rules parameter. Conditions are property (is, is_not,
contains, is_set, is_not_set, greater_than, less_than),
joined_within_days / joined_before_days, and engagement — delivered,
bounced, complained, opened, clicked with ever, never,
within_days, not_within_days.
match_ is all or any.
It is the same translation a broadcast uses, so what you count here is who a send to the same conditions would reach.