OpenPhn docs

Claude Agent SDK

Give a Claude Agent a phone tool via the OpenPhn API.

There's no dedicated OpenPhn SDK today — Claude Agents integrate with OpenPhn by calling the REST API directly as a tool. This works well because the OpenPhn POST /v1/calls shape is already agent-friendly (objective in, outcome schema defined up-front, outcome JSON back out).

If your Claude Agent supports MCP, this is the shortest path. See the MCP → Claude Desktop quickstart — the same mcpServers block works anywhere the Anthropic Desktop Extensions runtime reads config from.

Option B — hand-rolled REST tool

When you need fine-grained control (logging, retry policy, custom consent checks) you can register a tool on the agent that wraps POST /v1/calls:

import Anthropic from "@anthropic-ai/sdk";

const anthropic = new Anthropic();

const tools = [
  {
    name: "openphn_make_call",
    description: "Place a phone call via OpenPhn. Returns a call_id; poll openphn_get_call for outcome.",
    input_schema: {
      type: "object",
      required: ["to", "objective", "outcome_schema", "consent_type"],
      properties: {
        to:             { type: "string", description: "E.164 phone number" },
        objective:      { type: "string", description: "Plain-English goal for the call" },
        outcome_schema: { type: "object", description: "Typed fields you want back" },
        consent_type:   { type: "string", enum: ["prior_express", "existing_business_relationship", "emergency"] },
      },
    },
  },
  {
    name: "openphn_get_call",
    description: "Fetch the current state and outcome of an OpenPhn call by id.",
    input_schema: {
      type: "object",
      required: ["call_id"],
      properties: { call_id: { type: "string" } },
    },
  },
];

// In your tool-use loop, when the model invokes openphn_make_call:
async function handleOpenPhn(toolName: string, input: any) {
  const base = "https://api.openphn.com";
  const headers = {
    "Authorization": `Bearer ${process.env.OPENPHN_KEY!}`,
    "Content-Type":  "application/json",
  };
  if (toolName === "openphn_make_call") {
    const res = await fetch(`${base}/v1/calls`, {
      method:  "POST",
      headers: { ...headers, "Idempotency-Key": crypto.randomUUID() },
      body:    JSON.stringify(input),
    });
    return res.json();
  }
  if (toolName === "openphn_get_call") {
    const res = await fetch(`${base}/v1/calls/${input.call_id}`, { headers });
    return res.json();
  }
  throw new Error(`Unknown tool: ${toolName}`);
}

Why MCP is usually better

  • One config change, four tools, no hand-rolled schemas.
  • Scope + rate-limit handling is on OpenPhn's side.
  • You don't have to keep your tool schemas in sync when OpenPhn adds new capabilities.

Use Option B when your Claude Agent deployment doesn't support MCP yet or you need a custom retry/audit layer in front of OpenPhn.

On this page