Skip to content

DIDWW phone.systems integration

Yeti-Switch can be used as a front-end for the DIDWW phone.systems cloud PBX platform. In this scenario one Yeti installation covers three roles at once:

  • Interconnection SBC - all calls between the carriers and the customer's cloud PBX traverse Yeti, so the operator keeps a single point for media handling, number translations, CLI policies, capacity control and CDR collection.
  • Billing system - the PBX seat itself is charged as a Service, while the traffic is rated by the usual Yeti rateplans and rates.
  • Provisioning system - when the Service is created, Yeti calls the phone.systems Operator API and builds the whole customer configuration on the PBX side: customer, incoming trunk and - for services that are allowed to place outbound calls - termination gateway and termination route. When the Service is deleted, everything is removed again.

The integration is multitenant: the relation is always one Service - one phone.systems account, so a single Yeti installation provisions accounts of different customers as well as several accounts of the same customer, for example a separate PBX per branch office or department. Every Service gets its own phone.systems customer, incoming trunk, gateway and route, and its own gateway on the Yeti side.

This document explains how to configure such an integration.

Architecture

Call flows after provisioning:

  • Inbound (PSTN --> Yeti --> PBX) - a carrier delivers a call for the customer's DID number to Yeti. Yeti authenticates and rates it as usual, and the routing sends the call to the Yeti Gateway that points to the customer's incoming trunk domain on phone.systems.
  • Outbound (PBX --> Yeti --> PSTN) - phone.systems sends the call from the customer's termination gateway to Yeti. Yeti authenticates it with a Customer Auth object and routes it to the carriers according to the routing plan.

Prerequisites

This part is out of scope of this document, you have to complete these steps yourself:

  1. An operator account on phone.systems with the Operator API enabled. See https://doc.telecom.center/introduction.html.
  2. Operator API credentials (HTTP Basic username/password) and the API endpoint, for example https://api.telecom.center for production or https://api.sandbox.telecom.center for sandbox.
  3. A working Yeti installation reachable by phone.systems for outbound calls (public SIP signalling address, and RTP addresses opened for the phone.systems media subnets).
  4. At least one Codec Group created in Yeti - the provisioner assigns a codec group to the gateway it creates automatically.

Service Type configuration

Create a Service Type with Provisioning Class set to Billing::Provisioning::PhoneSystems. The Operator API credentials and the default customer attributes are stored in its Variables field as JSON:

{
  "endpoint": "https://api.telecom.center",
  "username": "operator_api_user",
  "password": "operator_api_password",
  "attributes": {
    "name": "Default customer name",
    "language": "EN",
    "trm_mode": "operator_customer",
    "capacity_limit": 100,
    "sip_account_limit": 50
  }
}
endpoint

Required. Base URL of the phone.systems Operator API. Trailing slash is stripped automatically.

username, password

Required. HTTP Basic credentials of the Operator API.

attributes

Required. Default attributes of the customer object on the phone.systems side.

name
Required. Customer name shown in the phone.systems UI.
language
Language of the phone.systems UI: EN, RU, LT or LV.
trm_mode
Outbound call handling mode of the customer, it defines which termination gateways and routes are available to the customer: customer or operator_customer.
capacity_limit
Maximum number of simultaneous calls of the customer.
sip_account_limit
Maximum number of SIP accounts the customer may create.

WARNING

The Service Type variables are validated when the Service Type is saved. Invalid or incomplete JSON is rejected with a validation error, so an invalid configuration can not be stored.

You may also put the trunk and gateway templates (ps_incoming_trunk, ps_trm_gw, described below) into the Service Type variables - they will be used as defaults for every Service of this type.

Set the UI Type field of the Service Type to phone_systems so that your customers can open their PBX from the Customer Portal, see Customer Portal integration below.

Service configuration

Create a Service on the customer's Account and select the Service Type created above. Service Variables define the per-customer part of the configuration:

{
  "attributes": {
    "name": "ACME Ltd",
    "language": "EN",
    "trm_mode": "operator_customer",
    "capacity_limit": 10,
    "sip_account_limit": 5
  },
  "ps_incoming_trunk": {
    "transport_protocol_id": 1,
    "codecs": ["PCMA", "PCMU", "g729", "telephone-event"],
    "destination_field": "RURI_USERPART"
  },
  "ps_trm_gw": {
    "host": "sip.example.com",
    "port": 5060,
    "authorization_name": "acme_ltd",
    "authorization_password": "secret_password",
    "codecs": ["PCMA", "PCMU", "g729", "telephone-event"]
  }
}
attributes

Required. Attributes of the customer created on the phone.systems side. Only name is mandatory. These values are sent as-is, the Service Type attributes are not merged into them - always specify the full set of attributes you need here.

ps_incoming_trunk

Attributes of the incoming trunk created on the phone.systems side. The trunk name is generated by Yeti and can not be overridden.

transport_protocol_id

Numeric id of the SIP transport: 1 - UDP, 2 - TCP, 3 - TLS. Defaults to 1 (UDP).

codecs

List of codec names, in priority order. The array is forwarded to the Operator API as-is and the names are matched exactly, the matching is case sensitive: OPUS, PCMU, PCMA, g722, g729, telephone-event. Note that g722 and g729 are lowercase and that there is no GSM.

A name outside this list makes the whole array invalid and the request is rejected with codecs - is invalid. A valid name can still be refused with codecs - contains not allowed values - that means the codec is not part of the set your operator account allows for this customer.

If the list is omitted, phone.systems applies the default codec set of the customer, which is always inside the allowed set.

destination_field

Defines where phone.systems takes the called DID number from: RURI_USERPART (default) or TO_USERPART. It must match the way Yeti sends the number to the trunk.

ps_trm_gw

Attributes of the termination gateway created on the phone.systems side, this is the gateway the customer PBX uses to send calls to Yeti. The gateway name is generated by Yeti and can not be overridden. Useful attributes are host, port, codecs, authorization_name, authorization_password, network_protocol, transport_protocol_id and the number rewrite rules (src_rewrite_rule/src_rewrite_result, dst_rewrite_rule/dst_rewrite_result).

codecs uses the same case sensitive names as ps_incoming_trunk above.

WARNING

ps_trm_gw is what enables the outbound direction. If neither the Service nor the Service Type defines it, the provisioner creates no termination gateway and no termination route on phone.systems, and the customer is left with an inbound-only configuration: calls reach the PBX, but the PBX has no way to send calls back to Yeti. Define the block - host at the very least - for every Service that has to place outbound calls.

INFO

authorization_name and authorization_password are optional. What you define here is provisioned into the phone.systems gateway unchanged; each of the two fields you leave out is filled with a randomly generated 20-character string. Either way the resulting pair is written into the Incoming Auth Username / Incoming Auth Password fields of the ps-<service id> Yeti gateway as well, so both sides always carry the same credentials and there is nothing to copy by hand, see Outbound calls from the PBX.

Yeti touches only name and the two credentials; every other attribute of the block is forwarded to the Operator API as-is and is not validated locally - a wrong attribute name or value is reported by phone.systems, and the Service is not created.

WARNING

The Service Type variables and the Service variables are merged one level deep only. If both define ps_trm_gw, the Service block replaces the Service Type block completely instead of being merged into it - a Service block that lists only host silently drops the port, codecs, rewrite rules and credentials of the Service Type template. Repeat the full set of attributes in the Service block.

An authorization_name you define yourself has to be unique across the whole Yeti installation - Yeti identifies the calling gateway by the SIP authentication username, so two services sharing one authorization_name make the outbound authentication ambiguous. Generated credentials are unique per Service by construction, so leaving both fields out avoids the problem altogether.

endpoint, username, password

Optional. Override the Operator API connection settings of the Service Type for this particular Service.

Provisioning workflow

Everything happens synchronously while the Service is being saved, so any API error is reported right in the Yeti web interface and the Service is not created.

  1. Customer is created on phone.systems with the attributes from the Service variables. The Service id in Yeti and the customer id on phone.systems are kept identical.

  2. Incoming trunk named gw-<service UUID> is created and linked to the customer. phone.systems generates a unique domain for it, this domain is where Yeti has to send inbound calls.

  3. Termination gateway named gw-<service UUID> is created and linked to the customer - this is how the PBX reaches Yeti. It carries the ps_trm_gw attributes, with the authorization_name/authorization_password pair either taken from that block or generated. This step is skipped when ps_trm_gw is not defined.

  4. Yeti Gateway named ps-<service id> is created with:

    • Host - the incoming trunk domain returned in step 2
    • Contractor - the contractor that owns the Service Account
    • Enabled - yes
    • Codec Group - the first codec group found in the database
    • Incoming Auth Username, Incoming Auth Password - the very same pair that was provisioned into the termination gateway in step 3, so that the PBX can authenticate on Yeti. Both stay empty when ps_trm_gw is not defined.

    WARNING

    The codec group is picked automatically and is not configurable. Review the created gateway and adjust the codec group, transport, capacity and other parameters to match the codec set you configured in ps_incoming_trunk.

  5. Termination route named gw-<service UUID> is created on phone.systems, linking the customer to the termination gateway from step 3. Skipped as well when ps_trm_gw is not defined - there is no gateway for the route to point at.

Deprovisioning

Deleting the Service deletes the customer on phone.systems, and the incoming trunk, termination gateway and termination route are removed together with it as dependent objects. The Yeti gateway ps-<service id> is deleted as well.

INFO

If the customer no longer exists on the phone.systems side, the web interface shows the warning "The Customer already deleted from the Phone Systems server" and deletes the Yeti Service anyway.

Yeti-side configuration

The provisioner creates the gateway only. The routing and authentication objects around it are not generated automatically and have to be configured by the operator.

Outbound calls from the PBX

The credentials the PBX uses to authenticate on Yeti are stored on the Gateway object, not on the Customer Auth. On the ps-<service id> gateway they are already in place:

Incoming Auth Username, Incoming Auth Password
Filled in by the provisioner with the authorization_name and authorization_password of ps_trm_gw, or with the pair it generated for it - the same credentials that were provisioned into the customer's termination gateway on the phone.systems side. Read them from the gateway when you need to hand them to the customer; change them only together with the phone.systems side.

WARNING

Both fields stay empty when ps_trm_gw is not defined, because in that case there is no termination gateway on the phone.systems side and no outbound direction at all. The Customer Auth below can not be saved with Require Incoming Auth enabled against such a gateway - add ps_trm_gw to the Service and recreate it instead of filling the credentials in by hand.

Then create a Customer Auth for the customer with:

Gateway
The ps-<service id> gateway - its incoming auth credentials are the ones Yeti will validate.
Require Incoming Auth
Should be YES so that Yeti challenges the calls coming from the PBX. Alternatively leave it NO and authenticate by the phone.systems signalling IP addresses instead.
Account
The Account the Service belongs to, so both the PBX seat fee and the outbound traffic are charged to the same account.
Routing Plan, Rateplan
As usual - they define the destinations available to this customer and their prices.

Inbound calls to the PBX

Route the customer's DID numbers to the ps-<service id> gateway by creating a Dialpeer per DID number or per number range, with this gateway and the Prefix matching the DID. The dialpeer has to be reachable from the routing plan used by the originating carrier's Customer Auth.

Make sure the number format Yeti sends matches the destination_field setting of the incoming trunk - with the default RURI_USERPART phone.systems looks the DID up in the R-URI user part. Use numbers translations on the gateway if the carrier delivers the number in a different format.

DID numbers on the phone.systems side

Provisioning of the DID numbers into the customer's phone.systems account is a separate operation. The numbers are pushed with the Operator API call POST /api/rest/public/operator/available_did_numbers, where the number attribute holds the DID and the customer relationship holds the id of the customer created by the provisioner - which is the same value as the Yeti Service id.

WARNING

The Billing::Provisioning::PhoneSystems provisioner itself does not create DID numbers - it only creates the customer, the trunks and the routes. Add the numbers to the customer either from the phone.systems operator UI or with your own Operator API integration, and route them in Yeti as described above.

Once the number is present in the customer's account, the customer assigns it to a call flow, SIP account or ring group in the phone.systems UI.

Customer Portal integration

The Customer Portal is the single place where your customer works with the service. There they see everything Yeti holds about them - CDRs and CDR exports, invoices, payments and transactions, origination and termination statistics, active calls, rates and rateplans - and from the same portal they open their phone.systems account, without a separate phone.systems login and password.

To enable this, set the UI Type field of the Service Type to phone_systems:

phone_systems

WARNING

The value must be exactly phone_systems. With any other value, or with an empty UI Type, the service is listed in the Customer Portal as a regular service and the sign-in button is not displayed.

After that, on the Services page of the Customer Portal every service of this type gets a Sign in button in the Actions column, with the "redirect to phone.systems" tooltip. Clicking it signs the customer in to the phone.systems account that was provisioned for this particular service, and opens the phone.systems UI in a new browser tab. From there the customer manages their own PBX: SIP accounts, call flows, ring groups, voicemail and the DID numbers you provisioned into their account.

The sign-in works per service, so a customer that has several PBX services sees a separate button for each of them, each one leading to its own phone.systems account. A customer can only sign in to the services of their own accounts.

Troubleshooting

  • Provisioning errors returned by the Operator API are shown as a validation error of the Service in the web interface, with the detail field of the API error as the message. The Service is not created in that case.
  • Every provisioning request is written to the Yeti web application log, so failed payloads can be inspected there.
  • A Service can not be created if its Service Type variables do not pass validation - check endpoint, username, password and attributes.name first.
  • codecs - is invalid means one of the names in ps_incoming_trunk.codecs or ps_trm_gw.codecs is not a known codec name. The names are case sensitive - g722 and g729 are lowercase, OPUS, PCMU and PCMA are uppercase, and there is no GSM.
  • codecs - contains not allowed values means the names are correct but at least one codec is not enabled for this customer on the phone.systems side.
  • transport_protocol is not allowed means the integer transport_protocol_id (1 - UDP, 2 - TCP, 3 - TLS) was sent as a transport_protocol string.
  • If inbound calls fail on the phone.systems side while Yeti reports the call as answered by the gateway, verify that the number Yeti sends matches the trunk destination_field and that the DID number is added and enabled in the customer's phone.systems account.