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

# Bulk create contacts

`POST /v1/contacts/bulk`

## Request

- Base URL: `https://api.postzen.dev`
- URL: `https://api.postzen.dev/v1/contacts/bulk`
- Auth: HTTP bearer

Requires read_write. Limited to 20 imports/hour/user. Runs as one mutation. Processes 1–1000 rows with individual errors; duplicate channel or profile email skips the row and merges only tags. Remaining rows fail once the contact cap is reached. platform is ignored with accountId and rejected without it. Envelope profile/account errors fail the request.

## Request body

- ContactBulkCreateRequest: Import 1–1000 contacts into one profile. A supplied accountId applies to every row. Duplicates by channel (first) or profile email are skipped and only new tags are merged, retaining existing case. A merged tag list over 50 is a row error. When the 5000-contact cap is reached, remaining rows receive contact limit reached errors.
  - `profileId` string, required: Owning profile id; immutable and must be in the API key scope.
  - `accountId` string: Connected account id; must belong to the same profile and caller.
  - `platform` string: Ignored when accountId is supplied. Without accountId, this field is rejected with 400 validation; platform disambiguation is not supported.
  - `contacts` ContactBulkCreateRow[], required: Rows to process in one mutation. Row validation errors are reported individually.
    - `name` string, required: Trimmed contact name, 1–200 characters.
    - `email` string: Trimmed lowercase email; unique within its profile.
    - `company` string: Company name, at most 200 characters.
    - `tags` string[]: At most 50 tags, trimmed and deduplicated case-insensitively, preserving original case. Send [] to clear.
    - `isSubscribed` boolean: Contact subscription state. False prevents comment automation sends.
    - `notes` string: Free-form notes, at most 5000 characters.
    - `customFields` object: At most 50 keys of 1–64 characters. Keys follow Convex record rules: printable ASCII, not starting with $ or _. Values are strings (at most 1000 characters), finite numbers, booleans, or null. PATCH replaces the entire object.
    - `platformIdentifier` string: Required when the bulk envelope has accountId. Supplying an identity without an envelope accountId is a per-row error.
    - `displayIdentifier` string: Optional username or friendly handle, at most 200 characters. Without a channel it is ignored and a warning is returned.

## Response `200`

Bulk create contacts.

- ContactBulkCreateResponse
  - `message` string, required: Import outcome summary.
  - `created` integer, required: Number of newly created contacts.
  - `skipped` integer, required: Number of duplicate contacts skipped, with tags merged.
  - `errors` string[], required: Per-row errors using 1-based row numbers.
  - `total` integer, required: Number of submitted rows; equals created + skipped + errors.length.

## Other responses

- `400`: Invalid request.
- `401`: Missing or invalid API key.
- `403`: The API key does not have sufficient permission or profile access.
- `404`: Resource not found.
- `429`: Rate limit exceeded. Retry after the interval indicated by the `Retry-After` header.
- `500`: Unexpected server error.

---

[API](https://skmtc.dev/postzen/apis/postzen-public-api.md) · [All operations](https://skmtc.dev/postzen/apis/postzen-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/postzen/apis/postzen-public-api/revisions/40863e3710ec?raw)
