This is a preliminary draft spec for a new calls API. As we are in a pre-release phase, this is subject to change.
Our intent with this API is to expose the same Slack UI surfaces to partner video conferencing applications as provided to our native Slack calls feature. The first iteration primarily focuses on the “call object” which is the message-like object dropped in a Slack channel to represent an ongoing or ended call. It will contain information relevant to the call, such as its title and start time, and will update participant details in real-time.
In order for your calls app to write to the calls API, it needs the calls:write
scope. Other suggestions and requirements for apps are outlined in our app guide.
Use the field desktop_app_join_url
in both the calls.add
and calls.update
API to indicate the url used to launch your desktop app. This url should begin with your_call_app_url://
or any other similar URL that supports directly launching their desktop app.
The Slack client will use this field to launch your company's desktop app directly if it is already installed on a user's computer.
If a desktop_app_join_url
is not provided or your app is not installed, the default behavior of opening the call_initiation_url
in a browser tab will remain in place.
When a call initiator clicks the call button in the Slack desktop or web client, Slack will send a HTTP POST request containing metadata of the calls request to your app’s preconfigured, whitelisted calls endpoint.
The calls app should then:
calls.add
to create the call objectThe HTTPS request Slack sends to your Calls endpoint will contain a payload similar to that of a slash command. This data will be sent to your URL as a HTTP POST request with a Content-type header set as application/x-www-form-urlencoded
Example payload:
{
"token": "<verification token>",
"team_id": "T12AES3D",
"team_domain": "my-team",
"channel_id": "C0231S23",
"channel_name": "test",
"user_id" : "U2144YR97",
"user_name": "mattjones",
"response_url":"https://slack.com/callback/123xyz"
}
Upon receiving the call request, the app must respond with a call initiation URL synchronously within 3 seconds. This specified URL will be automatically opened for user who has initiated the call in a separate window.
desktop_protocol_call_initiation_url
is an optional field, representing a custom url scheme that will be used to launch the calls app directly. If it is not available in the response then Slack will fallback by launching call_initiation_url
in a new browser window.
Example response:
{
"response_type":"call",
"call_initiation_url":"https://join.call.com/123456",
"desktop_protocol_call_initiation_url": "call://join&room_id=123456"
}
Slack uses the type
field in the request payload https:/your_company_url/your/call_url
to indicate the type of call:
type
: audio
or video
If type=video
then send the URL for initiating a video call or meeting:
{
...
"type": "video"
...
}
If type=audio
request payload will have additional phone_number
field, then send the URL for initiating a phone call:
{
...
"type": "audio",
"phone_number": "+1-202-555-0145",
...
}
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"
}
phone_number
(optional)A phone number is included when sending the audio type as an optional parameter/
Your app might not have a user token, which is typically required for posting messages to private channels, MPDMs or DMs, in order to post a call block via the usual chat.postMessage
method. You can work around this by utilizing the in_channel
slash command response type. This will allow your app to post a message directly to the channel the slash command request originated from, which can include a call block.
calls.add
Create the call object with the calls.add
method as detailed here
Once the call starts, you should let other users in the channel know so that they can join the call as well. Post the call object returned by calls.add
into the channel the call initiator started the call in using the provided response_url
Note that the top-level "text" field ensures that notifications on desktop and mobile apps have text, as call blocks do not appear in these notifications.
{
"response_type": "in_channel",
"text": "A new call was started by <name of call provider>",
"blocks": [{
"type": "call",
"call_id": "R123",
}]
}
Events sent from the Slack service to the call provider’s Slack integration
An HTTP POST request is sent when the user invokes a slash command (e.g. /my_favorite_calling_service
) or presses the Slack call button, as described here.
When receiving this event, the call provider should allocate a meeting/call ID, and return information via the calls.add
method.
If the provider is not able to create a call because the user needs to first authenticate, then the user should be prompted to log in or start the OAuth process. After authentication is complete, the provider should initiate a call and send connection information in a calls.add
method.
Learn how to respond to slash commands in DMs and MPDMs
link_shared
The existing link_shared method is
sent when a link from a specified domain is shared. Call Apps should respond to
this event with the calls.add
method to register the call, and then invoke the
chat.unfurl
method, which will cause a call object to appear in channel,
already populated with the call duration and participants.
calls.add
will return a call id that looks like Rxxx
.
Next, call chat.unfurl
and supply your call id:
{
"token": "xxxx-xxxxxxxxx-xxxx",
"channel": "Cxxx",
"ts": "ts",
"unfurls": {
"https:\/\/url.to\/your\/call": {
"blocks": [{
"type": "call",
"call_id": "Rxxx"
}]
}
}
}
Read more in in the registering your domain section of this doc.
call_rejected
If a call has been shared with a user in DM using the link_shared
method, and the user rejects the call, Slack will inform the call provider via this event.
Argument | Example | Description |
---|---|---|
type |
call_rejected | The type of event—in this case call rejected |
call_id |
123-456 | call provider ID |
user_id |
U123 | User who rejected the DM call |
external_unique_id |
123-456-7890 | ID of the external call |
channel_id |
DL5JN9K0T | The channel that contains the call being rejected |
Example:
{
"token": "12345FVmRUzNDOAuy4BiWh",
"team_id": "TL1BBBQBD",
"api_app_id": "BBBU04BB4",
"event": {
"type": "call_rejected",
"call_id": "RL731AVEF",
"user_id": "ULJS1TYR5",
"channel_id": "DL5JN9K0T",
"external_unique_id": "123-456-7890"
},
"type": "event_callback",
"event_id": "EvLLACMB6BB",
"event_time": 1563448153,
"authed_users": ["UBBB1TYR5"]
}
Slack API Methods called by the call provider’s Slack integration
calls.add
This method is called with connection information required for the Slack client to connect the user to a Platform call.
Return value: This method returns the call object json, of which only the
id
must be supplied when invoking calls.end
, calls.participants.add
,
calls.participants.remove
, and other methods that refer to this call.
Example return value:
{
"ok": true,
"call": {
"id": "R0120388",
"date_start": 1562002086,
"external_unique_id": "025169F6-E37A-4E62-BB54-7F93A0FC4C1F",
"join_url": "https://example.com/calls/1234567890",
"external_display_id": "705-292-868",
"title": "Daily sync up",
"users": [
{
"slack_id": "U0MQG83FD"
},
{
"external_id": "54321678",
"display_name": "External User",
"avatar_url": "https://example.com/users/avatar1234.jpg"
}
]
}
}
In order to update the join_url
or the name
, use the calls.update
method.
Argument | Example | Required | Description |
---|---|---|---|
token |
xxxx-xxxxxxxxx-xxxx | Required | Authentication token bearing required scopes. |
external_unique_id |
uuid | Required | This id is provided by the call provider, and must be unique across all calls from that service. |
external_display_id |
123-456 | Optional | |
join_url |
https://url.to/your/call | Required | |
start_time |
1532627506 | Optional | This information is necessary to display the ongoing duration of the call in the call object. If start_time is not provided, the start_time is assumed to be the time that this method was invoked. This should be a UNIX/epoch timestamp in UTC, similar to other timestamps used by the Slack API. The “1532627506” example string corresponds to “July 26th, 2018 at 17:51:46 UTC”. |
title |
Daily Standup | Optional | If the call is renamed, calls.add might be invoked again in order to update the call object. |
created_by |
U2144YR97 | Optional | The ID of the User who has started this call. This field can be populated using user_id sent in the HTTPS call made by Slack to your Calls Endpoint. |
users |
array of user objects (example below) | Optional | Send if this call is already in progress. The format of the participants array is the same as the calls.participants.add method, and more documentation is available there. |
calls.update
This method updates information about calls already started and registered via calls.add
.
The fields which may be provided for update are title
and join_url
, described in calls.add
.
calls.info
This method returns information about a call. It requires token
and the id
of the call being queried.
calls.participants.add
{#calls.participants.add}This method is sent from the call provider’s Slack integration when a new user joins a call.
If the call provider knows the Slack user ID of the participant, they may provide it, so Slack can show their name and avatar in the call object. If the Slack user ID is unknown, a user name can be provided instead for display in the call object, along with a URL for the avatar image.
What the user sees: The call object will be updated to show the user who joined the call. If Slack have the user’s Slack ID, then Slack can show their avatar on the call object.
Argument | Example | Required | Description |
---|---|---|---|
token |
xxxx-xxxxxxxxx-xxxx | Required | Authentication token bearing required scopes. |
id |
slack_call_id |
Required | This is the Slack call ID, which is returned by calls.add |
users |
array of user objects (example below) | Required* | If the call provider can’t provide the Slack user_id, then they still need to provide a platform-specific user id, along with a display_name |
users
example[
{
"slack_id": "U1H77"
},
{
"external_id": "54321678",
"display_name": "External User",
"avatar_url": "https://example.com/users/avatar1234.jpg"
}
]
calls.participants.remove
Removes participants from the call object when they leave the call.
Argument | Example | Required | Description |
---|---|---|---|
token |
xxxx-xxxxxxxxx-xxxx |
Required | Authentication token bearing required scopes. |
id |
slack_call_id |
Required | slack_call_id returned by calls.add |
users |
array of user objects (example below) | Required |
users
example[
{
"slack_id": "U1H77"
},
{
"external_id": "54321678",
"display_name": "External User",
"avatar_url": "https://example.com/users/avatar1234.jpg"
}
]
calls.end
The provider notifies Slack that the call has ended with this method. When received, the call object will gray out so no other users can try to join the call.
Argument | Example | Required | Description |
---|---|---|---|
token |
xxxx-xxxxxxxxx-xxxx | Required | Authentication token bearing required scopes. |
id |
slack_call_id |
Required | slack_call_id returned by calls.add |
duration |
65 | Optional | Duration in seconds. The call provider can optionally provide the exact duration of a call, which would show in the call object. If this value is not provided, then Slack will calculate call duration, using the time this method was invoked as the call end time. |
Error | Description |
---|---|
internal_error |
An unexpected exception with the service has occurred. |
invalid_start_time |
The start time is invalid. |
not_authorized |
User not authorized to create a call in this channel |
not_authed |
No authentication token provided. |
invalid_auth |
Some aspect of authentication cannot be validated. Either the provided token is invalid or the request originates from an IP address disallowed from making the request. |
account_inactive |
Authentication token is for a deleted user or workspace. |
token_revoked |
Authentication token is for a deleted user or workspace or the app has been removed. |
no_permission |
The workspace token used in this request does not have the permissions necessary to complete the request. Make sure your app is a member of the conversation it's attempting to post a message to. |
org_login_required |
The workspace is undergoing an enterprise migration and will not be available until migration is complete. |
ekm_access_denied |
Administrators have suspended the ability to post a message. |
missing_scope |
The token used is not granted the specific scope permissions required to complete this request. |
invalid_arguments |
The method was called with invalid arguments. |
invalid_arg_name |
The method was passed an argument whose name falls outside the bounds of accepted or expected values. This includes very long names and names with non-alphanumeric characters other than _. If you get this error, it is typically an indication that you have made a very malformed API call. |
invalid_charset |
The method was called via a POST request, but the charset specified in the Content-Type header was invalid. Valid charset names are: utf-8 iso-8859-1. |
invalid_form_data |
The method was called via a POST request with Content-Type application/x-www-form-urlencoded or multipart/form-data, but the form data was either missing or syntactically invalid. |
invalid_post_type |
The method was called via a POST request, but the specified Content-Type was invalid. Valid types are: application/json application x-www-form-urlencoded multipart/form-data text/plain. |
missing_post_type |
The method was called via a POST request and included a data payload, but the request did not include a Content-Type header. |
team_added_to_org |
The workspace associated with your request is currently undergoing migration to an Enterprise Organization. Web API and other platform operations will be intermittently unavailable until the transition is complete. |
invalid_json |
The method was called via a POST request with Content-Type application/json, but the body was not valid JSON. |
json_not_object |
The method was called via a POST request a valid JSON body, but the JSON value was not an object. |
request_timeout |
The method was called via a POST request, but the POST data was either missing or truncated. |
upgrade_required |
The calling application needs to be upgraded. |
fatal_error |
The server could not complete your operation(s) without encountering a catastrophic error. It's possible some aspect of the operation succeeded before the error was raised. |