> ## Documentation Index
> Fetch the complete documentation index at: https://docs.miraiminds.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Start a browser call

> Create a call that runs in your user's browser instead of on a phone line. Send channel web and no to; the answer carries the audio socket and the live event stream.

A browser call (also called a web call) runs one of your agents with the
user's microphone and speakers. It is the same endpoint as
[Place a call](/api-reference/calls/place-a-call), with two differences in the
body: `"channel": "web"`, and no `to`. Sending `to` with `channel: "web"`
returns `400 invalid_request`, because nothing is dialled.

Call it from your server, where your key lives. The `202` gives you two links
for this one call. Hand them to the page, and the page never sees your key:

| Field | What the page does with it |
| :- | :- |
| `ws_url` | Opens it as a WebSocket and streams audio both ways. **Single use**; connect within 5 minutes (`ws_url_expires_at`). |
| `events_url` | Opens it with `EventSource` to show the agent's state and each finished turn. Works for the whole call and an hour after. |

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://sandbox.voice.miraiminds.co/v2/calls \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: voice-session-sess_8f2c41" \
    -d '{
      "agent_id": "agt_01K2M4P7QRSTVWXYZ0A1B2C3",
      "channel": "web",
      "variables": { "first_name": "Asha" },
      "metadata": { "session_id": "sess_8f2c41", "user_id": "usr_1042" },
      "max_duration_secs": 600,
      "final_results": true,
      "webhook_url": "https://example.com/mirai/webhook"
    }'
  ```

  ```python Python theme={null}
  import os, httpx

  r = httpx.post(
      "https://sandbox.voice.miraiminds.co/v2/calls",
      headers={
          "Authorization": f"Bearer {os.environ['MIRAI_API_KEY']}",
          "Idempotency-Key": "voice-session-sess_8f2c41",
      },
      json={
          "agent_id": "agt_01K2M4P7QRSTVWXYZ0A1B2C3",
          "channel": "web",
          "variables": {"first_name": "Asha"},
          "metadata": {"session_id": "sess_8f2c41", "user_id": "usr_1042"},
          "max_duration_secs": 600,
          "final_results": True,
          "webhook_url": "https://example.com/mirai/webhook",
      },
      timeout=30,
  )
  call = r.raise_for_status().json()
  links = {"ws_url": call["ws_url"], "events_url": call["events_url"]}  # send these to the page
  ```

  ```javascript Node.js theme={null}
  const res = await fetch("https://sandbox.voice.miraiminds.co/v2/calls", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.MIRAI_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": "voice-session-sess_8f2c41",
    },
    body: JSON.stringify({
      agent_id: "agt_01K2M4P7QRSTVWXYZ0A1B2C3",
      channel: "web",
      variables: { first_name: "Asha" },
      metadata: { session_id: "sess_8f2c41", user_id: "usr_1042" },
      max_duration_secs: 600,
      final_results: true,
      webhook_url: "https://example.com/mirai/webhook",
    }),
  });
  const call = await res.json();
  if (!res.ok) throw new Error(`${call.error.code}: ${call.error.message}`);
  const links = { ws_url: call.ws_url, events_url: call.events_url }; // send these to the page
  ```
</RequestExample>

<ResponseExample>
  ```json 202 theme={null}
  {
    "id": "call_01M4ZQ7V3K9D2R8T5W1X6Y0B4N",
    "status": "queued",
    "transport": "web",
    "ws_url": "wss://sandbox.voice.miraiminds.co/v2/calls/call_01M4ZQ7V3K9D2R8T5W1X6Y0B4N/media?token=3q2-7wQx1mVb9L0cJf4kTz8RyPn6AeHu5sGd2KoWiYc",
    "ws_url_expires_at": "2026-10-18T09:20:00Z",
    "events_url": "https://sandbox.voice.miraiminds.co/v2/calls/call_01M4ZQ7V3K9D2R8T5W1X6Y0B4N/events?token=Vb7nQ2xK9pL4mR8tW1yZ6cF3hJ0sD5gA2eU7iO4kN9q"
  }
  ```

  ```json 400 theme={null}
  {
    "error": {
      "code": "invalid_request",
      "message": "to is not accepted for channel web: a web call connects the browser that placed it, and no number is dialled"
    }
  }
  ```

  ```json 402 theme={null}
  {
    "error": {
      "code": "insufficient_balance",
      "message": "wallet balance 3.20 INR is below the minimum for one minute at t5"
    }
  }
  ```
</ResponseExample>

## The audio socket

The page opens `ws_url` with `new WebSocket(ws_url)`. Audio is binary in both
directions: raw PCM, 16-bit signed little-endian, mono, **48,000 Hz**, with no
header. Send 20 ms frames (1,920 bytes) continuously, and send zeros to mute
rather than stopping. When the user interrupts, the server sends the text
message `{"event":"clear"}`: drop any agent audio you have queued but not yet
played. Closing the socket ends the call.

The call stays `queued` until the page connects, then moves to `in_progress`.
If no audio connects before `ws_url` expires, the call ends `failed` with
`ended_reason: "no-media"` and costs nothing.

## The live event stream

```javascript theme={null}
const events = new EventSource(events_url);
events.addEventListener("transcript.turn", (e) => {
  const { role, text } = JSON.parse(e.data).data;
});
events.addEventListener("call.ended", () => events.close());
```

Events are `agent.state` (`listening`, `processing`, `speaking`, `ended`),
`transcript.turn` (one per finished turn, for both speakers) and `call.ended`,
which is always last. Your server can read the same stream with its key at
[Stream live events](/api-reference/calls/stream-live-events).

## While it runs and after

* **Steer or end it** from your server with
  [Send a live control](/api-reference/calls/send-a-live-control): an
  `instruction` the agent follows from its next reply, or a `close` with a
  goodbye line.
* **Results** arrive as webhooks to `webhook_url`, the same as a phone call.
  With `final_results: true` you also get one `call.processed` carrying the
  finished transcript. See [Webhooks](/v2/webhooks).
* **Billing** starts when audio goes live and follows the same per-minute rate
  as a phone call.

The [browser calls guide](/v2/web-calls) has a complete page and backend,
timing options for timed sessions, and every event payload.


## OpenAPI

````yaml POST /v2/calls
openapi: 3.1.0
info:
  title: Mirai Voice API
  version: 2026-10-15.analysis-templates
  description: >-
    The v2 API for voice agents, calls, campaigns, phone numbers and speech.
    Every request carries `Authorization: Bearer sk_live_…`. Generated from the
    API's own contract and its Postman collection.
servers:
  - url: https://sandbox.voice.miraiminds.co
    description: 'Sandbox: trial workspaces, before your company goes live'
  - url: https://prod.voice.miraiminds.co
    description: 'Production: workspaces that have gone live'
security:
  - bearerAuth: []
tags:
  - name: Agents
    description: >-
      An agent is what a call runs: its prompt (or a node flow, see the Flows
      section), voice, language and limits. Write it once and dial it as often
      as you like; each call fills in its own `variables`.


      Every save creates a new revision. You can read old revisions, roll back
      to one, and publish a draft when it is ready. None of the requests here
      place a call or charge your wallet.
  - name: Calls
    description: >-
      Place a call, follow it while it runs, then read what happened: the
      transcript, the recording, the post-call analysis.


      `POST /v2/calls` answers before the phone rings, with an id. Everything
      after that is about that id. Live control and the live event stream work
      on browser calls (`channel: "web"`) and realtime sessions only; a phone
      call answers them with `400 unsupported_channel`.
  - name: Flows
    description: >-
      A node-based agent runs the call as a graph of steps. Each node has its
      own instructions, and the agent moves to the next node when a transition's
      condition is met, so a call with branches (wrong person, not now,
      reschedule) stays easy to follow and to change.


      The usual path: draft a graph from a brief or from recordings of your real
      calls, check it, test it with simulated calls, then save it on an agent.
      Drafting, transcribing and testing use AI models and charge your wallet;
      checking, saving and reading are free.


      Full guide: https://docs.miraiminds.co/v2/node-agents
  - name: Tools and secrets
    description: >-
      Connect your own APIs to an agent. A tool runs at one of three moments:


      * `pre_call`, before dialling: fetch context for the greeting, or skip the
      call.

      * `on_call`, when the agent decides to use it mid-conversation: look
      something up, book something.

      * `post_call`, after the call has settled: send the outcome to your CRM,
      schedule a call back.


      The order here is the order you'd use them in: see what's available, store
      your credential as a secret, add a tool, test it against your endpoint,
      then read each call's tool runs. Tools themselves cost nothing extra.


      Tool definitions use Mirai's own templates, like `{{ args.date }}` and `{{
      secrets.crm_key }}`.


      A definition that doesn't validate comes back as a list, so you can fix
      everything at once: `{"error": "invalid_tools", "details": [{"path",
      "message"}]}`. Everything else uses the usual `{"error": {"code",
      "message"}}`.
  - name: Campaigns
    description: >-
      Call a whole list with one agent. Upload contacts, say which days and
      hours the campaign may ring, and start it. From then on it dials by
      itself: it paces itself, waits overnight, retries calls that didn't
      connect, skips numbers on your do-not-call list, and pauses itself when
      its budget or your wallet runs out.


      Campaign calls are ordinary calls. They show up in `GET /v2/calls`, send
      the same `call.*` webhooks and bill the same per-minute rate. In a sandbox
      workspace every campaign runs and bills at T5 (₹5 a minute), whatever tier
      you ask for.


      Money on a campaign is in **paise**: `"budget_paise": 50000` is ₹500.


      The requests run top to bottom: create saves `campaign_id`, and the rest
      use it. Starting a campaign rings every contact on it, so put numbers
      you're allowed to call in the bodies first.
  - name: Do-not-call list
    description: >-
      Numbers your campaigns will never dial. The list covers every campaign in
      the workspace, including ones that are already running: it's checked at
      the moment a contact is about to be called, so a number added mid-campaign
      is skipped from then on. A skipped contact stays in its campaign as
      `suppressed` and costs nothing.


      It doesn't apply to single calls placed with `POST /v2/calls`; check the
      list yourself before those if you need to. It's your own list, not the
      national DND register, and adding a number here doesn't meet your DND
      obligations.
  - name: Phone numbers
    description: >-
      The numbers your agents answer. Each one comes from the **Telephony**
      section:


      * **Rented from Mirai.** Once the rental is active, the number shows up
      here by itself (`ownership: managed`).

      * **From your own Plivo account.** Connect the account in Telephony, list
      its numbers, then bring one here with [Import a Plivo
      number](/api-reference/phone-numbers/import-a-plivo-number) (`ownership:
      customer`). Plivo keeps billing you for it.


      After that it's two steps, in this order: [Assign an
      agent](/api-reference/phone-numbers/assign-an-agent) (who answers), then
      [Turn on incoming
      calls](/api-reference/phone-numbers/turn-on-incoming-calls). `state` is
      `imported` until calls are on and `ready` after; `error` means the last
      attempt to turn calls on failed, and `setup_error` says why.


      Every change sends the number's current `version`, and each change raises
      it by one. If you're not sure what it is, read the number first; a stale
      version is a 409 `conflict` and changes nothing.


      To call out from one of your numbers, place a call with `phone_number_id`
      set to its id once it is `ready` (Indian destinations only). Calls on your
      numbers are billed like any other call.


      Every number also says how it is doing in `health`: `state` is `active`,
      `warming` (its first week, at half its pool's pace), `resting`, `cooling`
      (rested three times in a day; waits for you) or `retired`, with this
      hour's attempts and seven days of answers. You can rest, resume and retire
      your own numbers; a resting or retired number still answers calls to it.
  - name: Phone pools
    description: >-
      A pool is a group of your own phone numbers that a campaign, an agent or a
      single call can ring from. Each call takes the number best placed for it:
      a number a contact has already been rung from stays theirs on a retry,
      numbers in the contact's own circle come first, and the pool's pace
      (`max_per_hour`, per number) is held across every campaign and API call at
      once. A number whose answers drop well below its pool-mates' rests on its
      own for 45 minutes.


      Point a campaign at a pool with `pool_id` on [Create a
      campaign](/api-reference/campaigns/create-a-campaign), an agent with
      `calls_from: {"pool_id": …}`, or one call with `pool_id` on [Place a
      call](/api-reference/calls/place-a-call). `pool_id` and `phone_number_id`
      never go together. With nothing chosen, calls come from the agent's
      setting, then the pool marked `default_for_campaigns`, then the Mirai
      shared line. A call's `calls_from_source` is `pool` (with `pool_id`) when
      a pool picked its number.


      A single call on a pool whose numbers are all resting or at their pace
      this hour answers 409 `pool_busy` with `Retry-After`; one with no number
      that can call, 409 `pool_unavailable`. A campaign doesn't fail: it waits
      and carries on.


      `purpose` is what the calls are for: `outreach` (promotional),
      `reminders`, `support` or `other`. It sets the starting pace: 40 an hour
      for support, 60 otherwise. Pools are free; numbers are billed as numbers.
  - name: Telephony
    description: >-
      Getting a phone number for your agent. There are two ways, and a workspace
      can use both.


      **1. Rent a number from Mirai.** ₹500 a month, paid as ₹1,500 from your
      wallet every three months, renewing until you turn it off. Indian numbers
      need a business verification that Plivo approves once: read the
      requirements, submit your details and documents, then refresh until it's
      `accepted`. After that: search, quote, rent. The rented number appears in
      **Phone numbers** by itself.


      **2. Connect your own Plivo account.** Plivo keeps billing you directly.
      Connect it with your Auth ID and Auth Token, list the numbers it owns, and
      bring one over with [Import a Plivo
      number](/api-reference/phone-numbers/import-a-plivo-number). A Plivo main
      account can also rent new numbers through the same search → quote → rent
      requests, with its connection id as `account`.


      Either way you finish in **Phone numbers**: assign the agent that answers,
      then turn on incoming calls.


      The last two requests verify your own phone, so the workspace can ring it
      from Mirai's shared test number (test calls are placed from the Numbers
      page in the console).


      Indian (+91) numbers only for now. If phone numbers aren't available on
      the host you're calling, every request here answers 503
      `telephony_unavailable`.
  - name: Transcriptions
    description: >-
      Turn a recorded call (or any recording) into a transcript with speakers
      and timestamps. Hindi, English, Gujarati and mixed speech are written the
      way they were spoken, never translated. ₹18 per hour of audio; failed and
      degraded jobs are free.
  - name: Speech to text
    description: >-
      Speech to text in ten languages, two ways: send one recording and get its
      text back in the same request ([Transcribe a
      recording](/api-reference/speech-to-text/transcribe-a-recording)), or
      stream live audio over one WebSocket per call and read partial transcripts
      while people speak, then one final transcript per utterance. Language
      codes: hi-IN, en-IN, gu-IN, mr-IN, pa-IN, bn-IN, ta-IN, te-IN, kn-IN or
      ml-IN.


      `wss://sandbox.voice.miraiminds.co/v1/audio/transcriptions/stream?language_code=hi-IN&encoding=mulaw&sample_rate=8000&endpointing=manual`


      (`wss://prod.voice.miraiminds.co` once your company has gone live), with
      the header `Authorization: Bearer sk_live_YOUR_API_KEY`. 8 or 16 kHz,
      16-bit PCM, μ-law or A-law. A browser uses `?token=` from [Mint stream
      tokens](/api-reference/speech-to-text/mint-stream-tokens) instead, because
      it cannot set headers on a WebSocket.


      Send JSON text frames: `{"event": "speech_start"}`, then `{"event":
      "audio_input", "audio": "<base64 audio>"}` as the audio arrives, then
      `{"event": "speech_end"}`; `{"event": "end"}` closes the session. You
      receive `session.begin` first, `transcript.partial` while an utterance is
      open, exactly one `transcript.final` per utterance, and `session.end` with
      `audio_seconds_billed` and `cost_paise`.


      Every event, both endpointing modes, limits and errors:
      https://docs.miraiminds.co/v2/stt-quickstart
  - name: Text to speech
    description: >-
      Turn text into speech in one request, and read back what each request
      cost.
  - name: Wallet
    description: >-
      Your prepaid balance and every line that moved it. Calls, text to speech,
      flow drafts, transcriptions and number rentals all debit the same wallet.
  - name: Reference
    description: The voice catalogue, and the API contract as a machine-readable document.
paths:
  /v2/calls:
    post:
      tags:
        - Calls
      summary: Place a call
      description: >-
        Rings `to` and runs `agent_id` on the call. **This rings a real phone
        and uses wallet credit.** It answers **202** once the call is accepted.
        The phone hasn't rung yet, so poll [Get
        call](/api-reference/calls/get-call) or take the webhooks sent to
        `webhook_url`.


        Before your company goes live, every call runs and is billed at t5 (₹5 a
        minute, in 10-second blocks), whatever tier you send. The wallet must
        cover one minute before anything is dialled, or you get a 402 and
        nothing is charged.


        **Idempotency-Key** keeps a retry to one phone call. The same key within
        24 hours replays the first 202 (with `Idempotent-Replay: true`) and
        dials nothing. In your own code, build the key from your own record,
        like `order-8842-reminder-1`.


        Everything but `agent_id` and `to` is optional:


        * `variables` fill the placeholders in the agent's prompt and first
        message (up to 32, 512 characters each). Tools read them as `vars.*`.

        * `metadata` is your own ids. They come back on the call and on every
        webhook, and the agent never sees them.

        * `webhook_url`, `max_duration_secs` (30–1800), `first_message`,
        `timing`, `recording_enabled` and `final_results` work as the docs
        describe.

        * `phone_number_id` calls from one of your own numbers (see *Phone
        numbers*) instead of the default route.


        **A browser call instead:** see [Start a browser
        call](/api-reference/calls/start-a-browser-call): the same request with
        `"channel": "web"` and no `to`. `"channel": "realtime"` opens an OpenAI
        Realtime-compatible session the same way. Both are billed per minute
        like a phone call.
      operationId: create_call
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          description: >-
            Up to 255 characters. The same key within 24 hours replays the first
            answer and creates nothing new. Build it from your own record, such
            as `order-8842-reminder-1`.
          schema:
            maxLength: 255
            type: string
          example: order-8842-reminder-1
      requestBody:
        required: true
        content:
          application/json:
            schema:
              additionalProperties: false
              properties:
                agent_id:
                  description: >-
                    The agent that runs the call. Required for channel phone and
                    web. Optional for channel realtime: without it the session
                    starts with an empty prompt, no tools, no greeting, the
                    default voice and automatic language, and the Realtime
                    client's session.update configures it. A realtime session
                    never plays the agent's first_message; the client's first
                    response.create starts the conversation.
                  minLength: 1
                  type: string
                agent_revision:
                  minimum: 1
                  type: integer
                caller_name:
                  type: string
                channel:
                  default: phone
                  description: >-
                    phone dials to. web is a browser session: no to, no route;
                    the answer adds ws_url and events_url. realtime is an OpenAI
                    Realtime-compatible session with the same rules, answer and
                    per-minute price as web, except that it is refused (429
                    concurrency_limit) rather than queued when no voice slot is
                    free; first_message, system_prompt, timing, test and flow
                    agents are not accepted on it.
                  enum:
                    - phone
                    - web
                    - realtime
                  type: string
                final_results:
                  default: false
                  description: >-
                    Send one consolidated call.processed after the call ends,
                    once its transcript, any analysis or post-call tools and a
                    flow agent's outcome settle, carrying data.transcript (and
                    data.call.flow for a flow agent). Requires webhook_url.
                  type: boolean
                first_message:
                  description: >-
                    Replaces the agent's opening line for this call only.
                    {{var}} placeholders are substituted and validated like the
                    agent's first_message. Not accepted for channel realtime.
                  maxLength: 500
                  minLength: 1
                  type: string
                from:
                  type: string
                max_duration_secs:
                  type: integer
                metadata:
                  additionalProperties:
                    maxLength: 256
                    type: string
                  description: >-
                    Your own correlation ids (for example session_id, user_id).
                    Frozen with the call and echoed unchanged in the call object
                    and every webhook's data.call. Never given to the agent.
                    Serialized size at most 4096 bytes. Do not put secrets here.
                  maxProperties: 16
                  propertyNames:
                    pattern: ^[A-Za-z0-9_][A-Za-z0-9_.:-]{0,39}$
                  type: object
                phone_number_id:
                  type: string
                pool_id:
                  type: string
                recording_enabled:
                  description: >-
                    Store the call's audio. Default true; a workspace whose
                    policy disables recording defaults to false and answers true
                    with 403 recording_disabled.
                  type: boolean
                route:
                  type: string
                system_prompt:
                  description: >-
                    Replaces the agent's system prompt for this call only; the
                    agent, its revision and every other setting stay the
                    agent's. {{var}} placeholders are filled from this call's
                    variables and validated like the agent's system_prompt (with
                    an input_schema, each must be a declared input, a system
                    variable or a pre-call tool output). Stored with the call
                    but never returned on the call object or in webhooks. Not
                    accepted for channel realtime (400 invalid_request) or for a
                    flow agent (409 flow_system_prompt_unsupported).
                  maxLength: 12000
                  minLength: 1
                  type: string
                test:
                  type: boolean
                tier:
                  type: string
                timing:
                  additionalProperties: false
                  description: >-
                    Web and phone calls only (not realtime). Seconds count from
                    live media start; max_duration_secs stays the hard cap. The
                    *_before_end values must be at most the call's effective
                    max_duration_secs minus 10, and close_secs_before_end less
                    than wrap_up_secs_before_end when both are set.
                  properties:
                    close_message:
                      description: >-
                        Requires close_secs_before_end. {{var}} placeholders are
                        substituted.
                      maxLength: 500
                      minLength: 1
                      type: string
                    close_secs_before_end:
                      minimum: 5
                      type: integer
                    user_silence_close_secs:
                      maximum: 600
                      minimum: 15
                      type: integer
                    user_silence_message:
                      description: >-
                        Requires user_silence_close_secs. {{var}} placeholders
                        are substituted.
                      maxLength: 500
                      minLength: 1
                      type: string
                    wrap_up_instruction:
                      description: >-
                        Requires wrap_up_secs_before_end. {{var}} placeholders
                        are substituted.
                      maxLength: 1000
                      minLength: 1
                      type: string
                    wrap_up_secs_before_end:
                      minimum: 10
                      type: integer
                  type: object
                to:
                  type: string
                variables:
                  additionalProperties: {}
                  type: object
                voice:
                  additionalProperties: false
                  properties:
                    language:
                      type: string
                    voice_id:
                      type: string
                  type: object
                webhook_url:
                  type: string
              type: object
            examples:
              Place a call:
                summary: Place a call
                value:
                  agent_id: agt_01K2M4P7QRSTVWXYZ0A1B2C3
                  to: '+919876543210'
                  variables:
                    name: राहुल
                    vehicle: स्विफ्ट
                    due_date: 18 अक्टूबर
                    customer_id: cus_42
                  metadata:
                    reminder_id: rem_8842
                  max_duration_secs: 300
              Start a browser call:
                summary: Start a browser call
                value:
                  agent_id: agt_01K2M4P7QRSTVWXYZ0A1B2C3
                  channel: web
                  variables:
                    name: राहुल
                    vehicle: स्विफ्ट
                    due_date: 18 अक्टूबर
                    customer_id: cus_42
                  metadata:
                    session_id: sess_8f2c41
                    user_id: usr_1042
                  max_duration_secs: 600
      responses:
        '202':
          description: Accepted, not dialled yet
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CallCreated'
              examples:
                Accepted, not dialled yet:
                  summary: 202 — accepted, not dialled yet
                  value:
                    id: call_01K2M4RB8CDEFGHJKMNPQRST
                    status: queued
                Accepted, waiting for the browser:
                  summary: 202 — accepted, waiting for the browser
                  value:
                    id: call_01K2M5W3B7D9F1H3K5M7P9R1T3
                    status: queued
                    transport: web
                    ws_url: >-
                      wss://sandbox.voice.miraiminds.co/v2/calls/call_01K2M5W3B7D9F1H3K5M7P9R1T3/media?token=c9oQ2xK9pL4mR8tW1yZ6cF3hJ0sD5gA2eU7iO4kN9qV
                    ws_url_expires_at: '2026-10-09T10:05:00Z'
                    events_url: >-
                      https://sandbox.voice.miraiminds.co/v2/calls/call_01K2M5W3B7D9F1H3K5M7P9R1T3/events?token=Vb7nQ2xK9pL4mR8tW1yZ6cF3hJ0sD5gA2eU7iO4kN9q
        '400':
          description: Not an E.164 number
          content:
            application/json:
              examples:
                Not an E.164 number:
                  summary: 400 — not an E.164 number
                  value:
                    error:
                      code: invalid_request
                      message: to must be an E.164 phone number, got '9876543210'
                To sent with channel web:
                  summary: 400 — to sent with channel web
                  value:
                    error:
                      code: invalid_request
                      message: >-
                        to is not accepted for channel web: a web call connects
                        the browser that placed it, and no number is dialled
        '402':
          description: The wallet will not cover a minute
          content:
            application/json:
              examples:
                The wallet will not cover a minute:
                  summary: 402 — the wallet will not cover a minute
                  value:
                    error:
                      code: insufficient_balance
                      message: >-
                        wallet balance 3.20 INR is below the minimum for one
                        minute at t5
components:
  schemas:
    CallCreated:
      description: >-
        202 response of POST /v2/calls. Web calls and realtime sessions add the
        session credentials: paths the public edge makes absolute. transport
        names the channel.
      properties:
        events_url:
          description: >-
            Live events (Server-Sent Events) path with a reusable read-only
            token, valid for the call's maximum duration plus one hour.
          type: string
        id:
          type: string
        status:
          enum:
            - queued
          type: string
        transport:
          enum:
            - web
            - realtime
          type: string
        ws_url:
          description: >-
            Browser audio socket path with a single-use token. Expires at
            ws_url_expires_at (300 seconds). An idempotent replay repeats it
            only while the token is unused.
          type: string
        ws_url_expires_at:
          format: date-time
          type: string
      required:
        - id
        - status
      type: object
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        Your workspace secret key, `sk_live_` followed by 32 hex characters.
        Create one in the console under **Developers**.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.