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.
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.
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.
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.
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.
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!
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"
}
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.
As a courtesy, post the Call to channel so the people in it know about the Call! Use the chat.postMessage
method 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",
}]
}
users
parameter When you register a Call with the calls.add
method, add participants with the calls.participants.add
method, or remove them with the calls.participants.remove
method, 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 the conversations.members
method. 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.
Subscribe to the link_shared
and call_rejected
events in your app settings page under Event Subscriptions, if you haven't already. 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"
}]
}
}
}
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.
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.
The Call object in channel will update automatically with any of these changes.
When a call ends, update the Call object in Slack by calling the calls.end
method.