Audience

Managing contacts

Add contacts to an audience with an email and optional name, track their subscribe state, and address them by id or email.

A contact is a single person on an audience. Contacts are nested under the audience that owns them — every contact operation runs against /audiences/:audience_id/contacts.

The only required field is email. You can optionally store a first_name and last_name, an unsubscribed flag that controls whether campaigns reach them, and a properties map of custom fields you can use to personalize campaigns.

The contact object

{
  "object": "contact",
  "id": "479e3145-dd0e-4f64-bf48-1d4b6d4cd8f6",
  "email": "steve@example.com",
  "first_name": "Steve",
  "last_name": "Wozniak",
  "unsubscribed": false,
  "properties": {
    "company_name": "Acme Corp"
  },
  "created_at": "2026-06-23T17:30:11.000Z"
}

Emails are stored lowercased. first_name and last_name are null when not provided. properties is always present and includes every registered custom property, merged with fallback values.

Adding a contact

Send the email (required) plus any optional fields to the audience’s contacts collection. Alongside first_name, last_name, and unsubscribed, you can include a properties object of custom field values — each key must already be registered as a contact property on your account and the value must match its type.

import { SendPing } from 'sendping';

const mb = new SendPing('mb_xxxxxxxxx');

const { data, error } = await mb.contacts.create({
  audienceId: 'AUDIENCE_ID',
  "email": "steve@example.com",
  "first_name": "Steve",
  "last_name": "Wozniak",
  "unsubscribed": false
});
console.log({ data, error });

Upsert by email

Contacts are unique by email within an audience. If you create a contact whose email already exists in that audience, SendPing merges into the existing contact instead of creating a duplicate. This makes the create call safe to call repeatedly (for example, on every signup) without producing duplicates.

The merge never destroys data: an omitted first_name/last_name keeps the value already stored, properties are merged key by key (incoming keys win), and unsubscribed is monotonic — a create can suppress a contact but can never re-subscribe one, so sending unsubscribed: false for an opted-out contact leaves the opt-out in place. Use PATCH to re-subscribe a contact or to clear a name.

Addressing a contact by id or email

Anywhere a contact identifier appears in the path — get, update, delete — you can pass either the contact id or its email. SendPing detects which you provided. Both of these refer to the same contact:

GET https://www.sendping.co/api/audiences/AUDIENCE_ID/contacts/479e3145-dd0e-4f64-bf48-1d4b6d4cd8f6
GET https://www.sendping.co/api/audiences/AUDIENCE_ID/contacts/steve@example.com

Contact properties

Every contact has four default properties — email, first_name, last_name, and unsubscribed. You can also register custom properties to store additional information (for example company_name or plan) and use those values to personalize campaigns. Properties are registered once per account with POST /contact-properties — there is no per-audience registry, so a registered key is valid for every contact in every audience.

Set custom values by passing a properties map when you create or update a contact:

{
  "email": "steve@example.com",
  "first_name": "Steve",
  "properties": {
    "company_name": "Acme Corp",
    "plan": "pro"
  }
}
A property key must already be registered on your account and the value must match its declared type. On POST /contacts (and the audience-scoped POST /audiences/:audience_id/contacts) unknown keys or mismatched types are rejected and the contact is not changed. Property keys are case-sensitive — company_name and companyName are different keys.

Bulk import by CSV

Upload a CSV up to 5 MB, choose a segment, and review validation counts and the first 20 contacts before importing. The super-admin is exempt from the file-size limit. All plans have unlimited stored contacts. Overlapping imports merge by normalized email; segment membership is unique and existing unsubscribe preferences are preserved. The original CSV stays in private S3 storage; sending uses validated database contacts and current suppression preferences.

on_conflictBehavior
upsertUpdate the existing contact with the values from the CSV row.
skipLeave the existing contact untouched and skip the row.

Automatic creation

Contacts are also created automatically when an automation runs for an email address that does not yet exist on the audience, so you do not have to pre-add every recipient.

Next steps