How to add phone calls to your own AI agent

Short answer: If your agent framework can connect to a remote MCP server, point it at https://callforme.tel/mcp and it gets place_call, get_call and the other tools. Otherwise use the REST API: POST /v1/calls to dial, GET /v1/calls/:id?wait=45 to follow it, and POST /v1/calls/:id/answer when the business asks something. No telephony or voice setup on your side.

Two ways in

MCP. If you're building on a framework that can use remote MCP servers, add https://callforme.tel/mcp as a server. Your model gets the same tools Claude and ChatGPT use: plan_call, place_call, get_call, answer_question, call_around and the rest, with descriptions written for models. Connecting needs no key; the first real call hands back a setup link. See the MCP reference.

REST. If you'd rather wrap it as your own tool, the API at https://callforme.tel/v1 has the same behavior over plain HTTP. The rest of this page walks through it in TypeScript. The full endpoint list is in the REST API docs, and the spec is at /openapi.json.

1. Place a call

const BASE = "https://callforme.tel/v1";
const KEY = process.env.CALLFORME_KEY; // not needed for demo lines
const headers: Record<string, string> = { "Content-Type": "application/json" };
if (KEY) headers.Authorization = `Bearer ${KEY}`;

const placed = await fetch(`${BASE}/calls`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    phone: "+14697707412", // Maple Street Pizza, a free fictional demo line
    business_name: "Maple Street Pizza",
    goal: "Ask how long a large pepperoni takes for pickup right now.",
    questions: ["How many minutes for a large pepperoni?"],
    on_behalf_of: "Sam",
  }),
}).then((r) => r.json());

if (placed.status === "needs_setup") {
  // First real call on a new account: show this to your user, then retry with setup_code.
  console.log(placed.message_for_user);
  process.exit(0);
}
const callId: string = placed.call_id;

The request takes the same fields as the MCP place_call tool: details for facts the business may ask for, if_asked for pre-approved answers, constraints for hard limits, callback_number, voicemail_message, transfer_to and language. See how to write a good call goal.

2. Follow it and answer questions

Long-poll with wait=45. The request returns early when something needs you: a question from the business, a new answer, or the end of the call.

async function ask(question: string): Promise<string> {
  // Answer from your agent's context, or ask your user. Return quickly:
  // the business is waiting on the line.
  return "Pickup, under the name Sam.";
}

let call: any;
do {
  call = await fetch(`${BASE}/calls/${callId}?wait=45&transcript=none`, { headers }).then((r) => r.json());
  if (call.pending_question) {
    const answer = await ask(call.pending_question);
    await fetch(`${BASE}/calls/${callId}/answer`, {
      method: "POST",
      headers,
      body: JSON.stringify({ answer, question_id: call.pending_question_id }),
    });
  }
} while (call.status !== "ended" || !call.outcome);

console.log(call.outcome.summary);
console.log(call.answers);

If your code doesn't answer within about 45 seconds, the assistant tells the business the customer will follow up on that point and carries on, so a slow answer never leaves anyone hanging. The same /answer endpoint steers a live call at any time: {"answer": "Also ask if they deliver."}.

3. Use the result

A finished call gives you structured fields, so your agent doesn't have to parse a transcript:

  • outcome.type: booked, quoted, answered, cancelled, voicemail, refused_ai and a few more
  • outcome.summary: one sentence for your user
  • answers: one entry per question, in your order, null when unanswered
  • outcome.price_quoted, outcome.booked_time, outcome.confirmation_number when they apply
  • cost: what the call cost

Add transcript=full when you want every line. See transcripts and recordings.

4. Expose it as one tool

Most agents work best with a single tool that does the whole call. Describe it plainly and let the model fill in the fields:

const phoneTool = {
  name: "call_business",
  description: "Phone a US or Canadian business and get something done: book, cancel, get a price or hours. Returns the outcome and answers.",
  input_schema: {
    type: "object",
    properties: {
      phone: { type: "string" },
      goal: { type: "string", description: "What the call should get done, 1 to 3 sentences" },
      questions: { type: "array", items: { type: "string" } },
      details: { type: "string", description: "Facts the business may ask for. Never card numbers." },
    },
    required: ["phone", "goal"],
  },
};

Run steps 1 to 3 inside the tool and return outcome and answers to the model. For quotes from several places, use POST /v1/calls/around instead of a loop of single calls: the server finds the businesses, paces the dialing, and returns one results table. See call around.

What you don't have to build

No phone numbers, carrier registration, voice models, menu navigation, hold detection, voicemail detection, transcription or call recording. Calls open with an AI disclosure, respect business-local quiet hours (10pm to 7am), and honor opt-outs across every customer. Compare that with building on Twilio yourself.

Cost

Demo lines are free. Real calls are $1 per answered call including the first 5 minutes, then $0.25 a minute, from a prepaid balance. Unanswered and busy calls are free. See pricing.

Questions

Do I need my own phone number or voice provider?

No. CallForMe places the call from its own number, runs the voice, and handles menus and hold. Your code sends a goal and reads back the result.

Can I try it without an account?

Yes. Calls to the fictional demo lines need no key and cost nothing, up to 12 a day. The example on this page calls one.

How does my agent get a key for real calls?

The first real call returns needs_setup with a link. A person opens it and adds $10 of credit, the retry dials, and the response includes account_key once. Save it and send it as a Bearer token.

How should I handle the business's questions?

Poll with wait=45. When pending_question is set, answer it with POST /v1/calls/:id/answer within about 45 seconds, from context or by asking your user.

Add CallForMe to your agent

One URL for any MCP agent. Connecting asks for nothing.

https://callforme.tel/mcp

Install steps for your agent · Free demo lines · Pricing