Skip to main content
A phone number that calls too many people too fast gets flagged as spam, and people stop answering it. A pool spreads your outbound calls over several of your numbers at a pace you choose, calls each person back from the same number, and rests a number that stops being answered before it is burnt. This page covers what a pool is, how the number for a call is chosen, what each health state means, and the API. To set one up from start to finish, follow Run a campaign from your own numbers. Base URL https://sandbox.voice.miraiminds.co. All endpoints require Authorization: Bearer sk_live_….
Numbers and pools need the matching dialer update on your workspace. Until it is there, the Pools tab in the console says pools are not on yet, and every other part of Phone numbers works as before. Pools are free. A number you rent through Mirai keeps its own monthly rental.

Why a pool

Think of a person on a sales desk. They make a few dozen calls an hour, to different people, and nobody blocks them. A single number that places 300 calls an hour looks nothing like that to the networks that decide which calls to flag. A pool gives you the desk’s pace from software. With four numbers at 60 calls an hour each, the pool places up to 240 attempts an hour, and no single number goes past 60. A pool keeps each number under the hourly and daily pace you set, and it sends a contact’s retries from the number that called them first, for as long as that number stays in the pool. A number that is answered far less than its siblings is rested before it is burnt. A number can be in several pools. Its counters are its own, so a call from it counts toward every pool it is in.

Purposes and pace

Each pool has a purpose. The purpose sets the starting pace, and in the console it also adds a one line reminder of what suits that purpose. Pace is attempts per number. max_per_hour takes 1 to 180 and max_per_day takes 1 to 10000. Counting uses India time, so the hour turns over at the top of the hour in Asia/Kolkata.

Choosing a pace

You hold the dial. Mirai does not block a higher pace, but the console tells you what it costs.
  • Above 60 an hour, a number is more likely to be flagged as spam and answered less.
  • Above 120 an hour, most sales desks never run this fast. Expect numbers to rest often.
The campaign form shows a capacity line under Calls come from. It compares what your campaign will try with what the pool can carry:
Four calls at once is about 360 attempts an hour. Four numbers at 60 can carry 240, so the form suggests lowering Calls at once to 2 or adding numbers.
Promotional calls from regular mobile numbers can be flagged more often than calls from a number series meant for them. The 140 series is the proper home for promotional calling. We do not sell 140 numbers yet. When an outreach pool holds regular mobile numbers, the console says so in one plain line when you create the pool and when you start a campaign, and it never blocks you.

Which number a call comes from

Every outbound phone call goes through one rule, whether it comes from a campaign or from POST /v2/calls. The first choice that applies wins:
  1. The call’s own phone_number_id or pool_id. A campaign’s own choice counts as the call’s own.
  2. The agent’s calls_from.
  3. Your workspace’s default pool, the one with default_for_campaigns: true.
  4. The Mirai shared line.
The Mirai shared line is always listed, last, as Mirai shared line. It is shared with other customers and the person called sees it as Mirai. It stays in every picker so you can always see where a call would go when you choose nothing. A call from your own number shows your name. The line a call ends up using is written on the call, as phone_number_id, from, and calls_from_source. When a pool picked the number, calls_from_source is pool and the call also carries pool_id. A number or pool you chose is never replaced silently. If it cannot place the call, the request is refused with the reason (see errors).

Health

Every number you own shows how it is doing. The console uses the words in the first column. The API publishes health.state in the second.

How a number comes to rest

A pool compares its numbers with each other. A number rests when all of these are true:
  • It has made at least 25 attempts since it was last resumed or rested.
  • Its answer rate is below half the average of the pool’s numbers that have that many attempts.
  • At least one other number in the pool can still call.
A pool with one number never rests it, because a number that nobody answers and a list that nobody answers look the same. You can turn automatic resting off for a pool with auto_rest: false. The second rule is an alert and nothing more. A number answered on fewer than 8% of at least 100 attempts in a day fires phone_number.alert once that day. It keeps calling. Check the number and the list. A rested number gets a clean second chance. Its evidence starts again when it comes back, from a rest that ended or from Resume.

Rest, resume and retire

Each of these is on the number’s row in Phone numbers, and each has an Undo in the notice that follows. The API takes the same three requests. A rest stops one number and leaves the rest of the pool dialling. A campaign that calls from a single resting number waits for it and carries on from the same number when it is back. It does not pause and does not switch to another number. A campaign on a retired number pauses and says why. When every number in a pool is resting or at its hourly pace, a campaign waits for the next free number, at most 5 minutes at a time. If a contact’s own number is resting and sticky_retries is on, that contact waits for it and the others go on. A pool with no number able to call at all pauses the campaign with pause_reason starting calls_from_unavailable.

The pool object

members carries each number as it is returned by GET /v2/phone-numbers/{id}, in pool order. It is on a single pool and absent from list pages. A member must be one of your numbers that is set up, on a verified connection and inside its rental term, and it must not be retired. A pool needs at least one member that is not resting or cooling. A number added in the last 7 days runs at half the hourly pace.

Create a pool

The answer is 201 Created with the pool object, including members.

List, get, update and delete

GET /v2/phone-pools answers { "data": [...], "has_more": false, "next_cursor": null }, 100 pools a page, and takes ?cursor=. Its pools have no members. PATCH takes any of the fields above, plus version, which is required. A stale version answers 409 conflict. Read the pool again and retry. Sending number_ids replaces the member list. If you shrink the pool below min_healthy and send no min_healthy, it is lowered to the new size.
DELETE answers { "id": "pool_…", "object": "phone_pool", "deleted": true }. A pool that a campaign or an agent calls from cannot be deleted. It answers 409 pool_in_use and names them.

Point a call, a campaign or an agent at a pool

caller_ids is the older campaign field for numbers that belong to a SIP line. It is not part of pools and keeps working as before. A campaign’s calls_from object says where its number comes from, and what the pool looks like at that moment:
source is campaign, agent, default (your workspace’s default pool) or shared. The pool fields appear only when a pool applies. While a pool is holding for a free number, the campaign’s progress carries holding_until. An agent’s calls_from on the agent object is { "pool_id", "pool_name" } for a pool and { "phone_number_id", "number" } for a number.

Number health

GET /v2/phone-numbers and GET /v2/phone-numbers/{id} carry health and pools on every number. So do the answers to import, PATCH, activate, rest, resume and retire. A trimmed number:
A call counts as answered when its media went live. The cap to read next to attempts_this_hour is the max_per_hour of the pool it is in, halved while it is warming. The number carries no cap of its own.

History

days holds the last 30 days, oldest first. hours_today holds today’s hours so far, each as yyyymmddhh in India time.

Rest, resume and retire

Each answers 200 with the number, including its new health. rest takes { "minutes": 60 }, from 1 to 1440.
resume and retire take no body. resume is also the way to bring back a retired number, which makes it the Undo for Retire. Resuming restarts the number’s evidence. A number in another workspace answers 404 not_found. Resting a retired number answers 409 number_retired, so resume it first.

Errors

Webhook events

Number and pool events use the same envelope and the same signature as call events: { "id", "type", "created_at", "data" }, signed with your workspace secret. See Webhooks to verify them. Each payload carries the whole object as it stands, plus a reason in plain words. A number event has data.phone_number and, when a pool was involved, data.pool_id. A pool event has data.phone_pool, with every member’s health, and data.pool_id.
POST https://example.com/mirai/webhook
These events go to the webhook_url of your running or paused campaigns that call from the pool, from the number, or from a pool the number belongs to. If no campaign uses the number or pool, or none has a webhook_url, nothing is sent. Workspace wide subscriptions for these events are not available yet. Events from a rest or resume that you ask for through the API are sent on a best effort basis. Dedupe on id, as for every other webhook.

Run a campaign from your own numbers

Rent or import numbers, build a pool, point a campaign at it and watch it.

Receive inbound phone calls

Buy a number or connect your own, then assign an agent to answer it.

Campaigns

The dialler that calls from a pool.

Errors

Every error code in one place.