An IP-authenticated Domain Application takes inbound SIP from your PBX and a SIP Gateway carries calls back to it.
Also called SIP trunk, FreePBX, 3CX, Asterisk, FusionPBX
sipbyoc
The claim
Bring-your-own-PBX is two resources, both created over REST. *Inbound (PBX → SignalWire): a Domain Application is a SIP domain, <identifier>.dapp.signalwire.com. It accepts INVITEs from the IP addresses you list and runs a SWML document for each call. Outbound (SignalWire → PBX): a SIP Gateway* is a Fabric resource with an address (/private/<name>) that any SWML can connect to. SignalWire delivers the call to the PBX’s SIP URI. Neither side needs SIP registration or credentials: the PBX trusts by IP, SignalWire trusts by IP.
The Domain Application bridges the incoming call with connect, using ${call.to} as the destination. That value is the PSTN number the PBX dialled. In the other direction, the SWML a PSTN number runs to reach the PBX is connect: { to: "/private/acme-pbx-gateway" }. Put an ai verb in either document and the PBX has an AI agent behind an extension.
The typed RestClient wraps SIP Gateways but not Domain Applications, so that one call goes through the client’s authenticated HTTP layer by path. Registering individual SIP phones instead of a trunk is register-a-sip-endpoint-and-receive-calls; a FreeSWITCH box has its own connector resource (connect-freeswitch-to-signalwire).
What to change first
Replace connect: { to: "${call.to}" } in the inbound document with an ai verb: every extension on the PBX can now dial an AI agent by number.