Skip to content

Leads

Add leads to a campaign (speed to lead), look them up, change them, opt them out.

Every example sends your key ID and secret as CALLVIEW_KEY_ID and CALLVIEW_SECRET (see Keys and authentication). The base address is https://v2-api.callview.ai/api/v1/external.

POST /leads

Checks the lead first: a valid +1 number, your Do Not Call list, the campaign’s retired numbers, duplicates (by external_id or phone), consent if the campaign asks for it, number rules (no premium or international numbers) and the 5,000 waiting-lead limit. If it passes, the lead goes straight into the campaign’s dial queue.

A call_now lead is dialed before the campaign’s other leads, oldest first, as the campaign’s lines free up. Outside the lead’s calling hours it is scheduled for the next window. A paused or not-started campaign holds the lead and dials it when the campaign runs, and so does a reached spend cap. A refused lead isn’t saved. place_in_line and estimated_wait_seconds are estimates.

With dry_run true every check runs and the lead isn’t saved. Needs leads:write.

Parameters

Name In Type Required Notes
Idempotency-Key header string Any string you choose (1 to 255 visible characters), new for each new action. Send the same key again within 24 hours and you get the first answer back instead of a second lead or call. At most 255 characters.

Body

Field Type Required Notes
campaign_id string (uuid) yes
external_id string Your own ID for the lead. The same external_id twice in a campaign is a duplicate. At most 200 characters.
phone string yes US or Canadian number. +1 and 10 digits is best; (212) 555-7812 is fine too. Numbers in the 555-0100 to 555-0199 range are refused as made up (test mode takes its magic numbers). At most 32 characters.
name string At most 200 characters.
email string At most 254 characters.
address string At most 500 characters.
fields object Your custom fields, at most 50. The campaign’s script can use them.
consent Consent
call_now boolean Dial ahead of the campaign’s other leads. Defaults to the campaign’s setting.
dry_run boolean Run every check and answer, without saving the lead.
Terminal window
curl -X POST 'https://v2-api.callview.ai/api/v1/external/leads' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET" \
-H 'Idempotency-Key: crm-10442-postLeads' \
-H 'Content-Type: application/json' \
-d '{
"campaign_id": "7c1f2b9e-4a3d-4e8f-9b21-5d6a7e8f9a01",
"external_id": "crm-10442",
"phone": "+15550100001",
"name": "Dana Smith",
"email": "dana@example.com",
"fields": {
"roof_age": "12"
},
"consent": {
"source": "web_form",
"agreed_at": "2026-10-06T16:58:02Z",
"url": "https://example.com/quote"
},
"call_now": true
}'

200 A dry run (not saved), or a lead that already existed and was put back in the queue (requeued true)

{
"data": {
"id": "2b8e4c1d-9f3a-4b7e-8c21-6a5d4e3f2b10",
"external_id": "crm-10442",
"status": "queued",
"call_now": true,
"place_in_line": 1,
"estimated_wait_seconds": 20,
"scheduled_for": null,
"scheduled_reason": null,
"held_reason": null,
"dry_run": false,
"livemode": true
}
}

201 Accepted. status says what happens next.

{
"data": {
"id": "2b8e4c1d-9f3a-4b7e-8c21-6a5d4e3f2b10",
"external_id": "crm-10442",
"status": "queued",
"call_now": true,
"place_in_line": 1,
"estimated_wait_seconds": 20,
"scheduled_for": null,
"scheduled_reason": null,
"held_reason": null,
"dry_run": false,
"livemode": true
}
}

Errors

Status Codes
400 invalid_request, invalid_phone
401 authentication_failed
403 permission_denied
404 not_found
409 duplicate_lead, campaign_closed, idempotency_mismatch, idempotency_in_progress
422 on_dnc_list, number_retired, consent_required, number_not_allowed
429 queue_full, lead_rate_limited, call_limit_reached, test_flows_busy, rate_limited, too_many_concurrent_requests
500 internal_error
503 service_unavailable

POST /leads/batch

Each lead gets the same checks as POST /leads and its own result, in the order you sent them. A lead that fails doesn’t stop the others. campaign_id may be on each lead or once for the batch. Each lead counts toward the key’s new leads a minute. Needs leads:write.

Parameters

Name In Type Required Notes
Idempotency-Key header string Any string you choose (1 to 255 visible characters), new for each new action. Send the same key again within 24 hours and you get the first answer back instead of a second lead or call. At most 255 characters.

Body

Field Type Required Notes
campaign_id string (uuid)
dry_run boolean
leads array of object yes At most 60 items.
leads[].campaign_id string (uuid)
leads[].external_id string At most 200 characters.
leads[].phone string yes At most 32 characters.
leads[].name string At most 200 characters.
leads[].email string At most 254 characters.
leads[].address string At most 500 characters.
leads[].fields object
leads[].consent Consent
leads[].call_now boolean
Terminal window
curl -X POST 'https://v2-api.callview.ai/api/v1/external/leads/batch' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET" \
-H 'Idempotency-Key: postLeadsBatch-0001' \
-H 'Content-Type: application/json' \
-d '{
"campaign_id": "7c1f2b9e-4a3d-4e8f-9b21-5d6a7e8f9a01",
"leads": [
{
"external_id": "crm-10443",
"phone": "+15550100002",
"name": "Lee Park",
"consent": {
"source": "web_form",
"agreed_at": "2026-10-06T16:58:02Z",
"url": "https://example.com/quote"
}
},
{
"external_id": "crm-10444",
"phone": "+15550100003",
"name": "Sam Ortiz",
"consent": {
"source": "web_form",
"agreed_at": "2026-10-06T16:58:02Z",
"url": "https://example.com/quote"
}
}
]
}'

200 A result per lead: { index, ok: true, lead } or { index, ok: false, error: { code, message, param, lead_id } }

{
"data": {
"succeeded": 1,
"failed": 1,
"dry_run": true,
"results": [
{
"index": 1,
"ok": true,
"lead": {
"id": "2b8e4c1d-9f3a-4b7e-8c21-6a5d4e3f2b10",
"external_id": "crm-10442",
"status": "queued",
"call_now": true,
"place_in_line": 1,
"estimated_wait_seconds": 20,
"scheduled_for": null,
"scheduled_reason": null,
"held_reason": null,
"dry_run": false,
"livemode": true
}
}
],
"livemode": true
}
}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
404 not_found
409 idempotency_mismatch, idempotency_in_progress
429 lead_rate_limited, rate_limited, too_many_concurrent_requests
500 internal_error
503 service_unavailable

GET /leads/{id}

The lead object: id, external_id, campaign_id, livemode, name, phone, email, address, fields, consent, lead_source, owner ({ id, name } of the SDR its latest call was dialed for, or null), created, updated, status, call_now, place_in_line and estimated_wait_seconds (while queued; estimates), scheduled_for, scheduled_reason, held_reason, callback_at, late, attempts, last_outcome (a stable word, the same as the call object’s outcome) and last_outcome_label (your organization’s name for it), next_dial_at, and calls (the last 10, newest first: { id, started, outcome, outcome_label, duration_seconds }).

status: new (not yet queued), queued (due now), scheduled (waits for scheduled_for: calling hours, a cooldown, a retry), held (held_reason: campaign_paused, campaign_not_started, spend_cap_reached), dialing, on_call, callback_scheduled (callback_at), done (finished, not coming back), out_of_queue (taken out, opted out or on the Do Not Call list).

A lead in a campaign outside the key’s, in another organization, or removed is 404 not_found.

Parameters

Name In Type Required Notes
id path string (uuid) yes
Terminal window
curl -X GET 'https://v2-api.callview.ai/api/v1/external/leads/2b8e4c1d-9f3a-4b7e-8c21-6a5d4e3f2b10' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET"

200 The lead

{
"data": {
"id": "2b8e4c1d-9f3a-4b7e-8c21-6a5d4e3f2b10",
"external_id": "crm-10442",
"campaign_id": "7c1f2b9e-4a3d-4e8f-9b21-5d6a7e8f9a01",
"name": "LEAD_NAME",
"phone": "+15555550142",
"email": "lead@example.com",
"address": "1 Example Street, Springfield",
"fields": {
"roof_age": "12"
},
"consent": {
"source": "web_form",
"agreed_at": "2026-10-06T16:58:02Z",
"url": "https://example.com/quote"
},
"lead_source": "Example CRM",
"owner": null,
"created": "2026-10-06T16:58:04.000Z",
"updated": "2026-10-06T16:58:04.000Z",
"status": "queued",
"call_now": true,
"place_in_line": 3,
"estimated_wait_seconds": 90,
"scheduled_for": null,
"scheduled_reason": null,
"held_reason": null,
"callback_at": null,
"late": false,
"attempts": 0,
"last_outcome": null,
"last_outcome_label": null,
"next_dial_at": null,
"calls": [],
"livemode": true
}
}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
404 not_found
429 rate_limited, too_many_concurrent_requests
500 internal_error

GET /leads

With external_id: the one lead carrying your ID, as { data: lead }. external_id is unique per campaign, not per organization: a match in two of the key’s campaigns is 409 ambiguous_external_id with candidates ([{ id, campaign_id }]); add campaign_id to pick one.

Without it: the key’s leads, newest first, keyset-paged (starting_after = the last lead’s id), as { data: [lead], meta: { next_cursor, has_more } }. With a status filter a page can hold fewer than limit leads while has_more is true; keep paging with next_cursor. place_in_line is only given on a single-lead read.

status is one of: new, queued, scheduled, held, dialing, on_call, callback_scheduled, done, out_of_queue.

Parameters

Name In Type Required Notes
external_id query string At most 200 characters.
campaign_id query string (uuid)
status query string One of new / queued / scheduled / held / dialing / on_call / callback_scheduled / done / out_of_queue.
created[gte] query string Created at or after (ISO 8601 or unix seconds).
limit query integer Default 20. 1 to 100.
starting_after query string (uuid)
Terminal window
curl -X GET 'https://v2-api.callview.ai/api/v1/external/leads' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET"

200 With external_id, the one lead. Without it, a page of leads.

{
"data": {
"id": "2b8e4c1d-9f3a-4b7e-8c21-6a5d4e3f2b10",
"external_id": "crm-10442",
"campaign_id": "7c1f2b9e-4a3d-4e8f-9b21-5d6a7e8f9a01",
"name": "LEAD_NAME",
"phone": "+15555550142",
"email": "lead@example.com",
"address": "1 Example Street, Springfield",
"fields": {
"roof_age": "12"
},
"consent": {
"source": "web_form",
"agreed_at": "2026-10-06T16:58:02Z",
"url": "https://example.com/quote"
},
"lead_source": "Example CRM",
"owner": null,
"created": "2026-10-06T16:58:04.000Z",
"updated": "2026-10-06T16:58:04.000Z",
"status": "queued",
"call_now": true,
"place_in_line": 3,
"estimated_wait_seconds": 90,
"scheduled_for": null,
"scheduled_reason": null,
"held_reason": null,
"callback_at": null,
"late": false,
"attempts": 0,
"last_outcome": null,
"last_outcome_label": null,
"next_dial_at": null,
"calls": [],
"livemode": true
}
}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
404 not_found
409 ambiguous_external_id
429 rate_limited, too_many_concurrent_requests
500 internal_error

PATCH /leads/{id}

name, email, address (null or “” clears one), fields (merged: a key sent as “” is removed; other keys are kept), consent (replaced), external_id (only while the lead has none), call_now: false (drops the speed-to-lead priority). The phone can’t be changed (phone_cannot_change): add a new lead instead. Answers the updated lead. Idempotency-Key is honoured.

Parameters

Name In Type Required Notes
id path string (uuid) yes
Idempotency-Key header string Any string you choose (1 to 255 visible characters), new for each new action. Send the same key again within 24 hours and you get the first answer back instead of a second lead or call. At most 255 characters.

Body

Field Type Required Notes
name string or null At most 200 characters.
email string or null At most 254 characters.
address string or null At most 500 characters.
fields object Merged: a key sent as “” is removed, other keys are kept.
consent Consent
external_id string Only while the lead has none. At most 200 characters.
call_now boolean false drops the speed-to-lead priority. One of false.
phone string Can’t be changed (phone_cannot_change). Add a new lead instead.
Terminal window
curl -X PATCH 'https://v2-api.callview.ai/api/v1/external/leads/2b8e4c1d-9f3a-4b7e-8c21-6a5d4e3f2b10' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET" \
-H 'Idempotency-Key: patchLeadsId-0001' \
-H 'Content-Type: application/json' \
-d '{
"name": "Dana Smith-Lee",
"fields": {
"roof_age": "13",
"old_field": ""
}
}'

200 The updated lead

{
"data": {
"id": "2b8e4c1d-9f3a-4b7e-8c21-6a5d4e3f2b10",
"external_id": "crm-10442",
"campaign_id": "7c1f2b9e-4a3d-4e8f-9b21-5d6a7e8f9a01",
"name": "LEAD_NAME",
"phone": "+15555550142",
"email": "lead@example.com",
"address": "1 Example Street, Springfield",
"fields": {
"roof_age": "12"
},
"consent": {
"source": "web_form",
"agreed_at": "2026-10-06T16:58:02Z",
"url": "https://example.com/quote"
},
"lead_source": "Example CRM",
"owner": null,
"created": "2026-10-06T16:58:04.000Z",
"updated": "2026-10-06T16:58:04.000Z",
"status": "queued",
"call_now": true,
"place_in_line": 3,
"estimated_wait_seconds": 90,
"scheduled_for": null,
"scheduled_reason": null,
"held_reason": null,
"callback_at": null,
"late": false,
"attempts": 0,
"last_outcome": null,
"last_outcome_label": null,
"next_dial_at": null,
"calls": [],
"livemode": true
}
}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
404 not_found
409 duplicate_lead, idempotency_mismatch, idempotency_in_progress
422 phone_cannot_change
429 rate_limited, too_many_concurrent_requests
500 internal_error
503 service_unavailable

Opt a lead out - stop calling, add to Do Not Call

Section titled “Opt a lead out - stop calling, add to Do Not Call”

POST /leads/{id}/opt_out

The number goes on the organization’s Do Not Call list (source “API”), so no campaign of the organization dials it again; the lead leaves the queue with the DNC outcome and its open callbacks are closed. A call in progress is NOT cut: the reply says call_in_progress true, and nothing dials the number again. Idempotent: a second opt_out answers the same, with no second Do Not Call entry. Answers the updated lead plus call_in_progress.

Parameters

Name In Type Required Notes
id path string (uuid) yes
Idempotency-Key header string Any string you choose (1 to 255 visible characters), new for each new action. Send the same key again within 24 hours and you get the first answer back instead of a second lead or call. At most 255 characters.

Body

Field Type Required Notes
reason string Why (kept in the audit log and on closed callbacks) At most 500 characters.
Terminal window
curl -X POST 'https://v2-api.callview.ai/api/v1/external/leads/2b8e4c1d-9f3a-4b7e-8c21-6a5d4e3f2b10/opt_out' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET" \
-H 'Idempotency-Key: postLeadsIdOptOut-0001' \
-H 'Content-Type: application/json' \
-d '{
"reason": "Asked to stop on our web chat"
}'

200 The lead, plus call_in_progress

{
"data": {
"id": "2b8e4c1d-9f3a-4b7e-8c21-6a5d4e3f2b10",
"external_id": "crm-10442",
"campaign_id": "7c1f2b9e-4a3d-4e8f-9b21-5d6a7e8f9a01",
"name": "LEAD_NAME",
"phone": "+15555550142",
"email": "lead@example.com",
"address": "1 Example Street, Springfield",
"fields": {
"roof_age": "12"
},
"consent": {
"source": "web_form",
"agreed_at": "2026-10-06T16:58:02Z",
"url": "https://example.com/quote"
},
"lead_source": "Example CRM",
"owner": null,
"created": "2026-10-06T16:58:04.000Z",
"updated": "2026-10-06T16:58:04.000Z",
"status": "queued",
"call_now": true,
"place_in_line": 3,
"estimated_wait_seconds": 90,
"scheduled_for": null,
"scheduled_reason": null,
"held_reason": null,
"callback_at": null,
"late": false,
"attempts": 0,
"last_outcome": null,
"last_outcome_label": null,
"next_dial_at": null,
"calls": [],
"livemode": true,
"call_in_progress": true
}
}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
404 not_found
409 idempotency_mismatch, idempotency_in_progress
429 rate_limited, too_many_concurrent_requests
500 internal_error
503 service_unavailable

GET /campaigns/{campaignId}/leads

A campaign’s leads, page by page (cursor = the next_cursor you were given). A live key gets the older lead shape here; GET /leads with campaign_id gives the lead object and is the one to use for new work. Needs leads:read.

Parameters

Name In Type Required Notes
campaignId path string (uuid) yes
cursor query string
limit query integer Default 50. 1 to 100.
search query string Part of a name, phone or email. At most 200 characters.
Terminal window
curl -X GET 'https://v2-api.callview.ai/api/v1/external/campaigns/7c1f2b9e-4a3d-4e8f-9b21-5d6a7e8f9a01/leads' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET"

200 A page of leads

{
"data": [
{
"id": "e4d3c2b1-a09f-4e8d-9c7b-6a5f4e3d2c1b",
"livemode": true
}
],
"meta": {
"next_cursor": null,
"has_more": false
}
}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
404 not_found
429 rate_limited, too_many_concurrent_requests
500 internal_error

POST /campaigns/{campaignId}/leads

The same checks, queue and reply as POST /leads, with the campaign in the path. customFields is still accepted (it is merged into fields). Use POST /leads for new work.

Parameters

Name In Type Required Notes
campaignId path string (uuid) yes
Idempotency-Key header string Any string you choose (1 to 255 visible characters), new for each new action. Send the same key again within 24 hours and you get the first answer back instead of a second lead or call. At most 255 characters.

Body

Field Type Required Notes
phone string yes At most 32 characters.
external_id string At most 200 characters.
name string At most 200 characters.
email string At most 254 characters.
address string At most 500 characters.
fields object
customFields object
consent Consent
call_now boolean
dry_run boolean
Terminal window
curl -X POST 'https://v2-api.callview.ai/api/v1/external/campaigns/7c1f2b9e-4a3d-4e8f-9b21-5d6a7e8f9a01/leads' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET" \
-H 'Idempotency-Key: crm-10442-postCampaignsCampaignIdLeads' \
-H 'Content-Type: application/json' \
-d '{
"external_id": "crm-10442",
"phone": "+15550100001",
"name": "Dana Smith",
"call_now": true,
"consent": {
"source": "web_form",
"agreed_at": "2026-10-06T16:58:02Z",
"url": "https://example.com/quote"
}
}'

200 A dry run, or a re-queued lead

{
"data": {
"id": "2b8e4c1d-9f3a-4b7e-8c21-6a5d4e3f2b10",
"external_id": "crm-10442",
"status": "queued",
"call_now": true,
"place_in_line": 1,
"estimated_wait_seconds": 20,
"scheduled_for": null,
"scheduled_reason": null,
"held_reason": null,
"dry_run": false,
"livemode": true
}
}

201 Accepted (see POST /leads)

{
"data": {
"id": "2b8e4c1d-9f3a-4b7e-8c21-6a5d4e3f2b10",
"external_id": "crm-10442",
"status": "queued",
"call_now": true,
"place_in_line": 1,
"estimated_wait_seconds": 20,
"scheduled_for": null,
"scheduled_reason": null,
"held_reason": null,
"dry_run": false,
"livemode": true
}
}

Errors

Status Codes
400 invalid_request, invalid_phone
401 authentication_failed
403 permission_denied
404 not_found
409 duplicate_lead, campaign_closed, idempotency_mismatch, idempotency_in_progress
422 on_dnc_list, number_retired, consent_required, number_not_allowed
429 queue_full, lead_rate_limited, test_flows_busy, rate_limited, too_many_concurrent_requests
500 internal_error
503 service_unavailable

POST /campaigns/{campaignId}/leads/batch

The same as POST /leads/batch, with the campaign in the path.

Parameters

Name In Type Required Notes
campaignId path string (uuid) yes
Idempotency-Key header string Any string you choose (1 to 255 visible characters), new for each new action. Send the same key again within 24 hours and you get the first answer back instead of a second lead or call. At most 255 characters.

Body

Field Type Required Notes
dry_run boolean
leads array of object yes At most 60 items.
leads[].phone string yes
leads[].external_id string
leads[].name string
leads[].email string
leads[].address string
leads[].fields object
leads[].customFields object
leads[].consent Consent
leads[].call_now boolean
Terminal window
curl -X POST 'https://v2-api.callview.ai/api/v1/external/campaigns/7c1f2b9e-4a3d-4e8f-9b21-5d6a7e8f9a01/leads/batch' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET" \
-H 'Idempotency-Key: postCampaignsCampaignIdLeadsBatch-0001' \
-H 'Content-Type: application/json' \
-d '{
"leads": [
{
"external_id": "crm-10443",
"phone": "+15550100002",
"consent": {
"source": "web_form",
"agreed_at": "2026-10-06T16:58:02Z",
"url": "https://example.com/quote"
}
}
]
}'

200 A result per lead (see POST /leads/batch)

{
"data": {
"succeeded": 1,
"failed": 1,
"dry_run": true,
"results": [
{
"index": 1,
"ok": true,
"lead": {
"id": "2b8e4c1d-9f3a-4b7e-8c21-6a5d4e3f2b10",
"external_id": "crm-10442",
"status": "queued",
"call_now": true,
"place_in_line": 1,
"estimated_wait_seconds": 20,
"scheduled_for": null,
"scheduled_reason": null,
"held_reason": null,
"dry_run": false,
"livemode": true
}
}
],
"livemode": true
}
}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
404 not_found
409 idempotency_mismatch, idempotency_in_progress
429 lead_rate_limited, rate_limited, too_many_concurrent_requests
500 internal_error
503 service_unavailable