Questions · Updated 2026-09-27

How do I create a segment of contacts?

Create a segment of contacts with POST /segments — a name and rules over email, status or a contact property, which AND together. GET /segments/{id}/members returns who matches right now, and POST /broadcasts sends one message to that segment.

Create a segment of contacts with POST /segments. The summary is "Create a dynamic segment. Rules AND together over properties and status." Each rule is a field, an op and a value, and field is email, status or property.<name>. Membership is never saved: GET /segments/{id}/members is "The segment evaluated RIGHT NOW — live member ids, never a snapshot." The contacts are people who gave you their address; a segment selects among them and imports nobody.

Contacts and properties

POST /contacts — "Create or update a contact by email. Properties are typed from their value and auto-created — nothing needs pre-declaring." The reply carries properties and property_types, so a plan of "pro" and a signed_up_at of "2026-09-01" are stored as a string and a date. status is active, unsubscribed or bounced; PATCH /contacts/{id} can set active or unsubscribed. Audience says what an unsubscribe is allowed to undo: an address that reported a message as spam does not come back.

The rules

The operators are equals, not_equals, contains, greater_than, less_than, in and exists. contains ignores case. greater_than and less_than compare two ISO dates as timestamps and anything else as numbers. in takes an array as value. A property that was never set misses equals, not_equals, greater_than and less_than; exists is the operator that asks whether it is there.

curl -sS -X POST https://api.agentisend.com/segments \
  -H "Authorization: Bearer $AGENTISEND_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"name":"yourdomain.com"}'
201
{
  "created_at": "2026-09-04T09:14:00Z",
  "id": "9c8f8f0e-3d1a-4d3f-9a1e-2b7c1a0f5e42",
  "name": "yourdomain.com",
  "rules": [],
  "updated_at": "2026-09-04T09:14:00Z"
}
Response

A bare field name such as plan is stored as property.plan. Any other dotted form is refused with invalid_parameter, whose message reads A segment rule cannot filter on "contact.plan". A rule field is email, status, or property.<name>. The fix gives the form that works: {"field":"property.plan","op":"equals","value":"pro"}. A segment with no rules matches every contact. Paying customers who can still be mailed is two rules:

{
  "name": "Pro, active",
  "rules": [
    { "field": "status", "op": "equals", "value": "active" },
    { "field": "property.plan", "op": "equals", "value": "pro" }
  ]
}

Reading and changing membership

GET /segments/{id}/members returns member_ids, total and truncated; truncated is true when the account has more contacts than one evaluation reads, so treat total as a floor in that case. PATCH /segments/{id} — "Rename or change the rules. Membership re-evaluates immediately." DELETE /segments/{id} — "Delete a segment. Contacts are untouched." An automation can use segment.joined or segment.left as its trigger, and both are also webhook events.

Sending to it

POST /broadcasts — "Draft a broadcast to a segment. Content comes from a template version or an inline body." Pass name, segment_id, from_address, subject, and either template_id or content; scheduled_at is optional. POST /broadcasts/{id}/send sends now: "Content is SNAPSHOTTED: the segment is evaluated and every member rendered with their properties; the result is immutable." GET /broadcasts/{id}/messages lists each member and what happened, and Broadcasts says a skipped address names the rule that stopped it. The FAQ's answer on newsletters is that they go "to people who asked for them"; a segment is how you say which of them.

Next