Create a SIP address that rings a hosted AI agent, so a SIP phone or PBX can reach it without a phone number in between.
restsip
The claim
A hosted resource is reachable two ways: by a phone number pointed at it, or by a SIP address. This recipe makes the second one. The response carries the uri, and that string is the whole integration on the PBX side.
Why it holds
The vendored REST spec, tools/openapi/rest.json, is the authority.
POST /api/fabric/sip_addresses requires name and calling_handler_resource_id. The name is “lowercase letters, numbers, and hyphens only” and “is used to build the address’s SIP URI”. The recipe refuses anything else before sending.
user defaults to *, which “accepts any username”. Set it when the PBX should reach the agent by one specific username.
encryption is required, optional or forbidden. The recipe asks for required.
codecs defaults to PCMU and PCMA, and ip_auth_enabled to false. The recipe leaves both alone.
Neither SDK wraps this path in the versions pinned here. The request goes through the HTTP client every namespace shares, as the subproject recipes do.
How it works
NAME_SHAPE = re.compile(r"^[a-z0-9-]+$")
def give_address(resource_id, name, user=None, encryption="required"):
if not NAME_SHAPE.match(name):
raise ValueError(...)
body = {"name": name, "calling_handler_resource_id": resource_id,
"encryption": encryption}
if user:
body["user"] = user
return http.post("/api/fabric/sip_addresses", body=body)
The response’s uri is what you dial. Its context says which domain the address lives under, public for the project’s default. With the default user, any username at that domain reaches the agent. With user set, only that one does.
Limitations
The verifier proves the request, not the call. Whether a given PBX accepts the URI, negotiates SRTP and reaches the agent is live behaviour.
password is write-only and never returned. A registration password belongs in your secrets, not in this recipe’s arguments.
What to change first
Change encryption="required" to "always" and run the verifier. The exact body comparison fails on a value outside the enum, which is the point. Three values are the whole vocabulary.