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.
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.comContact 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"
}
}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_conflict | Behavior |
|---|---|
upsert | Update the existing contact with the values from the CSV row. |
skip | Leave the existing contact untouched and skip the row. |
Automatic creation
Next steps
- Create a contact via the API.
- Update a contact — change a name, a property, or the subscribe state.
- Manage unsubscribed contacts.