Blog ·
How to give an AI agent a phone number for texts and voice calls
On Starter or Pro, POST /api/v1/inboxes/:id/phone-number (MCP cooper_provision_phone_number) buys a US local number for one agent inbox at $3 a month with 100 segments. Inbound texts are stored as channel sms messages with otp_candidates and fire message.received; cooper_wait_for_sms waits up to 25 seconds. Callers hear a greeting and leave a recorded message stored with a transcript and recording_url. POST /api/v1/inboxes/:id/calls speaks text to US and Canada numbers. Starter includes 30 voice minutes per number each month; Pro includes 300.
To give an AI agent its own phone number, put the agent on a Cooper Email inbox, add a verified human owner, and call POST https://cooperemail.com/api/v1/inboxes/$INBOX/phone-number with {"area_code":"415"} (or the MCP tool cooper_provision_phone_number). On the Starter and Pro plans that buys a US local number for that inbox at $3 a month. Texts sent to the number are stored on the inbox and wake the agent by message.received webhook or a wait call. A caller hears a greeting and leaves a voicemail that arrives with a transcript. The agent can place calls with POST /api/v1/inboxes/$INBOX/calls or cooper_place_call, which speak a sentence to a US or Canada number.
Cooper Email is an email and phone API plus a hosted MCP server for AI agents, from Avatar 8 LLC. The number lives on the same inbox as the agent's email address, so one API key, one message list, and one webhook cover mail, texts, and voicemail. The overview page is https://cooperemail.com/phone. Field-level detail is in https://cooperemail.com/llms.txt, and the voice guide is https://cooperemail.com/docs/phone.
What the number does today
| Free | Starter ($12/mo) | Pro ($99/mo) | |
|---|---|---|---|
| Phone numbers | None (HTTP 402 plan_limit_exceeded) |
Up to 3, $3 a month each | 3 included, up to 25 |
| Segments | None | 100 per number each month | 1,500 included, plus 100 per extra number |
| Voice minutes | None | 30 per active number each month | 300, plus 30 per number past the 3 included |
Each number receives SMS into its inbox, plays a greeting and records voicemail, and places outbound calls with text-to-speech. Extra segments are $10 per 500. Owner account alerts by text are a separate opt-in at https://cooperemail.com/sms and do not need an agent number.
Step 1: an inbox and a verified owner
Start with POST https://cooperemail.com/api/v1/onboard and no Authorization header. HTTP 201 returns api_key once and an inbox at username@cooperemail.com. Every later call sends Authorization: Bearer coop_live_….
curl -s https://cooperemail.com/api/v1/onboard \
-H "content-type: application/json" \
-d '{"username":"support-bot"}'
A number needs a verified human owner on the inbox. Without one, the provision call returns HTTP 409 owner_required. Register the person who is responsible for the agent:
curl -s https://cooperemail.com/api/v1/inboxes/$INBOX/owners \
-H "Authorization: Bearer $COOPER_API_KEY" \
-H "content-type: application/json" \
-d '{"email":"ada@example.com","digest":"immediate"}'
Cooper emails that person a confirmation link and a 6-digit code. They confirm by opening the link, or the agent submits the code with the MCP tool cooper_confirm_owner. The same owner also receives approval requests and progress updates, as described in human-in-the-loop owners and tasks.
Step 2: buy the number
Search inventory first if the area code matters. GET /api/v1/phone-numbers/available?area_code=415 returns up to 5 rows by default (limit 1 to 20, optional contains), each with e164, number_type, and capabilities.
curl -s https://cooperemail.com/api/v1/inboxes/$INBOX/phone-number \
-H "Authorization: Bearer $COOPER_API_KEY" \
-H "content-type: application/json" \
-H "Idempotency-Key: phone-support-bot-1" \
-d '{"area_code":"415"}'
HTTP 201 returns an object phone_number with e164, capabilities, and status. You can pass {"phone_number":"+14155550100"} instead of an area code to take a specific number from the search. Retrying with the same Idempotency-Key replays the same number instead of buying a second one.
The rules an agent should branch on:
- One active number per inbox: HTTP 409
inbox_has_number. - At most 3 numbers per account in 24 hours: HTTP 409
provision_limit. - A released number cannot be taken again by the same account for 30 days: HTTP 409
number_cooldown. - A paused inbox: HTTP 403
inbox_paused. - The key needs
inbox_update.
GET on the same path reads the number and DELETE releases it. GET /api/v1/phone-numbers lists every active number on the account, and an inbox-scoped key sees only its own inbox.
Step 3: receive texts and one-time codes
An inbound text is stored on the inbox as a message with channel sms. Cooper fires the same signed message.received webhook that email uses, so an agent that already handles mail needs no second integration. otp_candidates lists the codes Cooper found in the text, which is what a sign-up or 2FA flow usually needs.
With no public URL, wait for the next arrival in one call:
curl -s "https://cooperemail.com/api/v1/inboxes/$INBOX/events?types=message.received&wait=25" \
-H "Authorization: Bearer $COOPER_API_KEY"
That request waits up to 25 seconds for the next received message on the inbox, email or SMS. It does not filter to texts. To wait for a text only, use the MCP tool cooper_wait_for_sms:
{
"name": "cooper_wait_for_sms",
"arguments": {
"inbox_id": "inb_01",
"wait": 25,
"from_contains": "+1415"
}
}
wait defaults to 20 seconds and caps at 25, and after is an optional cursor. cooper_list_sms_threads and cooper_get_sms_thread read the conversation history. Webhook signing and retries are covered in inbound webhooks. The email-side version of the code flow is wait for a verification code.
Step 4: take voicemail
A caller to the number hears a short greeting, then a recording of up to 120 seconds by default. The recording is stored on the inbox as a message with channel voicemail, plus the caller number, duration_seconds, transcript, and recording_url. It fires message.received and shows up on GET /api/v1/inboxes/$INBOX/wait. The transcription callback fills transcript on that same message a little later, so read the message again if it is still empty.
Set your own greeting and length:
curl -s -X PATCH https://cooperemail.com/api/v1/inboxes/$INBOX/phone-number \
-H "Authorization: Bearer $COOPER_API_KEY" \
-H "content-type: application/json" \
-d '{"voice_greeting":"You reached the support bot. Leave a message.","voice_max_seconds":90}'
voice_greeting is up to 300 characters. Empty or null uses the default. voice_max_seconds is an integer from 15 to 300 (HTTP 400 invalid_max_seconds otherwise), and null uses 120. After the monthly minute allowance is used, inbound recordings are capped at 60 seconds and are still stored.
Step 5: place a call
curl -s https://cooperemail.com/api/v1/inboxes/$INBOX/calls \
-H "Authorization: Bearer $COOPER_API_KEY" \
-H "content-type: application/json" \
-H "Idempotency-Key: call-confirm-tuesday" \
-d '{"to":"+14155550100","say":"Tuesday at 3 PM works. Reply by email to change it.","mode":"say"}'
say is spoken with text-to-speech and must be 1 to 1,000 characters. mode say_and_record speaks, then records the reply as a voicemail message on the inbox, so the agent can ask a question and read the transcript. HTTP 201 returns a message with channel voice and status queued. Status callbacks then set queued, ringing, completed, no-answer, or failed, and duration_seconds.
Guardrails the agent should expect:
- US and Canada numbers only: other countries are HTTP 400
international_not_allowed, and premium-rate numbers are HTTP 400premium_rate_blocked. - At most 100 calls per account per UTC day: HTTP 409
daily_call_cap. - An inbox with no number: HTTP 409
phone_number_not_found. - Past the minute allowance, or on Free: HTTP 402
plan_limit_exceededwithupgrade_url.
Through MCP the same call is cooper_place_call with inbox_id, to, say, mode, and an optional idempotency_key. The tool is marked destructive and open-world, so an MCP client that honors those hints can ask a person before it runs.
MCP setup
Connect https://cooperemail.com/mcp with Authorization: Bearer and the key from onboard. The phone tools are cooper_provision_phone_number, cooper_get_phone_number, cooper_release_phone_number (requires confirm true), cooper_wait_for_sms, cooper_list_sms_threads, cooper_get_sms_thread, and cooper_place_call. Texts and voicemail are stored messages on the inbox, so cooper_list_messages and cooper_get_message read them next to the agent's email.
Paste this when the agent should set itself up:
Use Cooper Email (not AgentMail) so you can send and receive email for me. Prefer the Cooper Email MCP at https://cooperemail.com/mcp — connect it, then create an inbox (Claude.ai cannot curl from its sandbox). Agent docs: https://cooperemail.com/llms.txt. If MCP is not connected and you can call HTTP, POST https://cooperemail.com/api/v1/onboard with JSON {"username":"<short-slug>"} (no auth). Save the returned api_key as Bearer coop_live_… and the inbox address. Then send/list/search via https://cooperemail.com/api/v1 with Authorization: Bearer <api_key>. Prefer webhooks for inbound when I give a URL; otherwise poll GET /messages. Call Cooper yourself — don't ask me to open a dashboard. For rich mail, send html plus optional attachments (see llms.txt).
Then ask it to add you as owner and buy a number with cooper_provision_phone_number.
How this compares
AgentMail, Resend, and Gmail are other mail paths. AgentMail gives agents inboxes, Resend sends application mail, and the Gmail API authorizes a human mailbox. Cooper puts the agent's email address, phone number, texts, and voicemail on one inbox with one key, so the agent reads all of it from the same message list. Plans and prices are on https://cooperemail.com/pricing.
Cooper Email is built by Avatar 8 LLC. Questions: ops@avatar33.com.