Leads
Import leads into a campaign through the platform's own list-upload validation
POST /v1/leads/import
- Scope
leads:write- Tier
- Tier 1
- Data
- Personal data
- Idempotency
- Idempotency-Key: required
- Limit
- Up to 200 leads per request
Runs the real campaign list-upload path: sanctioned destinations, phone validation, duplicates in the request and in the campaign, the account's field rules and the Do-Not-Call screen.
Refused with 409 campaign_not_importable unless the campaign is paused, draft or ready: an import into a running campaign would place real calls.
If the Do-Not-Call screen cannot run, the WHOLE import is refused with 503 dnc_screen_unavailable; nothing was written and a retry with the same Idempotency-Key is safe. If the platform cannot confirm the write, the answer is 409 outcome_unknown on every retry of that key until DialerBee has reconciled it.
Exactly one result per input lead, by index (0-based). external_id is stored per API client (two integrations may both use 12345). At most 200 leads per request.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaign_id | query | string (CampaignId) | yes | |
Idempotency-Key | header | string | yes | Your unique value for this logical operation (a UUID is fine). Scoped to your API client, kept 24 hours. (min length 1; max length 255) |
X-Correlation-ID | header | string | no | Your own trace value, logged with the request. Metadata only, never identity. (min length 1; max length 128) |
Request body
The leads to import.
JSON: LeadImportRequest
Response
200: Every input lead has exactly one result.
| Header | Meaning |
|---|---|
X-Request-ID | The DialerBee request id. Quote it to support. Every response carries X-Request-ID: req_<ULID>, or edge_<32 hex> when the edge answered before the request reached the API. |
Cache-Control | Always no-store. |
Idempotency-Replayed | true when this answer is the stored answer of an earlier request with the same Idempotency-Key. |
Examples
Request example
curl
curl -sS -X POST \
"https://app.dialerbee.com/api/v1/leads/import?campaign_id=cmp_0f8fad5b-d9cb-469f-a165-70867728950e" \
-H "Authorization: Bearer $DIALERBEE_API_KEY" \
-H 'Idempotency-Key: 5f2b7c1e-8a3d-4c6f-9b0e-2d4a6c8e1f3a' \
-H "Content-Type: application/json" \
--data '{
"leads": [
{
"external_id": "CRM-1001",
"phone": "+12125550101",
"full_name": "Ann Lee",
"email": "[email protected]",
"custom_fields": {
"tier": "gold"
}
},
{
"external_id": "CRM-1002",
"phone": "+12125550102",
"full_name": "Omar Haddad"
}
]
}'
Python (SDK)
from dialerbee import DialerBee
db = DialerBee() # reads DIALERBEE_API_KEY from the environment
result = db.leads.import_(
campaign_id="cmp_0f8fad5b-d9cb-469f-a165-70867728950e",
leads=[
{
"external_id": "CRM-1001",
"phone": "+12125550101",
"full_name": "Ann Lee",
"email": "[email protected]",
"custom_fields": {
"tier": "gold"
}
},
{
"external_id": "CRM-1002",
"phone": "+12125550102",
"full_name": "Omar Haddad"
}
],
idempotency_key="5f2b7c1e-8a3d-4c6f-9b0e-2d4a6c8e1f3a",
)
Response example
200
{
"campaign_id": "cmp_0f8fad5b-d9cb-469f-a165-70867728950e",
"data": [
{
"index": 0,
"external_id": "CRM-1001",
"status": "accepted",
"reason": null,
"field": null,
"lead_id": "lead_0f8fad5b-d9cb-469f-a165-70867728950e"
},
{
"index": 1,
"external_id": "CRM-1002",
"status": "duplicate",
"reason": "duplicate_in_campaign",
"field": null,
"lead_id": null
}
],
"summary": {
"received": 2,
"accepted": 1,
"rejected": 1
}
}
Error examples
400 batch_too_large
{
"type": "https://docs.dialerbee.com/errors/batch-too-large",
"title": "Batch too large",
"status": 400,
"detail": "Too many items in one request.",
"instance": "urn:dialerbee:request:req_01K6BZ3M9X4T7Q2V8N5R6P1W0C",
"code": "batch_too_large",
"request_id": "req_01K6BZ3M9X4T7Q2V8N5R6P1W0C"
}
409 campaign_not_importable
{
"type": "https://docs.dialerbee.com/errors/campaign-not-importable",
"title": "Campaign not importable",
"status": 409,
"detail": "Leads can only be imported into a campaign that is paused, draft or ready (importing into a running campaign would place real calls; pause it first).",
"instance": "urn:dialerbee:request:req_01K6BZ3M9X4T7Q2V8N5R6P1W0C",
"code": "campaign_not_importable",
"request_id": "req_01K6BZ3M9X4T7Q2V8N5R6P1W0C"
}
503 dnc_screen_unavailable
{
"type": "https://docs.dialerbee.com/errors/dnc-screen-unavailable",
"title": "Do-Not-Call screen unavailable",
"status": 503,
"detail": "The Do-Not-Call screen could not run, so nothing was accepted.",
"instance": "urn:dialerbee:request:req_01K6BZ3M9X4T7Q2V8N5R6P1W0C",
"code": "dnc_screen_unavailable",
"request_id": "req_01K6BZ3M9X4T7Q2V8N5R6P1W0C"
}
Errors
| Status | Code | Title |
|---|---|---|
| 401 | invalid_api_key | Invalid API key |
| 403 | api_access_disabled | API access disabled |
| 403 | ip_not_allowed | IP address not allowed |
| 403 | insufficient_scope | Not permitted |
| 400 | credential_in_url | Credential in URL |
| 400 | credential_in_body | Credential in body |
| 400, 422 | validation_failed | Invalid request |
| 400 | batch_too_large | Batch too large |
| 413 | payload_too_large | Payload too large |
| 415 | unsupported_media_type | Unsupported media type |
| 400 | idempotency_key_required | Idempotency-Key required |
| 404 | not_found | Not found |
| 409 | campaign_not_importable | Campaign not importable |
| 503 | dnc_screen_unavailable | Do-Not-Call screen unavailable |
| 409 | conflict | Request in progress |
| 409 | idempotency_conflict | Idempotency key reused |
| 409 | outcome_unknown | Outcome unknown |
| 429 | rate_limit_exceeded | Too many requests |
| 503 | temporarily_unavailable | Temporarily unavailable |
| 503 | upstream_unavailable | Temporarily unavailable |
| 502 | upstream_invalid_response | Upstream error |
| 500 | internal_error | Internal error |
Objects
LeadImportRequest
| Field | Type | Required | Description |
|---|---|---|---|
leads | array of LeadImportItem | yes | (min items 1; max items 200) |
LeadImportResponse
| Field | Type | Required | Description |
|---|---|---|---|
campaign_id | string (CampaignId) | yes | A campaign. cmp_ + a lower-case UUID. |
data | array of LeadResult | yes | |
summary | LeadImportSummary | yes |
LeadImportSummary
| Field | Type | Required | Description |
|---|---|---|---|
received | integer | yes | |
accepted | integer | yes | |
rejected | integer | yes |
LeadImportItem
| Field | Type | Required | Description |
|---|---|---|---|
external_id | string | no | Your own id for this lead. Stored per API client; unique per client. (min length 1; max length 128) |
phone | string | yes | (min length 1; max length 32) |
first_name | string | no | (max length 100) |
last_name | string | no | (max length 100) |
full_name | string | no | (max length 200) |
email | string | no | (max length 254) |
custom_fields | object | no | (max keys 20) |
LeadResult
| Field | Type | Required | Description |
|---|---|---|---|
index | integer | yes | (min 0) |
external_id | string or null | yes | |
status | one of accepted, duplicate, on_dnc, invalid, blocked_country, failed | yes | |
reason | one of invalid_phone, missing_phone, field_rule, duplicate_in_request, duplicate_in_campaign, not_stored, unrecognised, null | yes | |
field | string or null | yes | The first field a field_rule refusal names, as the request sent it: phone, full_name, email, or custom_fields.<name>. Null for every other status. |
lead_id | string (LeadId) or null | yes |