Overview

Tamas is a SaaS (software as a service) to serve virtual rooms and provides a scalable and reliable service that uses enhanced BigBlueButton servers in the core.

This document describes the Tamas application programming interface (API).

For developers, this API enables you to

  • create meetings
  • join meetings
  • end meetings
  • get recordings for past meetings (and delete them)

To make an API call to Tamas like a BigBlueButton server, your application makes HTTPS requests to the Tamas API endpoint. All API calls must include checksum computed with a secret shared with Tamas.

Tamas like a BigBlueButton server returns an XML response to all API calls.

API Data Types

There are three types in the API.

String

This data type indicates a (UTF-8) encoded string. When passing String values to the Tamas API calls, make sure that you use correctly URL-encoded UTF-8 values so international text will show up correctly. The string must not contain control characters (values 0x00 through 0x1F).

Some Tamas API parameters put additional restrictions on which characters are allowed, or on the lengths of the string. These restrictions are described in the parameter documentation.

Number

This data type indicates a non-negative integer value. The parameter value must only contain the digits 0 through 9. There should be no leading sign (+ or -), and no comma or period characters.

Boolean

A true/false value. The value must be specified as the literal string true or false (all lowercase), other values may be misinterpreted.

API Security Model

The Tamas API security model enables 3rd-party applications to make API calls (if they have the shared secret), but not allow other people (end users) to make API calls.

The Tamas API calls are almost all made server-to-server.

Here’s a sample

    URL: https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/
    SECRET: ECCJZNJWLPEA3YB6Y2LTQGQD3GJZ3F93

You should not embed the shared secret within a web page and make Tamas API calls within JavaScript running within a browser. The built-in debugging tools for modern browser would make this secret easily accessible to any user. Once someone has the shared secret for yours, they could create their own API calls. The shared secret should only be accessible to the server-side components of your application (and thus not visible to end users).

Usage

The implementation of Tamas’s security model lies in the controller ApiController.groovy. For each incoming API request, the controller computes a checksum out of the combination of the entire HTTPS query string and the server’s shared secret. It then matches the incoming checksum against the computed checksum. If they match, the controller accepts the incoming request.

To use the security model, you must be able to create an SHA-1 checksum out of the call name plus the query string plus the shared secret that you configured on your server. To do so, follow these steps:

  1. Create the entire query string for your API call without the checksum parameter.
    • Example for create meeting API call: name=Test+Meeting&meetingID=abc123&attendeePW=111222&moderatorPW=333444
  2. Prepend the API call name to your string
    • Example for above query string:
      • API call name is create
      • String becomes: createname=Test+Meeting&meetingID=abc123&attendeePW=111222&moderatorPW=333444
  3. Now, append the shared secret to your string
    • Example for above query string:
      • shared secret is 639259d4-9dd8-4b25-bf01-95f9567eaf4b
      • String becomes: createname=Test+Meeting&meetingID=abc123&attendeePW=111222&moderatorPW=333444639259d4-9dd8-4b25-bf01-95f9567eaf4b
  4. Now, find the SHA-1 sum for that string (implementation varies based on programming language).
    • the SHA-1 sum for the above string is: 1fcbb0c4fc1f039f73aa6d697d2db9ba7f803f17
  5. Add a checksum parameter to your query string that contains this checksum.
    • Above example becomes: name=Test+Meeting&meetingID=abc123&attendeePW=111222&moderatorPW=333444&checksum=1fcbb0c4fc1f039f73aa6d697d2db9ba7f803f17

You MUST send this checksum with EVERY API call. Since end users do not know your shared secret, they can not fake calls to the server, and they can not modify any API calls since changing a single parameter name or value by only one character will completely change the checksum required to validate the call.

Implementations of the SHA-1 functionality exist in nearly all programming languages. Here are example methods or links to example implementations for various languages:

  • JavaScript
    • describes MD5 also
  • Java
    • You can use org.apache.commons.codec.digest.DigestUtils and call DigestUtils.shaHex(string + sharedSecret)
  • PHP
    • simply call sha1(string . sharedSecret)

Error handling

In the case of an error, all API calls make a best-effort attempt to return a properly formatted XML that contains enough information for the caller to determine the source of the error.

Errors are returned with a returncode value of FAILED and a message and messageKey value. We will try very hard to keep the messageKey stable (unchanging) throughout the life of the API. However, the message value is a plain text (English) value that may change with time.

You can use the messageKey to determine the type of error and look up internationalized text within your own system if needed. For example, an invalid request may return an error message of “No conference with that meeting ID exists”, but the messageKey is simple “invalidMeetingIdentifier”.

API Resources

Administration

The following section describes the administration calls

Resource Description
create Creates a new meeting.
join Join a new user to an existing meeting.
end Ends meeting.

Monitoring

The following section describes the monitoring calls

Resource Description
isMeetingRunning Checks whether if a specified meeting is running.
getMeetings Get the list of Meetings.
getMeetingInfo Get the details of a Meeting.

Recording

Resource Description
getRecordings Get a list of recordings.
deleteRecordings Deletes an existing recording

API Calls

The following response parameters are standard to every call and may be returned from any call.

Parameters:

Param Name Required / Optional Type Description
checksum Varies String See the API Security ModelAnchor section for more details on the usage for this parameter.
This is basically a SHA-1 hash of callName + queryString + sharedSecret. The security salt will be configured into the application at deploy time. All calls to the API must include the checksum parameter.

Response:

Param Name When Returned Type Description
returncode Always String Indicates whether the intended function was successful or not. Always one of two values:

FAILED – There was an error of some sort – look for the message and messageKey for more information. Note that if the returncode is FAILED, the call-specific response parameters marked as “always returned” will not be returned. They are only returned as part of successful responses.

SUCCESS – The call succeeded – the other parameters that are normally associated with this call will be returned.
message Sometimes String A message that gives additional information about the status of the call. A message parameter will always be returned if the returncode was FAILED. A message may also be returned in some cases where returncode was SUCCESS if additional information would be helpful.
messageKey Sometimes String Provides similar functionality to the message and follows the same rules. However, a message key will be much shorter and will generally remain the same for the life of the API whereas a message may change over time. If your third party application would like to internationalize or otherwise change the standard messages returned, you can look up your own custom messages based on this messageKey.

create

Creates a meeting.

The create call is idempotent: you can call it multiple times with the same parameters without side effects. This simplifies the logic for joining a user into a session as your application can always call create before returning the join URL to the user. This way, regardless of the order in which users join, the meeting will always exist when the user tries to join (the first create call actually creates the meeting; subsequent calls to create simply return SUCCESS).

Tamas will automatically remove empty meetings that were created but have never had any users after a number of minutes.

Resource URL:

https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/create?[parameters]&checksum=[checksum]

Parameters:

Param Name Required / Optional Type Description
name Required String A name for the meeting.
meetingID Required String A meeting ID that can be used to identify this meeting by the 3rd-party application.

This must be unique to the server that you are calling: different active meetings can not have the same meeting ID.

If you supply a non-unique meeting ID (a meeting is already in progress with the same meeting ID), then if the other parameters in the create call are identical, the create call will succeed (but will receive a warning message in the response). The create call is idempotent: calling multiple times does not have any side effect. This enables a 3rd-party applications to avoid checking if the meeting is running and always call create before joining each user.

Meeting IDs should only contain upper/lower ASCII letters, numbers, dashes, or underscores. A good choice for the meeting ID is to generate a GUID value as this all but guarantees that different meetings will not have the same meetingID.
attendeePW Optional (recommended) String The password that the join URL can later provide as its password parameter to indicate the user will join as a viewer. If no attendeePW is provided, the create call will return a randomly generated attendeePW password for the meeting.
moderatorPW Optional (recommended) String The password that will join URL can later provide as its password parameter to indicate the user will as a moderator. if no moderatorPW is provided, create will return a randomly generated moderatorPW password for the meeting.
welcome Optional String A welcome message that gets displayed on the chat window when the participant joins. You can include keywords (%%CONFNAME%%, %%DIALNUM%%, %%CONFNUM%%) which will be substituted automatically.

The welcome message has limited support for HTML formatting. Be careful about copy/pasted HTML from e.g. MS Word, as it can easily exceed the maximum supported URL length when used on a GET request.
maxParticipants Optional Number Set the maximum number of users allowed to joined the conference at the same time.
logoutURL Optional String The URL that Tamas client will go to after users click the OK button on the ‘You have been logged out message’.
duration Optional Number The maximum length (in minutes) for the meeting.

Normally, the Tamas server will end the meeting when either (a) the last person leaves (it takes a minute or two for the server to clear the meeting from memory) or when the server receives an end API request with the associated meetingID (everyone is kicked and the meeting is immediately cleared from memory).

Tamas begins tracking the length of a meeting when it is created. If duration contains a non-zero value, then when the length of the meeting exceeds the duration value the server will immediately end the meeting (equivalent to receiving an end API request at that moment).
meta Optional String This is a special parameter type (there is no parameter named just meta).

You can pass one or more metadata values when creating a meeting. These will be stored by Tamas can be retrieved later via the getMeetingInfo and getRecordings calls.

Examples of the use of the meta parameters are meta_Presenter=Jane%20Doe, meta_category=FINANCE, and meta_TERM=Fall2016.
moderatorOnlyMessage Optional String Display a message to all moderators in the public chat.

The value is interpreted in the same way as the welcome parameter.
autoStartRecording Optional Boolean Whether to automatically start recording when first user joins (default false).

When this parameter is true, the recording UI in Tamas will be initially active. Moderators in the session can still pause and restart recording using the UI control.<br/
NOTE: Don’t pass autoStartRecording=false and allowStartStopRecording=false - the moderator won’t be able to start recording!
allowStartStopRecording Optional Boolean Allow the user to start/stop recording. (default true)

If you set both allowStartStopRecording=false and autoStartRecording=true, then the entire length of the session will be recorded, and the moderators in the session will not be able to pause/resume the recording.
webcamsOnlyForModerator Optional Boolean Setting webcamsOnlyForModerator=true will cause all webcams shared by viewers during this meeting to only appear for moderators (added 1.1)
logo Optional String Setting logo=http://www.example.com/my-custom-logo.png will replace the default logo in the Flash client. (added 2.0)
bannerText Optional String Will set the banner text in the client. (added 2.0)
bannerColor Optional String Will set the banner background color in the client. The required format is color hex #FFFFFF. (added 2.0)
copyright Optional String Setting copyright=My custom copyright will replace the default copyright on the footer of the Flash client. (added 2.0)
muteOnStart Optional Boolean Setting muteOnStart=true will mute all users when the meeting starts. (added 2.0)
lockSettingsDisableCam Optional Boolean Default lockSettingsDisableCam=false. Setting lockSettingsDisableCam=true will prevent users from sharing their camera in the meeting. (added 2.2)
lockSettingsDisableMic Optional Boolean Default lockSettingsDisableMic=false. Setting to lockSettingsDisableMic=true will only allow user to join listen only. (added 2.2)
lockSettingsDisablePrivateChat Optional Boolean Default lockSettingsDisablePrivateChat=false. Setting to lockSettingsDisablePrivateChat=true will disable private chats in the meeting. (added 2.2)
lockSettingsDisablePublicChat Optional Boolean Default lockSettingsDisablePublicChat=false. Setting to lockSettingsDisablePublicChat=true will disable public chat in the meeting. (added 2.2)
lockSettingsDisableNote Optional Boolean Default lockSettingsDisableNote=false. Setting to lockSettingsDisableNote=true will disable notes in the meeting. (added 2.2)
lockSettingsLockedLayout Optional Boolean Default lockSettingsLockedLayout=false. Setting to lockSettingsLockedLayout=true will lock the layout in the meeting. (added 2.2)
lockSettingsLockOnJoin Optional Boolean Default lockSettingsLockOnJoin=true. Setting to lockSettingsLockOnJoin=false will not apply lock setting to users when they join. (added 2.2)
lockSettingsLockOnJoinConfigurable Optional Boolean Default lockSettingsLockOnJoinConfigurable=false. Setting to lockSettingsLockOnJoinConfigurable=true will allow applying of lockSettingsLockOnJoin param. (added 2.2)
guestPolicy Optional String Default guestPolicy=ALWAYS_ACCEPT. Will set the guest policy for the meeting. The guest policy determines whether or not users who send a join request with guest=true will be allowed to join the meeting. Possible values are ALWAYS_ACCEPT, ALWAYS_DENY, and ASK_MODERATOR.

Example Requests:

  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/create?name=Test&meetingID=test01&checksum=1234
  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/create?name=Test&meetingID=test01&moderatorPW=mp&attendeePW=ap&checksum=wxyz
  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/create?name=Test&meetingID=test01&moderatorPW=mp&attendeePW=ap&meta_presenter=joe&meta_category=education&checksum=abcd

Example Response:

<response>
  <returncode>SUCCESS</returncode>
  <meetingID>Test</meetingID>
  <internalMeetingID>640ab2bae07bedc4c163f679a746f7ab7fb5d1fa-1531155809613</internalMeetingID>
  <parentMeetingID>bbb-none</parentMeetingID>
  <attendeePW>ap</attendeePW>
  <moderatorPW>mp</moderatorPW>
  <createTime>1531155809613</createTime>
  <createDate>Mon Jul 09 17:03:29 UTC 2018</createDate>
  <hasUserJoined>false</hasUserJoined>
  <duration>0</duration>
  <hasBeenForciblyEnded>false</hasBeenForciblyEnded>
  <messageKey>duplicateWarning</messageKey>
  <message>This conference was already in existence and may currently be in progress.</message>
</response>

End meeting callback URL

You can ask the Tamas to make a callback to your application when the meeting ends. Upon receiving the callback your application could, for example, change the interface for the user to hide the ‘join’ button.

To specify the callback to Tamas, pass a URL using the meta-parameter meta_endCallbackUrl on the create command. When Tamas ends the meeting, it will check if meta_endCallbackUrl is sent URL and, if so, make a HTTP GET request to the given URL.

For example, to specify the callback URL as

  https://myapp.example.com/callback?meetingID=test01

add the following parameter to the create API call: &meta_endCallbackUrl=https%3A%2F%2Fmyapp.example.com%2Fcallback%3FmeetingID%3Dtest01 (note the callback URL needs to be URLEncoded).

Later, when the meeting ends, Tamas will make an HTTPS GET request to this URL (HTTPS is supported and recommended) and to the URL add an additional parameter: recordingmarks=true|false.

The value for recordingmarks will be true if (a) the meeting was set to be recorded (record=true was passed on the create API call), and (b) a moderator clicked the Start/Stop Record button during the meeting (which places recording marks in the events). Given the example URL above, here’s the final callback if both (a) and (b) are true:

https://myapp.example.com/callback?meetingID=test01&recordingmarks=true

Another param is the meetingEndedURL create param. This create param is a callback to indicate the meeting has ended. This is a duplicate of the endCallbackUrl meta param. We have this separate as we want this param to stay on the server and not propagated to client and recordings. Can be used by scalelite to be notified right away when meeting ends. The meta callback url can be used to inform third parties.

Recording ready callback URL

You can ask Tamas to make a callback to your application when the recording for a meeting is ready for viewing. Upon receiving the callback your application could, for example, send the presenter an e-mail to notify them that their recording is ready.

To specify the callback to Tamas, pass a URL using the meta-parameter meta_bbb-recording-ready-url on the create command. Later, when Tamas finishes processing the recording, it will check if meta_bbb-recording-ready-url is set and, if so, make a HTTP POST request to the given URL.

For example, given the callback URL

https://example.com/api/v1/recording_status

to pass this to Tamas add the following parameter to the create API call: &meta_bbb-recording-ready-url=https%3A%2F%2Fexample.com%2Fapi%2Fv1%2Frecording_status (note the callback URL needs to be URLEncoded).

Later, when the recording is ready, Tamas will make an HTTPS POST request to this URL (https is supported and recommended).

The POST request body will be in the standard application/x-www-form-urlencoded format. The body will contain one parameter, named signed_parameters. The value of this parameter is a JWT (JSON Web Tokens) encoded string.

The JWT will be encoded using the “HS256” method. (i.e. the header should be { "typ": "JWT", "alg": "HS256" } ). The payload will contain a the following JSON keys:

  • meeting_id - The value will be the meeting_id (as provided on the Tamas create API call).
  • record_id - The identifier of the specific recording to which the notification applies. This corresponds to the IDs returned in the getRecordings api, and the internalMeetingId field on the getMeetingInfo request.

The secret used to sign the JWT message will be the shared secret of the Tamas API endpoint that was used to create the original meeting.

The receiving endpoint should respond with one of the following HTTP codes to indicate status, as described below. Any response body provided will be ignored, although it may be logged as part of error handling.

Response Code Description
2XX All HTTP 2XX codes are treated the same way - the endpoint has received the notification, and the recording system will consider the callback completed. I suggest using the 200, 202, or 204 codes as appropriate to your application.
3XX Redirections are not supported, and will be treated as an error.
401 The shared secret does not match.
410 The callback is for a meeting/session/recording that has been deleted in the application. This code may in the future trigger the recording system to cancel the recording processing or unpublish and delete the recording.

All other HTTP response codes will be treated as transient errors.

join

Joins a user to the meeting specified in the meetingID parameter.

Resource URL:

https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/join?[parameters]&checksum=[checksum]

Parameters:

Param Name Required/Optional Type Description
fullName Required String The full name that is to be used to identify this user to other conference attendees.
meetingID Required String The meeting ID that identifies the meeting you are attempting to join.
password Required String The password that this attendee is using. If the moderator password is supplied, he will be given moderator status (and the same for attendee password, etc)
createTime Optional String Third-party apps using the API can now pass createTime parameter (which was created in the create call), Tamas will ensure it matches the ‘createTime’ for the session. If they differ, Tamas will not proceed with the join request. This prevents a user from reusing their join URL for a subsequent session with the same meetingID.
userID Optional String An identifier for this user that will help your application to identify which person this is. This user ID will be returned for this user in the getMeetingInfo API call so that you can check
defaultLayout Optional String The layout name to be loaded first when the application is loaded.
avatarURL Optional String The link for the user’s avatar to be displayed when displayAvatar in config.xml is set to true.
redirect Optional (Experimental) String The default behaviour of the JOIN API is to redirect the browser to the Flash client when the JOIN call succeeds. There have been requests if it’s possible to embed the Flash client in a “container” page and that the client starts as a hidden DIV tag which becomes visible on the successful JOIN. Setting this variable to FALSE will not redirect the browser but returns an XML instead whether the JOIN call has succeeded or not. The third party app is responsible for displaying the client to the user.
clientURL Optional (Experimental) String Some third party apps what to display their own custom client. These apps can pass the URL containing the custom client and when redirect is not set to false, the browser will get redirected to the value of clientURL.
joinViaHtml5 Optional String Set to “true” to force the HTML5 client to load for the user.
guest Optional String Set to “true” to indicate that the user is a guest, otherwise do NOT send this parameter.

Example Requests:

  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/join?meetingID=test01&password=mp&fullName=John&checksum=1234
  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/join?meetingID=test01&password=ap&fullName=Mark&checksum=wxyz
  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/join?meetingID=test01&password=ap&fullName=Chris&createTime=273648&checksum=abcd

Example Response:

There is only an XML response for this call if the redirect parameter is set to true. You should simply redirect the user to the call URL, and they will be entered into the meeting.

<response>
  <returncode>SUCCESS</returncode>
  <messageKey>successfullyJoined</messageKey>
  <message>You have joined successfully.</message>
  <meeting_id>640ab2bae07bedc4c163f679a746f7ab7fb5d1fa-1531155809613</meeting_id>
  <user_id>w_euxnssffnsbs</user_id>
  <auth_token>14mm5y3eurjw</auth_token>
  <session_token>ai1wqj8wb6s7rnk0</session_token>
  <url>https://tamas.lahzenegar.com/somewhereelse</url>
</response>

isMeetingRunning

This call enables you to simply check on whether or not a meeting is running by looking it up with your meeting ID.

Resource URL:

https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/isMeetingRunning?[parameters]&checksum=[checksum]

Parameters:

Param Name Required/Optional Type Description
meetingID Required String The meeting ID that identifies the meeting you are attempting to check on.

Example Requests:

https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/isMeetingRunning?meetingID=test01&checksum=1234

Example Response:

<response>
  <returncode>SUCCESS</returncode>
  <running>true</running>
</response>

running can be “true” or “false” that signals whether a meeting with this ID is currently running.

end

Use this to forcibly end a meeting and kick all participants out of the meeting.

Resource URL:

  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/end?[parameters]&checksum=[checksum]

Parameters:

Param Name Required/Optional Type Description
meetingID Required String The meeting ID that identifies the meeting you are attempting to end.
password Required String The moderator password for this meeting. You can not end a meeting using the attendee password.

Example Requests:

  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/end?meetingID=1234567890&password=mp&checksum=1234

Example Response:

<response>
  <returncode>SUCCESS</returncode>
  <messageKey>sentEndMeetingRequest</messageKey>
  <message>
    A request to end the meeting was sent.  Please wait a few seconds, and then use the getMeetingInfo or isMeetingRunning API calls to verify that it was ended
  </message>
</response>

IMPORTANT NOTE: You should note that when you call end meeting, it is simply sending a request to the backend (Red5) server that is handling all the conference traffic. That backend server will immediately attempt to send every connected client a logout event, kicking them from the meeting. It will then disconnect them, and the meeting will be ended. However, this may take several seconds, depending on network conditions. Therefore, the end meeting call will return a success as soon as the request is sent. But to be sure that it completed, you should then check back a few seconds later by using the getMeetingInfo or isMeetingRunning calls to verify that all participants have left the meeting and that it successfully ended.

getMeetingInfo

This call will return all of a meeting’s information, including the list of attendees as well as start and end times.

Resource URL:

  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/getMeetingInfo?[parameters]&checksum=[checksum]

Parameters:

Param Name Required/Optional Type Description
meetingID Required String The meeting ID that identifies the meeting you are attempting to check on.

Example Requests:

  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/getMeetingInfo?meetingID=test01&checksum=1234

Example Response:

<response>
  <returncode>SUCCESS</returncode>
  <meetingName>Demo Meeting</meetingName>
  <meetingID>Demo Meeting</meetingID>
  <internalMeetingID>183f0bf3a0982a127bdb8161e0c44eb696b3e75c-1531240585189</internalMeetingID>
  <createTime>1531240585189</createTime>
  <createDate>Tue Jul 10 16:36:25 UTC 2018</createDate>
  <attendeePW>ap</attendeePW>
  <moderatorPW>mp</moderatorPW>
  <running>true</running>
  <duration>0</duration>
  <hasUserJoined>true</hasUserJoined>
  <recording>false</recording>
  <hasBeenForciblyEnded>false</hasBeenForciblyEnded>
  <startTime>1531240585239</startTime>
  <endTime>0</endTime>
  <participantCount>2</participantCount>
  <listenerCount>1</listenerCount>
  <voiceParticipantCount>1</voiceParticipantCount>
  <videoCount>1</videoCount>
  <maxUsers>20</maxUsers>
  <moderatorCount>1</moderatorCount>
  <attendees>
    <attendee>
      <userID>w_2wzzszfaptsp</userID>
      <fullName>stu</fullName>
      <role>VIEWER</role>
      <isPresenter>false</isPresenter>
      <isListeningOnly>true</isListeningOnly>
      <hasJoinedVoice>false</hasJoinedVoice>
      <hasVideo>false</hasVideo>
      <clientType>FLASH</clientType>
    </attendee>
    <attendee>
      <userID>w_eo7lxnx3vwuj</userID>
      <fullName>mod</fullName>
      <role>MODERATOR</role>
      <isPresenter>true</isPresenter>
      <isListeningOnly>false</isListeningOnly>
      <hasJoinedVoice>true</hasJoinedVoice>
      <hasVideo>true</hasVideo>
      <clientType>HTML5</clientType>
    </attendee>
  </attenهdees>
  <metadata />
  <isBreakout>false</isBreakout>
</response>

getMeetings

This call will return a list of all the meetings found on this server.

Resource URL:

https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/getMeetings?checksum=[checksum]

Parameters:

It is no more required to pass any parameter for this call.

Example Requests:

https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/getMeetings?checksum=1234

Example Response:

<response>
  <returncode>SUCCESS</returncode>
  <meetings>
    <meeting>
      <meetingName>Demo Meeting</meetingName>
      <meetingID>Demo Meeting</meetingID>
      <internalMeetingID>183f0bf3a0982a127bdb8161e0c44eb696b3e75c-1531241258036</internalMeetingID>
      <createTime>1531241258036</createTime>
      <createDate>Tue Jul 10 16:47:38 UTC 2018</createDate>
      <attendeePW>ap</attendeePW>
      <moderatorPW>mp</moderatorPW>
      <running>false</running>
      <duration>0</duration>
      <hasUserJoined>false</hasUserJoined>
      <recording>false</recording>
      <hasBeenForciblyEnded>false</hasBeenForciblyEnded>
      <startTime>1531241258074</startTime>
      <endTime>0</endTime>
      <participantCount>0</participantCount>
      <listenerCount>0</listenerCount>
      <voiceParticipantCount>0</voiceParticipantCount>
      <videoCount>0</videoCount>
      <maxUsers>0</maxUsers>
      <moderatorCount>0</moderatorCount>
      <attendees />
      <metadata />
      <isBreakout>false</isBreakout>
    </meeting>
  </meetings>
</response>

getRecordings

Retrieves the recordings that are available for playback for a given meetingID (or set of meeting IDs).

Resource URL:

https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/getRecordings?[parameters]&checksum=[checksum]

Parameters:

Param Name Required / Optional Type Description
meetingID Optional String A meeting ID for get the recordings. It can be a set of meetingIDs separate by commas. If the meeting ID is not specified, it will get ALL the recordings. If a recordID is specified, the meetingID is ignored.
recordID Optional String A record ID for get the recordings. It can be a set of recordIDs separate by commas. If the record ID is not specified, it will use meeting ID as the main criteria. If neither the meeting ID is specified, it will get ALL the recordings. The recordID can also be used as a wildcard by including only the first characters in the string.
state Optional String Since version 1.0 the recording has an attribute that shows a state that Indicates if the recording is [processing|processed|published|unpublished|deleted]. The parameter state can be used to filter results. It can be a set of states separate by commas. If it is not specified only the states [published|unpublished] are considered (same as in previous versions). If it is specified as “any”, recordings in all states are included.

Example Requests:

  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/getRecordings?checksum=1234
  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/getRecordings?meetingID=CS101&checksum=abcd
  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/getRecordings?meetingID=CS101,CS102&checksum=wxyz
  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/getRecordings?recordID=652c9eb4c07ad49283554c76301d68770326bd93-1462283509434&checksum=wxyz
  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/getRecordings?recordID=652c9eb4c07ad49283554c76301d68770326bd93-1462283509434,9e359d17635e163c4388281567601d7fecf29df8-1461882579628&checksum=wxyz
  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/getRecordings?recordID=652c9eb4c07ad49283554c76301d68770326bd93&checksum=wxyz
  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/getRecordings?recordID=652c9eb4c07ad49283554c76301d68770326bd93,9e359d17635e163c4388281567601d7fecf29df8&checksum=wxyz

Example Response:

Here the getRecordings API call returned back two recordings for the meetingID c637ba21adcd0191f48f5c4bf23fab0f96ed5c18. Each recording had two formats: podcast and presentation.

<response>
   <returncode>SUCCESS</returncode>
   <recordings>
      <recording>
         <recordID>ffbfc4cc24428694e8b53a4e144f414052431693-1530718721124</recordID>
         <meetingID>c637ba21adcd0191f48f5c4bf23fab0f96ed5c18</meetingID>
         <internalMeetingID>ffbfc4cc24428694e8b53a4e144f414052431693-1530718721124</internalMeetingID>
         <name>Fred's Room</name>
         <isBreakout>false</isBreakout>
         <published>true</published>
         <state>published</state>
         <startTime>1530718721124</startTime>
         <endTime>1530718810456</endTime>
         <participants/>
         <playback>
            <format>
               <type>AV</type>
               <url>https://s3.ir-thr-at1.tamas.lahzenegar.com/bbb-recording/recordings/2020/12/20/89cee11d-aaa4-4134-a9c1-fd64bafb1e92/video.mp4?AWSAccessKeyId=417cd7ee-cc80-406a-a96a-04b467b205d4&Expires=1608571202&Signature=jdmuK7OtpDchqMTgSqsw9liPGbk%3D</url>
               <hls>https://vod.lahzecdn.com/tamas_hls/89cee11d-aaa4-4134-a9c1-fbafb1e92/index.m3u8?checksum=9bogX2KhqSS6ZJqPxx3A&expires=1608571203</hls>
               <player>https://tamas.lahzenegar.com/client/player/?v=aHR0cHM6Ly92b2QubGFoemVjZG4uY29tL3RhbWFzX2hscy84OWNlZTExZC1hYWE0LTQxMzQtYTljMS1mZD</player>
               <length>496</length>
               <preview>
                  <images>
                     <imagehttps://s3.ir-thr-at1.tamas.lahzenegar.com/bbb-recording/recordings/2020/12/20/89cee11d-aaa4-64bafb1e92/thumbnail.png?AWSAccessKeyId=417cd7ee-cc80-406a&Expires=1923844802&Signature=KbDqp6UTlMh7</image>
                  </images>
               </preview>
            </format>
         </playback>
      </recording>
   </recordings>
</response>

deleteRecordings

Delete one or more recordings for a given recordID (or set of record IDs).

Resource URL:

https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/deleteRecordings?[parameters]&checksum=[checksum]

Parameters:

Param Name Required / Optional Type Description
recordID Required String A record ID for specify the recordings to delete. It can be a set of record IDs separated by commas.

Example Requests:

  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/deleteRecordings?recordID=record123&checksum=1234
  • https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/deleteRecordings?recordID=record123,recordABC&checksum=wxyz

Example Response:

<response>
  <returncode>SUCCESS</returncode>
  <deleted>true</deleted>
</response>

This is a node.js application that listens for all events on Tamas and sends POST requests with details about these events to hooks registered via an API. A hook is any external URL that can receive HTTP POST requests.

These web hooks allow 3rd party applications to subscribe to different events that happen during a Tamas session. An event can be: a meeting was created, a user joined, a new presentation was uploaded, a user left, a recording is being processed, and many others.

Registering hooks: API calls

This application adds three new API calls to Tamas’s API.

Hooks/Create

Creates a new hook. This call is idempotent: you can call it multiple times with the same parameters without side effects (just like the create call for meetings). Can optionally receive a meetingID parameter: if informed, this hook will receive only events for this meeting; otherwise the hook will be global and will receive events for all meetings in the server.

A hook can be registered at any time. Even hooks for specific meetingIDs can be registered even if there is no meeting with that ID yet. Once the meeting is created, the hook will receive its events.

Hooks are permanently stored on redis and will enabled until the hook is explicitly removed via API.

Resource URL: https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/hooks/create?[parameters]&checksum=[checksum]

Parameters:

Param Name Required / Optional Type Description
callbackURL Required String The URL that will receive a POST call with the events. The same URL cannot be registered more than once.
meetingID Optional String A meetingID to bind this hook to an specific meeting. If not informed, the hook will receive events for all meetings.

Response when a hook is successfully registered:

<response>
  <returncode>SUCCESS</returncode>
  <hookID>1</hookID>
  <permanentHook>false</permanentHook>
</response>

Response when a hook is already registered:

<response>
  <returncode>SUCCESS</returncode>
  <hookID>1</hookID>
  <messageKey>duplicateWarning</messageKey>
  <message>There is already a hook for this callback URL.</message>
</response>

Response when there was an error registering the hook:

<response>
  <returncode>FAILED</returncode>
  <messageKey>createHookError</messageKey>
  <message>An error happened while creating your hook. Check the logs.</message>
</response>

Hooks/Destroy

Remove a previously created hook. A hookID must be passed in the parameters to identify the hook to be removed.

Resource URL: https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/hooks/destroy?[parameters]&checksum=[checksum]

Parameters:

Param Name Required / Optional Type Description
hookID Required Number The ID of the hook that should be removed, as returned in the create hook call.

Response when a hook is successfully removed:

<response>
  <returncode>SUCCESS</returncode>
  <removed>true</removed>
</response>

Response when a hook is not found:

<response>
  <returncode>FAILED</returncode>
  <messageKey>destroyMissingHook</messageKey>
  <message>The hook informed was not found.</message>
</response>

Response when a hook is not passed in the parameters:

<response>
  <returncode>FAILED</returncode>
  <messageKey>missingParamHookID</messageKey>
  <message>You must specify a hookID in the parameters.</message>
</response>

Response when there was an error removing the hook:

<response>
  <returncode>FAILED</returncode>
  <messageKey>destroyHookError</messageKey>
  <message>An error happened while removing your hook. Check the logs.</message>
</response>

Hooks/List

Returns the hooks registered. If a meetingID is informed, will return the hooks created specifically for this meeting plus all the global hooks (since they also receive events for this meetingID). If no meetingID is informed, returns all the hooks available (not only the global hooks, as might be expected).

Resource URL: https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/api/hooks/list?[parameters]&checksum=[checksum]

Parameters:

Param Name Required / Optional Type Description
meetingID Optional String A meeting ID to restrict the hooks returned only to the hooks that receive events for this meeting. Will include hooks that receive events for this meeting only plus all global hooks.

Response when there are hooks registered:

<response>
  <returncode>SUCCESS</returncode>
  <hooks>
    <hook>
      <hookID>1</hookID>
      <callbackURL><![CDATA[http://postcatcher.in/catchers/abcdefghijk]]></callbackURL>
      <meetingID><![CDATA[my-meeting</meetingID]]>> <!-- a hook created for this meeting only -->
      <permanentHook>false</permanentHook>
    </hook>
    <hook>
      <hookID>2</hookID>
      <callbackURL><![CDATA[http://postcatcher.in/catchers/1234567890]]></callbackURL>
      <!-- no meetingID means this is a global hook -->
      <permanentHook>false</permanentHook>
    </hook>
  </hooks>
</response>

Response when there are no hooks registered:

<response>
  <returncode>SUCCESS</returncode>
  <hooks></hooks>
</response>

Callback format

All hooks registered are called via HTTP POST with all the information about the event in the body of this request. The request is sent with the Content-type HTTP header set to application/x-www-form-urlencoded and the content in the body has the following format

event={"data":{"type":"event","attributes":{},"event":{"ts":0}}}
timestamp=1415900488797

The attribute timestamp is the timestamp of when this callback was made. If the web hooks application tries to make a callback and it fails, it will try again several times, always using the same timestamp. Timestamps will never be the same for different events and the value will always increase.

The attribute event is a stringified version of all the data from the event. The data varies for different types of events, check the documentation for more information.

Moreover, the callback call is signed with a checksum, that is included in the URL of the request. If the registered URL is https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/callback, it will receive the checksum as in https://tamas.lahzenegar.com/b/{YOUR_USERNAME}/callback?checksum=yalsdk18129e019iklasd90i.

sha1(<callback URL>+<data body>+<shared secret>)

Where:

  • <callback URL>: The original callback URL, that doesn’t include the checksum.
  • <data body as a string>: All the data sent in the body of the request, concatenated and joined by &, as if they were parameters in a URL.
  • <shared secret>: The shared secret of Tamas's user.

So, upon receiving a callback call, an application could validate the checksum as follows:

  • Get the body of the request, as in the example below:
event={"data":{"type":"event","attributes":{},"event":{"ts":0}}}
timestamp=1234567890
And convert it to a string like in the example below:
event={"data":{"type":"event","attributes":{},"event":{"ts":0}}}
timestamp=1234567890
  • Concatenate the original callback URL, the string from the previous step, and the Tamas’s salt.
  • Calculate a sha1() of this string.
  • The checksum calculated should equal the checksum received in the parameters of the request.

More details

  • Callbacks are always triggered for one event at a time and in order. They are ordered the same way

    they appear on redis pubsub (which might not exactly be the order indicated by their timestamps).

    The timestamps will almost always be ordered as well, but it’s not guaranteed.

  • The application assumes that events are never duplicated on pubsub. If they happen to be

    duplicated, the callback calls will also be duplicated.

  • Hooks are only removed if a call to /hooks/destroy is made or if the callbacks for the hook fail too

    many times (~12) for a long period of time (~5min). They are never removed otherwise. Valid for

    both global hooks and hooks for specific meetings. So it’s recommended for 3rd-party applications

    to register the hooks more than just once. You can either check if your hook is registered with

    /hooks/list and register it if it isn’t, or simply register your hook every e.g. 5 minutes.

  • The application uses internal mappings to find out to which meeting the events received from redis

    are related to. These mappings are removed after 24 hours of inactivity. If there are no events at

    all for a given meeting during this period, it will be assumed dead. This is done to prevent data

    from being stored forever on redis. This means that you can have issues if you have a hook

    registered for an specific meeting (doesn’t happen for global hooks) and this meeting happens to

    not generate events for 24 hours, but it’s still valid after it. Something very, very unlikely to

    happen!

  • External URLs are expected to respond with the HTTP status 2xx (200 would be the default expected).

    Anything different from these values will be considered an error and the callback will be called

    again. This includes redirects: if your hook redirects the request, it will be considered as

    invalid and the web hooks application will try to call this hook again.

  • If a meeting is created while the web hooks application is down, callbacks will never be triggered

    for this meeting. The application needs to detect the create event (meeting_created_message) to

    have a proper mapping of internal to external meeting IDs. So make sure the web hooks application

    is always running while Tamas is running!

Test it

The easiest way to test the web hooks application is to register hooks in Tamas using the API Mate and capture the callbacks using the service PostCatcher.

Follow the steps:

  • Open PostCatcher and click on “Start testing your POST requests now”

  • It will redirect you to an URL such as http://postcatcher.in/catchers/5527e67ba4c6dd0300000738.

    Save this URL to use later.

  • Open the API Mate and configure your URL access and shared secret.

  • On the menu “Custom parameters”, there’s a field “Custom API calls:”. Add these values to it:

hooks/create
hooks/list
  • On the same menu section, add the following values to “Custom parameters:”:
callbackURL=http://postcatcher.in/catchers/5527e67ba4c6dd0300000738
Modify this URL to the URL you got from PostCatcher earlier.
  • On the API Mate, click on the “custom call: hooks/create” link. It should respond with a success

    message.

  • On the API Mate, click on the “custom call: hooks/list” link to check if your hook was really

    registered.

  • Create a meeting and join it using the API Mate.

  • Do stuff inside the meeting and check your PostCatcher page, you should see events pop up on it

    as you interact in your meeting.