diff --git a/openapi.yaml b/openapi.yaml index 0ca489bb..fcacd027 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -13385,17 +13385,19 @@ paths: events: - video.encoding.quality.completed url: 'http://clientnotificationserver.com/notif?myquery=query' + signatureSecret: 'sig_sec_Abcd12348RLP7VPLi7nYVh' - webhookId: webhook_XXXXXXXXXYYYYYY createdAt: '2021-01-12T12:12:12+00:00' events: - video.encoding.quality.completed url: 'http://clientnotificationserver.com/notif?myquery=query2' + signatureSecret: 'sig_sec_Abcd12358RLP7VPLi7nYVy' pagination: currentPage: 1 pageSize: 25 pagesTotal: 1 - itemsTotal: 11 - currentPageItems: 11 + itemsTotal: 2 + currentPageItems: 2 links: - rel: self uri: 'https://ws.api.video/webhooks?currentPage=1' @@ -13648,6 +13650,7 @@ paths: events: - video.encoding.quality.completed url: 'http://clientnotificationserver.com/notif?myquery=query' + signatureSecret: 'sig_sec_Abcd12348RLP7VPLi7nYVh' '400': headers: X-RateLimit-Limit: @@ -14982,23 +14985,26 @@ components: properties: webhookId: type: string - description: Unique identifier of the webhook + description: A unique identifier of the webhook you subscribed to. example: webhook_XXXXXXXXXXXXXXX createdAt: type: string - description: 'When an webhook was created, presented in ATOM UTC format.' + description: 'The time and date when you created this webhook subscription, in ATOM UTC format.' format: date-time example: '2019-06-24T11:45:01+00:00' events: type: array - description: A list of events that will trigger the webhook. + description: A list of events that you subscribed to. When these events occur, the API triggers a webhook call to the URL you provided. example: '["video.encoding.quality.completed"]' items: type: string url: type: string - description: URL of the webhook + description: The URL where the API sends the webhook. example: 'http://clientnotificationserver.com/notif?myquery=query' + signatureSecret: + type: string + description: A secret key for the webhook you subscribed to. You can use it to verify the origin of the webhook call that you receive. video-status: title: VideoStatus type: object @@ -16220,4 +16226,191 @@ x-doctave: - go - node - php - - python \ No newline at end of file + - python +x-webhooks: + live-stream.broadcast.started: + post: + tags: + - Webhooks + summary: Live stream started + description: This webhook triggers when a live stream broadcast is started. + operationId: POST-webhooks + parameters: + - in: header + name: X-Api-Video-WebhookID + schema: + type: string + description: The unique ID of your webhook. + required: true + - in: header + name: X-Api-Video-Signature + schema: + type: string + description: The webhook's body encrypted using the webhook's signature secret, in HMAC SHA256. Use this hash to verify that api.video is the origin of this webhook notification. + required: true + requestBody: + content: + application/json: + schema: + type: object + properties: + type: + type: string + description: The name of the webhook event that occured. + example: live-stream.broadcast.started + emittedAt: + description: Returns the date-time when the webhook event occurred. + type: string + format: date-time + example: '2024-08-151T10:18:47+00:00' + liveStreamId: + description: The ID of the live stream that started broadcasting. + type: string + example: li400mYKSgQ6xs7taUeSaEap + responses: + '202': + summary: Accepted + description: Your webhook server may return this response to api.video to signal that the webhook is accepted. + live-stream.broadcast.ended: + post: + tags: + - Webhooks + summary: Live stream ended + description: This webhook triggers when a live stream broadcast is ended. + operationId: POST-webhooks + parameters: + - in: header + name: X-Api-Video-WebhookID + schema: + type: string + description: The unique ID of your webhook. + required: true + - in: header + name: X-Api-Video-Signature + schema: + type: string + description: The webhook's body encrypted using the webhook's signature secret, in HMAC SHA256. Use this hash to verify that api.video is the origin of this webhook notification. + required: true + requestBody: + content: + application/json: + schema: + type: object + properties: + type: + type: string + description: The name of the webhook event that occured. + example: live-stream.broadcast.ended + emittedAt: + description: Returns the date-time when the webhook event occurred. + type: string + format: date-time + example: '2024-08-151T10:18:47+00:00' + liveStreamId: + description: The ID of the live stream that ended broadcasting. + type: string + example: li400mYKSgQ6xs7taUeSaEap + responses: + '202': + summary: Accepted + description: Your webhook server may return this response to api.video to signal that the webhook is accepted. + video.source.recorded: + post: + tags: + - Webhooks + summary: Video source recorded + description: This webhook triggers when a live stream broadcast is completed and the recording of the stream is ready for transcoding. This means that the video is in queue for transcoding. + operationId: POST-webhooks + parameters: + - in: header + name: X-Api-Video-WebhookID + schema: + type: string + description: The unique ID of your webhook. + required: true + - in: header + name: X-Api-Video-Signature + schema: + type: string + description: The webhook's body encrypted using the webhook's signature secret, in HMAC SHA256. Use this hash to verify that api.video is the origin of this webhook notification. + required: true + requestBody: + content: + application/json: + schema: + type: object + properties: + type: + type: string + description: The name of the webhook event that occured. + example: video.source.recorded + emittedAt: + description: Returns the date-time when the webhook event occurred. + type: string + format: date-time + example: '2024-08-151T10:18:47+00:00' + liveStreamId: + description: The ID of the live stream that ended broadcasting. + type: string + example: li400mYKSgQ6xs7taUeSaEap + videoId: + description: The video ID of the live stream recording. + type: string + example: vi4blUQJFrYWbaG44NChkH11 + responses: + '202': + summary: Accepted + description: Your webhook server may return this response to api.video to signal that the webhook is accepted. + video.encoding.quality.completed: + post: + tags: + - Webhooks + summary: Video encoding completed + description: This webhook triggers when a new video is uploaded into your account, and all HLS and mp4 quality versions are encoded. + operationId: POST-webhooks + parameters: + - in: header + name: X-Api-Video-WebhookID + schema: + type: string + description: The unique ID of your webhook. + required: true + - in: header + name: X-Api-Video-Signature + schema: + type: string + description: The webhook's body encrypted using the webhook's signature secret, in HMAC SHA256. Use this hash to verify that api.video is the origin of this webhook notification. + required: true + requestBody: + content: + application/json: + schema: + type: object + properties: + type: + type: string + description: The name of the webhook event that occured. + example: video.encoding.quality.completed + emittedAt: + description: Returns the date-time when the webhook event occurred. + type: string + format: date-time + example: '2024-08-151T10:18:47+00:00' + videoId: + description: The ID of the video where a certain quality version's encoding is finished. + type: string + example: vi4blUQJFrYWbaG44NChkH11 + encoding: + description: The type of encoding that is finished. + type: string + enum: [hls, mp4] + example: hls + quality: + description: The quality version of encoding that is finished. + type: string + enum: [240p, 360p, 480p, 720p, 1080p] + example: 1080p + responses: + '202': + summary: Accepted + description: Your webhook server may return this response to api.video to signal that the webhook is accepted. \ No newline at end of file diff --git a/reference/create-and-manage-webhooks.md b/reference/create-and-manage-webhooks.md index 25763c00..1033ee09 100644 --- a/reference/create-and-manage-webhooks.md +++ b/reference/create-and-manage-webhooks.md @@ -1,138 +1,41 @@ --- title: Webhooks meta: - description: api.video provides you the possibility to get a `POST` request to your server that contains a JSON payload with event data. Webhooks can push notifications directly to your server, saving you the need to poll api.video for changes. This guide goes over how to create and manage your webhooks. + description: api.video provides webhook notifications in the form of `POST` requests, with a JSON payload that contains detailed event data. Webhooks can push notifications directly to your server, saving you the need to poll api.video for changes. This guide goes over how to create and manage your webhooks. --- # Create And Manage Webhooks -api.video provides you the possibility to get a `POST` request to your server that contains a JSON payload with event data. Webhooks can push notifications directly to your server, saving you the need to poll api.video for changes. +api.video provides webhook notifications in the form of `POST` requests, with a JSON payload that contains detailed event data. Webhooks can push notifications directly to your server, saving you the need to poll api.video for changes. -## Webhook events - -| Event | Description | -| :--------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `live-stream.broadcast.started` | Triggers to indicate that a live stream broadcast has started. | -| `live-stream.broadcast.ended` | Triggers to indicate that a live stream broadcast has ended. | -| `video.source.recorded` | Triggers to indicate that a live stream has been completed and the recording of the live stream (if you set it to record) is ready to be transcoded. NOTE: This means the video has been enqueued for transcoding. | -| `video.encoding.quality.completed` | Triggers when you upload a video, every time api.video finishes encoding a video in a set quality (up to the same level of quality that you uploaded), you get an announcement about it. | - ---- - -Here’s how the `video.encoding` webhook’s flow looks like: +Here’s how the webhook flow looks like, using `video.encoding` as an example: A diagram that shows the video.encoding webhook flow -## Event properties - -api.video offers the following webhook events that you can set up webhooks for: - -### `live-stream.broadcast.started` - -Triggers to indicate that a live stream broadcast has started. - -| Property | Type | Description | Example value | -| :----------- | :--------- | :---------------------------------------------------- | :------------------------------- | -| type | _string_ | the webhook type | `live-stream.broadcast.started` | -| emittedAt | _datetime_ | timestamp when the request was emitted from api.video | `2023-05-23T09:29:02.154104779Z` | -| liveStreamId | _string_ | the live stream id | `li3VbBGc4e6njqw7fRrELvKl` | - -### `live-stream.broadcast.ended` - -Triggers to indicate that a live stream broadcast has ended. - -| Property | Type | Description | Example value | -| :----------- | :--------- | :---------------------------------------------------- | :------------------------------- | -| type | _string_ | the webhook type | `live-stream.broadcast.ended` | -| emittedAt | _datetime_ | timestamp when the request was emitted from api.video | `2023-05-23T09:29:02.154104779Z` | -| liveStreamId | _string_ | the live stream id | `li3VbBGc4e6njqw7fRrELvKl` | - -### `video.source.recorded` - -Triggers to indicate that a live stream has completed and the recording of the live stream (if you set it to record) is ready to be transcoded. NOTE: This means the video has been enqueued for transcoding. - -| Property | Type | Description | Example value | -| :----------- | :--------- | :---------------------------------------------------- | :------------------------------- | -| type | _string_ | the webhook type | `video.source.recorded` | -| emittedAt | _datetime_ | timestamp when the request was emitted from api.video | `2023-05-23T09:29:02.154104779Z` | -| liveStreamId | _string_ | the live stream id | `li3VbBGc4e6njqw7fRrELvKl` | -| videoId | _string_ | the video id of the recorded stream | `viXXXXXXXX` | - -### `video.encoding.quality.completed` - -Triggers when you upload a video, every time api.video finishes encoding a video in a set quality (up to the same level of quality that you uploaded), you get an announcement about it. - -| Property | Type | Description | Example value | -| --------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | -| type | _string_ | the webhook type | `video.encoding.quality.completed` | -| emittedAt | _datetime_ | timestamp when the request was emitted from api.video | `2023-05-23T09:29:02.154104779Z` | -| videoId | _string_ | The ID of the video that was encoded. | `viXXXXXXXX` | -| encoding | _string_ | The asset that the encoding was finished for. There are two types of assets that you will receive in the encoding:
- HLS
- MP4 | `hls` | -| `quality` | `string` | The quality of the video was transcoded to the current encoding.

The MP4 asset will only be transcoded once, hence you will receive a webhook only once for the MP4 asset with the final source quality. While the HLS asset webhook will be emitted multiple times with each quality (from the lowest 240p) to the highest of the source (up to 4k).

For example, if you've uploaded a video where the source quality is 720p. You will receive 5 webhooks in total:

- **1 webhook** with 720p quality for the MP4 encoding
- **4 webhooks** for 240p, 360p, 480p and 720p for the HLS encoding | `1080p` | - -## Implementation - -### Testing - -You can test your webhooks with tools like [Pipedream](https://pipedream.com/workflows). These tools enable you to test that api.video sends the correct webhook events, and ensure that webhooks arrive to your server. - -### Retry policy - - -**Webhook retry policy** - -api.video’s webhook service makes 3 notification attempts, with 3 second intervals between each try. - - -### Choose an api.video client - -The clients offered by api.video include: - -- [NodeJS](../sdks/api-clients/apivideo-nodejs-client.md) -- [Python](../sdks/api-clients/apivideo-python-client.md) -- [PHP](../sdks/api-clients/apivideo-php-client.md) -- [Go](../sdks/api-clients/apivideo-go-client.md) -- [C#](../sdks/api-clients/apivideo-csharp-client.md) -- [Java](../sdks/api-clients/apivideo-java-client.md) -- [Swift](../sdks/api-clients/apivideo-swift5-client.md) -- [Android](../sdks/api-clients/apivideo-android-client.md) - -To install your selected client, do the following: - +## Webhook events - -```go -go get github.com/apivideo/api.video-go-client -``` -```php -composer require api-video/php-api-client -``` -```javascript -npm install @api.video/nodejs-client --save +These are the available webhook events: -...or with yarn: +| Event | Triggers when... | +| :--------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [`live-stream.broadcast.started`](/reference/api/Webhooks#live-stream-started) | A live stream broadcast has started. | +| [`live-stream.broadcast.ended`](/reference/api/Webhooks#live-stream-ended) | A live stream broadcast has ended. | +| [`video.source.recorded`](/reference/api/Webhooks#video-source-recorded) | A live stream has been completed and the recording of the live stream is ready to be transcoded. This means that the video in queue for transcoding. | +| [`video.encoding.quality.completed`](/reference/api/Webhooks#video-encoding-completed) | A set quality version of encoding is complete for a video that you uploaded.

For each video, the MP4 asset is transcoded only once, hence you only receive one webhook notification for the MP4 asset, with the final source quality. The HLS asset's webhook notification triggers multiple times with each quality from the lowest 240p to the highest, up to 4k, based on the source you uploaded.

For example, if you upload a video in 720p quality, you receive 5 webhooks in total:

- **1 webhook** with 720p quality for the MP4 encoding
- **4 webhooks** for 240p, 360p, 480p, and 720p for the HLS encoding. | -yarn add @api.video/nodejs-client -``` -```python -pip install api.video -``` -```csharp -Using Nuget +Check out the [API reference](/reference/api/Webhooks) for detailed descriptions of each webhook event's request headers and payloads. -Install-Package ApiVideo -``` -
+## Subscribe to webhooks -## Create an account +You can subscribe to webhooks via the Dashboard and the API. To actually receive the webhooks, you need to set up a server that accepts `POST` requests from api.video. You can use tools like [Webhook.site](https://webhook.site/) to test the process. Tools like this enable you to preview the webhook events, and test whether webhooks arrive to your server. -Before you can start creating webhooks, you need to [create an api.video account](https://dashboard.api.video/register). +### Via the dashboard -Once you are logged in to the Dashboard, select the environment of your choice (sandbox or production) and copy your API key. +You can subscribe to webhooks in just a couple of clicks on the [Webhooks tab](https://dashboard.api.video/project-settings/webhooks) in your Project settings. -### Create a webhook +### Via the API -To create a webhook, all you have to do is set up your server and provide api.video with the URL you want events sent to and the list of events you wish to be sent to that URL. +You can use the [Create webhook](/reference/api/Webhooks#create-webhook) endpoint to create a webhook subscription. Simply provide your server URL and the list of events you want to subscribe to: @@ -140,7 +43,7 @@ To create a webhook, all you have to do is set up your server and provide api.vi curl --request POST \ --url https://ws.api.video/webhooks \ --header 'Accept: application/json' \ - --header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE2NDI4MjQzMTkuMDk2NjY1LCJuYmYiOjE2NDI4MjQzMTkuMDk2NjY1LCJleHAiOjE2NDI4Mjc5MTkuMDk2NjY1LCJwcm9qZWN0SWQiOiJwclJ6SUpKQTdCTHNxSGpTNDVLVnBCMSJ9.rfchf3btbMTzSukcwhUS0u4fNY4Q3g1JpoMeIz_Dls1ADmqDdKw7yBOE893C7cagb0lpuvUJvhuhgusLStsJ4nqzTveDeM2oPBQBNJjzwaJZNrImTPD4mif7Tzgxvn1_jQJA5L4gQhjd7frCIJW1yAwywrtiDPbxiWNp8fVl7r_QILjZZfslxy-kblPrHJ20Zix9VURqkGIORY5G_457nHSV9Atks1sUlt49E8b_g3jORja3MnznXBS0-0dksz2K62-QMe1_dk78V9JwbLeydqcr15M1jDLA3H6qFGI7GTsTDdZ5jKLhg5OR6yeSHFysqr3kOteTqAGdp3JuTrpZIA' \ + --header 'Authorization: Bearer {your API key}' \ --header 'Content-Type: application/json' \ --data '{"events": [ "live-stream.broadcast.started", "live-stream.broadcast.ended", "video.encoding.quality.completed" @@ -246,316 +149,236 @@ print(response) ``` -### List all webhooks - -After you create webhooks, you can retrieve a complete list of the URLs and associated events going to them with this code sample: - - - -```curl -curl --request GET \ - --url 'https://ws.api.video/webhooks?events=video.encoding.quality.completed¤tPage=1&pageSize=25' \ - --header 'Accept: application/json' \ - --header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE2NDI4MjQzMTkuMDk2NjY1LCJuYmYiOjE2NDI4MjQzMTkuMDk2NjY1LCJleHAiOjE2NDI4Mjc5MTkuMDk2NjY1LCJwcm9qZWN0SWQiOiJwclJ6SUpKQTdCTHNxSGpTNDVLVnBCMSJ9.rfchf3btbMTzSukcwhUS0u4fNY4Q3g1JpoMeIz_Dls1ADmqDdKw7yBOE893C7cagb0lpuvUJvhuhgusLStsJ4nqzTveDeM2oPBQBNJjzwaJZNrImTPD4mif7Tzgxvn1_jQJA5L4gQhjd7frCIJW1yAwywrtiDPbxiWNp8fVl7r_QILjZZfslxy-kblPrHJ20Zix9VURqkGIORY5G_457nHSV9Atks1sUlt49E8b_g3jORja3MnznXBS0-0dksz2K62-QMe1_dk78V9JwbLeydqcr15M1jDLA3H6qFGI7GTsTDdZ5jKLhg5OR6yeSHFysqr3kOteTqAGdp3JuTrpZIA' -``` -```go -package main - -import ( - "context" - "fmt" - "os" - apivideosdk "github.com/apivideo/api.video-go-client" -) - -func main() { - client := apivideosdk.ClientBuilder("YOUR_API_TOKEN").Build() - // if you rather like to use the sandbox environment: - // client := apivideosdk.SandboxClientBuilder("YOU_SANDBOX_API_TOKEN").Build() - req := apivideosdk.WebhooksApiListRequest{} - - req.Events("video.encoding.quality.completed") // string | The webhook event that you wish to filter on. - req.CurrentPage(int32(2)) // int32 | Choose the number of search results to return per page. Minimum value: 1 (default to 1) - req.PageSize(int32(30)) // int32 | Results per page. Allowed values 1-100, default is 25. (default to 25) - - res, err := client.Webhooks.List(req) - - - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `Webhooks.List``: %v\n", err) - } - // response from `List`: WebhooksListResponse - fmt.Fprintf(os.Stdout, "Response from `Webhooks.List`: %v\n", res) -} -``` -```php -webhooks()->list(); -print($webhooks); -``` -```javascript -const ApiVideoClient = require("@api.video/nodejs-client"); - -(async () => { - try { - const client = new ApiVideoClient({ apiKey: "YOUR_API_TOKEN" }); - - const events = "video.encoding.quality.completed"; // The webhook event that you wish to filter on. - const currentPage = "2"; // Choose the number of search results to return per page. Minimum value: 1 - const pageSize = "30"; // Results per page. Allowed values 1-100, default is 25. - - // WebhooksListResponse - const result = await client.webhooks.list({ - events, - currentPage, - pageSize, - }); - console.log(result); - } catch (e) { - console.error(e); - } -})(); -``` -```python -## List all webhooks -import apivideo -from apivideo.apis import WebhooksApi -from apivideo.exceptions import ApiAuthException +### Via the dashboard -api_key = "your api key here" +Visit the [Webhooks tab](https://dashboard.api.video/project-settings/webhooks) in your Project settings. You can: -client = apivideo.AuthenticatedApiClient(api_key) +* see a list of all webhook subscriptions, +* filter for specific webhook events, +* delete webhook subscriptions. -## If you'd rather use the sandbox environment: -## client = apivideo.AuthenticatedApiClient(api_key, production=False) +### Via the API -client.connect() +The API enables you to [List all webhooks](/reference/api/Webhooks#list-all-webhooks), [Retrieve webhook details](/reference/api/Webhooks#retrieve-webhook-details), and to [Delete a webhook](/reference/api/Webhooks#delete-a-webhook). -webhooks_api = WebhooksApi(client) + +Deleting a webhook is a permanent action. Deleted webhooks cannot be recovered. + -## Create a webhook -response = webhooks_api.list() -print(response) -``` - +## Verify webhook origins -### Show a webhook +api.video provides secure signatures for each webhook you subscribe to. You can use this signature to verify that a webhook is indeed sent by api.video. -You can retrieve details about a specific webhook, including the URL and associated events, by sending a request with the unique webhook ID using this code sample: +### Verification process - -```curl -curl --request GET \ - --url https://ws.api.video/webhooks/webhook_XXXXXXXXXXXXXXX \ + + + + Use the [Create webhook](/reference/api/Webhooks#create-webhook) endpoint to subscribe to a webhook. We'll use `video.encoding.quality.completed` for this example: + +
+ + ```curl + curl --request POST \ + --url https://ws.api.video/webhooks \ --header 'Accept: application/json' \ - --header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE2NDI4MjQzMTkuMDk2NjY1LCJuYmYiOjE2NDI4MjQzMTkuMDk2NjY1LCJleHAiOjE2NDI4Mjc5MTkuMDk2NjY1LCJwcm9qZWN0SWQiOiJwclJ6SUpKQTdCTHNxSGpTNDVLVnBCMSJ9.rfchf3btbMTzSukcwhUS0u4fNY4Q3g1JpoMeIz_Dls1ADmqDdKw7yBOE893C7cagb0lpuvUJvhuhgusLStsJ4nqzTveDeM2oPBQBNJjzwaJZNrImTPD4mif7Tzgxvn1_jQJA5L4gQhjd7frCIJW1yAwywrtiDPbxiWNp8fVl7r_QILjZZfslxy-kblPrHJ20Zix9VURqkGIORY5G_457nHSV9Atks1sUlt49E8b_g3jORja3MnznXBS0-0dksz2K62-QMe1_dk78V9JwbLeydqcr15M1jDLA3H6qFGI7GTsTDdZ5jKLhg5OR6yeSHFysqr3kOteTqAGdp3JuTrpZIA' -``` -```go -package main - -import ( - "context" - "fmt" - "os" - apivideosdk "github.com/apivideo/api.video-go-client" -) - -func main() { - client := apivideosdk.ClientBuilder("YOUR_API_TOKEN").Build() - // if you rather like to use the sandbox environment: - // client := apivideosdk.SandboxClientBuilder("YOU_SANDBOX_API_TOKEN").Build() - - webhookId := "webhookId_example" // string | The unique webhook you wish to retreive details on. - - - res, err := client.Webhooks.Get(webhookId) - - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `Webhooks.Get``: %v\n", err) - } - // response from `Get`: Webhook - fmt.Fprintf(os.Stdout, "Response from `Webhooks.Get`: %v\n", res) -} -``` -```php -webhooks()->get('webhook ID here'); -print($webhooks); -``` -```javascript -const ApiVideoClient = require("@api.video/nodejs-client"); - -(async () => { - try { - const client = new ApiVideoClient({ apiKey: "YOUR_API_TOKEN" }); - - const webhookId = "webhookId_example"; // The unique webhook you wish to retreive details on. - - // Webhook - const result = await client.webhooks.get(webhookId); - console.log(result); - } catch (e) { - console.error(e); + --header 'Authorization: Bearer {your API key}' \ + --header 'Content-Type: application/json' \ + --data ' + {"events": [ + "video.encoding.quality.completed" + ], + "url": "https://nice.url/webhooks" + }' + ``` +
+ +
+ + + When this webhook subscription is created, sends a signature secret in a `201` response, with a similar body: + +
+ + ```json + { + "webhookId": "webhook_XXXXXXXXXXXXXXX", + "createdAt": "2024-08-08T14:12:18+00:00", + "events": [ + "video.encoding.quality.completed" + ], + "url": "http://nice.url", + "signatureSecret":"sig_sec_0000000000000000000000" } -})(); -``` -```python -## List all webhooks -import apivideo -from apivideo.apis import WebhooksApi -from apivideo.exceptions import ApiAuthException - -api_key = "your api key here" - -client = apivideo.AuthenticatedApiClient(api_key) - -## If you'd rather use the sandbox environment: -## client = apivideo.AuthenticatedApiClient(api_key, production=False) - -client.connect() - -webhooks_api = WebhooksApi(client) - -## Create a webhook -response = webhooks_api.get("your webhook ID here") -print(response) -``` -
- -### Delete a webhook - -You can delete a webhook using its unique ID with this code sample: - - -```curl -curl --request DELETE \ - --url https://ws.api.video/webhooks/webhook_XXXXXXXXXXXXXXX \ - --header 'Accept: application/json' \ - --header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE2NDI4MjQzMTkuMDk2NjY1LCJuYmYiOjE2NDI4MjQzMTkuMDk2NjY1LCJleHAiOjE2NDI4Mjc5MTkuMDk2NjY1LCJwcm9qZWN0SWQiOiJwclJ6SUpKQTdCTHNxSGpTNDVLVnBCMSJ9.rfchf3btbMTzSukcwhUS0u4fNY4Q3g1JpoMeIz_Dls1ADmqDdKw7yBOE893C7cagb0lpuvUJvhuhgusLStsJ4nqzTveDeM2oPBQBNJjzwaJZNrImTPD4mif7Tzgxvn1_jQJA5L4gQhjd7frCIJW1yAwywrtiDPbxiWNp8fVl7r_QILjZZfslxy-kblPrHJ20Zix9VURqkGIORY5G_457nHSV9Atks1sUlt49E8b_g3jORja3MnznXBS0-0dksz2K62-QMe1_dk78V9JwbLeydqcr15M1jDLA3H6qFGI7GTsTDdZ5jKLhg5OR6yeSHFysqr3kOteTqAGdp3JuTrpZIA' -``` -```go -package main - -import ( - "context" - "fmt" - "os" - apivideosdk "github.com/apivideo/api.video-go-client" -) - -func main() { - client := apivideosdk.ClientBuilder("YOUR_API_TOKEN").Build() - // if you rather like to use the sandbox environment: - // client := apivideosdk.SandboxClientBuilder("YOU_SANDBOX_API_TOKEN").Build() - - webhookId := "webhookId_example" // string | The webhook you wish to delete. - - - err := client.Webhooks.Delete(webhookId) - - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `Webhooks.Delete``: %v\n", err) - } -} -``` -```php -webhooks()->delete('webhook ID here'); -print($webhooks); -``` -```javascript -const ApiVideoClient = require("@api.video/nodejs-client"); - -(async () => { - try { - const client = new ApiVideoClient({ apiKey: "YOUR_API_TOKEN" }); - - const webhookId = "webhookId_example"; // The webhook you wish to delete. - - // void - const result = await client.webhooks.delete(webhookId); - console.log(result); - } catch (e) { - console.error(e); + ``` +
+ + + + Let's upload a video! When the encoding for that video is completed, you receive a webhook notification in the form a `POST` request from api.video. This would be the body: + + ```json + { + "type":"video.encoding.quality.completed", + "emittedAt":"2024-08-08T14:12:18+00:00", + "videoId":"vi0000000000000000000000", + "liveStreamId":"li0000000000000000000000", + "encoding":"hls", + "quality":"720p" } -})(); -``` -```python -## List all webhooks -import apivideo -from apivideo.apis import WebhooksApi -from apivideo.exceptions import ApiAuthException + ``` -api_key = "your api key here" +
-client = apivideo.AuthenticatedApiClient(api_key) + This `POST` request will have 2 headers: -## If you'd rather use the sandbox environment: -## client = apivideo.AuthenticatedApiClient(api_key, production=False) - -client.connect() - -webhooks_api = WebhooksApi(client) - -## Create a webhook -response = webhooks_api.delete("your webhook ID here") -print(response) -``` -
- - -**Warning** + ```json + { + "X-Api-Video-WebhookID": "webhook_1BWt3JArmQq9sNZzsHStRS", + "X-Api-Video-Signature": "3b7f8f40a6872cf979631f3bf84e6318ddd5cab8cd9d28f5ea1ea8f8a2ed1b11" + } + ``` +
+ + * `X-Api-Video-WebhookID` is the unique ID of your webhook subscription. + * `X-Api-Video-Signature` is the webhook's body encrypted using the webhook's signature secret, in `HMAC SHA256` + +
+ + + + + Grab the webhook ID from the `X-Api-Video-WebhookID` header in the `POST` request that you just received. Find the signature secret that belongs to it, using the [`GET /webhooks/{webhookId}`](/reference/api/Webhooks#retrieve-webhook-details) endpoint. + +
+ +
+ + Grab the JSON body of the webhook notification that you received earlier. Use the signature secret you retrieved in the previous step to encrypt the webhook notification's JSON body via `HMAC SHA256`. + +
+ +
+ + Compare the resulting hash with the value of the `X-Api-Video-Signature` header in the webhook notification that api.video sent you. When the results match, you have evidence that api.video is the origin of the webhook. + +
+ +
+ + + +### Sample implementation + +Here is a sample implementation to verify webhooks using PHP: + + + + + ```php + webhooks() + ->get($webhookId) + ->getSignatureSecret(); + + /** + * Build the signature based on the data you retrieved + */ + $actualSignature = hash_hmac("sha256", $webhookBody, $secret); + + /** + * Compare the signatures + */ + if ($actualSignature === $expectedSignature) { + echo "The webhook is valid." . PHP_EOL; + } else { + echo "The webhook is invalid." . PHP_EOL; + } + ``` +
+ +
+ + + For the sake of this example, we are running the listener in a local environment: + +
+ + ```php + $ php -S localhost:8181 + ``` +
+ +
+ + Let's pretend that api.video is sending a webhook notification to your local environment. Use this call: + + ```curl + $ curl --location 'http://localhost:8181' --header 'x-api-video-webhookid: webhook_XXXXXXXXXXXXXXX' --header 'x-api-video-signature: 27a77d3a7fc626854886b5dbfae4e32c8b0170c1ea1b714c91ba77f1e7774e8c' --header 'Content-Type: application/json' --data '{"type":"video.encoding.quality.completed","emittedAt":"2021-01-29T15:46:25.217Z","videoId":"vi0000000000000000000000","liveStreamId":"li0000000000000000000000","encoding":"hls","quality":"720p"}' + ``` +
+ + Note that this example call does not have any whitespaces. Copy and reuse it without modification, otherwise your call will not be successful. + +
+
+ + + The implementation should return `The webhook is valid.`. + +
+ +
+ +
+ +## Retries and failed webhooks + +api.video handles failed webhook deliveries using these rules: + +* We accept responses that you send in return to a webhook notification. +* We check for status codes in your responses above `HTTP 299`: `3xx` redirections, `4xx` client errors, and `5xx` server errors. +* In case of an unsuccessful delivery, api.video logs the issue and retries sending the webhook notification 3 times, with 3 second intervals between each try. +* In case the status code in your response is `1xx` or `2xx`, api.video assumes that the delivery is successful and does not retry. -Deleting a webhook is a permanent action and deleted webhooks cannot be recovered. -
+--- ## Next steps