Skip to main content

You are viewing Agora Docs forBetaproducts and features. Switch to Docs

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 Media Gateway 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 configure the URL of the webhooks to receive these events. Agora sends notifications of your events to your webhook 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.

  1. A user commits an action that creates an event.
  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 Notifications, 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. Set up Go

    Ensure you have Go installed on your system. If not, download and install it from the official Go website.

  2. Create a Go project for your server

    Create a new directory for your project and navigate into it:


    _2
    mkdir agora-webhook-server
    _2
    cd agora-webhook-server

    In the project directory, create a new file main.go. Open the file in your preferred text editor and add the following code:


    _62
    package main
    _62
    _62
    import (
    _62
    "encoding/json"
    _62
    "fmt"
    _62
    "io"
    _62
    "log"
    _62
    "net/http"
    _62
    )
    _62
    _62
    type WebhookRequest struct {
    _62
    NoticeID string `json:"noticeId"`
    _62
    ProductID int64 `json:"productId"`
    _62
    EventType int `json:"eventType"`
    _62
    Payload Payload `json:"payload"`
    _62
    }
    _62
    _62
    type Payload struct {
    _62
    ClientSeq int64 `json:"clientSeq"`
    _62
    UID int `json:"uid"`
    _62
    ChannelName string `json:"channelName"`
    _62
    }
    _62
    _62
    func rootHandler(w http.ResponseWriter, r *http.Request) {
    _62
    response := `<h1>Agora Notifications demo</h1>`
    _62
    w.WriteHeader(http.StatusOK)
    _62
    w.Write([]byte(response))
    _62
    }
    _62
    _62
    func ncsHandler(w http.ResponseWriter, r *http.Request) {
    _62
    agoraSignature := r.Header.Get("Agora-Signature")
    _62
    fmt.Println("Agora-Signature:", agoraSignature)
    _62
    _62
    body, err := io.ReadAll(r.Body)
    _62
    if err != nil {
    _62
    http.Error(w, "Unable to read request body", http.StatusBadRequest)
    _62
    return
    _62
    }
    _62
    _62
    var req WebhookRequest
    _62
    if err := json.Unmarshal(body, &req); err != nil {
    _62
    http.Error(w, "Invalid JSON", http.StatusBadRequest)
    _62
    return
    _62
    }
    _62
    _62
    fmt.Printf("Event code: %d Uid: %d Channel: %s ClientSeq: %d\n",
    _62
    req.EventType, req.Payload.UID, req.Payload.ChannelName, req.Payload.ClientSeq)
    _62
    _62
    w.WriteHeader(http.StatusOK)
    _62
    w.Write([]byte("Ok"))
    _62
    }
    _62
    _62
    func main() {
    _62
    http.HandleFunc("/", rootHandler)
    _62
    http.HandleFunc("/ncsNotify", ncsHandler)
    _62
    _62
    port := ":8080"
    _62
    fmt.Printf("Notifications webhook server started on port %s\n", port)
    _62
    if err := http.ListenAndServe(port, nil); err != nil {
    _62
    log.Fatalf("Failed to start server: %v", err)
    _62
    }
    _62
    }

  3. Run your Go server

    Run the server using the following command:


    _1
    go run main.go

  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 <authToken>

      To obtain an authToken, sign up with ngrok.

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


      _1
      ngrok http 127.0.0.1:8080

      You see a Forwarding URL and a Web Interface URL in the console. Open the web interface URL in your browser.

  5. Test the server

    Open a web browser and navigate to the public URL provided by ngrok to see the root handler response.

    Use curl, Postman, or another tool to send a POST request to https://<ngrok_url>/ncsNotify with the required JSON payload.

    Example using curl:


    _13
    curl -X POST <ngrok_url>/ncsNotify \
    _13
    -H "Content-Type: application/json" \
    _13
    -H "Agora-Signature: your_signature" \
    _13
    -d '{
    _13
    "noticeId": "some_notice_id",
    _13
    "productId": 12345,
    _13
    "eventType": 1,
    _13
    "payload": {
    _13
    "clientSeq": 67890,
    _13
    "uid": 123,
    _13
    "channelName": "test_channel"
    _13
    }
    _13
    }'

    Make sure you replace ngrok_url with the forwarding url.

    Once the HTTP request is successful, you see the following JSON payload in your browser:


    _10
    {
    _10
    "noticeId": "some_notice_id",
    _10
    "productId": 12345,
    _10
    "eventType": 1,
    _10
    "payload": {
    _10
    "clientSeq": 67890,
    _10
    "uid": 123,
    _10
    "channelName": "test_channel"
    _10
    }
    _10
    }

Enable Notifications

To enable Notifications:

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

  2. In the Features section, locate Notifications, and click Enable.

  3. On the configuration page, click on the service for which you want to enable notifications. The item expands to show configuration options.

  4. Fill in the following information:

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

      If the selected events generate a high number of queries per second (QPS), ensure that your server has sufficient processing capacity.

    • Receiving Server Region: Select the region where your server that receives the notifications is located. Agora connects to the nearest Agora node server based on your selection.

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

      info

      For enhanced security, 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
    • Whitelist: 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.

  5. Copy the Secret displayed against the product name by clicking the copy icon. You use this secret to Add signature verification.

  6. 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.

    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 saved, the Status of Notifications 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 as follows:

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

  2. 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.

  3. 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 crypto/sha1 algorithm.
    • To verify Agora-Signature-V2, use the secret, the raw request body, and the crypto/sha256 algorithm.

The following sample code uses crypto/sha1.

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

  1. In the main.go file, replace your imports with with the following:


    _10
    import (
    _10
    "crypto/hmac"
    _10
    "crypto/sha1"
    _10
    "encoding/hex"
    _10
    "encoding/json"
    _10
    "fmt"
    _10
    "io"
    _10
    "log"
    _10
    "net/http"
    _10
    )

  2. Add the following code after the list of imports:


    _17
    // Replace with your NCS secret
    _17
    const secret = "<Replace with your secret code>"
    _17
    _17
    // calcSignatureV1 computes the HMAC/SHA256 signature for a given payload and secret
    _17
    func calcSignatureV1(secret, payload string) string {
    _17
    mac := hmac.New(sha1.New, []byte(secret))
    _17
    mac.Write([]byte(payload))
    _17
    return hex.EncodeToString(mac.Sum(nil))
    _17
    }
    _17
    _17
    // verify checks if the provided signature matches the HMAC/SHA256 signature of the request body
    _17
    func verify(requestBody, signature string) bool {
    _17
    calculatedSignature := calcSignatureV1(secret, requestBody)
    _17
    fmt.Println("Calculated Signature:", calculatedSignature)
    _17
    fmt.Println("Received Signature:", signature)
    _17
    return calculatedSignature == signature
    _17
    }

  3. In the main.go file, add the following code after fmt.Println("Request Body:", string(body)):


    _5
    // Verify the signature
    _5
    if !verify(string(body), agoraSignature) {
    _5
    http.Error(w, "Invalid signature", http.StatusUnauthorized)
    _5
    return
    _5
    }

  4. To test the server, follow the steps given in the Enable notifications section.

  5. When you receive an event from the console, and if the signature matches, the event details are displayed in your browser.

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:
  • 1: Realtime Communication (RTC) service
  • 3: Cloud Recording
  • 4: Media Pull
  • 5: Media Push
eventTypeNumberThe type of event being notified. For details, see event types.
notifyMsNumberThe Unix timestamp (ms) when Notifications sends a callback to your server. This value is updated when Notifications resends the notification callback.
payloadJSON ObjectThe content of the event being notified. The payload varies with event type.

Example


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

Event types

Notifications can notify your server of the following Media Gateway events:

1 live_stream_connected

The gateway has received the RTMP or SRT stream and successfully entered the channel.

Payload example:


_10
{
_10
"sid": "55df7402-8778-11ee-92ed-07ec2e86c928",
_10
"region": "na",
_10
"streamKey": "7B***Qbs",
_10
"rtcInfo": {
_10
"channel": "123",
_10
"uid": "1234"
_10
},
_10
"beginAt": "2023-11-21T02:27:31Z"
_10
}

The payload contains the following fields:

FieldData typeDescription
sidStringThe unique ID of each streaming session.
regionStringThe server area that has received the pushed stream.
streamKeyStringThe used streaming key.
rtcInfoObjectRTC information:
  • channel: The channel name.
  • uid: The host UID. Supports integer and string data types.
beginAtStringThe start time of the streaming in the RFC3339 format.

This event is usually followed by a corresponding live_stream_disconnected event.

2 live_stream_disconnected

The gateway was disconnected (actively or passively) and left the channel.

Payload example:


_11
{
_11
"sid": "55df7402-8778-11ee-92ed-07ec2e86c928",
_11
"region": "na",
_11
"streamKey": "7B***Qbs",
_11
"rtcInfo": {
_11
"channel": "123",
_11
"uid": "1234"
_11
},
_11
"beginAt": "2023-11-21T02:27:31Z",
_11
"endAt": "2023-11-21T03:27:31Z"
_11
}

The payload contains the following fields:

FieldData typeDescription
sidStringThe unique ID of each streaming session.
regionStringThe server area that has received the pushed stream.
streamKeyStringThe used streaming key.
rtcInfoObjectRTC information:
  • channel: The channel name.
  • uid: The host UID. Supports integer and string data types.
beginAtStringThe start time of the streaming in the RFC3339 format.
endAtStringThe end time of the streaming in the RFC3339 format.

3 live_stream_aborted

The gateway has received an RTMP or SRT stream but terminated it for some reason.

Payload example:


_12
{
_12
"sid": "55df7402-8778-11ee-92ed-07ec2e86c928",
_12
"region": "na",
_12
"streamKey": "7B***Qbs",
_12
"rtcInfo": {
_12
"channel": "123",
_12
"uid": "1234"
_12
},
_12
"beginAt": "2023-11-21T02:27:31Z",
_12
"errorCode": 100,
_12
"reason": "invalid"
_12
}

The payload contains the following fields:

FieldData typeDescription
sidStringThe unique ID of each streaming session.
regionStringThe server area that has received the pushed stream.
streamKeyStringThe used streaming key.
rtcInfoObjectRTC information:
  • channel: The channel name.
  • uid: The host UID. Supports integer and string data types.
beginAtStringThe start time of the streaming in the RFC3339 format.
errorCodeNumberThe stream termination error code.
reasonStringThe error message.

This event may be sent alone or between the connected and disconnected events.

The possible values for the errorCode field include the following:

ValueDescriptionRecommended actions
1Illegal streamKey. For example, channelName is empty or contains illegal characters.Check the streamKey format, especially for locally generated ones.
2Invalid streamKey (expired or deleted)Create a new streamKey and try again.
3No permission to use this streamKey. For example, the customer-defined domain name and streamKey under the associated app ID do not match.Check whether the streamKey matches the domain name used for the push.
4Number of concurrent streams exceeds the limit.Wait and retry.
5Conflict detected, for example, pushing to the same channel and at the same.If the streams are not being pushed at the same time, try again 5-10 seconds later.
6The stream attribute exceeds the limit (currently applies to bitrate only).Check the streaming software configuration and lower the target bitrate.
7Streaming without any audio or video data for more than 10 secondsCheck whether the last push exited abnormally, and then try again.
8Failed to join channelThe reason field will provide the specific error reason, for example: "connect to rtc failed, reason:$N". Refer to the API documentation for details.
9Disconnected from the main network. Specific reasons need to be investigated by contacting technical support.Try again several times. If you still have problems, contact technical support to confirm whether the app certificate provided during activation is valid.
10Unknown internal service error. Specific reasons need to be investigated by contacting technical support.Try again a few times. If you still have problems, contact technical support.

4 live_profile_updated

Stream properties have been updated. For example, the first audio or video frame has been received or the audio or video profile has changed.

Payload example:


_19
{
_19
"sid": "55df7402-8778-11ee-92ed-07ec2e86c928",
_19
"region": "na",
_19
"streamKey": "7B***Qbs",
_19
"rtcInfo": {
_19
"channel": "123",
_19
"uid": "1234"
_19
},
_19
"videoProfile": {
_19
"codec": "H.264",
_19
"width": 1920,
_19
"height": 1080
_19
},
_19
"audioProfile": {
_19
"sampleRate": 48000,
_19
"channels": 2
_19
},
_19
"beginAt": "2023-11-21T02:27:31Z"
_19
}

The payload contains the following fields:

FieldData typeDescription
sidStringThe unique ID of each streaming session.
regionStringThe server area that has received the pushed stream.
streamKeyStringThe used streaming key.
rtcInfoObjectRTC information:
  • channel: The channel name.
  • uid: The host UID. Supports integer and string data types.
videoProfileObjectVideo properties. Not applicable for audio-only streams.
  • codec: Video codec format, such as "H.264", "H.265", "VP8", "VP9", "AV1", and so on.
  • width: Video width.
  • height: Video height.
audioProfileObjectAudio properties:
  • sampleRate: The sampling rate in Hz.
  • channels: The number of channels.
beginAtStringThe start time of the streaming in the RFC3339 format.

IP address query API

If your server that receives notification callbacks is behind a firewall, 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

  • Notifications does not guarantee that notification callbacks arrive at your server in the same order as events occur. Implement a strategy to handle messages arriving out of order.

  • For improved reliability of Notifications, your server may receive more than one notification callback for a single event. Your server must be able to handle repeated messages.

    Tip

    To implement a strategy to ensure that you log only one callback event and ignore duplicate events, use a combination of the noticeId and notifyMs fields in the response body.

vundefined