Create SIP credentials for a softphone, register it as an endpoint, and route calls to its address.
Also called SIP registration, softphone or desk phone, Grandstream, Zoiper
sipcall-fabric
The claim
The vendored REST spec’s POST /api/fabric/resources/subscribers/{fabric_subscriber_id}/sip_endpoints “Create Subscriber SIP credential” requires exactly username and password. It also takes caller_id, send_as, ciphers, codecs and encryption, whose values are required, optional or default. The subscriber it hangs off is one POST /api/fabric/resources/subscribers with an email, and GET /api/fabric/resources/{id}/addresses lists the subscriber’s Fabric address. The bundled schema lists a “Call Fabric Resource address” among the forms connect.to takes. A document that connects to that address therefore sends a call to whatever registered with the credential. Whether it rings is the platform’s side of a live call. You reach the REST calls as client.fabric.subscribers.create, list_addresses and create_sip_endpoint.
How it works
def add_sip_credential(subscriber_id, username=SIP_USERNAME, password=SIP_PASSWORD,
caller_id=CALLER_ID):
if not password:
raise SystemExit("SIP_PASSWORD is required; see .env.example")
return client.fabric.subscribers.create_sip_endpoint(
subscriber_id, username=username, password=password, caller_id=caller_id)
def ring(address, service=None):
service = service or SWMLService(name="ring", route="/ring")
service.add_verb("answer", {})
service.add_verb("connect", {"to": address, "timeout": 30})
service.add_verb("hangup", {})
return service
What the platform receives:
POST /api/fabric/resources/subscribers
{"email": "workshop@ridgeline.example", "display_name": "Workshop desk"}
GET /api/fabric/resources/<resource_id>/addresses
POST /api/fabric/resources/subscribers/<resource_id>/sip_endpoints
{"username": "workshop-desk", "password": "<from SIP_PASSWORD>", "caller_id": "+1555XXXXXXX"}
And the document a number runs, with the address from the listing:
The function reads the password from SIP_PASSWORD when it runs, and a missing one stops the call before any request. The recipe leaves ciphers, codecs and encryption at the platform’s defaults; set them when your softphone needs a particular one.
Limitations
You prove the requests, the shapes and the document. Whether the softphone registers and rings, and which SIP domain it registers against, are the platform’s side. The domain is in your Dashboard, not in the vendored spec.
The spec also documents POST /api/fabric/resources/sip_endpoints, a credential that is not under a subscriber. Its documented required list includes fields a create cannot supply, such as id, so this recipe uses the subscriber form.
What to change first
Pass encryption="required" in add_sip_credential and run the verifier. The exact-body assertion fails, and the enum assertion says the value is legal. Put it in the expected body too, and the same document rings a softphone that only registers over TLS.