Embedded
developer guide

Whereby Embedded is an easy-to-use video meetings API. Embed video meetings into an application or website with the REST API ↗ allowing your team to build faster and ship more often.

Get started

Anchor link for how to start a meeting

To use the Embedded API you need to be on our Embedded product ↗, and you’ll need an API key. A new key is generated from the “Account settings” section in the Embedded dashboard. API keys can be renamed and deleted.

Create a meeting by sending a HTTP request to Whereby’s servers from your server. A successful response contains a roomUrl. Your API key is secret and should only be used from your server. Create a meeting.

Embed a meeting in your website or app with an iframe. The iframe’s src attribute is specified as the roomUrl. You can customize the meeting with URL parameters.

Whereby REST API

Anchor link for Embed a meeting

Create a meeting with a HTTP request containing your API key sent from your server to Whereby’s. The response contains a roomUrl that is embedded in your client within an iframe.

Calling Whereby’s API from your client should be done through an endpoint on your server. This will help keep the API key safe from exposing it to users. For this reason, the API does not return an Access-Control-Allow-Origin header in its response.

Create a meeting

Anchor link for how to create a meeting

Simply create a meeting with an HTTP request and pass necessary parameters as body. Available parameters and formats can be found in the API docs ↗. Both startDate and endDate are interpreted as UTC by default. Other time zones are supported by including an offset in hours and minutes. For example, Eastern Standard Time (EST) would be expressed as 2021-08-11T07:56:01-05:00.

curl https://api.whereby.dev/v1/meetings \
  --header "Authorization: Bearer $API_KEY" \
  --header "Content-Type: application/json" \
  --request POST \
  --data @- << EOF
{
  "startDate": "2021-05-06T12:51:00.000Z",
  "endDate": "2021-05-07T12:50:00.000Z",
  "fields": ["hostRoomUrl"]
}
EOF
$api_key = "YOUR_API_KEY";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.whereby.dev/v1/meetings');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
  "startDate": "2021-05-06T12:51:00.000Z",
  "endDate": "2021-05-07T12:50:00.000Z",
  "fields": ["hostRoomUrl"]}'
);

$headers = [
  'Authorization: Bearer ' . $api_key,
  'Content-Type: application/json'
];

curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);

curl_close($ch);
const fetch = require("node-fetch");

const API_KEY = "YOUR_API_KEY";

const data = {
  startDate: "2021-05-06T12:51:00.000Z",
  endDate: "2021-05-07T12:50:00.000Z",
  fields: ["hostRoomUrl"],
};

(async () => {
  const response = await fetch("https://api.whereby.dev/v1/meetings", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(data),
  });
})();
import requests

API_KEY = "YOUR_API_KEY"

data = {
    "startDate": "2021-05-06T12:51:00.000Z",
    "endDate": "2021-05-07T12:50:00.000Z",
    "fields": ["hostRoomUrl"],
}

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

response = requests.post(
    "https://api.whereby.dev/v1/meetings",
    headers=headers,
    json=data
)
{
    "meetingId": "1",
    "startDate": "2021-05-06T12:51:00.000Z",
    "endDate": "2021-05-07T12:50:00.000Z",
    "roomUrl": "https://example.whereby.com/room",
    "hostRoomUrl": "https://example.whereby.com/room?roomKey=eFhcG...i00ZG"
}

401 Response: API key missing or invalid

Embed a meeting

Anchor link for how to embed a meeting

Embedding a meeting into a service or app requires using an iframe with the src attribute specified as the roomUrl. Read the Allowed domains section to learn how to allow your website’s domain so that browsers don’t block the iframe.

<iframe
  src="https://subdomain.whereby.com/room?embed"
  allow="camera; microphone; fullscreen; speaker; display-capture"
></iframe>

Embedding in Android

Anchor link for embedding in android

Embedding in Android requires use of the WebView class. The following method should be overridden WebChromeClient.onPermissionRequest in combination with ?skipMediaPermissionPrompt url parameter to allow Whereby access the camera.

Embedding in iOS

Anchor link for embedding in iOS

WKWebView supports embedding pages that use WebRTC from iOS 14.3 onwards. To support older iOS versions it is recommended to use one of the following options:

  • Redirect to mobile Safari.
  • Use SFSafariViewController to open a website containing an iframe with its src specified as a Whereby meeting, alongside a custom user interface.

To use Whereby with Cordova (Phonegap) please use the plugin for SafariViewController

Meeting customization

Anchor link for meeting customization

Meeting customization is achieved with url parameters for each iframe instance. It’s possible for each participant in a meeting to have different parameter combinations. Learn more about combining parameters.

URL ParameterDescription
?embedApply default embedded UI.
?video=offParticipant joins the meeting with camera turned off.
?audio=offParticipant joins the meeting with microphone turned off.
?screenshare=<on|off>Show/hide the screenshare button.
?chat=<on|off> Show/hide the chat button.
?people=off Hide the people button.
?leaveButton=<on|off>Show/hide the leave button.
?displayName=<name> Set display name of participant.
?background=offHide the meeting background.
?lang=<en|es|nb|pt|ja>Set the meeting UI language to either English (en), French (fr), Spanish (es), Norwegian (nb), Portuguese (pt), or Japanese (jp).
?floatSelfFloat the self view to the bottom right.

Property details

?embedAnchor link for ?embed

The embed parameter applies a combination of UI adjustments to simplify the embedded meeting interface.

Hidden items: Status bar, chat button, screensharing button, leave button, and Whereby’s branding.

Shown items: Video and audio buttons.

For further adjustments, additional parameters can be combined with ?embed. For example ?embed&chat=on will show the chat button.

?video=offAnchor link for ?video=off

Participants join the meeting with their camera off, they can turn it on whenever they want.

Usecase: A sales representative showcasing a product to a customer relaxing at home.

?audio=offAnchor link for ?audio=off

Participants join the meeting with their microphone off, they can turn it on whenever they want.

Usecase: A presentation is being given in a big meeting where attendees are not expected to participate verbally.

?screenshare=<on|off>Anchor link for ?screenshare=<on|off>

Show/hide the screensharing button for the meeting participant.

Screensharing is available on all browsers that support this natively. Currently no mobile browsers support screensharing.

?chat=<on|off>Anchor link for ?chat=<on|off>

Show/hide the chat button. Messages are not stored after the meeting has ended.

?people=offAnchor link for ?people=off

Hide the people button.

Usecase: The people button shows the participant list, which can be useful for bulk management of participants in bigger meetings.

?displayName=<name>Anchor link for ?displayName=<name>

Set the display name for a participant instead of prompting the user for this information.

Usecase: A participant’s name may be known before they join the meeting. Including this information as a parameter will save the user from entering their name again.

?background=offAnchor link for ?background=off

Hide the default meeting background.

Usecase: Hiding the meeting background allows the meeting to appear more integrated by allowing the app or service’s branding shine through as the new background.

?lang=<en|es|nb|pt|ja>Anchor link for url-paramater-?lang=<en|es|nb|pt|ja>

Set the meeting UI language to match your product or service. Select from either English (en), Spanish (es), Norwegian (nb), Portuguese (pt), or Japanese (jp).

?floatSelfAnchor link for url-paramater-?floatSelf

Float the self view to the bottom right.

Usecase: Floating the self view to the bottom right maximizes the space for other meeting participants.

Combining parameters

Anchor link for combining parameters

Further customize the meeting by combining parameters by using the ampersand symbol (&). The following example combines the embed with screenshare=off and people=off

https://subdomain.whereby.com/room?screenshare=off&people=off

Host privileges

Anchor link for host privileges

Hosts can join the meeting with the hostRoomUrl. They have the following features available:

  • Lock and unlock the meeting.
  • Remove, mute, and spotlight meeting participants.
  • Enter locked rooms without knocking.
  • Host privileges are valid an hour before the startDate and an hour after the endDate.

An example of the returned JSON containing the hostRoomUrl. Explore more in the API docs ↗.

{
    "meetingId": "1",
    "startDate": "2021-05-06T12:51:00.000Z",
    "endDate": "2021-05-07T12:50:00.000Z",
    "roomUrl": "https://example.whereby.com/room",
    "hostRoomUrl": "https://example.whereby.com/room?roomKey=eFhcG...i00ZG"
}

Localhost

Anchor link for testing with localhost

Currently, embedding on localhost is not supported. An alternative is to redirect a local DNS name to localhost (127.0.0.1) by adding an entry to the file /etc/hosts, and checking the domain is allowed. Only HTTPS domains are allowed, so a self-signed SSL certificate is also required. Follow this guide to learn more ↗.

Allowed domains

Anchor link for allowed domains

For embedded meetings in an iframe to work inside a website, its domain has to be allowed. The list of allowed domains can be updated from the “Account settings” section in the Embedded dashboard. Please note that domains must be prefixed by https:// and have no path. Wildcards to allow all subdomains under a domain are permitted, for example https://*.domain.com.

To validate which domains are allowed, follow the instructions in Troubleshooting.

Webhooks

Anchor link for webhooks

Webhooks are user-defined callbacks triggered by meeting events. They are created in ”Account settings”. These are the two supported event types:

  • room.client.joined: Sent when a user joins a meeting after the pre-call screen if enabled.
  • room.client.left: Sent when a user leaves a meeting room, either by closing the browser tab or by click on the leave button.

Please note that webhook events are sent for interactions that happen between one hour before thestartDate and an hour after the endDateof a meeting.

Event objects

Events are delivered to their corresponding webhook endpoint as the JSON body of an HTTP request. The table below describes top-level attributes.

PropertyDescription
apiVersionThe Whereby API version used to populate data.
createdAtISO representation of the creation date of the event.
typeThe event’s type identifier.
dataObject containing information associated with the event.

Data properties

The data property for both room.client.joined and room.client.left has the following properties:

PropertyDescription
roleNameThe client’s role depending on what URL they use to access the meeting.
meetingIdThe identifier of the meeting that the user has joined/left.
roomNameThe string that identifies the room assigned to the meeting. It’s the last path parameter of the roomUrl.
numClientsNumber of clients connected to the meeting after the event.

The property roleName will have one of the following values:

  • host: A user joined using the hostRoomUrl.
  • visitor: A user joined using the regular roomUrl.
  • granted_visitor: Same as a visitor but can join without knocking if the room is locked.
  • member: A user with an account in your Embedded organization.
  • owner: A user with an admin account in your Embedded organization.

An example of a webhook event object:

{
    "apiVersion": "1.0",
    "createdAt": "2021-01-21T16:29:59.681Z",
    "type": "room.client.joined",
    "data": {
        "roleName": "host",
        "meetingId": "134",
        "roomName": "/af0b7b66-c738-4981-887a-ad416754f32d",
        "numClients": 8,
    }
}

Validating events

To prevent from man-in-the-middle attacks ↗ , webhook requests to your endpoint contain a signature in the Whereby-Signature header. This string is generated with a unique secret that only you can view when creating or editing a webhook in the Embedded dashboard. Only Whereby and you have access to this secret, and no third party can send forged events to your endpoint. On top of that the header also includes a timestamp to help you prevent replay attacks. The header is composed of a timestamp and the signature itself, for example:

Whereby-Signature: t=1606227791,v1=94a23dc9d73e8e6abdf9d4095aee954697e9317e9649e742361b35707edd45a3

To verify an event’s signature follow this steps:

  1. Extract the timestamp and signature by splitting the string on , then removing both t= and v1= from the resulting strings.
  2. Prepare the signedPayload string by concatenating the timestamp (as a string), the character . and the JSON event object (the request body).
  3. Calculate the HMAC using the SHA256 as the hashing function of signedPayload with the endpoint’s signing secret as the key.
  4. Compare the signature from the header to the one you just generated. To protect yourself from timing attacks consider using a constant-time equality function instead of the default equality operator of the language you’re using. Finally, to prevent replay attacks, compare the header’s timestamp with the current one and decide if the elapsed time is within your allowed threshold.

Failed delivery

Any 5xx response to the webhook delivery request will trigger a retry, for a total of 2 retries. A short exponential backoff will be used.

Troubleshooting

Anchor link for troubleshooting

Verify an API key

Check if an API key is valid with the simple interface below. Alternatively use cURL from either a terminal window or server.

curl https://api.whereby.dev/v1/hello \
  --head \
  -H "Authorization: Bearer API_KEY"

A 200 response indicates the API key is working. A 401 response means the provided key is incorrect.

Check if a domain is allowed

Enter your Whereby organization’s subdomain and run the cURL command in a terminal window.

curl --head "https://YOUR_SUBDOMAIN.whereby.com"

A successful response is indicated with your allowed domains included in the Content-Security-Policy’s header.