Recipes← all recipesView on GitHub

Route a call to an AI agent

AI AgentsAI call answering

Point a phone number at an agent and let it answer.

Also called AI phone answering, point a number at a voice bot

call-fabric

The claim

Two requests bind a number you own to a SWML webhook resource that holds your agent’s URL. The first creates the resource. The second attaches the number’s phone route to it.

Why it holds

The number is bound to the resource rather than the URL. Moving the agent is then one update of the resource, however many numbers point at it.

How it works

POST /api/fabric/resources/swml_webhooks creates the resource. primary_request_url is the only required field, and it is where SignalWire fetches the document when a call arrives.

resource = client.fabric.swml_webhooks.create(
    name="support agent",
    primary_request_url=AGENT_URL,
    primary_request_method="POST",
    fallback_request_url=FALLBACK_URL,
)

The fallback is worth setting even though it is optional: it gives SignalWire a second URL to try when the primary request fails. Host it apart from the agent, or it shares the outage it exists to cover.

Then the number. assign_phone_route posts to the resource’s phone_routes, taking the route id and a handler:

client.fabric.resources.assign_phone_route(
    resource["id"], phone_route_id=PHONE_ROUTE_ID, handler="calling",
)

handler is calling or messaging, the spec’s UsedForType enum. The same resource type serves both, so a number routed for calls is not routed for texts, and the mistake is silent until somebody texts you.

The second request uses the id the first returned. That ordering is the whole shape of the recipe: there is no way to bind a number to a resource that does not exist yet.

Limitations

This points a number at an agent. It does not check the agent answers: a resource happily holds a URL that 404s, and the failure shows up as a call that goes nowhere.

Basic auth on your agent has to be in the URL you register, because the resource is the only place SignalWire learns it.

The TypeScript SDK prints a note on both calls, preferring its phoneNumbers.setSwmlWebhook, which writes the URL onto the number’s call handler directly. That is the older binding, and it skips the resource. This recipe keeps the two documented requests because the resource is the point; the note is the SDK’s preference, not an error.

What to change first

Set handler to messaging and call the number. Nothing answers, because the number is now routed for texts and the call has no handler at all.

Where this sits

Seen in a build

One of 8 recipes composed by Order status desk: one omnichannel AI agent for web chat and phone.