Bulk create or update contacts
Up to 500 per request, keyed on phone number, with the same merge rule as POST /contacts.
Body Parameters
- contactsarray of ContactInputrequired
At most 500 items.
- campaign_idstring
Applies to every opt_in row that does not name its own campaign_id Example:
reg_a1B2c3D4e5F6. - dry_runboolean
- check_line_typesboolean
dry_run only. Looks up line types to count landlines; live lookups are paid, so only the first 500 numbers are checked.
- import_idstring
From a previous response, to group several requests as one import.
- namestring
A label for the import (first request only).
Details
Rows that cannot be imported come back in skipped; the rest still land. dry_run: true returns the summary (found, valid, malformed, duplicates, landlines, already opted out, will create / update, eligible) and writes nothing.
A row with opt_in.status: true (or a date or source) stores opt-in evidence in the consent ledger; opt_in.status: false records the number as opted out. An import never opts anyone back in.
Responses
- 200JSON object
Import result, or the dry-run preview
- 400Error
Invalid request
- 401Error
Missing, malformed, or revoked API key
- 402Error
Billable live calls only: the prepaid credit balance cannot cover the call (insufficient_credits); nothing was done or charged
- 429Error
Rate limit or quota exceeded
Response Fields
- objectcontact_import, contact_import_preview
- createdinteger
- updatedinteger
- skippedarray of object
- skipped[].indexinteger
Position of the row in the request
- skipped[].valuestring
- skipped[].reasonstring
- import_idstring
Example:
imp_a1B2c3D4e5. - opted_outinteger
Rows recorded as opted out because they were marked unsubscribed.
- summaryobject
dry_run only.
- summary.foundinteger
- summary.validinteger
- summary.malformedinteger
- summary.duplicatesinteger
- summary.landlinesinteger
null unless check_line_types was set Nullable.
- summary.already_opted_outinteger
- summary.marked_unsubscribedinteger
- summary.will_createinteger
- summary.will_updateinteger
- summary.eligibleinteger
Would receive a broadcast today
- rejectedarray of object
dry_run only.
- rejected[].indexinteger
- rejected[].phone_numberstring
- rejected[].reasonmalformed, duplicate, landline
- rejected[].detailstring
Errors
Every error has the same JSON shape, and request_id matches the X-Request-Id response header. Errors lists every code and what to do about it.
- 400
Invalid request
- 401
Missing, malformed, or revoked API key
- 402
Billable live calls only: the prepaid credit balance cannot cover the call (insufficient_credits); nothing was done or charged
- 429
Rate limit or quota exceeded