Create a contact
const url = 'https://api.vocapable.com/v1/contacts';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"phone_e164":"example","first_name":"example","last_name":"example","company":"example","title":"example","email":"example","timezone":"example","jurisdictions":["example"],"attributes":{},"lead_status":"new","owner_user_id":"example","tags":["example"],"consent":{"consent_basis":"pewc","captured_at":"2026-04-15T12:00:00Z","scope":{},"evidence":{"artifact_type":"example","artifact_ref":"example","content_hash":"example"},"disclosure_text_shown":"example","expires_at":"2026-04-15T12:00:00Z"}}'};
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 \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "phone_e164": "example", "first_name": "example", "last_name": "example", "company": "example", "title": "example", "email": "example", "timezone": "example", "jurisdictions": [ "example" ], "attributes": {}, "lead_status": "new", "owner_user_id": "example", "tags": [ "example" ], "consent": { "consent_basis": "pewc", "captured_at": "2026-04-15T12:00:00Z", "scope": {}, "evidence": { "artifact_type": "example", "artifact_ref": "example", "content_hash": "example" }, "disclosure_text_shown": "example", "expires_at": "2026-04-15T12:00:00Z" } }'Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Header Parameters
Section titled “Header Parameters”Request Bodyrequired
Section titled “Request Bodyrequired”Create one API contact and its initial lawful-consent record together.
This is intentionally stricter than the operator fields below: a programmatic create is headless contact intake, so it cannot first land a dialable-looking contact and ask the customer to append consent later. The matching tenant-level API-source attestation is resolved only on the server and is written into the ConsentRecord proof.
object
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.
Consent that must land atomically with a headless contact create.
scope is deliberately explicit rather than defaulting to {}: an empty scope
would make a contact look broadly consented while saying nothing about which calls or
channels the customer captured permission for. The policy engine remains the
authority for whether that stored scope covers a later call purpose.
object
CANON fact 18 - the four consent classes (docs/07-compliance.md §consent).
object
The immutable customer-side artifact behind one API-created contact’s consent.
A standing API-source attestation says the tenant may create contacts through this surface; it does not replace evidence for an individual person. The server links the resulting ConsentRecord to that standing attestation itself, so callers cannot name or substitute an attestation id here.
object
Responses
Section titled “Responses”Successful Response
object
CANON fact 18 - the four consent classes (docs/07-compliance.md §consent).
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.
object
Example
{ "best_consent_class": "pewc", "do_not_call": false, "lead_status": "new"}Validation Error
object
object
object
Examplegenerated
{ "detail": [ { "loc": [ "example" ], "msg": "example", "type": "example", "input": "example", "ctx": {} } ]}