---
title: "Place Call"
method: POST
path: "/ai-calls"
tags: ["ai-calls"]
---

# Place Call

`POST /ai-calls`

## Request

- Base URL: `https://dev.whispa.net` (the document declares no server; this is the origin it was published from)
- URL: `https://dev.whispa.net/ai-calls`
- Auth: one of:
  - OAuth 2
    - Password
    - Token URL: `auth/bearer/login`
  - API key in cookie `access_token`

Place an outbound AI-collector call to ``phone_number``.

Admin-only: placing outbound PSTN calls is a privileged, billable action.
Returns the ``session_id`` you should subscribe to via
``GET /sessions/{session_id}/stream`` for live transcripts and action cards.

## Request body

- PlaceAiCallRequest: Payload to place an outbound AI-collector call.
  - `telephony_provider` 'threecx' | 'tcn' | 'twilio', nullable
  - `phone_number` string, required: E.164 phone number to dial, e.g. +14155551212
  - `scenario` string, required: Scenario name with mode='ai_agent' (its scenario_metadata.voice_agent_config defines the persona).
  - `crm_account_id` string, nullable: Optional CRM account id to dial against. When CRM integration is enabled the account is resolved and mapped into the voice agent's context (unless an explicit demo_context is given), and the call session is auto-linked to it on placement.
  - `demo_context` AiCallDemoContext: Per-call account context for the AI collector. Every value is substituted into the scenario's ``voice_agent_config`` system prompt / greeting (``$customer_name`` etc., see ``service._apply_demo_context``) and the names are seeded as STT keyterms. All fields are optional — anything omitted falls back to the built-in fictional demo account so a call works with no context at all. Values are spoken by the agent and matched against the customer's spoken answers, so write them the way they should be said/heard (e.g. a date as "12 March 1990", an amount as "$320").
    - `customer_name` string, nullable
    - `customer_dob` string, nullable
    - `customer_address` string, nullable
    - `customer_email` string, nullable
    - `customer_ssn_last4` string, nullable
    - `customer_postal_code` string, nullable
    - `loan_id` string, nullable
    - `loan_product` string, nullable
    - `loan_balance` string, nullable
    - `loan_interest_rate` string, nullable
    - `original_balance` string, nullable
    - `referred_date` string, nullable
    - `amount_overdue` string, nullable
    - `days_overdue` string, nullable
    - `agent_name` string, nullable
    - `company_name` string, nullable
    - `arrangement_amount` string, nullable
    - `arrangement_frequency` string, nullable
    - `arrangement_remaining` string, nullable
    - `missed_amount` string, nullable
    - `missed_date` string, nullable
    - `payment_method` string, nullable
  - `override_compliance` boolean: Admin escape hatch: skip the outbound compliance gate (do-not-call, suppression, contact windows, frequency caps) for this manual dial. The override is logged with the acting user.
  - `voice_id` string, nullable: Provider-qualified TTS voice for THIS call only, overriding the scenario's configured voice. Lets a voice be tried back-to-back without re-configuring the scenario (which would change it for every call in flight). The voice actually used is recorded on the call as tts_voice_id either way.
  - `cartesia_voice_id` string, nullable: Deprecated compatibility alias for voice_id.

## Response `201`

Successful Response

- PlaceAiCallResponse: Response after the outbound call has been dispatched to the voice runtime.
  - `session_id` string, uuid, required: CallSession id; use as :session_id in /sessions/{id}/stream to subscribe to live events.
  - `conversation_id` string, required: The call's correlation handle — also stored in CallSession.agent_id.

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/whispa/apis/whispa-api.md) - [All operations](https://skmtc.dev/whispa/apis/whispa-api/llms.txt) - [OpenAPI document](https://skmtc.dev/whispa/apis/whispa-api/revisions/12c2e4aca43c?raw)
