Contacts

The people your marketing email goes to, with custom properties and their consent.

Each environment keeps its own contacts: one per email address, with a first and last name, custom properties, and their consent to marketing email. Contacts are what audiences and segments select and what broadcasts are sent to. How many an environment may keep depends on the plan (see Billing).

A contact's status says whether they want marketing email:

Consent is separate from the suppression list: bounces and complaints stay suppressions, and unsubscribing never adds one. Re-subscribing a contact never removes a suppression either, so an address that bounced stays protected.

Creating and updating

upsert creates the contact with that address, or updates the existing one: names and properties are merged (null removes a property), and status only changes when you pass it.

const { :  } = await ...({
  : "ada@example.com",
  : "Ada",
  : { : "pro", : 12 },
});

// By id or by address.
await ...("ada@example.com", { : { : 15 } });
await ...("ada@example.com", { : "unsubscribed" });

Custom properties

Define a property before you set it. Its key and type (string, number, boolean or date) can't change; values of the wrong type are refused with a 422 naming the property. A fallback is used in templates when a contact has no value.

await ....({ : "plan", : "string", : "free" });
await ....({ : "trial_ends", : "date" });

An environment has at most 50 properties. A property a segment filters on can't be deleted. Keys that name a built-in field or a column the CSV import reads as one (email, first_name, status, created_at, given_name, subscribed and the like) are reserved.

Importing and exporting

import takes any number of contacts and sends them 1,000 per request. Each one is validated on its own (invalid ones are reported by position), existing contacts are updated, and an import never re-subscribes someone who unsubscribed. Imports send no webhooks.

const { :  } = await ...({
  : [
    { : "ada@example.com", : "Ada", : { : "pro" } },
    { : "grace@example.com" },
  ],
});
// result?.created, result?.updated, result?.kept_unsubscribed, result?.invalid

// Every contact as CSV (here only subscribed ones).
const { :  } = await ...({ : "subscribed" });

The dashboard's Contacts page imports a CSV file of up to 10,000 rows (an email column, plus first_name, last_name, status and one column per property) and downloads the same export.

Events

Single changes send contact.created, contact.updated, contact.deleted, contact.unsubscribed and contact.confirmed webhooks with the contact's id, address and status (never its properties).