Introduction
Webhooks allow you to build or set up integrations which subscribe to certain events on your SHIFT72 platform. When one of those events is triggered, we’ll send a HTTPS POST payload to the webhook’s configured URL. Webhooks can be used to be notified when an upload starts or is completed or be notified of certain ingestion events.
Currently, each webhook needs to be configured by SHIFT72. Once configured, they will be triggered each time one or more subscribed events occurs on your platform.
Webhook URLs need to be accessible on the public internet. See the security section below for advice on securing your webhook integration.
Events
When configuring a webhook, you can choose which events you would like to receive payloads for. Only subscribing to the specific events you plan on handling is useful for limiting the number of HTTP requests to your server. Contact your SHIFT72 account manager to change the list of subscribed events.
Each event corresponds to a certain set of actions that can happen on your platform. For example, if you subscribe to the upload event you’ll receive detailed payloads every time an upload is started or completed.
Each event type has a specific payload format with the relevant event information.
The available events are:
Name | Description |
---|---|
upload_started | Any time an upload starts. |
upload_completed | Any time an upload completes. |
ingestion_updated | Any time the ingestion status is updated. |
shopping_order_success | Any time a shopping order completes successfully. |
Security
Webhook URLs must be accessible over the public internet and should verify the signature of each incoming request to ensure it came from us.
Every webhook request we send includes a cryptographic signature header (X-Shift-Signature) containing an HMAC SHA-256 digest of the raw request body. This is generated using a secret key that we’ll share with you.
Your server should verify that the request body matches the signature header using the shared secret.
Verifying the signature
Here’s an example webhook request signed using secret key abracadabra
:
POST /s72/webhook HTTP/1.1
Content-Type: application/json
X-Shift-Signature: abdb146ad5e847c03e723caf593bc124f5e5441f1c155c980616d3d3ead2a872
{
"eventType":"upload_started",
"eventDatetime":"2025-04-20T23:38:05.477Z",
"slug":"/film/123456",
"uploadToken":"f6c179d841ef2c510687c739ae0ae93b",
"status":"claimed"
}
Your server should calculate a HMAC digest of the raw body, exactly as received, using the expected secret. If it does not match the header, a 403 Forbidden response should be returned.
This will vary by programming language and web framework, for example in Ruby on Rails it might look something like this:
require 'openssl'
class S72WebhookController < ApplicationController
SECRET = 'abracadabra'
def handle
calculated_sig = OpenSSL::HMAC.hexdigest('sha256', SECRET, request.raw_body)
unless calculated_sig == request.headers['X-Shift-Signature']
return head :forbidden
end
# perform your application logic here
return head :ok
end
end
IP ranges and network security
Because of our cloud-based infrastructure, webhook requests are not sent from a fixed set of IP addresses.
If network-layer security is required — for example, when testing in a restricted development environment — we recommend setting up a proxy server to receive incoming webhooks, or using a managed solution like AWS API Gateway to filter and forward trusted traffic into your secure network.
If you need help setting this up, reach out to your account manager or contact support.
Delivery failures
If your server does not return a successful HTTP response (any 2xx status code), we will automatically retry the webhook delivery using an exponential backoff strategy.
Your integration should be prepared for events to arrive out of order, or for retried events to contain outdated or already-processed information.
ingestion_updated
Description
Triggered when the ingestion status is updated.
Response Parameters
Parameter | Type | Description |
---|---|---|
eventType | string | The event type. This will be set to ingestion_updated for this event. |
notify | string | The internal url of the SHIFT72 API that was notified by the ingestion manager. |
slug | string | The slug of the film or TV show and season. |
publish | bool | The publish_after_ingestion flag set during the Upload Invite. |
status | string | The overall status of the ingestion job. Can be one of: notstarted, started, encoding, packaging, completed, errored, cancelled. |
updates | array | Array of the sub tasks within the ingestion job. See below for more details. |
Response Parameters - Updates Array
Parameter | Type | Description |
---|---|---|
ingestion_uuid | string | The unique ID of the ingestion job. |
package_output_id | number | The unique ID of the ingestion sub task. |
drm_key_widevine | string | The drm key for Widevine DRM. |
drm_key_playready | string | The drm key for PlayReady DRM. |
drm_key_fairplay | string | The drm key for Fairplay DRM. |
drms | array of string | DRM types. Can be one of: none, widevine, playready, widevine_classic. |
content_encoding | string | Content encoding type. Can be one of trailer_mp4, sd_widevine_classic, sd_widevine_classic_download, dash_live_cenc, dash_cenc. |
output_path | string | The relative path to where the content is stored. |
status | string | The status of the ingestion sub task. Can be one of: queued, started, completed, errored. |
width | number | The width of the media content. |
height | number | The height of the media content. |
bitrate | number | The bitrate of the media content. |
error_message | string | The error message if the status is errored. |
created_at | string | The ISO 8601 time and date the item was created. |
updated_at | string | The ISO 8601 time and date the item was last updated. |
source_url | string | The path/filename of the ingested file. |
Examples
Ingestion Completed Notification for a Trailer of Film 176
{
"notify":"https://store.shift72.com/services/content/v1/encoding",
"publish":false,
"slug":"/film/176",
"status":"completed",
"updates":[
{
"ingestion_uuid":"7e6aa985-c486-4b54-85a8-76c16514f44e",
"package_output_id":9,
"drm_key_widevine":null,
"drm_key_playready":null,
"drm_key_fairplay":null,
"drms":[
"none"
],
"content_encoding":"trailer_mp4",
"output_path":"/7e6aa985-c486-4b54-85a8-76c16514f44e/marks_ingestion_test_1_trailer_kb.mp4",
"status":"completed",
"width":1024,
"height":576,
"bitrate":1603,
"error_message":"",
"created_at":"2016-04-07T23:09:19.914Z",
"updated_at":"2016-04-07T23:28:35.071Z",
"source_url":"s3://s72-bucket/test.mp4"
}
],
"eventType":"ingestion_updated"
}
Ingestion Completed Notification for Film 176
{
"notify":"https://store.shift72.com/services/content/v1/encoding",
"publish":false,
"slug":"/film/176",
"status":"completed",
"updates":[
{
"ingestion_uuid":"c876eed9-dead-4869-8231-d94847a36b5b",
"package_output_id":6,
"drm_key_widevine":"36623281",
"drm_key_playready":null,
"drm_key_fairplay":null,
"drms":[
"widevine_classic"
],
"content_encoding":"sd_widevine_classic",
"output_path":"/c876eed9-dead-4869-8231-d94847a36b5b/6/marks_ingestion_test_1.wvm",
"status":"completed",
"width":1024,
"height":576,
"bitrate":1996,
"error_message":"",
"created_at":"2016-04-07T20:49:52.491Z",
"updated_at":"2016-04-07T22:57:02.771Z",
"source_url":"s3://s72-bucket/test.mp4"
},
{
"ingestion_uuid":"c876eed9-dead-4869-8231-d94847a36b5b",
"package_output_id":5,
"drm_key_widevine":"36612585",
"drm_key_playready":null,
"drm_key_fairplay":null,
"drms":[
"widevine_classic"
],
"content_encoding":"sd_widevine_classic_download",
"output_path":"/c876eed9-dead-4869-8231-d94847a36b5b/5/marks_ingestion_test_1.wvm",
"status":"completed",
"width":1024,
"height":576,
"bitrate":1996,
"error_message":"",
"created_at":"2016-04-07T20:49:52.489Z",
"updated_at":"2016-04-07T22:57:02.923Z",
"source_url":"s3://s72-bucket/test.mp4"
},
{
"ingestion_uuid":"c876eed9-dead-4869-8231-d94847a36b5b",
"package_output_id":8,
"drm_key_widevine":null,
"drm_key_playready":"490db495-4957-4957-b96b-65a76c703a6c",
"drm_key_fairplay":null,
"drms":[
"playready"
],
"content_encoding":"dash_live_cenc",
"output_path":"/c876eed9-dead-4869-8231-d94847a36b5b/8/live/marks_ingestion_test_1.mpd",
"status":"completed",
"width":1024,
"height":576,
"bitrate":1996,
"error_message":"",
"created_at":"2016-04-07T20:49:52.495Z",
"updated_at":"2016-04-07T22:57:03.055Z",
"source_url":"s3://s72-bucket/test.mp4"
},
{
"ingestion_uuid":"c876eed9-dead-4869-8231-d94847a36b5b",
"package_output_id":7,
"drm_key_widevine":"c876eed9-dead-4869-8231-d94847a36b5b_HD",
"drm_key_playready":null,
"drm_key_fairplay":null,
"drms":[
"widevine"
],
"content_encoding":"dash_cenc",
"output_path":"/c876eed9-dead-4869-8231-d94847a36b5b/7/marks_ingestion_test_1.mpd",
"status":"completed",
"width":1024,
"height":576,
"bitrate":1996,
"error_message":"",
"created_at":"2016-04-07T20:49:52.493Z",
"updated_at":"2016-04-07T22:57:03.136Z",
"source_url":"s3://s72-bucket/test.mp4"
}
],
"eventType":"ingestion_updated"
}
screener_updated
Description
Triggered when the screener status is updated.
Response Parameters
Parameter | Type | Description |
---|---|---|
eventType | string | The event type. This will be set to screener_updated for this event. |
token | string | The unique ID of the ingestion job. |
slug | string | The slug of the film or TV show and season. |
status | string | The overall status of the ingestion job. Can be one of: “in_progress”, “completed”, or “errored”. |
Examples
Screener Updated Notification for Film 176
{
"slug":"/film/176",
"status":"in_progress",
"token":"blon572akl4c05mq2fd0",
"eventType":"screener_updated"
}
Screener Completed Notification for Film 176
{
"slug":"/film/176",
"status":"completed",
"token":"blon572akl4c05mq2fd0",
"eventType":"screener_updated"
}
shopping_order_success
Description
Triggered when a shopping order successfully completes.
Response Parameters
Parameter | Type | Description |
---|---|---|
eventType | string | The event type. This will be set to shopping_order_success for this event. |
userId | number | The user’s unique ID. |
orderId | number | The unique order ID. |
item | string | The slug of the item being purchased. |
title | string | The title of the item being purchased. |
amount | number | The price of the item being purchased. |
currency | string | ISO 4217 currency code. |
ownership | string | The ownership type that was requested, i.e. “buy” or “rent”. |
quality | string | The quality. This will either be “hd” or “sd”. |
external_id | string | The external_id stored in meta for this item. |
external_id2 | string | The external_id2 stored in meta for this item. |
Examples
Shopping Order Success Notification for User 99 Purchasing Film 176
{
"eventType":"shopping_order_success",
"userId":99,
"orderId":11,
"item":"/film/176",
"title":"The Matrix",
"amount":12.99,
"currency":"NZD",
"ownership":"buy",
"quality":"hd",
"external_id":"AB123",
"external_id2":null
}
upload_completed
Description
Triggered when an upload completes.
Response Parameters
Parameter | Type | Description |
---|---|---|
eventType | string | The event type. This will be set to upload_completed for this event. |
uploadToken | string | The upload token created when creating the Upload Invite. |
slug | string | The slug of the film or TV show and season. |
eventDatetime | string | The date and time, in ISO 8601 format, when the event was created. |
status | string | The status of the Upload Invite. |
Examples
Upload Completed Notification for Film 176
{
"eventType":"upload_completed",
"uploadToken":"f6c179d841ef2c510687c739ae0ae93b",
"slug":"/film/176",
"eventDatetime":"2016-04-06T23:40:56.724+00:00",
"status":"completed"
}
upload_started
Description
Triggered when an upload starts.
Response Parameters
Parameter | Type | Description |
---|---|---|
eventType | string | The event type. This will be set to upload_started for this event. |
uploadToken | string | The upload token created when creating the Upload Invite. |
slug | string | The slug of the film or TV show and season. |
eventDatetime | string | The date and time, in ISO 8601 format, when the event was created. |
status | string | The status of the Upload Invite. |
Examples
Upload Started Notification for Film 176
{
"eventType":"upload_started",
"uploadToken":"f6c179d841ef2c510687c739ae0ae93b",
"slug":"/film/176",
"eventDatetime":"2016-04-06T23:38:05.477+00:00",
"status":"claimed"
}