Preview a segment
/api/v1/segments/previewHow many contacts a set of rules currently matches, and a sample of them, without saving the segment. Call this before sending to one.
Rules take one of four kinds of field:
| Kind | Fields | Example |
|---|---|---|
| Contact columns | email, name, status |
{"field": "email", "op": "ends_with", "value": "@acme.com"} |
| Custom fields | any key from GET /contact-fields |
{"field": "plan", "op": "equals", "value": "pro"} |
| Engagement | opened, clicked, emailed |
{"field": "opened", "op": "within_days", "value": "90"} |
| Membership | tag, interest |
{"field": "tag", "op": "equals", "value": "vip"} |
tag matches by NAME, interest matches by ID. That asymmetry is deliberate. A tag is
written by name everywhere — created on first use, case-insensitively — so a rule holding a
ULID would break the moment somebody renamed it. An interest is an answer to a question the
contact was asked and its name is form copy, so rewording "Product updates" must not
silently empty every segment built on it.
Membership fields take equals, not_equals, is_set (has any) and is_not_set (has
none). Deliberately not contains: a tag is on a contact or it is not, and a substring
match over a set would let contains "vip" quietly also match vip-churn-risk.
not_equals means "does not carry it", not "carries something else". A contact with
both vip and churn-risk is EXCLUDED by tag is not vip — they carry it. A contact with
no tags at all is included, because they do not.
A rule we cannot evaluate — an unparseable number or date, a blank tag — matches nothing. Widening is the dangerous direction: it mails people who were never meant to be in the audience, and it does so quietly.
Request
/api/v1/segments/previewcurl -X POST 'https://app.mailyte.com/api/v1/segments/preview' \
-H 'Authorization: Bearer mk_live_YOUR_API_KEY'const response = await fetch('https://app.mailyte.com/api/v1/segments/preview', {
method: 'POST',
headers: {
Authorization: 'Bearer mk_live_YOUR_API_KEY',
},
});
const { data } = await response.json();import requests
response = requests.post(
"https://app.mailyte.com/api/v1/segments/preview",
headers={"Authorization": "Bearer mk_live_YOUR_API_KEY"},
)
data = response.json()["data"]<?php
$response = Http::withToken('mk_live_YOUR_API_KEY')
->post('https://app.mailyte.com/api/v1/segments/preview');
$data = $response->json('data');require "net/http"
require "json"
uri = URI("https://app.mailyte.com/api/v1/segments/preview")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer mk_live_YOUR_API_KEY"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }Response
Success.
dataobjectobjectstringsegment_previewcountintegerEvery contact the rules match — exact, and NOT the size of `sample`.
samplearray<object>At most five matches, in the query's own order, so an author can see the audience is the one they meant. It is a sample, not a page: there is no pagination and no promise about which five. Rows are not contact objects and carry no id — the preview query selects only these three columns; save the segment if you want the matching contacts.
emailstringnamestringThe contact's display name, read from the same column `contact.name` publishes. `null` means NONE — this contact has no name recorded — never "the preview left it out": `name` is one of the three columns the preview query selects, so it is always a real answer.
statestringsubscribed | unsubscribed | bounced | complained | suppressedLiterally `contact.state`, resolved by the same code against the same suppression list, so a preview can never disagree with the contact endpoint about who is mailable.
Returned inside the standard envelope.
Errors
| Status | When |
|---|---|
401 | The API key is missing, unknown, revoked or expired. All four answer identically, on purpose: distinguishing them would confirm which keys exist. |
403 | The key is valid but may not do this: it lacks the required scope, its IP allowlist does not include you, or this endpoint does not accept API keys. |
404 | No such resource in this organization. |
422 | The request was understood but the values were not acceptable. |
429 | Too many requests, or the organization has spent its sending allowance. `Retry-After` says how long to wait. |
Every status, with what causes it and what to do, is on the error reference.