> ## 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.

# Rebuild insights

> Counts the report again from scratch instead of serving the cached one. Call summaries and outcomes can arrive a few minutes after a call ends, so rebuild when the outcome numbers look behind. No body, no charge.



## OpenAPI

````yaml /api-reference/openapi.json post /v2/campaigns/{campaign_id}/insights
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/campaigns/{campaign_id}/insights:
    post:
      tags:
        - Campaigns
      summary: Rebuild insights
      description: >-
        Counts the report again from scratch instead of serving the cached one.
        Call summaries and outcomes can arrive a few minutes after a call ends,
        so rebuild when the outcome numbers look behind. No body, no charge.
      operationId: rebuild_insights
      parameters:
        - name: campaign_id
          in: path
          required: true
          description: The campaign's id (`cmp_…`).
          schema:
            type: string
          example: cmp_01K79Q4T6W8XZ2B5D7F9H3JKMN
      responses:
        '200':
          description: Freshly counted
          content:
            application/json:
              examples:
                Freshly counted:
                  summary: 200 — freshly counted
                  value:
                    object: campaign_insights
                    schema: insights.v1.6
                    campaign_id: cmp_01K79Q4T6W8XZ2B5D7F9H3JKMN
                    funnel:
                      tier: measured
                      stage_order:
                        - list
                        - valid
                        - deduped
                        - dialable
                        - attempted
                        - reached_the_network
                        - connected
                        - conversation
                        - classified
                      stages:
                        list: 3
                        valid: 3
                        deduped: 3
                        dialable: 3
                        attempted: 3
                        reached_the_network: 3
                        connected: 2
                        conversation: 2
                        classified: 2
                      rates:
                        answer_rate_pct: 66.7
                        conversation_rate_pct: 100
                        classified_rate_pct: 100
                      failed_before_media:
                        value: 0
                        tier: measured
                        reasons: {}
                        note: >-
                          dials that never connected audio (a carrier or
                          platform outage), neither an answer nor a rejection
                      not_attempted:
                        value: 0
                        tier: measured
                      connected_without_speech:
                        value: 0
                        tier: measured
                      retry_effectiveness:
                        value: 0
                        tier: measured
                        contacts_retried: 1
                        answered_after_a_retry: 0
                        note: >-
                          attempts is the contact's total; this is 'answered
                          with more than one attempt recorded', not per-attempt
                          history
                    outcomes:
                      tier: measured
                      conversations: 2
                      counts:
                        booked: 1
                        will_call_back: 1
                      percent_of_conversations:
                        booked: 50
                        will_call_back: 50
                      warm:
                        value: 2
                        tier: assumption_based
                        assumptions_used:
                          - C7
                        definition:
                          - booked
                          - callback_human
                          - will_call_back
                        percent_of_conversations: 100
                      unclassified:
                        value: 0
                        tier: measured
                        analysis_not_run: 0
                        analysis_returned_no_outcome: 0
                        connected_but_nobody_spoke: 0
                        never_reached: 1
                      bookings:
                        value:
                          - name: राहुल
                            phone: '+919876543210'
                            call_id: call_01K2M4RB8CDEFGHJKMNPQRST
                            contact_id: lead-1041
                            summary: ग्राहक ने 18 अक्टूबर सुबह 10 बजे की सर्विस बुक की।
                            when: 18 अक्टूबर, सुबह 10 बजे
                        tier: measured
                      callbacks:
                        value:
                          - name: अमित
                            phone: '+919876501234'
                            call_id: call_01K7D3G5J7M9P1R3T5V7X9Z1B4
                            contact_id: lead-1043
                            summary: >-
                              ग्राहक अभी गाड़ी चला रहे थे, शाम को खुद कॉल
                              करेंगे।
                            when: ''
                        tier: measured
                      handoffs:
                        value: []
                        tier: measured
                      label_confidence:
                        tier: assumption_based
                        assumptions_used:
                          - C6
                        value: null
                        note: outcome labels are AI-classified (±5-10%)
                    money:
                      tier: measured
                      source: wallet_ledger
                      total_spend_inr:
                        value: 15
                        tier: measured
                        debit_inr: 15
                        credit_inr: 0
                        calls_charged: 2
                        calls_without_ledger_line: 1
                        ledger_truncated: false
                        scope_note: costs counted are call charges only
                      talk_minutes:
                        value: 1.87
                        tier: measured
                        talk_seconds: 112
                      billed_minutes:
                        value: 3
                        tier: measured
                        charged_calls: 2
                        calls_under_one_minute: 1
                        source: wallet_ledger
                        from_statement: 2
                        from_rule: 0
                        rule: 'per call: ceil(duration / 60), minimum 1'
                        expected_by_rule: 3
                        matches_rule: true
                      billed_vs_talk_note: >-
                        3 minutes were billed against 1.87 minutes of talk time
                        because billing is per call, rounded up, with a
                        one-minute minimum — 1 of the 2 charged calls lasted
                        under a minute.
                      cost_per_conversation_inr:
                        value: 7.5
                        tier: measured
                        conversations: 2
                      cost_per_booking_inr:
                        value: 15
                        tier: measured
                        bookings: 1
                      cost_per_warm_inr:
                        value: 7.5
                        tier: assumption_based
                        assumptions_used:
                          - C7
                        warm: 2
                      cost_per_talk_minute_inr:
                        value: 8.02
                        tier: measured
                      vs_human:
                        value: -0.04
                        tier: assumption_based
                        assumptions_used:
                          - C4
                        human_cost_inr: 14.96
                        human_rate_inr_per_min: 8
                        machine_cost_inr: 15
                      expected_pipeline_inr:
                        value: 1950
                        tier: assumption_based
                        assumptions_used:
                          - C1
                          - C2
                          - C3
                          - C7
                        bookings: 1
                        warm: 2
                      roi_statement:
                        value: ₹15.0 spent → ₹1950.0 expected pipeline
                        tier: assumption_based
                        assumptions_used:
                          - C1
                          - C2
                          - C3
                          - C7
                    ops:
                      tier: measured
                      calls_without_timestamps:
                        value: 1
                        tier: measured
                        dialled: 3
                        note: >-
                          a call record whose start stamp is missing or is a
                          zero value; excluded from the wall clock, the
                          concurrency sweep and the hour histogram
                      talk_total_secs:
                        value: 112
                        tier: measured
                      talk_avg_secs:
                        value: 56
                        tier: measured
                        calls: 2
                      talk_p50_secs:
                        value: 44
                        tier: measured
                      talk_max_secs:
                        value: 68
                        tier: measured
                      answer_rate_by_hour:
                        value:
                          '10':
                            attempted: 2
                            connected: 2
                            conversations: 2
                            answer_rate_pct: 100
                          '11':
                            attempted: 1
                            connected: 0
                            conversations: 0
                            answer_rate_pct: 0
                        tier: measured
                        timezone: Asia/Kolkata
                        timezone_source: zoneinfo
                        basis: started_at, else created_at (the dial moment)
                        bucketed_by_created_at: 1
                        attempts_without_a_timestamp: 0
                      peak_concurrency_upper_bound:
                        value: 1
                        tier: measured
                        method: >-
                          sweep over started_at + duration_secs, whole-second
                          stamps
                        calls_with_a_full_window: 2
                        calls_missing_a_window: 1
                        configured_max_concurrent: 3
                        exceeds_configured: false
                      wall_clock_secs:
                        value: 3664
                        tier: measured
                        first_call_at: '2026-10-12T04:30:48+00:00'
                        last_call_ended_at: '2026-10-12T05:31:52+00:00'
                    quality:
                      tier: measured
                      voice_to_voice_p50_ms:
                        value: 790
                        tier: measured
                        calls_measured: 2
                        calls_unmeasured: 1
                        sources:
                          telemetry_v2v: 2
                        calls_discarded_implausible: 0
                        floor_ms: 200
                      voice_to_voice_p90_ms:
                        value: 820
                        tier: measured
                        calls_measured: 2
                      turn_end_to_end_p50_ms:
                        value: null
                        tier: measured
                        calls_measured: 0
                        definition: user stopped speaking -> bot stopped speaking
                      turns_per_conversation_avg:
                        value: 6.5
                        tier: measured
                        p50: 5
                        conversations_counted: 2
                      barge_ins_total:
                        value: 0
                        tier: measured
                        calls_with_turn_timing: 2
                        calls_without_turn_timing: 1
                        method: transcript_overlap
                        is_lower_bound: true
                        definition: a user turn that began before the bot's turn ended
                        note: >-
                          a lower bound: an interruption that produced no
                          transcribed user turn is not counted
                      short_call_rate_pct:
                        value: 0
                        tier: measured
                        threshold_secs: 15
                        calls: 0
                        of: conversations
                      engaged_rate_pct:
                        value: 50
                        tier: measured
                        threshold_secs: 60
                        calls: 1
                        of: conversations
                    hygiene:
                      tier: measured
                      invalid_numbers:
                        value: 0
                        tier: measured
                        reasons: {}
                        rows: []
                      duplicate_phones:
                        value: 0
                        tier: measured
                        extra_rows: 0
                        rows: []
                      wrong_numbers:
                        value: 0
                        tier: measured
                        rows: []
                      recently_serviced_contradictions:
                        value: 0
                        tier: measured
                        rows: []
                      unreachable:
                        value: 1
                        tier: measured
                        rows:
                          - phone: '+919812345678'
                            name: प्रिया
                            attempts: 2
                            status: exhausted
                            last_status: no_answer
                        note: busy / no-answer is not a rejection
                      cleanup_value_inr:
                        value: 0
                        tier: assumption_based
                        assumptions_used:
                          - C5
                        corrected_records: 0
                    deliverables:
                      tier: measured
                      csv_url: >-
                        /v2/campaigns/cmp_01K79Q4T6W8XZ2B5D7F9H3JKMN/report?format=csv
                      csv_columns:
                        - id
                        - phone
                        - name
                        - due_date
                        - vehicle
                        - status
                        - attempts
                        - last_call_id
                        - started_at
                        - duration_secs
                        - ended_reason
                        - cost_inr
                        - outcome
                        - success
                        - summary
                        - transcript
                        - recording_url
                      csv_variable_columns:
                        - due_date
                        - vehicle
                      recordings:
                        value: 2
                        tier: measured
                        expected: 2
                        missing: 0
                        link_expiry_days: 7
                        basis: call records that name a recording object
                      transcripts:
                        value: 2
                        tier: measured
                        expected: 2
                        missing: 0
                      call_records:
                        value: 3
                        tier: measured
                        expected: 3
                        contacts_never_dialled: 0
                    cited_calls:
                      call_01K2M4RB8CDEFGHJKMNPQRST:
                        name: राहुल
                        phone_masked: •••••••••3210
                        outcome: booked
                        duration_secs: 68
                        turns:
                          - role: assistant
                            text: >-
                              नमस्ते, मैं आशु बोल रहा हूं मिराई मोटर्स से. एक
                              मिनट है आपके पास?
                          - role: user
                            text: हाँ बोलिए
                          - role: assistant
                            text: >-
                              आपकी स्विफ्ट की सर्विस 18 अक्टूबर को ड्यू है.
                              स्लॉट बुक कर दूं?
                          - role: user
                            text: हाँ, सुबह 10 बजे कर दीजिए
                        recording: true
                      call_01K7D3G5J7M9P1R3T5V7X9Z1B4:
                        name: अमित
                        phone_masked: •••••••••1234
                        outcome: will_call_back
                        duration_secs: 44
                        turns:
                          - role: assistant
                            text: >-
                              नमस्ते, मैं आशु बोल रहा हूं मिराई मोटर्स से. एक
                              मिनट है आपके पास?
                          - role: user
                            text: अभी ड्राइव कर रहा हूं, शाम को कॉल करता हूं
                        recording: true
                    assumptions:
                      C1:
                        label: average service ticket
                        value: 1500
                        unit: inr
                        source: default
                      C2:
                        label: warm-lead close rate
                        value: 0.3
                        unit: rate
                        source: default
                      C3:
                        label: booking show-up rate
                        value: 0.7
                        unit: rate
                        source: default
                      C4:
                        label: human telecaller cost
                        value: 8
                        unit: inr_per_min
                        source: default
                      C5:
                        label: value of one corrected CRM record
                        value: 10
                        unit: inr
                        source: default
                      C6:
                        label: outcome labels are AI-classified (±5-10%)
                        value: null
                        unit: note
                        source: default
                      C7:
                        label: warm = booked + will_call_back + callback_human
                        value:
                          - booked
                          - will_call_back
                          - callback_human
                        unit: outcome_set
                        source: default
                      C8:
                        label: costs counted are call charges only
                        value: null
                        unit: note
                        source: default
                      C9:
                        label: recording links expire
                        value: 7
                        unit: days
                        source: default
                      C10:
                        label: busy / no-answer is not a rejection
                        value: null
                        unit: note
                        source: default
                    meta:
                      workspace_id: ws_3f9a1c27d8e4b610
                      generated_at: '2026-10-12T06:02:11Z'
                      data_version: insights.v1.6|2026-10-12T05:41:09Z|completed|1500
                      campaign:
                        name: सर्विस रिमाइंडर — अक्टूबर
                        status: completed
                        tier: t5
                        agent_id: agt_01K2M4P7QRSTVWXYZ0A1B2C3
                        timezone: Asia/Kolkata
                        created_at: '2026-10-09T06:12:40Z'
                        updated_at: '2026-10-12T05:41:09Z'
                      contacts_read: 3
                      calls_named: 3
                      call_records_found: 3
                      call_records_missing: 0
                      calls_without_timestamps: 1
                      calls_failed_before_media: 0
                      contacts_with_multiple_attempts: 0
                      representative_overrides: 0
                      attempts_recovered: 0
                      group: null
                      cited_calls_carried: 2
                      cited_calls_truncated: false
                      cited_calls_max: 80
                      cited_transcript_chars: 269
                      ledger_transactions_scanned: 2
                      ledger_truncated: false
                      tiers_present:
                        - measured
                        - assumption_based
                      contacts_truncated: false
                      served_from_cache: false
        '404':
          description: Not in this workspace
          content:
            application/json:
              examples:
                Not in this workspace:
                  summary: 404 — not in this workspace
                  value:
                    error:
                      code: not_found
                      message: no campaign cmp_01K79Q4T6W8XZ2B5D7F9H3JKMN
components:
  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.