Contacts

Import contacts

Upsert up to 500 contacts by email. For existing contacts, attributes are merged and first_name, last_name and status are updated only when the row sets them, so an unsubscribed contact stays unsubscribed. New contacts default to subscribed.

POSThttps://api.sndr.sh/v1/contacts/bulk
Import contacts
curl -X POST 'https://api.sndr.sh/v1/contacts/bulk' \
  -H "Authorization: Bearer $SNDR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "contacts": [
      { "email": "alice@example.com", "first_name": "Alice", "attributes": { "tier": "gold" } },
      { "email": "bob@example.com",   "first_name": "Bob" }
    ],
    "source":    "import",
    "group_ids": ["grp_4d8a0c5e-1f7"]
  }'
200OK
{
  "inserted": 1,
  "updated":  1,
  "skipped":  0
}

Authorization

Authorizationstringheaderrequired

Bearer followed by your API key. Needs the send scope.

Body

application/json
contactsobject[]required

Contacts as {email, first_name?, last_name?, status?, attributes?}, 1–500 per request.

sourcestring

Source label for newly created contacts. Defaults to manual.

group_idsstring[]

Groups (grp_...) to add every contact in the batch to.

Errors

401unauthenticatedMissing or invalid API key.
400invalid_requestBody is not valid JSON, has an unknown field, or a field has the wrong type.
400chunk_too_largeMore than 500 contacts in one request. Split the import.
403insufficient_scopeThe API key is missing the send scope.
422validation_failedcontacts is empty, or a row has a missing or invalid email or an unknown status (fields names each row, e.g. row.<index>.email). Nothing is saved.