Skip to main content
This recipe answers one phone number on behalf of many of your users. Every call reaches the same agent, and before the caller is answered your server says whose call it is. The agent then greets the caller for that user, speaks in that user’s voice and language, and writes the summary in the language the user reads. Call-screening apps, shared support lines, personal assistant numbers and any app that gives many accounts one number follow the same pattern.

What you’ll build

  • A shared number whose calls go to one agent.
  • A lookup on your server that answers within two seconds: whose call it is, the greeting, and the voice and languages for that user. When it says “not ours”, or can’t answer in time, the caller is not answered and nothing is charged.
  • A background lookup for slower data, such as notes about the caller. Its values reach the agent during the call.
  • A summary of each call in the user’s own language, delivered to your webhook.
  • A way for your app to end a call while it runs.
You need:
  • A workspace API key and its webhook secret. See the Quickstart.
  • A phone number in your workspace that answers incoming calls. The inbound calling cookbook covers buying or connecting one.
  • A public HTTPS server on port 443 for the lookups and the webhook. While you build, a tunnel to your laptop works.
  • Python 3.10+ with FastAPI and httpx, or Node.js 18+ with Express. The setup steps also work with cURL and jq.

How it works

The caller is ringing while your lookup runs, so time matters: The two-second budget is shared by every pre-call tool the call waits for. The Tools page explains how it works on incoming calls.

Step 1: Answer “whose call is it?” on your server

Each incoming call sends your server the caller’s number (caller_number), the number they dialled (called_number) and the call’s id. Your server decides whose call it is from those and your own records, and answers with: Each value you want in the prompt is at most 512 characters, so keep instructions short. Save the call id against the user: the webhook in step 4 uses it to find whose call it was. The second route serves the background lookup. It starts at the same moment as the first, so it works the user out again instead of waiting for the first request to finish. Both routes check a shared key that Mirai sends in the Authorization header. db, crm and verify_mirai_signature stand in for your own code.
server.py
A user who prefers Gujarati gets a different answer from the same route, and the same agent sounds different on their calls:
For signature checks on /mirai/events, see signature verification.

Step 2: Create the agent

Save this as shared-line-agent.json, with your server’s address in place of api.example.com.
shared-line-agent.json
What each part does:
  • owner waits for your answer. Its timeout_ms of 1.5 seconds leaves room inside the incoming-call budget, and on_failure: "abort" means a caller is never answered with a greeting that has no user in it. A call your server couldn’t answer ends failed with precall-tool-failed.
  • The call_settings in your answer set the voice and languages. select doesn’t need to name them. See Set the voice and language for the call.
  • skip_call runs after owner and turns the call away when your server answered "answer": false. The call ends aborted with skipped-by-condition, and nothing is charged.
  • notes runs in the background, so it never holds the answer. It reads the call’s own variables only: a background tool can’t read owner’s values, because both start together. When it answers, the agent gets the caller’s name and last message. See Run a slow lookup in the background.
  • analysis.prompt reads {{owner.summary_language}}, so each summary is written in that user’s language. See Variables in the prompt.
  • The agent’s own voice and language are what a call uses when your answer leaves call_settings out.

Step 3: Store the key, create the agent and point the number at it

Store the key your server checks as a workspace secret, create the agent, then assign it to the number with a webhook. The number update needs its current version.
If the number has never answered calls, activate it first. The inbound calling cookbook shows how, and its step 5 says which secret signs the number’s webhooks.

Step 4: Read each call’s result

Every call carries the voice and languages it used, and who chose each, in call_settings. On a call your server configured, the sources name your tool:
After the call, call.processed brings the summary in data.call.analysis. The /mirai/events route in step 1 finds the user from the call id it saved and stores the message. A call your server turned away sends call.aborted (skipped-by-condition) or call.failed (precall-tool-failed) and no summary. To show a call while it runs, open its live events with your key from the moment whose-call gives you the call id. The pre-call tools’ events arrive while the caller’s phone is still ringing.

Step 5: End a call from your app

Your app has the call id from the lookup, so it can end a call at any time, for example when your user picks up elsewhere or blocks the caller.
The call hangs up at once, without a goodbye, and ends aborted with aborted-by-api. See Abort a call.

Test it

This test agent needs no server of your own. It uses httpbin.org, a public echo service, in place of both lookups. Anything you send it is public, and it is sometimes slow, so use it only for this test.
shared-line-test.json
Create it as in step 3 and assign it to your number, then:
  1. Call the number. The agent says “The secret word is PINEAPPLE. You called from” and your number, in the sameer voice.
  2. Read the call with GET /v2/calls/{id}. call_settings.sources shows pre_call:echo for voice_id and language.
  3. Wait about five seconds into the call and ask “Who am I?”. The agent answers “Ravi”, from the background tool.
  4. Hang up. The summary in GET /v2/calls/{id}/analysis is in Gujarati. Change summary to Tamil, call again, and the next summary is in Tamil.
  5. Change voice to robot and call. The agent speaks in neha, the agent’s own voice. The echo receipt in GET /v2/calls/{id}/tool_runs has a warning naming call_settings.voice_id.
  6. Call again and, while the agent talks, send POST /v2/calls/{id}/abort. The call hangs up and ends aborted.

Privacy and compliance

  • The caller’s number goes to your server on every call. Treat it as personal data: keep it only as long as you need it and protect it like the rest of your user records.
  • Caller ID can be faked. Use it to choose a greeting and settings, never as proof of who is calling. Don’t let the agent read out a user’s private details because of the caller’s number alone.
  • Tell callers they’re speaking with an AI voice agent, and give a recording notice if you record. Your greeting is the place for both.
  • The callers are usually not your users and have no account with you. Their words reach your users as summaries, so tell your users what is stored and for how long, and honour the data protection law that applies to you, such as India’s DPDP Act or GDPR.
  • Keep lookup_key in workspace secrets. Never put keys in prompts or variables. Check webhook signatures on every event.
  • Transcripts, recordings and summaries are kept for 90 days with the call. Copy what you need into your own system.

Production checklist

  • whose-call answers in well under 1.5 seconds at your busiest hour, including the network between us and your server.
  • Every user has a voice and languages your server can send, and the receipts of test calls carry no warnings.
  • Calls that aren’t your users’ answer "answer": false, and you’ve tested that the caller is not answered.
  • The background lookup has a timeout_ms that fits it, and the agent copes when its values never arrive.
  • Summaries arrive in each user’s language on test calls for at least two languages.
  • Webhooks are verified, deduplicated on the event id, and matched to users by the call id saved during the lookup.
  • Your app can end a call with POST /v2/calls/{id}/abort, and you’ve tested it on a live call.

Tools

Pre-call tools, the incoming-call budget, call settings and background lookups.

Calls

Call settings, the call object and ended reasons.

Call analysis

Summaries and success checks with variables.

Live events

Follow a call, its pre-call tools included.

Receive inbound phone calls

Buy or connect the number and turn on incoming calls.

Webhooks

Signed events, final results and signature checks.