Webhook
Instead of polling a retrieve endpoint with multiple requests, you can setup a webhook endpoint and receive notifications on your web server.
info
To get started, please contact Shakr’s customer success team and send us your web endpoint that will be triggered. Once it’s registered, Shakr will send events to your endpoint with POST method.
Available webhooks
Event Name | Description |
---|---|
batch_show.status.changed | BatchShow status is changed |
feed.status.changed | Feed status is changed |
render_session.status.changed | RenderSession status is changed |
render_session.external_upload.complete | RenderSession external_upload (Automated Video Delivery) is complete |
template_style_version.status.changed | TemplateStyleVersion status is changed |
Examples
render_session.status.changed
This event is triggered whenever RenderSession status
is changed. RenderSession status
can be one of the following:
Status | Description |
---|---|
draft | Initial state, RenderSession is created and can be edited |
preview_rendering | RenderSession is being rendered |
preview_rendered | RenderSession is rendered |
preview_rendered
status essentially indicates that the RenderSession is fully rendered. You will be able to retrieve video via the video_url
attribute.
Here is an example payload you can expect:
{
"render_session": {
"id": "deJIKN",
"title": "My RenderSession",
"status": "preview_rendered",
...
"render_progress": 100,
"thumbnails": [...],
"video_url": "...",
...
}
}
feed.status.changed
This event is triggered whenever Feed status
is changed. Feed status
can be one of the following:
Status | Description |
---|---|
pending | Initial state, Feed is being processed and not ready yet |
postprocessing | Feed is going through additional processing; this status might be skipped if feed doesn't need additional processing |
ready | Feed is ready |
failed | Feed processing failed |
Here is an example payload you can expect:
{
"feed": {
"id": "zknqQo",
"status": "ready",
"upload": { ... },
...
}
}
render_session.external_upload.complete
This event is triggered when you specified an external_uploads
parameter when creating a RenderSession, and one of the external_upload
is completed. Webhook is supported on all Automated Video Delivery destinations.
Here are example payloads you can expect:
- Facebook Ad Account
- AWS S3
- Azure Blob Storage
{
"render_session_id": "RENDER_SESSION_ID",
"to": "fbadact://act_123",
"remote_id": "CREATED_FACEBOOK_ADVIDEO_ID"
}
In this payload, remote_id
key represents AdVideo ID created in Facebook Ad Account you have specified in to
key.
{
"render_session_id": "RENDER_SESSION_ID",
"to": "s3://bucket/path/to/object.mp4",
"remote_id": "path/to/object.mp4"
}
In this payload, referring to to
key should be sufficient, since you explicitly specify bucket name and absolute object path. However, remote_id
will still be available for consistency, and will include path of the object.
{
"render_session_id": "RENDER_SESSION_ID",
"to": "wasbs://container@storageaccount.blob.core.windows.net/path/to/object.mp4",
"remote_id": "path/to/object.mp4"
}
In this payload, referring to to
key should be sufficient, since you explicitly specify container name, storage account name, and absolute object path. However, remote_id
will still be available for consistency, and will include path of the object.
batch_show.status.changed
This event is triggered whenever BatchShow status
is changed. BatchShow status
can be one of the following:
Status | Description |
---|---|
draft | Initial state, BatchShow is created and can be edited |
preview_rendering | Subset of BatchShow outputs are being rendered as a preview |
preview_rendered | Subset of BatchShow outputs are rendered as a preview |
rendering | BatchShow outputs are being rendered |
rendered | BatchShow outputs are rendered |
Here is an example payload you can expect:
{
"batch_show": {
"id": "zbkqwA",
"title": "My BatchShow",
"status": "preview_rendered",
"rendered_outputs_count": 3,
"failed_outputs_count": 0,
"feed_items_count": 10,
...
}
}
template_style_version.status.changed
This event is triggered whenever TemplateStyleVersion status
is changed. TemplateStyleVersion status
can be one of the following:
Status | Description |
---|---|
created | Initial state, TemplateStyleVersion is created |
processing | Shakr is analyzing the project file |
demo_rendering | Shakr is performing a test render of the template |
edit_ready | Template is ready to be used in Template Wizard |
Signature Validation
Since the Webhook endpoint on your server is accessible publicly on the internet, it is possible that attackers may find your endpoint and send malicious requests to it. We send a SHA-256 signature on each payload so you can verify requests on your end.
Signature is included in the header of Webhook request as X-Shakr-Signature
. You can verify signature with your client_id
, like this:
- Ruby
- Elixir
- Node.js
require "json"
require "rack"
digest = OpenSSL::Digest.new("sha256")
# Get your client_id, used when retrieving an access token
client_id = "YOUR_SHAKR_CLIENT_ID"
# Get "X-Shakr-Signature" header from Shakr API response
# Example: request.env["HTTP_X_SHAKR_SIGNATURE"] when using Sinatra
returned_signature = "HEADER_RETURNED_FROM_SHAKR_API"
# Get raw body returned from Shakr API response
# Example: request.body when using Sinatra
body = "BODY_RETURNED_FROM_SHAKR_API"
calculated_signature = OpenSSL::HMAC.hexdigest(digest, client_id, body)
calculated_signature_str = "sha256=#{calculated_signature}"
# Use secure comparison method to prevent timing attack
# Returns true if matches
Rack::Utils.secure_compare(returned_signature, calculated_signature_str)
# Get your client_id, used when retrieving an access token
client_id = "YOUR_SHAKR_CLIENT_ID"
# Get "X-Shakr-Signature" header from Shakr API response
# Example: hd(Plug.Conn.get_req_header(conn, "x-shakr-signature")) when using Plug
returned_signature = "HEADER_RETURNED_FROM_SHAKR_API"
# Get raw body returned from Shakr API response
# Example: {:ok, body, conn} = Plug.Conn.read_body(conn) when using Plug
body = "BODY_RETURNED_FROM_SHAKR_API"
calculated_signature =
:hmac
|> :crypto.mac(:sha256, client_id, body)
|> Base.encode16(case: :lower)
calculated_signature_str = "sha256=#{calculated_signature}"
# Use secure comparison method to prevent timing attack
# Returns true if matches
Plug.Crypto.secure_compare(returned_signature, calculated_signature_str)
const crypto = require('crypto');
// Get your client_id, used when retrieving an access token
const client_id = 'YOUR_SHAKR_CLIENT_ID';
// Get "X-Shakr-Signature" header from Shakr API response
// Example: req.headers.HTTP_X_SHAKR_SIGNATURE when using expressjs
const returned_signature = 'HEADER_RETURNED_FROM_SHAKR_API';
// Get raw body returned from Shakr API response
// Example: req.body when using expressjs
const body = 'BODY_RETURNED_FROM_SHAKR_API';
const calculated_signature = crypto.createHmac('sha256', client_id).update(body, 'utf-8').digest('hex');
const calculated_signature_str = `sha256=${calculated_signature}`;
// Use secure comparison method to prevent timing attack
// Returns true if matches
crypto.timingSafeEqual(Buffer.from(returned_signature, 'utf-8'), Buffer.from(calculated_signature_str, 'utf-8'));
You need to add sha256= in front of the signature string before comparison.
Prevent timing attack
Plain ==
operator may expose certain timing attack possibilities to attackers. We strongly recommend using Constant time string comparison methods, like Ruby Rack's secure_compare
, PHP's hash_equals
, or Python's hmac.compare_digest
.