OpenAI Agents
Give an OpenAI Agent a phone tool via the OpenPhn API.
Like with the Claude Agent SDK, there's no OpenAI-specific OpenPhn SDK. Wire it in as a function-calling tool over REST.
from openai import OpenAI
import os, uuid, requests
client = OpenAI()
TOOLS = [
{
"type": "function",
"function": {
"name": "openphn_make_call",
"description": "Place a phone call via OpenPhn. Returns call_id.",
"parameters": {
"type": "object",
"required": ["to", "objective", "outcome_schema", "consent_type"],
"properties": {
"to": {"type": "string"},
"objective": {"type": "string"},
"outcome_schema": {"type": "object"},
"consent_type": {
"type": "string",
"enum": [
"prior_express",
"existing_business_relationship",
"emergency",
],
},
},
},
},
},
{
"type": "function",
"function": {
"name": "openphn_get_call",
"description": "Fetch an OpenPhn call's current state and outcome.",
"parameters": {
"type": "object",
"required": ["call_id"],
"properties": {"call_id": {"type": "string"}},
},
},
},
]
BASE = "https://api.openphn.com"
HEADERS = {"Authorization": f"Bearer {os.environ['OPENPHN_KEY']}"}
def handle_openphn(name: str, args: dict) -> dict:
if name == "openphn_make_call":
r = requests.post(
f"{BASE}/v1/calls",
headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())},
json=args,
timeout=10,
)
return r.json()
if name == "openphn_get_call":
r = requests.get(f"{BASE}/v1/calls/{args['call_id']}", headers=HEADERS, timeout=10)
return r.json()
raise ValueError(f"unknown tool: {name}")Polling vs webhooks
OpenAI Agents can't receive webhook POSTs. Two patterns work:
- Poll in-loop — the agent calls
openphn_get_callevery N seconds untilstatus == "completed". Fine for one-off calls under a minute. - Queue and return — the agent fires
make_calland ends its turn. A separate worker consumes OpenPhn's webhook (signed; see Webhooks) and writes the outcome back to your conversation store. The next agent turn finds the outcome and continues.
For batch / high-volume workloads, pattern 2 scales; pattern 1 keeps agent latency budget under control for single calls.
Consent pre-flight
Same rule as with Claude Agents — consent_type should be passed in
by your orchestration layer, not inferred by the model. See
Consent & opt-in.