Have you heard about our latest addition to the Infobip API family, Calls? Our flexible and granular API has been designed to cater to any voice scenario you can think of without compromising performance.

Its granularity allows you to design your user journey exactly how you had it in mind. You don’t have to adapt to a particular scenario dictated by an API infrastructure.

In this blog post, we will discuss how to use the Calls API to make a one-on-one call using the conferencing feature.

Use case overview

Let’s use the Calls API to recreate the following scenario:

—————

A user calls a DID number and an application accepts the call. The application then creates a conference room and moves the call there. The user is informed that another call is being connected. While waiting for the second party to join the call, they can enjoy some music. In the meantime, the application makes a call to the other party. If they answer the call, the music stops, and both users can have a conversation. However, if the party doesn’t answer the call, the music stops and the first caller is informed that the other party was not able to join. The call than terminates.

—————

Tools you need

You’ll need an active Infobip account with an enabled Voice channel. You should also have your own application. However, if you want to test the Calls API without developing an application, use any online webhook simulator, like Beeceptor or Mocky.

Prepare your app to work with Infobip

To set up the Infobip environment, you’ll need to do these three things:

  • Declare the application you’re going to use.
  • Set up an authentication method (HMAC or Basic).
  • Expose the following webhooks: receiveUrl and eventUrl.

receiveUrl —> receives all CALL_RECEIVED events.

eventUrl —-> catches all events you have subscribed your app to.

Use the subscribedEvents field to pass the events you want to subscribe your app to. That way the Infobip platform knows which events it needs to send to the app.

curl -L -g -X POST 'https://{baseUrl}/calls/1/applications' \
-H 'Authorization: {authorization}' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
--data-raw '{
  "name": "Example application",
  "subscribedEvents": [
    "CALL_RECEIVED",
    "CALL_RINGING",
    "CALL_ESTABLISHED",
    "CALL_FINISHED",
    "CALL_FAILED",
    "CONFERENCE_CREATED",
    "CONFERENCE_FINISHED",
    "PARTICIPANT_JOIN_FAILED",
    "PARTICIPANT_JOINED",
    "PARTICIPANT_JOINING",
    "PARTICIPANT_REMOVED",
    "PLAY_FINISHED",
    "SAY_FINISHED"
  ],
  "webhook": {
    "receiveUrl": "https://www.example.com/receive",
    "eventUrl": "https://www.example.com/event"
  }
}'

Key points

  • baseUrl is a custom URL you’ll see in your Infobip account where you can also grab the API Key.
  • Familiarize yourself with the complete list of events to which you can subscribe your app.

The response will contain applicationId which you will then use for creating calls.

Answer a call and add it to a conference

In our scenario, it is the end user who calls the application, so we need to prepare it to answer a call. The app will first receive a CALL_RECEIVED event on its receiveUrl.

Then, it will extract the callId from the event, and pass it as a path parameter it in the POST answer method, which should leave you with a 200OK response with a status IN_PROGRESS.

curl -L -g -X POST 'https://{baseUrl}/calls/1/calls/{callId}/answer' \
-H 'Authorization: {authorization}' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
--data-raw '{}'

Once the call is live, we would have to transfer it into a conference. To do that, we need to first create one, and then add a call to it.

To create a conference, simply pass your application ID and give it a name. Make sure you do that, as otherwise, the name will be autogenerated.

curl -L -g -X POST 'https://{baseUrl}/calls/1/conferences' \
-H 'Authorization: {authorization}' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
--data-raw '{
  "name": "Example conference",
  "applicationId": "61c060db2675060027d8c7a6"
}'

Once the conference is created and you got its id from the response, use it to add an existing inbound call. All you need to do is to pass the conference ID and the call ID as path parameters.

curl -L -g -X POST 'https://{baseUrl}/calls/1/conferences/{conferenceId}/call/{callId}' \
-H 'Authorization: {authorization}' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json'

Interact with the caller during the conference

First and foremost, we want to make sure that the caller has joined the call successfully. To do so, we need to ensure we have received a PARTICIPANT_JOINED event that confirms it. Knowing that the caller is in the conference, we want to inform them that we are trying to connect another call. Finally, to make the waiting time pleasant, we want to play some relaxing whale sounds while the caller’s waiting.

  1. Use text-to-speech messaging to inform the caller about the call connect attempt.
curl -L -g -X POST 'https://{baseUrl}/calls/1/calls/{callId}/say' \
-H 'Authorization: {authorization}' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
--data-raw '{
  "text": "Hello, we are trying to connect another caller to this conference. Please wait and enjoy the sounds of nature.",
  "language": "en"
}'

As we want to be sure that our Say action has been completed, will wait for the PLAY_FINISHED event to arrive to our application, before we can proceed to the next action.

  1. Once we’re sure that the previous action is complete, we can add another one. We want to share some joyful nature sounds to make the waiting time easy peasy API squeezy. 😉 What you need here, is the call ID and a URL of the track you want to play or a file ID of the previously uploaded file in WAV format. If you’re worried that your track is too short, you can always set the loopCount parameter to specify how many times in a row the track should be played.
curl -L -g -X POST 'https://{baseUrl}/calls/1/calls/{callId}/play' \
-H 'Authorization: {authorization}' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
--data-raw '{
  "loopCount": 3,
  "content": {
    "fileId": "a8b4cc89-a2d7-4a4c-adaf-c7d921b9f52a",
    "type": "FILE"
  }
}'

Connect another party

Your original caller is happily waiting. You can now try to connect another party and add them to the conference.

While you’re at it, remember to also cater to the possibility that they may not pick up. If that happens, you’ll need to inform the caller about it and terminate the conference.

Add a new call to the conference

Let’s start with adding a new call to the conference we have just created and setting up a timeout period. After this specified period, the call is dropped if the other party doesn’t pick up.

We will use the connectTimeout field to set up the number of seconds to wait before dropping the call.

curl -L -g -X POST 'https://{baseUrl}/calls/1/conferences/{conferenceId}/call' \
-H 'Authorization: {authorization}' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
--data-raw '{
  "callRequest": {
    "endpoint": {
      "type": "PHONE",
      "phoneNumber": "447415784323"
    },
    "applicationId":"61e983736574eb453b06c922",
    "from": "4592457976",
    "connectTimeout": 60
  }
}'

The response we’ll get from this method will include the callId for the new call.

Once generated, all subsequent events received by the application can now be related to the original inbound call or to the new outbound call.

Stop playing music for the first caller

Regardless of whether the call is answered or not, we need to stop playing music for the first caller. We can also inform them that the other party is joining or is not joining the call.

To learn about the call status, we’re going to wait for the events the Infobip platform will send to our application, which in this particular case would be either a PARTICIPANT_JOINED or PARTICIPANT_JOINED_FAILED event.

We can then verify the payload of these events to check whether their callId matches the callId of the new call we’ve requested.

To stop playing music, we will fire the POST stop-play endpoint providing the conference ID as a path parameter.

curl -L -g -X POST 'https://{baseUrl}/calls/1/conferences/{conferenceId}/stop-play' \
-H 'Authorization: {authorization}' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json'

Inform the caller of the call status

Next, once the whales have stopped sparking joy in the original caller and we’ve received a PLAY_FINISHED event, we can proceed to the next action and inform the caller that another party is joining the call.

Alternatively, in the case of the PARTICIPANT_JOINED_FAILED event, we can inform them that the party has not picked up, and the conference will be terminated. We’ll use the POST say method, we’ve used before for both scenarios.

curl -L -g -X POST 'https://{baseUrl}/calls/1/calls/{callId}/say' \
-H 'Authorization: {authorization}' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
--data-raw '{
  "text": "Another caller is joining the call now.",
  "language": "en"
}'

And finally, as part of the scenario when the second party has not picked up, we will need to terminate the conference with the POST hangup method.

You don’t have to use this method if the conference actually happened. Once all callers hang up, the conference is automatically terminated.

curl -L -g -X POST 'https://{baseUrl}/calls/1/conferences/{conferenceId}/hangup' \
-H 'Authorization: {authorization}' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json'

And that’s basically it!

To sum up!

As you can see, there are a lot of possible scenarios you can explore with this use case that we haven’t delved into in this post.

You can record the conference. Choose the accent or the gender of your text-to-speech message. Add logic for muting a caller so that they can’t speak. Or you can deafen them so that they can’t hear other participants.

In the case of Calls API, the world is your oyster!