---
title: "Bulk create contacts"
method: POST
path: "/v1/contacts/bulk"
tags: ["Contacts"]
---

# Bulk create contacts

`POST /v1/contacts/bulk`

Import up to 1000 contacts at a time. Skips duplicates, merging any new tags onto the existing contact. accountId is required whenever contacts carry a platformIdentifier (or a row-level accountId); platform is always derived from the resolved account, never used to decide whether channels are created, and a mismatched platform 404s as account not found. When accountId is set, each contact must carry a platformIdentifier; a row missing it is rejected individually (reported in errors[], HTTP 200), not a 400 for the whole import. On phone platforms (whatsapp, sms) the platformIdentifier is normalized to digits and a value that is not phone-shaped is rejected per contact and reported in errors[], not imported.

## Request body

- object
  - `profileId` string, required
  - `accountId` string — Required when contacts carry channel data (platformIdentifier or a row-level accountId). Omit for a plain CRM import with no channels.
  - `platform` string — Ignored when accountId is set: the platform is derived from the resolved account. Only relevant to disambiguate accountId lookup; a mismatch 404s.
  - `contacts` object[], required
    - `name` string, required
    - `platformIdentifier` string — Required when the top-level accountId is set (channel mode). A row missing it in that mode is rejected individually and reported in errors[], not a 400 for the whole import.
    - `displayIdentifier` string
    - `email` string
    - `company` string
    - `tags` string[]

## Response `200`

Bulk import results

- object
  - `success` boolean
  - `created` integer
  - `skipped` integer
  - `errors` string[] — Per-contact failures, e.g. an identifier that is not a valid phone number
  - `total` integer

## Other responses

- `400` — Contact missing required field name, or a row carries platformIdentifier/accountId with no top-level accountId to attach it to. A row missing platformIdentifier while accountId IS set is not a 400: it is reported in errors[] under a 200.
- `401` — Unauthorized

---

[API](https://skmtc.net/zernio/apis/zernio-api.md) · [All operations](https://skmtc.net/zernio/apis/zernio-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/zernio/zernio-api/revisions/b8c9216f378a/schema)
