Handle a Call Queue

👍

You're ready for this tutorial if you've got the following:

A FreeClimb account
A registered application
A configured FreeClimb Number
Your tools and language installed


Node.js

In response to a POST request a number of PerCL actions may be supplied in the JSON encoded response. In this tutorial the Say, Pause and Enqueue PerCL actions are used to greet and enqueue the calling party. As part of the Enqueue PerCL action the InboundCallAction actionUrl is provided to process the selection results. In addition to the actionUrl the optional waitUrl InboundCallWait is also in the Enqueue PerCL action.

Create your package.json file and save in the root directory of your project:

{
  "name": "node-inbound-call-queue-tutorial",
  "version": "1.0.0",
  "dependencies": {
    "@freeclimb/sdk": "^1.0.0",
    "body-parser": "^1.19.0",
    "dotenv": "^8.1.0",
    "express": "^4.17.1"
  }
}

Install the package by running the following in the command line/terminal:

yarn install

Example code:

require('dotenv').config()
const express = require('express')
const bodyParser = require('body-parser')
const freeclimbSDK = require('@freeclimb/sdk')
 
const app = express()
app.use(bodyParser.json())
// Where your app is hosted ex. www.myapp.com
const host = process.env.HOST
const port = process.env.PORT || 3000
// your FreeClimb API credentials (available in the Dashboard) - be sure to set up environment variables to store these values
const accountId = process.env.ACCOUNT_ID
const apiKey = process.env.API_KEY
const freeclimb = freeclimbSDK(accountId, apiKey)
app.post('/incomingCall', (req, res) => {
  const options = {
    alias: 'Test',
    maxSize: 25
  }
  //Invoke method to create a queue with the options provided
  freeclimb.api.queues.create(options).then(queue => {
    // use created queue
    const enqueue = freeclimb.percl.enqueue(queue.queueId, `${host}/inboundCallAction`, `${host}/inboundCallWait`)
    const percl = freeclimb.percl.build(enqueue)
    res.status(200).json(percl)
  }).catch(err => { /* Handle Errors */ })
})

Upon invocation the Enqueue PerCL action the call will be enqueued and the InboundCallWait Url invoked; additional PerCL actions may accompany the response. In this tutorial the PerCL Say and GetDigits actions are used to provide instructions on how to exit the Queue. As part of the GetDigits PerCL action the CallDequeueSelect actionUrl is provided to process the results.

app.post('/inboundCallWait', (req, res) => {
  const queueId = req.params.queueId
  const callId = req.body.callId
 
  // Create PerCL say script
  const say = freeclimb.percl.say('Press any key to exit queue.')
  // Create options for getDigits script
  const prompts = freeclimb.percl.build(say)
  const options = {
    prompts,
    maxDigits: 1,
    minDigits: 1,
    flushBuffer: true
  }
  // Create PerCL for getDigits script
  const getDigits = freeclimb.percl.getDigits(`${host}/callDequeue`, options)
  // Build and respond with Percl script
  const percl = freeclimb.percl.build(getDigits)
  res.status(200).json(percl)
})

Upon invocation completion of the GetDigits PerCL action, the CallDequeueSelect Url is invoked. If a GetDigits actions result is a digit, a PerCL Dequeue action is returned in the response. Otherwise, the PerCL Say, Play and GetDigits actions are used again to provide hold music as well as instruction on how to exit the Queue.

app.post('/callDequeue', (req, res) => {
  const getDigitsResponse = req.body
  const digits = getDigitsResponse.digits
  if (digits && digits.length > 0) {
    const dequeue = freeclimb.percl.dequeue()
    const percl = freeclimb.percl.build(dequeue)
    res.status(200).json(percl)
  } else {
    const redirect = freeclimb.percl.redirect(`${host}/inboundCallWait`)
    const percl = freeclimb.percl.build(redirect)
    res.status(200).json(percl)
  }
})

Upon invocation completion of the Dequeue PerCL action the CallDequeueSelect Url is invoked; additional PerCL actions may accompany the response. In this tutorial the PerCL Say and Hangup actions are used to indicate that the call was dequeued, as well as to disconnect the call.

app.post('/inboundCallAction', (req, res) => {
  const say = freeclimb.percl.say('Call exited queue')
  const percl = freeclimb.percl.build(say)
  res.status(200).json(percl)
})

Handle status updates:

// Specify this route with 'Status Callback URL' in App Config
app.post('/status', (req, res) => {
  // handle status changes
  res.status(200)
})

Start the server:

app.listen(port, () => {
  console.log('Listening on port ' + port)
})

Java

In response to a POST request a number of PerCL actions may be supplied in the JSON encoded response. In this tutorial the Say, Pause and Enqueue PerCL actions are used to greet and enqueue the calling party. As part of the Enqueue PerCL action the InboundCallAction actionUrl is provided to process the selection results. In addition to the actionUrl the optional waitUrl InboundCallWait is also in the Enqueue PerCL action.

Create your build.gradle file and save it to the root directory in your project:

/*
 * This file was generated by the Gradle 'init' task.
 *
 * This is a general purpose Gradle build.
 * Learn how to create Gradle builds at https://guides.gradle.org/creating-new-gradle-builds
 */

buildscript {
    repositories {
        mavenCentral()
        maven { url 'https://jitpack.io' }
    }
  //Add the dependency
    dependencies {
        classpath "org.springframework.boot:spring-boot-gradle-plugin:2.1.6.RELEASE"
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

bootJar {
    baseName = 'gs-spring-boot'
    version =  '0.1.0'
}

repositories {
    mavenCentral()
    maven { url 'https://jitpack.io' }
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile "org.springframework.boot:spring-boot-starter-web"
    testCompile "junit:junit"
    compile 'com.github.FreeClimbAPI:FreeClimb-Java-SDK:3.0.0'
}

sourceSets {
    main {
        java {
            srcDirs = ['src']
        }
    }
}

Build the file by running the following in your terminal/command line:

gradle build

Example code:

import com.vailsys.freeclimb.api.FreeClimbClient;
import com.vailsys.freeclimb.api.FreeClimbException;
import com.vailsys.freeclimb.api.call.CallStatus;
import com.vailsys.freeclimb.api.queue.Queue;
import com.vailsys.freeclimb.api.queue.QueueCreateOptions;
 
import com.vailsys.freeclimb.percl.PerCLScript;
import com.vailsys.freeclimb.percl.Say;
import com.vailsys.freeclimb.percl.Language;
import com.vailsys.freeclimb.percl.Pause;
import com.vailsys.freeclimb.percl.Enqueue;
 
import com.vailsys.freeclimb.webhooks.application.ApplicationVoiceCallback;
 
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

Example code:

//To properly communicate with FreeClimb's API, set your FreeClimb app's VoiceURL endpoint to '{yourApplicationURL}/InboundCall' for this example
//Your FreeClimb app can be configured in the FreeClimb Dashboard
@RequestMapping(value = {"/InboundCall"}, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<?> inboundCall(@RequestBody String request){
    //Create an empty PerCL script container
    PerCLScript script = new PerCLScript();
 
    try {
        //Create a FreeClimbClient object
        //accountId & api key can be found under API credentials on the FreeClimb Dashboard
        FreeClimbClient client = new FreeClimbClient(accountId, apiKey);
 
        if(request != null){
            //Convert the JSON into a request object
            ApplicationVoiceCallback callback = ApplicationVoiceCallback.createFromJson(request);
 
            //Verify inbound call is in the proper state
            if(callback.getCallStatus() == CallStatus.RINGING){
                //Create PerCL say script with US English as the language
                Say say = new Say("Hello. Your call will be queued.");
                say.setLanguage(Language.ENGLISH_US);
 
                //Add PerCL say script to PerCL container
                script.add(say);
 
                //Create PerCL pause script with a 100 millisecond pause
                script.add(new Pause(100));
 
                //Create Queue options with an alias
                QueueCreateOptions options = new QueueCreateOptions();
                options.setAlias("InboundCallQueue");
 
                //Create a queue with an alias
                Queue queue = client.queues.create(options);
                //Create PerCL say to enqueue the call into the newly created queue with an actionUrl
                Enqueue enqueue = new Enqueue(queue.getQueueId(), {yourApplicationURL} + "/InboundCallAction");
 
                //Add waitUrl
                enqueue.setWaitUrl({yourApplicationURL} + "/InboundCallWait");
 
                // Add PerCL enqueue script to PerCL container
                script.add(enqueue);
            }
        }
    }
    catch(FreeClimbException pe) {
        System.out.println(pe.getMessage());
    }
 
    //Convert PerCL container to JSON and append to response
    return new ResponseEntity<>(script.toJson(), HttpStatus.OK);
}

Upon invocation of the Enqueue PerCL action, the call will be enqueued and the InboundCallWait Url invoked; additional PerCL actions may accompany the response. In this tutorial the PerCL Say and GetDigits actions are used to provide instruction on how to exit the queue. As part of the GetDigits PerCL action, the CallDequeueSelect actionUrl is provided to process the results.

Imports used:

import com.vailsys.freeclimb.api.FreeClimbException;
 
import com.vailsys.freeclimb.percl.PerCLScript;
import com.vailsys.freeclimb.percl.Say;
import com.vailsys.freeclimb.percl.Language;
import com.vailsys.freeclimb.percl.GetDigits;
import com.vailsys.freeclimb.percl.GetDigitsNestable;
 
import com.vailsys.freeclimb.webhooks.queue.QueueWaitCallback;
 
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

Example code:

@RequestMapping(value = {"/InboundCallWait"}, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<?> inboundCallWait(@RequestBody String request){
    //Create an empty PerCL script container
    PerCLScript script = new PerCLScript();
     
    if (request != null) {
 
        try {
            // Convert the JSON into a request object
            QueueWaitCallback callback = QueueWaitCallback.createFromJson(request);
 
            //Create PerCL getdigits script
            GetDigits digits = new GetDigits({yourApplicationURL} + "/CallDequeueSelect");
 
            //Create a list of prompts to use with the getdigits command
            LinkedList<GetDigitsNestable> prompts = new LinkedList<>();
 
            //Create PerCL say script with US English as the language
            Say say = new Say("Thank you for waiting. Press any key to exit queue.");
            say.setLanguage(Language.ENGLISH_US);
 
            //Add say script to the list of prompts
            prompts.add(say);
 
            //Set the list as the prompts to use with the getdigits command
            digits.setPrompts(prompts);
 
            // Add PerCL getdigits script to PerCL container
            script.add(digits);
        }
        catch(FreeClimbException pe) {
            System.out.println(pe.getMessage());
        }
    }
 
    //Convert PerCL container to JSON and append to response
    return new ResponseEntity<>(script.toJson(), HttpStatus.OK);
}

Upon invocation completion of the GetDigits PerCL action the CallDequeueSelect Url is invoked. If a GetDigits action result is a digit, a PerCL Dequeue action is returned in the response. Otherwise, the PerCL Say and GetDigits actions are used again to provide continuous instruction on how to exit the Queue.

Imports used:

import com.vailsys.freeclimby.api.FreeClimbyException;
 
import com.vailsys.freeclimb.percl.PerCLScript;
import com.vailsys.freeclimb.percl.Say;
import com.vailsys.freeclimb.percl.Language;
import com.vailsys.freeclimb.percl.GetDigits;
import com.vailsys.freeclimb.percl.GetDigitsNestable;
import com.vailsys.freeclimb.percl.Dequeue;
 
import com.vailsys.freeclimb.webhooks.percl.GetDigitsActionCallback;
 
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

Example code:

@RequestMapping(value = {"/CallDequeueSelect"}, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<?> callDequeue(@RequestBody String request){
    //Create an empty PerCL script container
    PerCLScript script = new PerCLScript();
 
    if (request != null) {
        try {
            // Convert JSON into a request object
            GetDigitsActionCallback callback = GetDigitsActionCallback.createFromJson(request);
 
            // Check if a digit was pressed
            if(callback.getDigits() != null && callback.getDigits().length() > 0) {
                // Create PerCL dequeue script and add to PerCL container
                script.add(new Dequeue());
            } else {
                //Create PerCl getdigits script
                GetDigits digits = new GetDigits({yourApplicationURL} + "/CallDequeueSelect");
 
                // Create a list of prompts to use with the getdigits command
                LinkedList<GetDigitsNestable> prompts = new LinkedList<>();
 
                // Create PerCL say script with US English as the language
                Say say = new Say("Thank you for waiting. Press any key to exit queue.");
                say.setLanguage(Language.ENGLISH_US);
 
                // Add say script to prompts list
                prompts.add(say);
 
                //Add prompts list to the getdigits command
                digits.setPrompts(prompts);
 
                //Add PerCL getdigits script to PerCL container
                script.add(digits);
            }
        }
        catch(FreeClimbException pe) {
            System.out.println(pe.getMessage());
        }
    }
 
    //Convert PerCL container to JSON and append to response
    return new ResponseEntity<>(script.toJson(), HttpStatus.OK);
}

Upon invocation completion of the Dequeue PerCL action the InboundCallAction Url is invoked; additional PerCL actions may accompany the response. In this tutorial the PerCL Say and Hangup actions are used to indicate that the call was dequeued, as well as to disconnect the call.

Imports used:

import com.vailsys.freeclimb.api.FreeClimbException;
 
import com.vailsys.freeclimb.percl.PerCLScript;
import com.vailsys.freeclimb.percl.Say;
import com.vailsys.freeclimb.percl.Language;
import com.vailsys.freeclimb.percl.Hangup;
 
import com.vailsys.freeclimb.webhooks.queue.QueueActionCallback;
 
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

Example code:

@RequestMapping(value = {"/InboundCallAction"}, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<?> dequeueAction(@RequestBody String request){
    //Create an empty PerCL script container
    PerCLScript script = new PerCLScript();
     
    if (request != null) {
        //Convert JSON into a request object
        try {
            QueueActionCallback callback = QueueActionCallback.createFromJson(request);
 
            //Create PerCL say script with US English as the language
            Say say = new Say("Call exited queue.");
            say.setLanguage(Language.ENGLISH_US);
 
            // Add PerCL say script to PerCL container
            script.add(say);
 
            //Create and add PerCL hangup script to PerCL container
            script.add(new Hangup());
        }
        catch(FreeClimbException pe) {
            System.out.println(pe.getMessage());
        }
    }
 
    //Convert PerCL container to JSON and append to response
    return new ResponseEntity<>(script.toJson(), HttpStatus.OK);
}

C#

In response to a POST request a number of PerCL actions may be supplied in the JSON encoded response. In this tutorial the Say, Pause and Enqueue PerCL actions are used to greet and enqueue the calling party. As part of the Enqueue PerCL action the InboundCallAction actionUrl is provided to process the selection results. In addition to the actionUrl the optional waitUrl InboundCallWait is also in the Enqueue PerCL action.

Example code:

[HttpPost("InboundCall")]
public ActionResult InboundCall (CallStatusCallback freeClimbRequest) {
  // Create an empty PerCL script container
  PerCLScript script = new PerCLScript ();
  // Verify inbound call is in proper state
  if (freeClimbRequest.getCallStatus == ECallStatus.Ringing) {
    // Create PerCL say script with US English as the language
    Say say = new Say ();
    say.setLanguage (ELanguage.EnglishUS);
    // Set greeting prompt
    say.setText ("Hello. Your call will be queued.");

    // Add PerCL say script to PerCL container
    script.Add (say);

    // Create PerCL pause script with a 100 millisecond pause
    script.Add (new Pause (100));

    // Create queue options with an alias
    QueueOptions options = new QueueOptions ();
    options.setAlias ("InboundCallQueue");

    // Create FreeClimbClient object
    FreeClimbClient client = new FreeClimbClient (getFreeClimbAccountId (), getFreeClimbApiKey ());

    // Create a queue with an alias
    Queue queue = client.getQueuesRequester.create (options);

    // Create PerCL say to enqueue the call into the newly created queue with an actionUrl
    Enqueue enqueue = new Enqueue (queue.getQueueId, getAppUrl() + "/voice/InboundCallAction");
    // Add waitUrl
    enqueue.setWaitUrl (getAppUrl() + "/voice/InboundCallWait");

    // Add PerCL enqueue script to PerCL container
    script.Add (enqueue);
  }

  // Convert PerCL container to JSON and append to response
  return Content (script.toJson (), "application/json");
}

Upon invocation of the Enqueue PerCL command the call will be enqueued and the InboundCallWait Url invoked; additional PerCL actions may accompany the response. In this tutorial the PerCL Say, Play and GetDigits actions are used to provide hold music as well as instruction on how to exit the Queue. As part of the GetDigits PerCL action the CallDequeueSelect actionUrl is provided to process the results.

Example code:

[HttpPost("InboundCallWait")]
public ActionResult InboundCallWait (QueueWaitCallback queueWaitStatusCallback) {
  // Create an empty PerCL script container
  PerCLScript script = new PerCLScript ();
  // Create PerCL getdigits script
  string getDigitsUrl = Url.Action (getAppUrl() + "/voice/CallDequeueSelect");
  GetDigits digits = new GetDigits (getDigitsUrl); // actionUrl

  // Create PerCL say script with US English as the language
  Say say = new Say ();
  say.setLanguage (ELanguage.EnglishUS);
  // Add prompt to for queue exit
  say.setText ("Press any key to exit queue.");

  // Add say script as a prompt to getdigits
  digits.setPrompts (say);

  // Add PerCL getdigits script to PerCL container
  script.Add (digits);

  // Convert PerCL container to JSON and append to response
  return Content (script.toJson (), "application/json");
}

Upon invocation completion of the GetDigits PerCL action the CallDequeueSelect Url invoked. If a GetDigits action result is a digit, a PerCL Dequeue action is returned in the response. Otherwise, the PerCL Say, Play and GetDigits actions are used again to provide hold music as well as instruction on how to exit the Queue.

Example code:

[HttpPost("CallDequeueSelect")]
public ActionResult CallDequeueSelect (GetDigitsActionCallback getDigitsStatusCallback) {
  // Create an empty PerCL script container
  PerCLScript script = new PerCLScript ();
  if ((getDigitsStatusCallback.getDigits != null) &&
      (getDigitsStatusCallback.getDigits.Length > 0)) {
    // Create PerCL dequeue script and add to PerCL container
    script.Add (new Dequeue ());
  } else {
    // Create PerCL getdigits script
    GetDigits digits = new GetDigits (getAppUrl() + "/voice/CallDequeueSelect");

    // Create PerCL say script with US English as the language
    Say say = new Say ();
    say.setLanguage (ELanguage.EnglishUS);
    // Add prompt to for queue exit
    say.setText ("Press any key to exit queue.");

    // Add say script as a prompt to getdigits
    digits.setPrompts (say);

    // Add PerCL getdigits script to PerCL container
    script.Add (digits);
  }
  // Convert PerCL container to JSON and append to response
  return Content (script.toJson (), "application/json");
}

Upon invocation completion of the Dequeue PerCL action the CallDequeueSelect Url is invoked; additional PerCL actions may accompany the response. In this tutorial the PerCL Say and Hangup actions are used to indicate the call was dequeued as well as to disconnect the call.

Example code:

[HttpPost("InboundCallAction")]
public ActionResult InboundCallAction (QueueActionCallback queueActionStatusCallback) {
  // Create an empty PerCL script container
  PerCLScript script = new PerCLScript ();

  // Create PerCL say script with US English as the language
  Say say = new Say ();
  say.setLanguage (ELanguage.EnglishUS);
  // Add prompt for queue exit
  say.setText ("Call exited queue.");

  // Add PerCL say script to PerCL container
  script.Add (say);

  // Create and add PerCL hangup script to PerCL container
  script.Add (new Hangup ());

  // Convert PerCL container to JSON and append to response
  return Content (script.toJson (), "application/json");
}