Skip to main content
The search API lets you query your contacts using a flexible condition-based language. You can filter by any combination of personal info, address, tags, financial activity (transactions, donations, memberships), email campaign engagement, sanctions, and custom fields. Two endpoints share the same query format:
  • POST /search — returns a paginated list of matching contacts
  • POST /kpi — returns only the count of matching contacts, with no contact data

How queries are structured

Every search query is a two-level tree. The outer group sets the top-level logic; each inner group contains the individual conditions.
Each group is either:
  • $all — ALL conditions inside must match (AND logic)
  • $at_least_one — AT LEAST ONE condition must match (OR logic)
The minimum shape — even for a single condition — always requires two levels of nesting:
Example: City is Paris AND has a mobile number AND (tagged volunteer OR tagged donor)

Operators

Date fields accept relative values: "now", "now-30d", "now-1y", "now+1y". All dates are interpreted as UTC.

Pagination and sorting

Getting a count without results

Use POST /kpi with the same query body to get the number of matching contacts instantly without fetching the full contact list.
Response: { "data": { "total": 1042 }, "status": "success" }

Examples

Contacts whose membership started on or before today and ends on or after today.
Amount values are always passed as strings in euros.
Members in 2024 who also made at least one donation.
In Paris or Lyon, and has a mobile number.

Attribute reference

Contact fields

Address fields

Financial fields

These fields match contacts who have at least one matching record. For example, transactions.amount gte "50" returns contacts with at least one transaction ≥ €50, not contacts whose total is ≥ €50 — use sum_amount for totals. Amount fields are in euros and must always be passed as strings: "value": "50" not "value": 50.
Transactions (transactions.*) Donations (donations.*) Memberships (memberships.*)

Email engagement fields

These match contacts who have at least one email record where that field is set. A contact with no email history will not match ext or not_ext.

Sanctions fields

sanctions.validity is a computed field — it does not store a date, it tells you whether a sanction is currently active: "ongoing" (started and not yet ended) or "ended" (end date is in the past).

Custom fields and form answers

These attributes use a different condition shape — you must also provide form_id and form_ref_ids:
Retrieve your form_id values from GET /v1/forms/type/{type} and form_ref_ids from GET /forms/{id}.
ext / not_ext only check whether the contact has filled in the given form_idform_ref_ids is ignored. eql without a value checks that all listed form_ref_ids are present. eql with a value additionally checks that value matches the stored answer.
Last modified on June 8, 2026