Skip to content

Create a contact

POST
/v1/contacts
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" } }'
Idempotency-Key
Any of:
string

Unique key for this request, so a retry replays the original result instead of repeating the work. Stored for 24 hours; a replayed response carries Idempotent-Replay: true. A UUID is the documented shape.

Media typeapplication/json
ContactCreateRequest

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
phone_e164
required
Phone E164
string
/^\+[1-9]\d{6,14}$/
first_name
Any of:
string
last_name
Any of:
string
company
Any of:
string
title
Any of:
string
email
Any of:
string
timezone
Any of:
string
jurisdictions
Jurisdictions
Array<string>
attributes
Attributes
object
key
additional properties
any
lead_status
Any of:
LeadStatus

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.

string
Allowed values: new working qualified unqualified won lost
owner_user_id
Any of:
string
tags
Tags
Array<string>
<= 32 items
consent
required
ApiContactConsentInput

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
consent_basis
required
ConsentBasis

CANON fact 18 - the four consent classes (docs/07-compliance.md §consent).

string
Allowed values: pewc pec ebr transactional
captured_at
required
Captured At
string format: date-time
scope
required
Scope
object
>= 1 properties
key
additional properties
any
evidence
required
ApiContactConsentEvidence

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
artifact_type
required
Artifact Type
string
>= 1 characters <= 100 characters
artifact_ref
required
Artifact Ref
string
>= 1 characters <= 2000 characters
content_hash
required
Content Hash
string
/^[0-9a-f]{64}$/
disclosure_text_shown
Any of:
string
expires_at
Any of:
string format: date-time

Successful Response

Media typeapplication/json
Contact
object
id
required
Id
string
phone_e164
required
Phone E164
string
first_name
Any of:
string
last_name
Any of:
string
company
Any of:
string
title
Any of:
string
email
Any of:
string
timezone
Any of:
string
best_consent_class
Any of:
ConsentBasis

CANON fact 18 - the four consent classes (docs/07-compliance.md §consent).

string
Allowed values: pewc pec ebr transactional
do_not_call
Do Not Call
boolean
lead_status
Any of:
LeadStatus

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.

string
Allowed values: new working qualified unqualified won lost
owner_user_id
Any of:
string
tags
Tags
Array<string>
created_at
required
Created At
string format: date-time
updated_at
required
Updated At
string format: date-time
jurisdictions
Jurisdictions
Array<string>
attributes
Attributes
object
key
additional properties
any
Example
{
"best_consent_class": "pewc",
"do_not_call": false,
"lead_status": "new"
}

Validation Error

Media typeapplication/json
HTTPValidationError
object
detail
Detail
Array<object>
ValidationError
object
loc
required
Location
Array
msg
required
Message
string
type
required
Error Type
string
input
Input
ctx
Context
object
Examplegenerated
{
"detail": [
{
"loc": [
"example"
],
"msg": "example",
"type": "example",
"input": "example",
"ctx": {}
}
]
}