curl --request POST \
--url https://api.squawkvoice.ai/api/v1/campaigns/{campaignId}/contacts/on-demand \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"phone": "+15551234567",
"postcode": "94107",
"has_pewc": true,
"pewc_date": "2026-01-04"
}
'{
"success": true,
"data": {
"contact_id": "6f1c2a9e-4b7d-4e2a-9c51-0d3e8f7a1b24",
"request_id": "2b8e4f10-9a3c-4d6e-8f21-7c5a0b9d3e18",
"run_id": "9d4a7c3e-1f2b-4e8d-a6c5-3b0e2f9d8a71",
"run_status": "running",
"dialing_status": "pending",
"scheduled_at": null,
"retry_after": null,
"scrub_status": "pending",
"is_on_demand": true,
"dispatched_scrub": true
}
}Place a call
Add one contact to a voice campaign and call it as soon as the campaign allows, or at a time up to 48 hours ahead
curl --request POST \
--url https://api.squawkvoice.ai/api/v1/campaigns/{campaignId}/contacts/on-demand \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"phone": "+15551234567",
"postcode": "94107",
"has_pewc": true,
"pewc_date": "2026-01-04"
}
'{
"success": true,
"data": {
"contact_id": "6f1c2a9e-4b7d-4e2a-9c51-0d3e8f7a1b24",
"request_id": "2b8e4f10-9a3c-4d6e-8f21-7c5a0b9d3e18",
"run_id": "9d4a7c3e-1f2b-4e8d-a6c5-3b0e2f9d8a71",
"run_status": "running",
"dialing_status": "pending",
"scheduled_at": null,
"retry_after": null,
"scrub_status": "pending",
"is_on_demand": true,
"dispatched_scrub": true
}
}has_pewc is true, with a pewc_date. Without consent the request still returns 202, but the contact shows as Blocked in On-Demand activity and is never dialed. Send has_pewc: true only for contacts who have given you prior express written consent.- A
202is not a call. Calling hours, consent, opt-out, Do Not Call scrubbing and frequency caps are checked when the call is due. See Compliance Still Applies. - Don’t retry blindly. There is no idempotency key: each request is a new attempt with its own
request_id, even for the same phone number, so a retry places a second call. - Store the
request_id. It is how you cancel the call if you didn’t keep thecontact_id. - Results stay in Studio. No endpoint returns how a call went. Outcomes are on the campaign’s On-Demand tab and in Call History.
Authorizations
An API key from Manage → API Keys in Studio. See Authentication.
Path Parameters
The campaign's ID, copied from its On-Demand tab in Studio.
Body
The number to call, in E.164 format: +, the country code and the number, with no spaces, dashes or brackets.
^\+[1-9]\d{1,14}$"+15551234567"
The contact's postcode. It sets the contact's timezone, which decides the legal calling hours. A number is also accepted, but send a string: JSON drops a leading zero.
"94107"
ISO 3166-1 alpha-2 country code, used with postcode to find the timezone.
"US"
Whether the contact has given prior express written consent. A call is only placed when this is true. Without it, the request still returns 202, but the contact is blocked and never dialed.
When consent was given. Required when has_pewc is true. Accepts 2026-01-04, 1/4/2026, 01/04/2026 or Jan 4 2026.
"2026-01-04"
Whether the contact has opted out of voice calls. When true, the request returns 202 but the contact is blocked and never dialed.
When to call, as ISO 8601, no more than 48 hours from now. Leave it out to call as soon as the campaign's calling hours allow. With an offset or Z it is an exact time. Without one, it is read in scheduled_at_timezone, or in the postcode's timezone if that is missing too.
"2026-11-03T15:30:00-06:00"
IANA timezone name used to read a scheduled_at that has no offset.
"America/Chicago"
Values for the campaign's custom fields. Every key must already be set up on the campaign; a campaign with no custom fields refuses any. Up to 50 keys and 16 KB.
{
"plan": "Premium",
"renewal_date": "2026-12-01"
}
Was this page helpful?