Apply one action to up to 1000 contacts
const url = 'https://api.vocapable.com/v1/contacts/bulk';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"contact_ids":["example"],"action":"add_to_list","contact_list_id":"example","lead_status":"new"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.vocapable.com/v1/contacts/bulk \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "contact_ids": [ "example" ], "action": "add_to_list", "contact_list_id": "example", "lead_status": "new" }'The morning-after actions, in one request instead of one at a time.
Every branch is the existing per-contact write, run over a batch - the suppression
goes through the revocation path with all its derived writes, the delete is the same
soft delete DELETE /contacts/{id} performs, and list membership is the same join
POST /contact-lists/{id}/members writes. None of them invents a shortcut, which is
why a bulk suppress cannot end up weaker than a single one.
suppress additionally requires dnc:manage: it writes the internal DNC list, and a
key trusted to edit contacts is not thereby trusted to change what may be dialed.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”One action over up to 1000 contacts.
The same cap as POST /contact-lists/{id}/members, for the same reason: the whole
action runs in one request and one transaction.
object
Where the tenant’s own pipeline holds a contact (migration 0035).
Durable per-contact intent, deliberately separate from Disposition, which is pinned
(CANON fact 28) and answers “what happened to the dial” rather than “is this person
interested”. A contact is dialed many times and disposed once per attempt; the lead
status is the one value that survives across those attempts.
It carries NO compliance meaning whatsoever: LOST is not a suppression, and marking
a contact WON neither grants nor implies consent. Suppression is dnc_entries and
consent is consent_records - both have their own writers, and neither reads this
column.
Responses
Section titled “Responses”Successful Response
What the action did, per outcome rather than per id.
unknown_contact_ids is enumerated because a caller pasting stale ids has to find
out; matched and changed differ whenever an action was already applied - bulk
writes are idempotent, so re-running one reports changed = 0 rather than failing.
object
Example
{ "action": "add_to_list"}Validation Error
object
object
object
Examplegenerated
{ "detail": [ { "loc": [ "example" ], "msg": "example", "type": "example", "input": "example", "ctx": {} } ]}