Using the Calls API

You can integrate your calls with Slack so that they're more interactive, less intrusive, and easier for users to join.

Your call app will appear in the Slack client natively, under the Call icon if you choose.

Whenever someone starts or shares a call, it appears in Slack with all the bells and whistles: a list of participants, a join button, and information about the call.

Overview

The Calls API provides a way for your call app to tell Slack about the calls you're making between users.

It's important to know that Slack doesn't make the call. The API allows you to do your work and include your call, pleasantly and productively, within the Slack client. In exchange, Slack allows users to start, end, and enter your Calls from inside Slack.

Quick note: just to make things clearer, we'll talk about your app's 3rd-party call with a lowercase "c", while the full Call inside Slack is capitalized.

Slack also shows off your call natively, with lists of participants, a join button, and metadata.

Image of a call object generated from a link

There are two ways for your app to integrate with Slack so that users can initiate and deal with Calls within Slack.

One way for a user to initiate your app is via a Slash command—for example, by typing /mycallapp into the message composer. The other way for a user to initiate your app is directly via the Call icon.

Luckily, these two interaction patterns work the same for your app. Once you decide on one or the other, only the app setup is different. The payloads you receive are the same, and the way that you use the API methods to inform Slack about your calls remains the same as well.

App setup

Users of non-partnered apps will need to initiate Calls using a slash command.

To get started, create your Slack app. Under the Add features and functionality header, select the Slash Commands button and then Create a New Command. Setting up your slash command app here is exactly the same as documented in the slash command documentation.

Don't worry too much about the Request URL (the URL where Slack will send information about users interacting with calls to your app). You can change that later. You can also change the name of the command later.

You'll need two scopes for interacting with calls:

Request these two scopes under the OAuth & Permissions sidebar on the left (scroll down to the Scopes section). Then click the Install App to Workspace button. You're all setup to work with Calls.

Call functions: dialing to hanging up and everything in between

If you want to give users a smartphone for their calling needs, there are several different features you'll want to provide. Initiating and rejecting a Call are the starting point, but far more can happen.

The five main actions that a smart Call app has to handle are: initiation of a Call, unfurling a link to a Call, responding to a rejected Call, updating Call info and adding/removing participants, and finally hanging up a Call.

Next we're going to go through each in a bit more detail, starting with Call initiation.

Responding to a Call initiation

When a user initiates a call with your app, either by using a slash command or the Call icon, Slack sends a payload to your app.

For example, if the call is initiated with the Call icon, your app might receive the following in an HTTP POST request:

{
    "token": "<verification token>",
    "team_id": "T123ABC456",
    "team_domain": "my-team",
    "channel_id": "C123ABC456",
    "channel_name": "test",
    "user_id" : "U123ABC456",
    "user_name": "mattjones",
    "response_url":"https://slack.com/callback/123xyz",
    "type": "video"
}

If the call is initiated with a slash command (e.g., /mycall), expect a normal Slash command payload sent to your app instead.

In turn, your app makes two responses. Well, maybe three, if you include posting the Call to channel afterward!

1. Immediate response

First up is an immediate, synchronous response within 3 seconds. This quick ack tells Slack where to send the calling user. Post your response to the response_url indicated in the payload you receive.

In the example above, you'd respond by pinging https://slack.com/callback/123xyz with:

{
    "response_type":"call",
    "call_initiation_url":"https://join.call.com/123456",
    "desktop_protocol_call_initiation_url": "call://join&room_id=123456"
}

The specified call_initiation_url will be automatically opened for the initiating user in a separate window.

Sometimes, you might prefer to use a custom URL scheme to launch your app in desktop directly. If you wish, include the desktop_protocol_call_initiation_url optional field, representing the URL that will be used to launch your calls app directly. If you don't include it, Slack will fallback by launching call_initiation_url in a new browser window.

You'll always need to include the regular call_initiation_url in case a user doesn't have, or doesn't want, your app to be launched in desktop.

A type might be included in the payload sent to your app to indicate whether the call should be audio or video. For video, you don't need to do anything special except make sure your initiation URL begins a video. For audio, you'll receive a phone_number, and you'll want to make use of that in your response to Slack.

Example response:

{
    "response_type": "audio",
    "call_initiation_url": "https://your_company_url/...",
    "desktop_protocol_call_initiation_url": "your_call_app_url://+1-202-555-0145"
}

2. Register the call with Slack

After you've made your quick response to Slack with a redirect call_initiation_url, you'll want to actually register the details of the call with Slack. Use the calls.add method to add the Call to Slack.

You'll receive an id from Slack in the response. Make sure you store the Call's id, since you'll need it to reference the call if you want to update or end the Call.

3. Post the Call to channel

As a courtesy, post the Call to channel so the people in it know about the Call! Use chat.postMessage with a call block:

"blocks": [
    {
        "type": "call",
        "call_id": "R123",
    }
]

Your app might not have permission to post to private channels, MPDMs, or DMs in order to post a call block via the usual chat.postMessage method. In that case, use the in_channel slash command response type. This posts a message directly to the channel the slash command request originated from, and can include a call block:

{
    "response_type": "in_channel",
    "text": "A new call was started by <name of call provider>",
    "blocks": [{
        "type": "call",
        "call_id": "R123",
    }]
}

A note on users

When you register a Call with calls.add, add participants with calls.participants.add, or remove them with calls.participants.remove, you'll notice a users parameter.

Each method requires user objects to include either a slack_id or external_id, or both.

A slack_id is the id of the user in Slack—you might receive this when interacting with any Slack API method, such as conversations.members. An external_id may be used if you don't know the slack_id for your users. In this case, external_id is a unique id created by your app for your users.

Here's an example users array containing two users identified in those two distinct ways:

[
    {
        "slack_id": "U123ABC456",
    },
    {
        "external_id": "54321678",
        "display_name": "Kim Possible",
        "avatar_url": "https://callmebeepme.com/users/avatar1234.jpg"
    }
]

If you aren't using the application/json Content-type, remember to encode users appropriately for the Content-type you send.

Unfurling a link to a Call

Subscribe to the link_shared and call_rejected events in your App configuration page under Event Subscriptions, if you haven't already. Remember to reinstall your app afterward.

Slack notifies your app with a link_shared event whenever a link from a specified domain (i.e., your app's domain representing calls) is shared.

Similar to Call initiation, your app should respond to the link_shared event with the calls.add method to register the call. You'll receive an id from Slack in the response. Make sure you store the Call's id, since you'll need it to reference the call here and elsewhere.

In this case, you'll then invoke the chat.unfurl method. That way, you unfurl a Call in channel, already populated with the Call's duration and participants.

Here's an example call to chat.unfurl, supplying a call_id received from calls.add:

{
    "token": "xxxx-xxxxxxxxx-xxxx",
    "channel": "C123ABC456",
    "ts": "12345.6789",
    "unfurls": {
        "https:\/\/url.to\/your\/call": {
            "blocks": [{
                "type": "call",
                "call_id": "Rxxx"
            }]
        }
    }
}

Responding to a rejected Call

Slack notifies your app with a call_rejected event whenever a Call is rejected by an invited user. Here's an example payload your app might receive:

{
    "token": "12345FVmRUzNDOAuy4BiWh",
    "team_id": "T123ABC456",
    "api_app_id": "B123ABC456",
    "event": {
        "type": "call_rejected",
        "call_id": "RL731AVEF",
        "user_id": "U123ABC456",
        "channel_id": "D123ABC456",
        "external_unique_id": "123-456-7890"
    },
    "type": "event_callback",
    "event_id": "Ev123ABC456",
    "event_time": 1563448153,
    "authed_users": ["U123ABC456"]
}

Your app can then choose to handle the rejected call according to its own logic.

Updating a Call and adding/removing participants

Use the calls.update method to update a Call's title, join_url, or desktop_app_join_url.

Use the calls.participants.add method and the calls.participants.remove method to add or remove participants.

Cool news: the Call object in channel will update automatically with any of these changes.

Hanging up a Call

When a call ends, update the Call object in Slack by calling the calls.end method.

Image of a call that has ended