Blog · For developers
Placing a phone call from code: REST, keys and what comes back
One request to place the call, one to read the result. The interesting part is the few minutes in between.
By the CosVoice team · · 5 minute read
Two requests, with a wait in the middle
Placing a phone call from code, on our API, is a POST to the calls endpoint with a number and a purpose. You get a call id back straight away. Later you GET that call by its id and read what happened. For the common case, that's the whole interface.
This is the road for agents and scripts that don't speak MCP. If yours does, connecting by address is less work, and what an MCP phone tool is covers it. The REST API does the same things under the same names. The base address is cosvoice.com/api/v1, with JSON in and JSON out.
The key
Every request carries a key in the Authorization header, as a bearer token. The owner of the line makes the key in Settings, under Connect. Keys start with cv_live_ which makes one easy to spot in a log where it shouldn't be. A key is shown once when it's made and stored hashed on our side, so a lost key can't be looked up. You replace it, which you can do any time.
Where the key lives matters more than how it's sent. If an agent needs it, the agent should ask through its secure credential prompt and not in the chat, where it would sit in the history. Don't commit it. Don't paste it into a shared channel. It's the key to a line, and whoever holds it can place calls from that number.
The request body
Two fields are required and three are optional. There's no script and no prompt template. The purpose is the brief, and how to write a call brief is about getting that one field right.
- to (required): who to call, in E.164 format. That's a plus sign, the country code and the number, with no spaces.
- purpose (required): the job in plain English. Say what you'd tell a person, including what to accept if the first answer is no.
- callee_name: who is being called, for example a restaurant's host stand.
- desired_resolution: what a good ending looks like. "A confirmed reservation with a time."
- max_minutes: a hard stop for the call. The default is 10.
What you get back, and when
The POST returns at once with a call object, and the part you need from it is the id. The call has been placed. It hasn't happened. Calls take minutes, not seconds: there may be a menu, a hold, a person who goes off to check the book.
The status field says where things stand. While the call is live it's queued, ringing or in-progress. It ends as completed, no-answer, busy or failed.
Once it's completed, the same object carries the rest: the outcome in one line, a written summary, a list of action items, the notes the line captured (names, amounts, dates, reference numbers), the transcript turn by turn, and the duration in seconds. We've argued for reading those fields before the transcript in structured call outcomes.
Poll, or be told
There are two ways to find out a call is done. Polling is the simple one. GET the call every twenty seconds or so until the status is final. The limit is 240 requests a minute per key, and a sensible polling loop comes nowhere near it.
The other way is a webhook. Register an HTTPS address and we post a call.completed event to it when the call is written up. No loop, no wasted requests. The price is a public endpoint and a signature to verify.
Plenty of integrations do both: take the webhook, keep a slow poll as a net. And if your process was down for a while, the activity endpoint returns everything since a timestamp you give it, so catching up is one request.
Errors that mean stop, and errors that mean wait
Errors come back as JSON with a message in plain words, written so you can show it to the owner. Four codes are worth handling, and they call for different reactions.
- 400: something in the request is missing or malformed. The message says which field. Fix it and send again.
- 401: the key is missing, wrong or revoked. Don't retry. Ask the owner for a new one.
- 404: no such call, email or contact on this line. Check the id.
- 429: over the rate limit. Wait a little and try again.
Everything that isn't a call
The line has texts, email, contacts and settings too, and each has endpoints. You can list recent calls, add a note to one, book a table by giving the venue's number, a party size and a time, read the texts and mail that reached the line, forward an email, manage contacts, change settings, and pull the history as JSON or CSV.
One thing to know before you build on sending texts. Carriers may filter them for now, so when something has to arrive, make it a call or an email.
Let the agent read the spec
The API is described in an OpenAPI 3.1 document at cosvoice.com/openapi.json, readable without signing in. That's deliberate. Some assistants can't add an MCP server but can write their own integration code, and a spec they can fetch beats a docs page they have to interpret.
So the quickest integration may be one you don't write. Point the agent at the spec, hand it a key through a secure prompt, and let it build its own connector. One instruction we'd add: confirm with the owner before placing a call, and say who you're about to ring and why. The version for human eyes is the docs page.
Common questions
Is there a phone call API that works without MCP?
Yes. The CosVoice REST API places calls, reads results and manages the line over HTTPS with a bearer key. It does the same things as the MCP tools.
How do I know when the call has finished?
Poll the call by its id about every twenty seconds until the status is final, or register a webhook and wait for the call.completed event.
What format should the phone number be in?
E.164: a plus sign, the country code, then the number, with no spaces or brackets. A US number is +1 followed by ten digits.
Is there a rate limit on the API?
Yes, 240 requests a minute per key. Going over returns a 429, and the right response is to wait a little and try again.
Read next: The docs, on one page · Signed webhooks for call events · Connecting without a key
Hear it for yourself.
Call our own AI agent and ask her anything, or get a number in your area code in about a minute.