Skip to main content

Receive notifications about channel events

A webhook is a user-defined callback over HTTP. You use webhooks to notify your app or back-end system when certain Video Calling events occur. Agora Notifications enables you to subscribe to events and receive notifications about them across multiple product lines.

Understand the tech

Using Agora Console you subscribe to specific events for your project and tell Notifications the URL of the webhooks you have configured to receive these events. Notifications sends notifications of your events to your webhooks every time they occur. Your server authenticates the notification and returns 200 Ok to confirm reception. You use the information in the JSON payload of each notification to give the best user experience to your users.

The following figure illustrates the workflow when Notifications is enabled for the specific events you subscribe to:

  1. A user commits an action that creates an event. For example, creates a channel.
  2. Notifications sends an HTTPS POST request to your webhook.
  3. Your server validates the request signature, then sends a response to Notifications within 10 seconds. The response body must be in JSON.

If Notifications receives 200 OK within 10 seconds of sending the initial notification, the callback is considered successful. If these conditions are not met, Notifications immediately resends the notification. The interval between notification attempts gradually increases. Notifications stops sending notifications after three retries.

Prerequisites

To set up and use Agora NCS, you must have:

Handle notifications for specific events

In order to handle notifications for the events you subscribe to you need to:

Create your webhook

Once Notifications is enabled, Agora SD-RTN™ sends notification callbacks as HTTPS POST requests to your webhook when events that you are subscribed to occur. The data format of the requests is JSON, the character encoding is UTF-8, and the signature algorithm is HMAC/SHA1 or HMAC/SHA256.

For Notifications, a webhook is an endpoint on an HTTP server that handles these requests. In a production environment you write this in your web infrastructure, for development purposes best practice is to create a simple local server and use a service such as ngrok to supply a public URL that you register with Agora SD-RTN™ when you enable Notifications.

To do this, take the following steps:

  1. Setup a Java project for your server

    Your server receives and handles Notifications notifications. The RootHandler handles requests sent to the root address of your server and the NcsHandler handles the Notifications notifications sent to <your server address>/ncsNotify. To Set up your server, create a new Java project and add the following code to a file named Main.java:


    _34
    import java.io.IOException;
    _34
    import java.net.InetSocketAddress;
    _34
    import com.sun.net.httpserver.HttpServer;
    _34
    _34
    public class Main {
    _34
    public static int port = 80;
    _34
    _34
    public static void main(String[] args) {
    _34
    // Start http server
    _34
    SimpleHttpServer httpServer = new SimpleHttpServer();
    _34
    httpServer.Start(port);
    _34
    }
    _34
    _34
    static class SimpleHttpServer {
    _34
    private HttpServer server;
    _34
    _34
    public void Start(int port) {
    _34
    try {
    _34
    server = HttpServer.create(new InetSocketAddress(port), 0);
    _34
    System.out.println("Notifications webhook server started at port " + port);
    _34
    server.createContext("/", new Handlers.RootHandler());
    _34
    server.createContext("/ncsNotify", new Handlers.NcsHandler());
    _34
    server.setExecutor(null);
    _34
    server.start();
    _34
    } catch (IOException e) {
    _34
    e.printStackTrace();
    _34
    }
    _34
    }
    _34
    _34
    public void Stop() {
    _34
    server.stop(0);
    _34
    }
    _34
    }
    _34
    }

  2. Add a JSON library to your project

    The body of an HTTP request that your server receives contains event parameters in JSON format. To read these parameters download the json-simple-1.1.1.jar library and add it to your JAVA project.

  3. Handle Notifications callbacks

    To define the RootHandler and the NcsHandler, create a new file named Handlers.java in your JAVA project folder. Add the following code to this file:


    _86
    import java.io.BufferedReader;
    _86
    import java.io.IOException;
    _86
    import java.io.InputStreamReader;
    _86
    import java.io.OutputStream;
    _86
    import java.util.stream.Collectors;
    _86
    _86
    import com.sun.net.httpserver.Headers;
    _86
    import com.sun.net.httpserver.HttpExchange;
    _86
    import com.sun.net.httpserver.HttpHandler;
    _86
    import org.json.simple.JSONObject;
    _86
    import org.json.simple.parser.JSONParser;
    _86
    _86
    public class Handlers {
    _86
    _86
    public static class RootHandler implements HttpHandler {
    _86
    @Override
    _86
    public void handle(HttpExchange he) throws IOException {
    _86
    String response = "<h1>Agora Notifications demo</h1>" + "<h2>Port: " + Main.port + "</h2>";
    _86
    he.sendResponseHeaders(200, response.length());
    _86
    OutputStream os = he.getResponseBody();
    _86
    os.write(response.getBytes());
    _86
    os.close();
    _86
    }
    _86
    }
    _86
    _86
    public static class NcsHandler implements HttpHandler {
    _86
    _86
    @Override
    _86
    public void handle(HttpExchange he) throws IOException {
    _86
    Headers headers = he.getRequestHeaders();
    _86
    // Read signatures from the request header
    _86
    String agoraSignature = headers.getFirst("Agora-Signature");
    _86
    //String agoraSignatureV2 = headers.getFirst("Agora-Signature-V2");
    _86
    _86
    InputStreamReader isr = new InputStreamReader(he.getRequestBody(), "utf-8");
    _86
    BufferedReader br = new BufferedReader(isr);
    _86
    _86
    // Read the request body
    _86
    String body = br.lines()
    _86
    .collect(Collectors.joining(System.lineSeparator()));
    _86
    _86
    String noticeId, channelName = "";
    _86
    long productId, clientSeq = 0;
    _86
    int uid = 0, eventType;
    _86
    _86
    // Read event parameters from JSON in the request body
    _86
    try {
    _86
    JSONObject jsonObj = (JSONObject) new JSONParser().parse(body);
    _86
    _86
    noticeId = (String) jsonObj.get("noticeId");
    _86
    productId = (long) jsonObj.get("productId");
    _86
    eventType = (int) (long) jsonObj.get("eventType");
    _86
    JSONObject payload = (JSONObject) jsonObj.get("payload");
    _86
    _86
    // Read payload
    _86
    if (payload.containsKey("clientSeq"))
    _86
    clientSeq = (long) payload.get("clientSeq");
    _86
    _86
    if (payload.containsKey("uid"))
    _86
    uid = (int) (long) payload.get("uid");
    _86
    _86
    if (payload.containsKey("channelName"))
    _86
    channelName = (String) payload.get("channelName");
    _86
    _86
    System.out.println(
    _86
    "Event code: " + eventType
    _86
    + " Uid: " + uid
    _86
    + " Channel: " + channelName
    _86
    + " ClientSeq: " + clientSeq);
    _86
    _86
    } catch (Exception e) {
    _86
    System.out.println("Error parsing JSON: " + e.toString());
    _86
    return;
    _86
    }
    _86
    _86
    // Send OK response code 200
    _86
    String response = "Ok";
    _86
    he.sendResponseHeaders(200, response.length());
    _86
    OutputStream os = he.getResponseBody();
    _86
    os.write(response.toString().getBytes());
    _86
    os.close();
    _86
    _86
    }
    _86
    }
    _86
    _86
    }

  4. Create a public URL for your server

    In this example you use ngrok to create a public URL for your server.

    1. Download and install ngrok. If you have Chocolatey, use the following command:


      _1
      choco install ngrok

    2. Add an authtoken to ngrok:


      _1
      ngrok config add-authtoken <token>

      To obtain an authtoken, sign up with ngrok.

    3. Start a tunnel to your local server using the following command:


      _1
      ngrok http <local server port>

      You see a Forwarding URL displayed such as https:// 1111-123-456-789-99.ap.ngrok.io. This is the public URL for your local server that you use to enable Notifications.

Enable Notifications

To enable Notifications:

  1. Log in to Agora Console. On the Project Management tab, locate the project for which you want to enable Notifications and click Config.

  2. Select the Service Config tab, locate Notification Center Service, and click Enable.

  3. In Notification Center Service Configuration, fill in the following information:

    • Product Name: Select the product for which you wish to enable notifications.

    • Event: Select all the channel events that you want to subscribe to.

      If the events that you want to subscribe to generate a high number of queries per second (QPS), such as events 105 and 106, ensure your server has sufficient processing capacity.

    • Receive Server Location: Select the region where your server that receives the notifications is located. Agora connects to the nearest Agora node server based on your specified location.

    • Receive Server URL: The HTTPS public address of your server that receives the notifications. For example, https://1111-123-456-789-99.ap.ngrok.io/ncsNotify.

      • To enhance security, Agora Notifications no longer supports HTTP addresses.

      • To reduce the delay in notification delivery, best practice is to activate HTTP persistent connection (also called HTTP keep-alive) on your server with the following settings:

        • MaxKeepAliveRequests: 100 or more
        • KeepAliveTimeout: 10 seconds or more
    • Secret: Copy and save the displayed secret to Add signature verification.

    • Allowed IP List: If your server is behind a firewall, check the box here, and ensure that you call the IP address query API to get the IP addresses of the Agora Notifications server and add them to the firewall's allowed IP list.

  4. Press Save. Agora performs a health test for your configuration as follows:

    1. The Notifications health test generates test events that correspond to your subscribed events, and then sends test event callbacks to your server. In test event callbacks, the channelName is test_webhook, and the uid is 12121212.

    2. After receiving each test event callback, your server must respond within 10 seconds with a status code of 200. The response body must be in JSON format.

    3. When the Notifications health test succeeds, read the prompt and press Save Notifications Configuration. After your configuration is approved, the Status of Notification Center Service shows Enabled.

      If the Notifications health test fails, follow the prompt on the Agora Console to troubleshoot the error. Common errors include the following:

      • Request timeout (590): Your server does not return the status code 200 within 10 seconds. Check whether your server responds to the request properly. If your server responds to the request properly, contact Agora Technical Support to check if the network connection between the Agora Notifications server and your server is working.

      • Domain name unreachable (591): The domain name is invalid and cannot be resolved to the target IP address. Check whether your server is properly deployed.

      • Certificate error (592): The Agora Notifications server fails to verify the SSL certificates returned by your server. Check if the SSL certificates of your server are valid. If your server is behind a firewall, check whether you have added all IP addresses of the Agora Notifications server to the firewall's allowed IP list.

      • Other response errors: Your server returns a response with a status code other than 200. See the prompt on the Agora Console for the specific status code and error messages.

Add signature verification

To communicate securely between Notifications and your webhook, Agora SD-RTN™ uses signatures for identity verification.

  • When you configure Notifications in Agora Console, Agora SD-RTN™ generates the secret you use for verification.

  • When sending a notification, Notifications generates two signature values from the secret using HMAC/SHA1 and HMAC/SHA256 algorithms. These signatures are added as Agora-Signature and Agora-Signature-V2 to the HTTPS request header.

  • When your server receives a callback, you can verify Agora-Signature or Agora-Signature-V2.

    • To verify Agora-Signature, use the secret, the raw request body, and the HMAC/SHA1 algorithm.
    • To verify Agora-Signature-V2, use the secret, the raw request body, and the HMAC/SHA2 algorithm.

To add signature verification to your server, take the following steps:

  1. In your JAVA project folder, add a new file named Signature.java containing the following code:


    _40
    import javax.crypto.Mac;
    _40
    import javax.crypto.spec.SecretKeySpec;
    _40
    _40
    public class Signature {
    _40
    static String secret = "<your NCS secret>";
    _40
    _40
    public static String bytesToHex(byte[] bytes) {
    _40
    // Convert an encrypted byte array into a hex string
    _40
    StringBuffer sb = new StringBuffer();
    _40
    for (int i = 0; i < bytes.length; i++) {
    _40
    String hex = Integer.toHexString(bytes[i] & 0xFF);
    _40
    if (hex.length() < 2) {
    _40
    sb.append(0);
    _40
    }
    _40
    sb.append(hex);
    _40
    }
    _40
    return sb.toString();
    _40
    }
    _40
    _40
    // Use the HMAC/SHA1 algorithm and get the encrypted hex string
    _40
    // To use the HMAC/SHA256 algorithm, replace "HmacSHA1" with "HmacSHA256"
    _40
    public static String hmacSha1(String message) {
    _40
    try {
    _40
    SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes(
    _40
    "utf-8"), "HmacSHA1");
    _40
    Mac mac = Mac.getInstance("HmacSHA1");
    _40
    mac.init(signingKey);
    _40
    byte[] rawHmac = mac.doFinal(message.getBytes("utf-8"));
    _40
    return bytesToHex(rawHmac);
    _40
    } catch (Exception e) {
    _40
    throw new RuntimeException(e);
    _40
    }
    _40
    }
    _40
    _40
    public static boolean verify(String request_body, String signature) {
    _40
    // Check the signature against the encrypted request body
    _40
    // Returns true if the signature matches the encrypted hex string
    _40
    return (hmacSha1(request_body).equals(signature));
    _40
    }
    _40
    }

    Make sure you update your Notifications secret in the code. To verify authenticity using Agora-Signature-V2, replace HmacSHA1 with HmacSHA256 in the sample code.

  1. To verify data in the Notifications callback, add the following code to your Notifications notification handler:


    _3
    // Pass the request body and the signature from the request header
    _3
    boolean isVerified = Signature.verify(body, agoraSignature);
    _3
    System.out.println("Signature verified: " + isVerified);

Implement online user status tracking

This section provides sample Java code to show how to use channel event callbacks to maintain online user status at your app server.

To maintain a user registry, take the following steps:

  1. Create a new file in you JAVA project folder named UserRegistry.java containing the following code.


    _147
    import java.util.HashMap;
    _147
    import java.util.Timer;
    _147
    import java.util.TimerTask;
    _147
    _147
    public class UserRegistry {
    _147
    public static int EVENT_BROADCASTER_JOIN = 103;
    _147
    public static int EVENT_BROADCASTER_QUIT = 104;
    _147
    public static int EVENT_AUDIENCE_JOIN = 105;
    _147
    public static int EVENT_AUDIENCE_QUIT = 106;
    _147
    public static int EVENT_CHANGE_ROLE_TO_BROADCASTER = 111;
    _147
    public static int EVENT_CHANGE_ROLE_TO_AUDIENCE = 112;
    _147
    _147
    public static int ROLE_BROADCASTER = 1;
    _147
    public static int ROLE_AUDIENCE = 2;
    _147
    public static int WAIT_TIMEOUT_MS = 60 * 1000;
    _147
    private static Timer timer = new Timer();
    _147
    _147
    class User { // Holds user information
    _147
    int uid; // user ID
    _147
    int role; // user role
    _147
    boolean isOnline; // whether the user is in a channel
    _147
    long lastClientSeq; // clientSeq of the last event handled by your server
    _147
    _147
    public User(int uid, int role, boolean isOnline, long clientSeq) {
    _147
    this.uid = uid;
    _147
    this.role = role;
    _147
    this.isOnline = isOnline;
    _147
    this.lastClientSeq = clientSeq;
    _147
    }
    _147
    };
    _147
    _147
    // Channel list
    _147
    private static HashMap<String, Channel> channels = new HashMap<>();;
    _147
    _147
    class Channel { // Holds the list of users in each channel
    _147
    HashMap<Integer, User> users = new HashMap<>();
    _147
    };
    _147
    _147
    // Process Agora Notifications callbacks to update user registry
    _147
    public void HandleNcsEvent(String channelName, int uid, int eventType, long clientSeq) {
    _147
    // Check the eventType to process events that notify of users joining or
    _147
    // leaving a channel or a change in the user role
    _147
    if (eventType != EVENT_BROADCASTER_JOIN &&
    _147
    eventType != EVENT_BROADCASTER_QUIT &&
    _147
    eventType != EVENT_AUDIENCE_JOIN &&
    _147
    eventType != EVENT_AUDIENCE_QUIT &&
    _147
    eventType != EVENT_CHANGE_ROLE_TO_BROADCASTER &&
    _147
    eventType != EVENT_CHANGE_ROLE_TO_AUDIENCE) {
    _147
    _147
    return;
    _147
    }
    _147
    _147
    // Determine whether a user is online
    _147
    boolean isOnlineInNotice = IsUserOnlineInNotice(eventType);
    _147
    // Get the user role from eventType
    _147
    int roleInNotice = GetUserRoleInNotice(eventType);
    _147
    _147
    Channel channel = channels.get(channelName);
    _147
    if (channel == null) {
    _147
    // If a channel does not exist, create a channel and add it to the list
    _147
    channel = new Channel();
    _147
    channels.put(channelName, channel);
    _147
    System.out.println("New channel " + channelName + " created");
    _147
    }
    _147
    _147
    User user = channel.users.get(uid);
    _147
    // Get whether a user has left a channel
    _147
    boolean isQuit = !isOnlineInNotice && (user == null || user.isOnline);
    _147
    if (user == null) {
    _147
    // Create a new user and add it to the user list of the corresponding channel
    _147
    user = new User(uid, roleInNotice, isOnlineInNotice, clientSeq);
    _147
    channel.users.put(uid, user);
    _147
    _147
    if (isOnlineInNotice) {
    _147
    System.out.println("New User " + uid + " joined channel " + channelName);
    _147
    } else {
    _147
    // Set a timer for deleting a user's data after the user leaves a channel
    _147
    DelayedRemoveUserFromChannel(channelName, uid, clientSeq);
    _147
    }
    _147
    } else if (clientSeq > user.lastClientSeq) {
    _147
    /*
    _147
    * If the data for a user already exists, compare the clientSeq
    _147
    * of the latest notification with that of the last notification
    _147
    * callback handled by your server. If the latest value is greater,
    _147
    * update the user data; otherwise, ignore the notification callback.
    _147
    */
    _147
    user.role = roleInNotice;
    _147
    user.isOnline = isOnlineInNotice;
    _147
    user.lastClientSeq = clientSeq;
    _147
    _147
    if (isQuit) {
    _147
    // Mark the status of a user as offline, and delete the user after one minute
    _147
    System.out.println("User " + uid + " quit channel " + channelName);
    _147
    DelayedRemoveUserFromChannel(channelName, uid, clientSeq);
    _147
    }
    _147
    }
    _147
    }
    _147
    _147
    // Set a timer for deleting the data of an offline user
    _147
    private void DelayedRemoveUserFromChannel(final String channelName, final int uid, final long clientSeq) {
    _147
    timer.schedule(new TimerTask() {
    _147
    @Override
    _147
    public void run() {
    _147
    Channel channel = channels.get(channelName);
    _147
    if (channel == null) return;
    _147
    User user = channel.users.get(uid);
    _147
    if (user == null) return;
    _147
    _147
    // If the value in the clientSeq field changes, do not delete data
    _147
    if (user.lastClientSeq != clientSeq) return;
    _147
    _147
    if (!user.isOnline) {
    _147
    // Delete user data only when the user is offline
    _147
    channel.users.remove(uid);
    _147
    System.out.println("Removed user " + uid + " from channel " + channelName);
    _147
    } else {
    _147
    System.out.println("User " + uid + " is online while delayed removing, cancelled");
    _147
    }
    _147
    _147
    // If there are no users left in the channel, delete the channel
    _147
    if (channel.users.isEmpty()) {
    _147
    channels.remove(channelName);
    _147
    System.out.println("Removed channel " + channelName);
    _147
    }
    _147
    }
    _147
    }, WAIT_TIMEOUT_MS);
    _147
    }
    _147
    _147
    // Determine whether a user is online.
    _147
    private static boolean IsUserOnlineInNotice(int eventType) {
    _147
    return eventType == EVENT_BROADCASTER_JOIN ||
    _147
    eventType == EVENT_AUDIENCE_JOIN ||
    _147
    eventType == EVENT_CHANGE_ROLE_TO_BROADCASTER ||
    _147
    eventType == EVENT_CHANGE_ROLE_TO_AUDIENCE;
    _147
    }
    _147
    _147
    // Get the user role.
    _147
    private static int GetUserRoleInNotice(int eventType) {
    _147
    if (eventType == EVENT_BROADCASTER_JOIN ||
    _147
    eventType == EVENT_BROADCASTER_QUIT ||
    _147
    eventType == EVENT_CHANGE_ROLE_TO_BROADCASTER) {
    _147
    return ROLE_BROADCASTER;
    _147
    } else {
    _147
    return ROLE_AUDIENCE;
    _147
    }
    _147
    }
    _147
    }

  2. Instantiate the UserRegistry class

    Add the following code to the Handlers class after public class Handlers {:


    _1
    public static UserRegistry userRegistry = new UserRegistry();

  3. To update the user registry when you receive a Notifications callback, add the following code to the handle method in the NcsHandler class after os.close();:


    _2
    // Maintain user registry
    _2
    userRegistry.HandleNcsEvent(channelName, uid, eventType, clientSeq);

When adopting the solutions recommended by Agora to maintain user online status, you need to recognize the following:

  • The solutions only guarantee eventual consistency of user status.
  • To improve accuracy, notification callbacks specific to one channel must be handled in a single process.

Handle redundant notifications and abnormal user activity

When using Notifications to maintain the online status of your app users, your server might experience the following issues:

  • Message notifications are redundant. You receive multiple notifications because the Agora Notifications server can send more than one notification callback for each channel event to ensure reliability of the service.

  • Message notifications arrive out of order. Network issues cause callbacks to arrive at your server in a different order than the order of event occurrence.

To accurately maintain the online status of users, your server needs to be able to deal with redundant notifications and handle received notifications in the same order as events occur. The following section shows you how to use channel event callbacks to accomplish this.

Handle redundant or out of order notifications

Agora Notifications sends RTC channel event callbacks to your server. All channel events, except for 101 and 102 events, contain the clientSeq field (Unit64) in payload, which represents the sequence number of an event. This field is used to identify the order in which events occur on the app client. For notification callbacks reporting the activities of the same user, the value of the clientSeq field increases as events happen.

Refer to the following steps to use the clientSeq field to enable your server to handle redundant messages, and messages arriving out of order:

  1. Enable Agora Notifications, and subscribe to RTC channel event callbacks. Best practice is to subscribe to the following event types according to your scenario:

    • In the LIVE_BROADCASTING profile: 103, 104, 105, 106, 111, and 112.
    • In the COMMUNICATION profile: 103, 104, 111, and 112.
  2. Use the channel event callbacks to get the latest status updates about the following at your server:

    • Channel lists
    • User lists in each channel
    • Data for each user, including the user ID, user role, whether the user is in a channel, and clientSeq of channel events
  3. When receiving notification callbacks of a user, search for the user in the user lists. If there is no data for the user, create data specific to the user.

  4. Compare the value in the clientSeq field of the latest notification callback you receive with that of the last notification callback handled by your server:

    • If the former is greater than the latter, the notification callback needs to be handled.
    • If the former is less than the latter, the notification callback should be ignored.
  5. When receiving notification callbacks reporting a user leaving a channel, wait for one minute before deleting the user data. If it is deleted immediately, your server cannot handle notifications in the same order as channel events happen when receiving redundant notifications or notifications out of order.

Deal with abnormal user activities

When your server receives a notification callback of event 104 with reason as 999, it means that the user is considered to have abnormal activities due to frequent login and logout actions. In this case, best practice is that your server calls the Banning user privileges API to remove the user from the current channel one minute after receiving such notification callback; otherwise, the notification callbacks your server receives about the user's events might be redundant or arrive out of order, which makes it hard for you to accurately maintain the online status of this user.

Reference

This section contains in depth information about Notifications

Request Header

The header of notification callbacks contains the following fields:

Field nameValue
Content-Typeapplication/json
Agora-SignatureThe signature generated by Agora using the Secret and the HMAC/SHA1 algorithm. You need to use the Secret and HMAC/SHA1 algorithm to verify the signature value. For details, see Signature verification.
Agora-Signature-V2The signature generated by Agora using the Secret and the HMAC/SHA256 algorithm. You need to use the Secret and the HMAC/SHA256 algorithm to verify the signature value. For details, see Signature verification.

Request Body

The request body of notification callbacks contains the following fields:

Field nameTypeDescription
noticeIdStringThe notification ID, identifying the notification callback when the event occurs.
productIdNumberThe product ID. Value 1 means the Realtime Communication (RTC) service.
eventTypeNumberThe type of events being notified. For details, see event types.
notifyMsNumberThe Unix timestamp (ms) when the Agora Notifications server sends a notification callback to your server. This value is updated when the Agora server resends the notification callback.
payloadJSON ObjectThe content of the event being notified. The payload varies with event type. For details, see Channel event types.

Example


_9
{
_9
"noticeId":"2000001428:4330:107",
_9
"productId":1,
_9
"eventType":101,
_9
"notifyMs":1611566412672,
_9
"payload":{
_9
...
_9
}
_9
}

Channel events

The Agora Notifications server notifies your server of the following channel event types when you use the RTC service:

eventTypeEvent nameDescription
101channel createInitializes the channel.
102channel destroyDestroys the channel.
103broadcaster join channelIn the live streaming profile, the host joins the channel.
104broadcaster leave channelIn the live streaming profile, the host leaves the channel.
105audience join channelIn the live streaming profile, an audience member joins the channel.
106audience leave channelIn the live streaming profile, an audience member leaves the channel.
107user join channel with communication modeIn the communication profile, a user joins the channel. This events applies to the communication mode in RTC v3.x products only. For the communication profile in RTC v4.x (v4.0.0 and higher versions) products, your server receives the 103 event instead.
108user leave channel with communication modeIn the communication profile, a user leaves the channel. This events applies to the communication profile in RTC v3.x products only. For the communication profile in RTC v4.x products, your server receives the 104 event instead.
111client role change to broadcasterIn the communication profile in RTC v4. x products or in the live streaming profile, an audience member switches their user role to host.
112client role change to audienceIn the communication profile in RTC v4. x products or in the live streaming profile, a host switches their user role to audience member.

101 channel create

This event type indicates that a channel is initialized (when the first user joins the channel). The payload contains the following fields:

Field nameTypeDescription
channelNameStringThe name of the channel.
tsNumberThe Unix timestamp (s) when the event occurs on the Agora RTC server.
Example

_4
{
_4
"channelName":"test_webhook",
_4
"ts":1560399999
_4
}

102 channel destroy

This event type indicates that the last user in the channel leaves the channel and the channel is destroyed. The payload contains the following fields:

Field nameTypeDescription
channelNameStringThe name of the channel.
tsNumberThe Unix timestamp (s) when the event occurs on the Agora RTC server.
Example

_4
{
_4
"channelName":"test_webhook",
_4
"ts":1560399999
_4
}

103 broadcaster join channel

This event type indicates that a host joins the channel in the live streaming profile. The payload contains the following fields:

Field nameTypeDescription
channelNameStringThe name of the channel.
uidNumberThe user ID of the host in the channel.
platformNumberThe platform type of the host's device:
  • 1: Android
  • 2: iOS
  • 5: Windows
  • 6: Linux
  • 7: Web
  • 8: macOS
  • 0: Other platform
clientTypeNumberThe type of services used by the host on Linux. Common return values include:
  • 3: On-premise Recording
  • 10: Cloud Recording
This field is only returned when platform is 6.
clientSeqNumberThe sequence number, which is used to identify the order in which events occur on the app client. You can use the value of this field to sort the events of a user into chronological order.
tsNumberThe Unix timestamp (s) when the event occurs on the Agora RTC server.
Example

_7
{
_7
"channelName":"test_webhook",
_7
"uid":12121212,
_7
"platform":1,
_7
"clientSeq":1625051030746,
_7
"ts":1560396843
_7
}

104 broadcaster leave channel

This event type indicates that a host leaves the channel in the live streaming profile. The payload contains the following fields:

Field nameTypeDescription
channelNameStringThe name of the channel.
uidNumberThe user ID of the host in the channel.
platformNumberThe platform type of the host's device:
  • 1: Android
  • 2: iOS
  • 5: Windows
  • 6: Linux
  • 7: Web
  • 8: macOS
  • 0: Other platform
clientTypeNumberThe type of services used by the host on Linux. Common return values include:
  • 3: On-premise Recording
  • 10: Cloud Recording
This field is only returned when platform is 6.
clientSeqNumberThe sequence number, which is used to identify the order in which events occur on the app client. You can use the value of this field to sort the events of a user into chronological order.
reasonNumberThe reason why the host leaves the channel:
  • 1: The host quits the call.
  • 2: The connection between the app client and the Agora RTC server times out, which occurs when the Agora SD-RTN does not receive any data packets from the app client for more than 10 seconds.
  • 3: Permission issues. For example, the host is kicked out of the channel by the administrator through the Banning user privileges RESTful API.
  • 4: Internal issues with the Agora RTC server. For example, the Agora RTC server disconnects from the app client for a short period of time for load balancing. When the load balancing is finished, the Agora RTC server reconnects with the client.
  • 5: The host uses a new device to join the channel, which forces the old device to leave the channel.
  • 9: The app client has multiple IP addresses, therefore the SDK actively disconnects from the Agora RTC server and reconnects. The user is not aware of this process. Check whether the app client has multiple public IP addresses or uses a VPN
  • 10: Due to network connection issues, for example, the SDK does not receive any data packets from the Agora RTC server for more than 4 seconds or the socket connection error occurs, the SDK actively disconnects from the Agora server and reconnects. The user is not aware of this process. Check the network connection status.
  • 999: The user has unusual activities, such as frequent login and logout actions. 60 seconds after receiving the 104 or 106 event callback with reason as 999, your app server needs to call the Banning user privileges API to remove the user from the current channel; otherwise, your server could fail to receive any notification callbacks about the user's events if the user rejoins the channel.
  • 0: Other reasons.
tsNumberThe Unix timestamp (s) when the event occurs on the Agora RTC server.
durationNumberThe length of time (s) that the host stays in the channel.
Example

_9
{
_9
"channelName":"test_webhook",
_9
"uid":12121212,
_9
"platform":1,
_9
"clientSeq":1625051030789,
_9
"reason":1,
_9
"ts":1560396943,
_9
"duration":600
_9
}

105 audience join channel

This event type indicates that an audience member joins the channel in the live streaming profile The payload includes the following fields:

Field nameTypeDescription
channelNameStringThe name of the channel.
uidNumberThe user ID of the audience member in the channel.
platformNumberThe platform type of the audience member's device:
  • 1: Android
  • 2: iOS
  • 5: Windows
  • 6: Linux
  • 7: Web
  • 8: macOS
  • 0: Other platform
clientTypeNumberThe type of services used by the host on Linux. Common return values include:
  • 3: On-premise Recording
  • 10: Cloud Recording
This field is only returned when platform is 6.
clientSeqNumberThe sequence number, which is used to identify the order in which events occur on the app client. You can use the value of this field to sort the events of a user into chronological order.
tsNumberThe Unix timestamp (s) when the event occurs on the Agora RTC server.
Example

_7
{
_7
"channelName":"test_webhook",
_7
"uid":12121212,
_7
"platform":1,
_7
"clientSeq":1625051035346,
_7
"ts":1560396843
_7
}

106 audience leave channel

This event type indicates that an audience member leaves the channel in the live streaming profile. The payload includes the following fields:

Field nameTypeDescription
channelNameStringThe name of the channel.
uidNumberThe user ID of the audience member in the channel.
platformNumberThe platform type of the audience member's device:
  • 1: Android
  • 2: iOS
  • 5: Windows
  • 6: Linux
  • 7: Web
  • 8: macOS
  • 0: Other platform
clientTypeNumberThe type of services used by the audience member on Linux. Common return values include:
  • 3: On-premise Recording
  • 10: Cloud Recording
This field is only returned when platform is 6.
clientSeqNumberThe sequence number, which is used to identify the order in which events occur on the app client. You can use the value of this field to sort the events of a user into chronological order.
reasonNumberThe reason why the audience member leaves the channel:
  • 1: The audience member quits the call.
  • 2: The connection between the app client and the Agora RTC server times out, which occurs when the Agora SD-RTN does not receive any data packets from the app client for more than 10 seconds.
  • 3: Permission issues. For example, the audience member is kicked out of the channel by the administrator through the Banning user privileges RESTful API.
  • 4: Internal issues with the Agora RTC server. For example, the Agora RTC server disconnects from the app client for a short period of time for load balancing. When the load balancing is finished, the Agora RTC server reconnects with the client.
  • 5: The audience member uses a new device to join the channel, which forces the old device to leave the channel.
  • 9: The app client has multiple IP addresses, therefore the SDK actively disconnects from the Agora RTC server and reconnects. The user is not aware of this process. Check whether the app client has multiple public IP addresses or uses a VPN
  • 10: Due to network connection issues, for example, the SDK does not receive any data packets from the Agora RTC server for more than 4 seconds or the socket connection error occurs, the SDK actively disconnects from the Agora server and reconnects. The user is not aware of this process. Check the network connection status.
  • 999: The user has unusual activities, such as frequent login and logout actions. 60 seconds after receiving the 104 or 106 event callback with reason as 999, your app server needs to call the Banning user privileges API to remove the user from the current channel; otherwise, your server could fail to receive any notification callbacks about the user's events if the user rejoins the channel.
  • 0: Other reasons.
tsNumberThe Unix timestamp (s) when the event occurs on the Agora RTC server.
durationNumberThe length of time (s) that the audience member stays in the channel.
Example

_9
{
_9
"channelName":"test_webhook",
_9
"uid":12121212,
_9
"platform":1,
_9
"clientSeq":1625051035390,
_9
"reason":1,
_9
"ts":1560396943,
_9
"duration":600
_9
}

107 user join channel with communication mode

This event type indicates that a user joins the channel in the communication profile. The payload includes the following fields:

Field nameTypeDescription
channelNameStringThe name of the channel.
uidNumberThe user ID of the user in the channel.
platformNumberThe platform type of the host's device:
  • 1: Android
  • 2: iOS
  • 5: Windows
  • 6: Linux
  • 7: Web
  • 8: macOS
  • 0: Other platform
clientSeqNumberThe sequence number, which is used to identify the order in which events occur on the app client. You can use the value of this field to sort the events of a user into chronological order.
tsNumberThe Unix timestamp (s) when the event occurs on the Agora RTC server.
Example

_7
{
_7
"channelName":"test_webhook",
_7
"uid":12121212,
_7
"platform":1,
_7
"clientSeq":1625051035369,
_7
"ts":1560396834
_7
}

108 user leave channel with communication mode

This event type indicates that a user leaves the channel in the communication profile. The payload includes the following fields:

Field nameTypeDescription
channelNameStringThe name of the channel.
uidNumberThe user ID of the user in the channel.
platformNumberThe platform type of the user's device:
  • 1: Android
  • 2: iOS
  • 5: Windows
  • 6: Linux
  • 7: Web
  • 8: macOS
  • 0: Other platform
clientSeqNumberThe sequence number, which is used to identify the order in which events occur on the app client. You can use the value of this field to sort the events of a user into chronological order.
reasonNumberThe reason why a user leaves the channel:
  • 1: The user quits the call.
  • 2: The connection between the app client and the Agora RTC server times out, which occurs when the Agora SD-RTN does not receive any data packets from the app client for more than 10 seconds.
  • 3: Permission issues. For example, the user is kicked out of the channel by the administrator through the Banning user privileges RESTful API.
  • 4: Internal issues with the Agora RTC server. For example, the Agora RTC server disconnects from the app client for a short period of time for load balancing. When the load balancing is finished, the Agora RTC server reconnects with the client.
  • 5: The user uses a new device to join the channel, which forces the old device to leave the channel.
  • 9: The app client has multiple IP addresses, therefore the SDK actively disconnects from the Agora RTC server and reconnects. The user is not aware of this process. Check whether the app client has multiple public IP addresses or uses a VPN
  • 10: Due to network connection issues, for example, the SDK does not receive any data packets from the Agora RTC server for more than 4 seconds or the socket connection error occurs, the SDK actively disconnects from the Agora server and reconnects. The user is not aware of this process. Check the network connection status.
  • 999: The user has unusual activities, such as frequent login and logout actions. 60 seconds after receiving the 104 or 106 event callback with reason as 999, your app server needs to call the Banning user privileges API to remove the user from the current channel; otherwise, your server could fail to receive any notification callbacks about the user's events if the user rejoins the channel.
  • 0: Other reasons.
tsNumberThe Unix timestamp (s) when the event occurs on the Agora RTC server.
durationNumberThe length of time (s) that the user stays in the channel.
Example

_9
{
_9
"channelName":"test_webhook",
_9
"uid":12121212,
_9
"platform":1,
_9
"clientSeq":1625051037369,
_9
"reason":1,
_9
"ts":1560496834,
_9
"duration":600
_9
}

111 client role change to broadcaster

This event type indicates that an audience member calls setClientRole to switch their user role to host in the live streaming profile. The payload includes the following fields:

Field nameTypeDescription
channelNameStringThe name of the channel.
uidNumberThe user ID of the user in the channel.
clientSeqNumberThe sequence number, which is used to identify the order in which events occur on the app client. You can use the value of this field to sort the events of a user into chronological order.
tsNumberThe Unix timestamp (s) when the event occurs on the Agora RTC server.
Example

_6
{
_6
"channelName":"test_webhook",
_6
"uid":12121212,
_6
"clientSeq":1625051035469,
_6
"ts":1560396834
_6
}

112 client role change to audience

This event type indicates that a host call setClientRole to switch their user role to audience member in the live streaming profile. The payload contains the following fields:

Field nameTypeDescription
channelNameStringThe name of the channel.
uidNumberThe user ID of the user in the channel.
clientSeqNumberThe sequence number, which is used to identify the order in which events occur on the app client. You can use the value of this field to sort the events of a user into chronological order.
tsNumberThe Unix timestamp (s) when the event occurs on the Agora RTC server.
Example

_6
{
_6
"channelName":"test_webhook",
_6
"uid":12121212,
_6
"clientSeq":16250510358369,
_6
"ts":1560496834
_6
}

IP address query API

If your server that receives notification callbacks is behind a firewall, you need to call the IP address query API to retrieve the IP addresses of Notifications and configure your firewall to trust all these IP addresses.

Agora occasionally adjusts the Notifications IP addresses. Best practice is to call this endpoint at least every 24 hours and automatically update the firewall configuration.

Prototype

  • Method: GET
  • Endpoint: https://api.agora.io/v2/ncs/ip

Request header

Authorization: You must generate a Base64-encoded credential with the Customer ID and Customer Secret provided by Agora, and then pass the credential to the Authorization field in the HTTP request header.

Request body

This API has no body parameters.

Response body

When the request succeeds, the response body looks like the following:


_14
{
_14
"data": {
_14
"service": {
_14
"hosts": [
_14
{
_14
"primaryIP": "xxx.xxx.xxx.xxx"
_14
},
_14
{
_14
"primaryIP": "xxx.xxx.xxx.xxx"
_14
}
_14
]
_14
}
_14
}
_14
}

Each primary IP field shows an IP address of Notifications server. When you receive a response, you need to note the primary IP fields and add all these IP addresses to your firewall's allowed IP list.

Considerations

  • The Agora Notifications does not guarantee that notification callbacks arrive at your server in the same order as events occur.
  • Your server needs to be able to handle messages arriving out of order.
  • To improve the reliability of Notifications, there can be more than one notification callback for each event, and your server needs to be able to handle repeated messages.

Video Calling