API Reference

Import contacts (CSV)

POST /audiences/:audience_id/contacts/import — bulk-import contacts from a CSV.

POST/audiences/:audience_id/contacts/import

Import up to 10,000 contacts (max 5 MB) from a CSV. The CSV can be sent as a JSON body field or as a raw text/csv / text/plain body. A header row is optional — if present, column names are matched to contact fields (email, first_name, last_name, unsubscribed). By default, any other columns are automatically registered as custom properties (so company, plan, … survive and become {{merge}} tags). Pass ?create_properties=false on the query string for strict mode, where only columns matching an already-registered property are kept and the rest are reported in ignored_columns.

Body
csvstringrequired

CSV text. The email column is always required. Other columns map to contact fields or custom properties. You can also POST a raw text/csv body instead of a JSON wrapper.

on_conflictstringoptional

upsert (default) — update the existing contact when the email already exists. skip — leave it untouched. Can also be passed as a query parameter ?on_conflict=skip when using a raw CSV body.

Query parameters
create_propertiesbooleanoptional

Read from the query string only — a create_properties field in the JSON body is ignored. Defaults to true, so non-builtin CSV columns are auto-registered as string custom properties (up to 50 new per import) and no data is silently dropped. Pass ?create_properties=false to keep only already-registered columns.

segment_idstringoptional

Read from the query string only. Also add every imported email to this segment. The segment must be one of yours and must belong to the audience you are importing into — otherwise the request is rejected with 422 validation_error before any contact is written. When set, the response carries a segment_added count.

Request
import { SendPing } from 'sendping';

const mb = new SendPing('mb_xxxxxxxxx');

const { data, error } = await mb.contacts.import({
  audienceId: 'AUDIENCE_ID',
  "csv": "email,first_name,last_name\nsteve@example.com,Steve,Wozniak\nada@example.com,Ada,Lovelace"
});
console.log({ data, error });

Response (201)

{
  "object": "contact_import",
  "imported": 1,
  "updated": 1,
  "skipped": 0,
  "total": 2,
  "invalid_rows": 0,
  "limit_skipped": 0,
  "system_skipped": 0,
  "ignored_columns": [],
  "source_file": {
    "file_name": "contacts.csv",
    "storage_key": "contact-imports/9f3c1d7a4b2e6058c1d9e2f4/2026/06/23/20260623T172243000Z-7d3f0c1a-5b8e-4a92-9c07-1f6d2e4b8a35/contacts.csv",
    "archived": true
  },
  "contact_limit": {
    "plan": { "id": "free", "name": "Free" },
    "used_before": 12,
    "limit": 0,
    "remaining_before": null,
    "remaining_after": null,
    "limit_skipped": 0,
    "reached": false,
    "message": "Your plan includes unlimited stored contacts. Added 1 new contact and updated 1 existing contact. The complete original CSV is safely archived."
  }
}

imported counts new contacts; updated counts existing contacts merged by email. skipped includes invalid email rows and conflicts skipped by request. total counts source rows including duplicates, so it need not equal the sum of the other counts. limit_skipped and system_skipped are retained for compatibility and are zero: stored contacts are unlimited.

ignored_columns lists unregistered fields omitted when create_properties=false. source_file identifies the original S3 archive; send storage_key instead of csv to re-import without re-uploading. contact_limit remains a compatibility field: limit=0 and remaining=null mean unlimited storage. segment_added counts newly created memberships. Contacts and segment membership are committed atomically.

An empty CSV, malformed quoting, invalid UTF-8, ambiguous column names, or more than 50 custom property columns is rejected. Property values can contain up to 1,000 characters. Invalid email rows are counted and skipped. Inline API imports support up to 10,000 contacts; the direct-S3 dashboard path supports larger row counts within the file-size limit. Unknown audiences return 404.