#Outbound Campaigns

8 min read

Outbound campaign management routes are mounted under /v1/outbound-campaigns.

These routes manage partner-facing campaign records over the existing AiDial outbound runtime tables.

Production API: https://api.aidial.ai

This page omits environment-specific host names, internal topology, and deployment details.

These routes do not expose raw runtime configuration editing, imported contact phone numbers, imported CSV content, ciphertext, provider secrets, secret-backend references, API keys, bearer tokens, or transcripts. Campaign detail can include configured CLI disclosure fields such as cli_return_number because those fields are part of the campaign compliance record, not imported contact data.

#Authentication and Scope

All routes require authentication through the shared API auth layer:

  1. X-API-Key
  2. Authorization: Bearer <jwt>

If both headers are present, the API key is used and the bearer token is ignored. Missing, invalid, revoked, or expired credentials return 401 Unauthorized.

Bearer authentication requires ZITADEL_ISSUER, ZITADEL_AUDIENCE, and ZITADEL_JWKS_URL; these settings are required and have no fallback defaults. Bearer tenant assignment is resolved from portal_users and portal_user_client_assignments.

Both authentication modes resolve to an AuthContext. This router scopes all campaign queries and mutations to the resolved client_id and data_env; it does not accept a client or data-environment override in the request. Outbound campaign records are read and written through the tenant data access layer using the strict (client_id, data_env) route in the tenant routing map. Authentication, idempotency, project metadata, and route lookup use the local API metadata store on the API host.

Write routes require partner_admin. Read routes allow partner_admin, partner_user, aidial_admin, and aidial_operator within the resolved authenticated scope. Out-of-scope campaigns, invalid campaign ids, and role-denied mutations return non-enumerating 404 behavior.

#Routes

EndpointMethodScopePurpose
/v1/outbound-campaignsGETreadList campaign summaries with project, status, call type, and search filters.
/v1/outbound-campaignsPOSTpartner_adminCreate a campaign.
/v1/outbound-campaigns/{campaign_id}GETreadRead safe campaign detail.
/v1/outbound-campaigns/{campaign_id}PATCHpartner_adminUpdate mutable campaign metadata while state allows edits.
/v1/outbound-campaigns/{campaign_id}/contactsGETreadList masked contact status, outcome, retry, consent, and registry summaries.
/v1/outbound-campaigns/{campaign_id}/contacts/importPOSTpartner_adminImport CSV contacts. Requires Idempotency-Key.
/v1/outbound-campaigns/{campaign_id}/registry-wash-recordsPOSTpartner_adminAttach DNCR/registry wash evidence. Requires Idempotency-Key.
/v1/outbound-campaigns/{campaign_id}/validationGETreadRead launch validation state.
/v1/outbound-campaigns/{campaign_id}/validatePOSTpartner_adminRecompute and audit launch validation.
/v1/outbound-campaigns/{campaign_id}/runPOSTpartner_adminLaunch after validation passes. Requires Idempotency-Key.
/v1/outbound-campaigns/{campaign_id}/pausePOSTpartner_adminPause campaign dispatch. Requires Idempotency-Key.
/v1/outbound-campaigns/{campaign_id}/resumePOSTpartner_adminResume after validation passes. Requires Idempotency-Key.
/v1/outbound-campaigns/{campaign_id}/cancelPOSTpartner_adminCancel without deleting history. Requires Idempotency-Key.
/v1/outbound-campaigns/{campaign_id}/reportGETreadRead reporting aggregates and validation state.

#Query Parameters

GET /v1/outbound-campaigns supports:

NameTypeDefaultDescription
pageinteger1Page number, minimum 1.
page_sizeinteger20Page size, minimum 1, maximum 100.
sort_bystringupdated_at_utcOne of updated_at_utc, created_at_utc, name, or status.
sort_orderstringdescasc or desc.
project_idstring-Filters campaigns to one project within the authenticated client scope.
statusstring-Filters by campaign status.
campaign_call_typestring-Filters by telemarketing, research, or service.
searchstring-Case-insensitive campaign-name search, maximum 120 characters.

GET /v1/outbound-campaigns/{campaign_id}/contacts supports:

NameTypeDefaultDescription
pageinteger1Page number, minimum 1.
page_sizeinteger50Page size, minimum 1, maximum 200.
sort_bystringcreated_at_utcOne of created_at_utc, updated_at_utc, status, or external_contact_id.
sort_orderstringascasc or desc.
statusstring-Contact status filter.
dispositionstring-Filters by last_disposition.
callableboolean-Filters by is_callable.
validation_codestring-Filters by not_callable_reason.
retry_dueboolean-true filters contacts whose next_attempt_at_utc is due. false is treated the same as omitted.
external_contact_idstring-Filters by exact external contact id.

#Request Bodies

#Create Campaign

POST /v1/outbound-campaigns accepts a JSON body with:

FieldTypeRequiredDescription
project_idstringYesProject owned by the authenticated client.
namestringYesCampaign name, 1 to 255 characters.
descriptionstring or nullNoOptional description, maximum 4000 characters.
campaign_typestringNosingle, batch, or scheduled; default is scheduled.
campaign_call_typestringYestelemarketing, research, or service.
priorityintegerYes1 to 100.
schedule_start_at_utcdatetime or nullNoOptional UTC schedule start.
schedule_end_at_utcdatetime or nullNoOptional UTC schedule end; must be after start when both are supplied.
timezonestringYesCampaign timezone name.
retry_policyobjectYesRetry settings.
voicemail_policyobjectYesVoicemail and IVR handling settings.
personalizationobjectYesApproved personalization keys.
complianceobjectYesCampaign compliance settings.

retry_policy contains enabled, max_attempts (0 to 20), backoff_base_seconds (0 to 604800), backoff_strategy (constant, linear, or exponential), and optional booleans retry_on_no_answer, retry_on_voicemail, and retry_on_busy.

voicemail_policy is the partner-facing name for the campaign's answering-machine handling policy. It contains detection_enabled, on_voicemail (leave_message, hangup, or retry), on_ivr (hangup or retry), on_silence (retry or hangup), on_unknown (proceed, retry, or hangup), and optional message_template. Create reads the current project runtime detector configuration from outbound_call.answering_machine_detection and persists the campaign snapshot into the current answering_machine_detection_* runtime columns. The old outbound project keys outbound_call.voicemail_detection and outbound_call.voicemail_handling are not accepted for campaign creation.

personalization.required_keys and personalization.allowed_keys must use keys of 64 characters or fewer containing only letters, numbers, hyphen, or underscore. Required keys must also be listed as allowed keys.

compliance contains registry_wash_required, registry_wash_max_age_days (1 to 365), consent_required, prevent_after_hours, check_public_holiday, recipient_timezone_aware, and optional CLI or exemption fields: cli_return_number, cli_employer_name, cli_authorizer_name, cli_call_purpose, and exemption_type.

Create loads the published project runtime configuration for the authenticated client. Missing, archived, unpublished, undeployed, or outbound-incomplete project runtime state returns a 422 validation response. A successful create returns 201 Created and the new campaign detail. Created campaigns start in draft.

#Update Campaign

PATCH /v1/outbound-campaigns/{campaign_id} accepts at least one of:

  • name
  • description
  • priority
  • schedule_start_at_utc
  • schedule_end_at_utc

Only draft, scheduled, and paused campaigns can be updated. Other states return 422 invalid_campaign_state.

#Registry Wash Record

POST /v1/outbound-campaigns/{campaign_id}/registry-wash-records accepts:

FieldTypeRequiredDescription
jurisdictionstringYesJurisdiction code, 2 to 10 characters.
registry_typestringYesRegistry type, for example dncr.
vendorstring or nullNoRegistry vendor name.
ruleset_idstring or nullNoRuleset identifier.
wash_channelstringYesWash channel.
transaction_idstring or nullNoExternal transaction id.
wash_file_namestring or nullNoExternal wash file name.
numbers_submittedintegerYesTotal submitted numbers.
numbers_on_registerintegerYesCount found on the registry.
numbers_not_on_registerintegerYesCount not found on the registry.
numbers_invalidintegerYesInvalid-number count.
credits_chargedintegerYesRegistry credits charged.
credits_remaininginteger or nullNoRemaining registry credits.
washed_at_utcdatetimeYesWash completion time.
valid_until_utcdatetimeYesEvidence expiry time; must be after washed_at_utc.
receipt_referencestring or nullNoExternal receipt reference.

The three result counts must add up to numbers_submitted. Secret-like strings such as passwords, API keys, tokens, secret-backend paths, or PEM markers are rejected in registry metadata fields. If a transaction_id already exists for the campaign, the latest matching record is returned instead of inserting a duplicate.

#CSV Import

POST /v1/outbound-campaigns/{campaign_id}/contacts/import accepts UTF-8 CSV, with an optional UTF-8 BOM, up to 1 MB and 5000 contact rows. Contacts can only be imported into draft or paused campaigns.

Required header:

  • to_number

Optional headers include:

  • external_contact_id
  • recipient_timezone
  • recipient_country
  • recipient_subdivision
  • registry_status
  • registry_checked_at_utc
  • registry_valid_until_utc
  • registry_result_code
  • registry_vendor
  • registry_ruleset_id
  • consent_type
  • consent_source
  • consent_given_at_utc
  • consent_expires_at_utc
  • consent_withdrawn_at_utc
  • consent_evidence_reference
  • exemption_type
  • exemption_verified
  • call_type
  • priority_override
  • max_attempts

Campaign-approved personalization keys may also be included as columns. Unsupported columns are rejected before row processing.

to_number must be E.164. Duplicate external_contact_id values in the same CSV are rejected row by row. For persisted rows, the API stores phone numbers as a hash plus server-side ciphertext, and stores personalization as server-side ciphertext plus a hash. Raw phone numbers and plaintext personalization are not returned.

Valid rows are accepted and invalid rows return row-level errors. A CSV with any row-level validation failures, including a file where every contact row is invalid, returns an import response with accepted and rejected row counts. Header-level, encoding, and size failures return 422.

#Launch Validation

GET /v1/outbound-campaigns/{campaign_id}/validation and POST /v1/outbound-campaigns/{campaign_id}/validate compute the same launch validation result. Run and resume controls recompute validation before changing state. If validation is blocked, run and resume return the current campaign and validation result without transitioning the campaign.

Launch is blocked when required evidence or runtime prerequisites are missing, including:

  • no imported contacts
  • missing, stale, expired, or count-mismatched DNCR/registry wash evidence for telemarketing or research
  • contacts on a registry, missing registry status, missing registry check timestamps, stale registry checks, or expired registry validity when enforcement is enabled
  • missing, expired, withdrawn, or unverified consent or exemption evidence where consent is required
  • missing or invalid recipient timezone, missing recipient location, after-hours, or public-holiday blockers for telemarketing or research campaigns governed by calling-window policy
  • missing project runtime configuration or blocking project outbound compliance findings
  • outbound capacity not configured
  • missing CLI disclosure fields for telemarketing or research

Validation responses contain status (ready, blocked, or warning), blockers, warnings, info, and contact_blocker_counts.

#Responses

Campaign list responses return:

FieldTypeDescription
itemsarrayCampaign summaries.
paginationobjectpage, page_size, total, and total_pages.

Campaign summaries include campaign_id, project_id, name, description, campaign_type, campaign_call_type, status, priority, timezone, counts, validation_state, schedule timestamps, registry-wash summary fields, and created/updated timestamps.

Campaign detail responses add started_at_utc, completed_at_utc, retry_policy, voicemail_policy, personalization, compliance, and nullable last_registry_wash_record_id.

Contact list responses return items and pagination. Contact items include contact_id, external_contact_id, masked_phone, personalization_keys, status, is_callable, not_callable_reason, registry summary fields, consent and exemption summary fields, attempt and retry timestamps, last_disposition, and nullable last_call_id.

Contact import responses include accepted_rows, rejected_rows, duplicate_rows, row_errors, and the refreshed campaign detail.

Registry wash responses include registry_wash_record_id, campaign_id, jurisdiction, registry_type, wash_channel, transaction_id, submitted/on-register/not-on-register/invalid counts, washed_at_utc, and valid_until_utc.

Control responses include the campaign detail and, for run and resume, the launch validation result. Report responses include campaign-level aggregate counts by contact status, callable state, disposition, registry status, linked calls, retry-due total, empty voicemail_ivr_counts, and the current validation result.

#Outbound Evidence

#GET /v1/compliance/calls/{call_id}/outbound-evidence

Returns the safe outbound-compliance evidence summary for a scoped call. The response includes calling-window, registry-wash, consent/exemption, retry, and CLI-disclosure summaries only. It never returns raw phone numbers, imported CSV content, transcript text, recordings, ciphertext, API keys, bearer tokens, or provider credentials.

#Response Safety

Responses return only safe summaries and campaign configuration fields:

  • masked contact phone placeholders. The current contact list uses ****
  • contact status and outcome metadata
  • registry, consent, and exemption summaries
  • campaign counts and validation findings
  • linked-call aggregate counts
  • configured campaign compliance fields, including CLI disclosure values

The API never returns raw imported CSV content, decrypted imported contact phone numbers, plaintext personalization, encrypted database fields, secret-backend material, raw runtime configuration, or provider credentials.

#Error Semantics

Outbound campaign domain errors use the partner error envelope from core.error_envelope, except framework-level authentication and validation errors which use the shared API error shape.

ConditionStatus
Missing, invalid, revoked, or expired authentication401 Unauthorized
Valid bearer token with no active supported assignment404 Not Found
Role not allowed, out-of-scope campaign, missing campaign, or invalid campaign id404 Not Found
Missing or invalid Idempotency-Key on required mutation routes400 Bad Request
FastAPI request-shape validation failure422 Unprocessable Entity
Campaign, CSV, registry, runtime-readiness, or state validation failure422 Unprocessable Entity
Duplicate Idempotency-Key with a different request body422 Unprocessable Entity
Registry idempotency replay cannot find a completed prior record409 Conflict
Missing (client_id, data_env) route in the tenant routing map500 Internal Server Error

#Deletion Policy

There is no delete endpoint. Use POST /v1/outbound-campaigns/{campaign_id}/cancel to stop a campaign while preserving audit and reporting history.