Webhooks and Callbacks

Alternatives to polling for job status

As described in How It Works the Dolby.io Media APIs are asynchronous requests. While you can poll at regular intervals to determine when a job is complete, this can create unwanted network congestion and inefficiency. To solve this, Dolby.io Media APIs support both webhooks and callbacks.

  • A webhook is registered ahead of time and will be triggered at the conclusion of every job
  • A callback is specified at the time of a request and is executed only once for that particular job

This flexibility is to help support various use cases.

📘

When using the Dolby.io Transcode API, Webhooks and Callbacks can be a useful way track job status.

Webhooks

Webhooks allow you to set a URL that will receive a POST request whenever a Media API job finishes. For example, when a Media Enhance job is completed, it will send a JSON response with the completed job status.

Once a webhook is successfully registered, it is triggered for all subsequent jobs. A registered webhook configuration can be retrieved, modified or deleted at anytime.

🚧

One Webhook Per API Token

Only one webhook configuration is supported per API Token. You can create a new application from the dashboard to generate additional API Tokens if you would like separate responses to an event.

To register a webhook for an application, call the Webhooks API:

import os
import requests
 
# Add your API token as an environmental variable or hard coded value.
api_token = os.getenv("DOLBYIO_API_TOKEN", "your_token_here")

webhook_url = os.environ['WEBHOOK_URL']
 
 
url = "https://api.dolby.com/media/webhooks"
 
payload = {"callback": {"url": webhook_url} }
 
headers = {
    "Authorization": "Bearer {0}".format(api_token),
    "Content-Type": "application/json",
    "Accept": "application/json"
}
 
response = requests.request("POST", url, json=payload, headers=headers)
 
print(response.text)
const fetch = require('node-fetch');
 
// Add your API token as an environmental variable or hard coded value.  
const api_token = process.env.DOLBYIO_API_TOKEN || "your_token_here";  

const webhook_url = process.env.WEBHOOK_URL;
 
const url = 'https://api.dolby.com/media/webhooks';
const options = {
  method: 'POST',
  headers: {
    "Authorization": `Bearer ${api_token}`,
    "Content-Type": "application/json",
    "Accept": "application/json"
  },
  body: JSON.stringify({callback: {url: webhook_url}})
};
 
fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error('error:' + err));
# Add your API token as an environmental variable or hard coded value.
API_TOKEN=${DOLBYIO_API_TOKEN:-"your_token_here"}

curl --request POST \
     --url https://api.dolby.com/media/webhooks \
     --header "Authorization: Bearer $API_TOKEN" \
     --header 'Content-Type: application/json' \
     --header 'Accept: application/json' \
     --data '
            {
                "callback": {
                    "url": "$WEBHOOK_URL"
                }
            }
            '

Ensure to edit the placeholder <WEBHOOK_URL> with the URL you wish the webhook payload to be sent to.

Further information and languages can be found on the Webhooks API reference page.

Notification Schema

When a webhook fires, a notification is delivered as a POST request to a service that you create. The following schema represents the notification request that is triggered when a job completes:

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "title": "Webhook Notification Schema",
    "description": "Schema for the webhook notification request body.",
    "type": "object",
    "properties": {
        "job_id": {
            "type": "string",
            "description": "The ID of the job for which the notification is triggered.",
            "example": "57a60686-b223-48f1-9a06-c035b3ae3ce7"
        },
        "webhook_id": {
          "type": "string",
          "description": "The ID of the webhook that triggered the notification.",
          "example": "webhook-b945376fa616cea6f4df652150fcb85c"
        },
        "created_at": {
          "type": "string",
          "description": "Time at which the notificaiton was initiated",
          "example": "2021-05-21T09:11:31.361Z"
        },
        "path": {
          "type": "string",
          "description": "The Media API Endpoint",
          "example": "/media/enhance"
        },
        "api_version": {
          "type": "string",
          "description": "Version of the API that processed the job.",
          "example": "v1.1"
        },
       "status": {
          "type": "string",
          "description": "Status of the job.",
          "enum": [
              "Success",
              "Failed",
              "InternalError"
          ],
          "example": "Success"
        },
        "progress": {
          "type": "number",
          "description": "Progress for the job.",
          "example": 100
        },
        "result": {
          "type": "object",
          "description": "Contains result information for the processed job."
        },
        "error": {
          "type": "object",
          "properties": {
            "type": {
              "type": "string",
              "description": "Type of the error.",
              "example": "/problems/invalid-input-file"
            },
            "title": {
              "type": "string",
              "description": "Title describing the error.",
              "example": "Input file not supported"
            },
            "detail": {
              "type": "string",
              "description": "Additional details specific to the error",
              "example": "Content less than 2.0 sec long cannot be analyzed"
            }
          },
          "required": [
            "type",
            "title"
          ]
        }
    },
    "required": [
        "job_id",
        "webhook_id",
        "created_at",
        "path",
        "status",
        "progress",
        "api_version"
    ]
}

Callbacks

To use callbacks, add the on_complete attribute to the body of any individual Media API request. The callback will be executed for that job and that job only.

For example, a request to the Enhance API might look like this:

{
  "input": "dlb://in.mp3",
  "output": "dlb://out.mp3",
  "on_complete": {
     "url": "https://webhook_endpoint_url",
     "body": "{\"key\": \"value\"}",
     "headers": {
        "content-type": "application/json",
        "header-example": "value example"
     }
  }
}

The url identifies the endpoint that will be called when a job completes. When the job reaches a completed state such as Success, Failed, or InternalError the Dolby.io Media API platform will trigger a request to your endpoint.

This will be a POST request and include any of the headers specified as a list of key-value pairs. The body specified when the job was initiated will also be passed as the payload. You can use this to embed a serialized JSON object or raw data as needed to support your workflow. The content-type header should correspond to the data MIME type included in the body.

Unlike webhooks, callbacks allow custom webhook URLs on a per call basis, instead of a per-application basis. This flexibility allows for including a number of things such as authorization headers, correlation IDs, tracking IDs, customer IDs, output URLs, or whatever data is helpful for your use case.

👍

Tip: Tracking Usage

You may want to be able to correlate a user with a job. This would be common if you want to charge your customers for usage or to send a notification when a job is complete. To accomplish this you could keep your own records of a customer's requests with the corresponding job_id. A webhook would let you know when the job is complete. Alternatively, you could embed the user identifier in the on_complete callback so that you can send notification to that user or record the transaction in your own services.

x-job-id Header

For callbacks, the request will contain a special x-job-id header to help identify the job_id that triggered the call. This can be useful for correlation or fetching additional job details and results.

This is in addition to any headers that may have been specified in the on_complete callback.

Timeout and Retries

The request triggered by the service is set to timeout at 10s. Additionally, the service treats any response other than HTTP 2xx as a failure.

In case of timeout and failure cases described above, the request is retried one more time. If the second attempt also fails for same or different reason, the webhook/callback attempt is concluded and marked as failure.

API Reference