Example: switchboard

Install DotSIP, open the web admin, connect real SIP, and decide each call from your own HTTP API.

This is a complete switchboard with no voice agent. The caller hears a recording. Press 1 and the call goes to the director. Press 2 and another recording says the opening hours, then the call ends. If nobody presses a key, the call ends.

1. Record two files

Record welcome.wav: “You have reached Example Company. Press 1 for the director. Press 2 for opening hours.” Record hours.wav: “We are open from 8 to 16. Goodbye.”

Export each file as one-channel 16-bit PCM WAV at 16000 Hz. Copy them to data/media in the DotSIP folder:

data/media/welcome.wav
data/media/hours.wav

2. Create the director’s phone

Open SIP phones and add an extension whose number is 200. Register the director’s IP phone to DotSIP with that number and its password. The transfer step uses 200.

3. Point the route at your server

Under SIP accounts, the trunk that receives the call. Set its inbound route to route-tools, or leave that field empty so the call uses route-tools.

Open Routes, edit route-tools, and set the URL to http://127.0.0.1:9099/route when the server runs on the same machine. Save. The license must allow SIP, and the initial password reminder must be cleared, or lines will not register. See First run and license.

4. The plan DotSIP should receive

Your server answers the route POST with this JSON and HTTP 200. The menu is in the plan, so this call does not need a second webhook.

{
  "format": "dotsip.route-result",
  "format_version": 2,
  "commands": [
    { "do": "answer" },
    { "do": "play", "media": "welcome.wav" },
    {
      "do": "gather",
      "max_digits": 1,
      "timeout_ms": 20000,
      "digits": {
        "1": [ { "do": "transfer", "phone": "200" } ],
        "2": [
          { "do": "play", "media": "hours.wav" },
          { "do": "wait", "ms": 8000 },
          { "do": "hangup" }
        ],
        "timeout": [ { "do": "hangup" } ]
      }
    }
  ]
}

welcome.wav plays to the end, because barge_in is not set and the default is false. The keypad step starts after that recording. timeout_ms is 20 seconds from the start of gather. The hours recording is followed by an 8 second wait so the caller hears it before hangup. Change ms if your file is longer. A missing or invalid WAV is skipped.

5. Your database

This file is yours. It is not data/dotsip.sqlite. Digit 1 transfers to the target phone. Digit 2 plays the target file. The welcome row is the first recording.

CREATE TABLE menu (
  digit TEXT PRIMARY KEY,
  kind TEXT NOT NULL,
  target TEXT NOT NULL
);
INSERT INTO menu(digit, kind, target) VALUES
  ('welcome', 'play', 'welcome.wav'),
  ('1', 'transfer', '200'),
  ('2', 'play', 'hours.wav');

6. Your server

PHP, Python, and Node.js read those rows and return the same plan. Switch the language above the sample. Change the director by updating the row for digit 1. Restarting DotSIP is not required.

<?php
$db = new PDO("sqlite:" . __DIR__ . "/operator.sqlite");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->exec("CREATE TABLE IF NOT EXISTS menu (digit TEXT PRIMARY KEY, kind TEXT NOT NULL, target TEXT NOT NULL)");
$db->exec("INSERT OR IGNORE INTO menu(digit, kind, target) VALUES
  ('welcome', 'play', 'welcome.wav'), ('1', 'transfer', '200'), ('2', 'play', 'hours.wav')");
$body = json_decode(file_get_contents("php://input"), true);
header("Content-Type: application/json");
if (!is_array($body) || (isset($body["format"]) ? $body["format"] : "") !== "dotsip.route") {
    http_response_code(400);
    echo json_encode(array("error" => "bad request"));
    return;
}
$welcome = $db->query("SELECT target FROM menu WHERE digit = 'welcome'")->fetchColumn();
$director = $db->query("SELECT target FROM menu WHERE digit = '1'")->fetchColumn();
$hours = $db->query("SELECT target FROM menu WHERE digit = '2'")->fetchColumn();
echo json_encode(array(
    "format" => "dotsip.route-result",
    "format_version" => 2,
    "commands" => array(
        array("do" => "answer"),
        array("do" => "play", "media" => $welcome, "barge_in" => false),
        array(
            "do" => "gather",
            "max_digits" => 1,
            "timeout_ms" => 20000,
            "digits" => array(
                "1" => array(array("do" => "transfer", "phone" => $director)),
                "2" => array(
                    array("do" => "play", "media" => $hours, "barge_in" => false),
                    array("do" => "wait", "ms" => 8000),
                    array("do" => "hangup"),
                ),
                "timeout" => array(array("do" => "hangup")),
            ),
        ),
    ),
));

7. Place a test call

  1. Start your route server and confirm DotSIP can open its URL.
  2. Call the SIP account that registers to your trunk.
  3. You should hear the welcome recording. Press 1. The director’s phone 200 should ring.
  4. Call again and press 2. You should hear the hours recording, then the call ends.
  5. Call again and press nothing. After the gather time, the call ends.

Open Call debugging if the recording never starts. A skipped file means the WAV is missing, not mono, not 16-bit PCM, or not 8000, 16000, or 24000 Hz.

To hand the same menu to a live agent, add a key whose command is agent. The next page builds that desk: Example: appointments.