Grow · Audiences

One record per person, for every team.

Contacts, properties, topics and segments, shared by your API and your campaigns. Sync from your app, import a CSV, and let consent and suppression follow the person everywhere.

Also in the API
  • /contacts, Live
  • /segments, Live
  • /topics, Live
Contacts · Asha K.Sample data
GET /contacts/[email protected]JSON
{
  "object": "contact",
  "id": "<contact id>",
  "email": "[email protected]",
  "first_name": "Asha",
  "last_name": "K.",
  "created_at": "2026-03-02T05:12:40.000Z",
  "unsubscribed": false,
  "properties": {
    "city": { "type": "string", "value": "Pune" },
    "orders": { "type": "number", "value": 3 }
  }
}
Sample contact record: properties, topics and consent, then one timeline holding the login code and order confirmation her backend sent, the campaign she clicked, her consent and the segment she joined. Switch to API to see the same contact as the API returns it.

01, Properties

Fields you define, choices they make.

Add the properties your product cares about, typed so that segments and merge tags treat them properly. Topics let each person choose what they hear about, from a preference page you do not have to build.

  • Typed properties. String, number, boolean or date, each with an optional fallback for merge tags. The keys are yours: plan, city, last_order_at.
  • Topics. Opt-in or opt-out by default, and public or private. A private topic shows on the preference page only to people already in it.
  • One link in every campaign. The preference page lets people change topics or leave marketing altogether.
Preference pageSample data
Sample hosted preference page for a reader of Nimbu Books. Her choices save to the same contact record your API reads.

02, Segments

Segments that keep themselves current.

Describe who you mean once. As orders come in and emails are opened, clicked or bounced, people move in and out of the segment without anyone re-exporting a list.

  • Fields and properties: equals, contains, greater than, between, before, in the last N days.
  • Topics and static segments: opted in or out, member or not.
  • Email activity: delivered, opened, clicked or bounced, for any campaign, one campaign or one link, with machine opens and clicks left out.
  • Revenue: order value over a period, from the orders your code sends.
  • Groups nest up to five levels with and, or and not. A rule that does not validate is an error, never a quietly wider list.
Segments · Recent repeat buyersSample data
POST /segmentsJSON
{
  "name": "Recent repeat buyers",
  "filter": {
    "type": "and",
    "rules": [
      { "type": "rule", "field": "properties.orders",
        "operator": "gte", "value": 2 },
      { "type": "rule", "field": "properties.last_order_at",
        "operator": "within_last_days", "value": 30 },
      { "type": "rule", "field": "topic",
        "operator": "opted_in", "value": "<New arrivals topic id>" }
    ]
  }
}
Sample segment with three rules. The preview names one matching contact instead of a count. Switch to API to see the request that creates the same segment.

03, Import

Bring your list without breaking it.

Upload a CSV of up to 50 MB, map its columns, and say how consent was collected. The import runs in chunks and picks up where it stopped if anything restarts.

Coming from another marketing tool? Export your audience as a CSV file and map its columns once: the example maps Email Address and First Name, a common export layout.

  1. Upload

    A CSV of up to 50 MB, from any tool that exports one.
  2. Map the columns

    Exactly one email column. The rest become names or typed properties, and everyone can join a static segment or a topic on the way in.
  3. Record the basis

    Say how these people agreed to hear from you. Contacts imported without a basis are kept, but campaigns and journeys skip them.
  4. Read the report

    Created, updated, skipped and failed counts, with a CSV of every failed row and the reason.
Shell
curl -X POST https://api.refiremail.com/contacts/imports \
  -H "Authorization: Bearer $REFIREMAIL_API_KEY" \
  -F "[email protected]" \
  -F 'column_map={
        "email": "Email Address",
        "first_name": "First Name",
        "properties": { "city": { "column": "City" } }
      }' \
  -F "on_conflict=skip"

# 201 Created
# {"object":"contact_import","id":"<import id>"}
Shell
curl -X POST https://api.refiremail.com/contacts \
  -H "Authorization: Bearer $REFIREMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "first_name": "Asha",
    "properties": { "city": "Pune", "orders": 3 },
    "topics": [
      { "id": "<New arrivals topic id>", "subscription": "opt_in" }
    ]
  }'
  • An import never re-subscribes a contact who opted out.
  • When an address appears twice in one file, the first row wins.
  • Suppressed addresses are skipped.
  • Imported contacts start no journeys unless you turn that on for the import.

04, Suppression

One suppression list, two kinds of mail.

Bounces and complaints are recorded once and respected by every send, whether it came from your code or a campaign. A marketing unsubscribe is respected just as firmly, but only where it applies, so password resets still arrive.

What each event stops. One list, read by the API and by every campaign and journey.
When this happensCampaigns and journeysReceipts, OTPs and resets
Permanent bounceStoppedStopped
Spam complaintStoppedStopped
Unsubscribe from marketingStoppedStill sent
Opt-out of one topicStopped for that topicStill sent

For the email your team writes, on the same contacts.

Bring your list.

Import a CSV or sync from your app. Both land on the same records.