Skip to content

Segments & topics

The segment filter format and segment routes, topics, subscriber import/export and bulk labels.

Segments

/api/v1/segments — saved filters you can send to (segmentId), leave out of a send (excludeSegmentId), or attach to an RSS feed or a recurring schedule. A segment's filters, and the inline filters / excludeFilters of a send, use one format:

JSON
{ "match": "all",                  // "all" = every rule must match (default), "any" = at least one
  "rules": [
    { "field": "country",  "op": "in", "value": ["IN", "US"] },
    { "field": "tag:plan", "op": "eq", "value": "pro" },
    { "field": "tag:vip",  "op": "exists" }
  ] }
PartValues
fieldcountry (the 2-letter upper-case code from the visitor's IP), language, url (the subscriber's last page), external_id (or externalId), or tag:KEY for one of your tags. An unknown field matches nobody (the rule fails closed, so a typo can't turn a targeted send into a send to everyone).
opeq (default; also used for an unknown op), neq, contains (case-insensitive), in (value is a list), exists, not_exists (no value needed). For a tag, neq also matches subscribers without that tag.
valueCompared as text, exactly: eq, neq and in are case-sensitive (only contains ignores case), so write country codes in upper case, e.g. "IN". For country, language, url and external_id, neq doesn't match subscribers who have no value.
RequestWhat it does
GET /api/v1/segments{ segments: [{ id, name, filters, created_at }] }, newest first.
POST /api/v1/segmentsBody { name, filters } → 201 { segment }. 400 name_required without a name. A segment needs at least one complete rule (a field — a tag: field with its key — and a value, unless the op is exists / not_exists): otherwise 400 segment_needs_a_rule, because a segment with no rules would include every subscriber.
PUT /api/v1/segments/:idChanges name and/or filters (the same rule check) → { segment }. 400 nothing_to_update when neither is sent; 404 not_found for another website's id.
DELETE /api/v1/segments/:id{ ok: true }. While an enabled RSS feed, an enabled recurring schedule, or a scheduled or queued send uses it (to include or to exclude), it answers 409 { "error": "segment_in_use", "feeds", "schedules", "pending" } with how many of each.
POST /api/v1/segments/previewBody { filters, topicId? } → { count }: how many subscribed browsers match right now (a person on two devices counts twice), optionally within a topic (id or slug).
GET /api/v1/audience/segmentsYour saved segments with their size: { segments: [{ id, name, filters, created_at, count, lastUsedAt, sends, usedBy: { feeds, schedules } }] }. count is the same number /segments/preview gives. Needs subscribers:read.

Writes need segments:write. A send that names a segment which isn't in this website is refused (400 segment_not_found), and one whose segment is deleted before it goes out ends failed with segment_missing — a missing segment never means "everyone".

Topics

/api/v1/topics — preference-center categories. GET lists { id, name, slug, created_at, subscribers }; POST { name, slug? } creates one (the slug is made from the name when left out; posting an existing slug renames that topic); PUT /:id { name } renames it (the slug never changes, since subscribers opt in by slug); DELETE /:id. Writes need settings:write. Subscribers opt in via RelayBell.setTopics(["slug"]) / showPreferences(); target a send with topicId (id or slug).

Subscribers

  • GET /api/v1/subscribers/export — CSV of subscribers. GET /api/v1/subscribers/recent?limit=25 — the newest ones (up to 100).
  • POST /api/v1/subscribers/import — body { subscribers: [{ externalId, tags: { … }, topics: ["slug"] }] } (up to 10,000 rows) creates or enriches subscribers by external id → { ok, processed } (400 no_subscribers for an empty list). Push subscriptions themselves can't be imported: each browser must opt in on your site.
  • GET /api/v1/subscribers/:externalId/profile — one person (by external id or relaybell id): { subscriber, tags, endpoints, topics, sends, events, stats }, with their last 50 deliveries/clicks and events; /data and DELETE are under Compliance.
  • GET /api/v1/audience/subscribers — the dashboard's paged, filterable list; POST /api/v1/audience/subscribers/bulk-tag { ids, set: { key: value }, remove: [key] } (at most 20 labels at a time; rb_ keys are reserved) and /bulk-delete { ids } → { ok, deleted }.