If you'd like to build your own consumer for Frame.io Webhooks, feel free to grab and extend our example app on Github.
Introduction
Webhooks provide a way to leverage events that occur inside of Frame.io into notifications that can be sent to external systems for processing, API callbacks, and ultimately, workflow automation.
Setup
Webhooks can be configured in the Webhooks area of our developer site. A Webhook requires:
- Name — Will be shown on the developer site only.
- URL — Where to deliver events.
- Team — Which team this webhook will be added to.
- Events — Which event, or events, should trigger the Webhook.
Supported events
A single Webhook can subscribe to any number of the following events:
Projects
Event | Trigger |
---|---|
project.created | A new Project is created |
project.updated | A Project's settings are updated |
project.deleted | A Project is deleted |
Assets
Event | Trigger |
---|---|
asset.created | An Asset is first added/created in Frame.io, but likely before the asset is fully uploaded |
asset.copied | An Asset has been copied |
asset.updated | An Asset's description, name, or other file information is changed |
asset.deleted | An Asset is deleted (manually or otherwise) |
asset.ready | All transcodes have completed, after an Asset has been uploaded and processed |
asset.label.updated | An Asset's status label is set, changed, or removed |
asset.versioned | An asset is versioned |
When the asset.versioned
event fires, you're going to receive a payload with the id of the asset that was versioned, not the version stack itself. So if you expect to be able to pass that id
along to another function thinking it's the version stack's id, you're going to have to look-up and track down that particular 'parent' resource first.
The asset.label.updated
event will not fire when the status label is changed via a PUT
call to the /v2/assets/:id
endpoint via the public API (BES-408
). It will however fire when the status label is updated using any native Frame.io apps and integrations (Web, iOS, Premiere, After Effects, FCPX, etc).
Review Links
Event | Trigger |
---|---|
reviewlink.created | A new Review Link is created |
Collaborators
Event | Trigger |
---|---|
collaborator.created | A Collaborator has been added to your Account |
collaborator.deleted | A Collaborator has been removed from your Account |
Team Members
Event | Trigger |
---|---|
teammember.created | A Team Member has been added to your Account |
teammember.deleted | A Team Member has been removed from your Account |
Payload
Frame.io delivers a JSON payload to the specified webhook endpoint. Here's an example payload for an asset.created event:
{
"type": "asset.created",
"resource": {
"type": "asset",
"id": "<asset-id>"
},
"user": {
"id": "<user-id>"
},
"team": {
"id": "<team-id>"
}
}
All payloads contain a type
field, indicating the type of event occurring, as well as a resource
object. The resource
object specifies the type
and id
of the resource related to this event.
In the above example of an asset.created event, this would be the id
for the newly created Asset. Additionally, user
and team
objects are included. These reference the User who triggered the event, and the Team context for the resource.
Aside from the immediate User and Team context, we do not include any additional information about the subscribed resource. If your application requires additional information or context, we recommend using our HTTP API to make follow-up requests.
Retries
Should an error (non-200 status code response) or timeout occur while delivering the webhook to your service, the payload will be retried three times, for a total of four delivery attempts.
Security
By default, all Webhooks are provided with a signing key. This is not configurable. This key can be used to verify that the request originates from Frame.io.
Verify Webhook Signatures
To guard an integration against man-in-the-middle and replay attacks it is essential to verify webhook signatures. Verification ensures that webhook payloads were actually sent by Frame.io and payload content has not been modified in transport.
Included in the POST
request are the following headers:
Name | Description |
---|---|
X-Frameio-Request-Timestamp | The time of Webhook delivery |
X-Frameio-Signature | The computed signature |
The timestamp is the time of delivery from Frame.io's systems. This can be used to prevent replay attacks. We recommended verifying this time is within 5 minutes of local time.
The signature is a HMAC SHA256 hash using the signing key provided when the Webhook is first created.
Follow these steps to verify the signature:
- Extract the signature from the HTTP headers
- Create a message to sign by combining the version, delivery time, and request body:
v0:timestamp:body
- Compute the HMAC SHA256 signature using your signing secret. Note: The provided signature is prefixed with
v0=
. Currently Frame.io only has this one version for signing requests. Be sure this prefix is prepended to your computed signature. - Compare!
import hmac
import hashlib
def verify_signature(curr_time, req_time, signature, body, secret):
"""
Verify Webhook signature
:Args:
curr_time (float): Current epoch time
req_time (float): Request epoch time
signature (str): Signature provided by the Frame.io API for the given request
body (str): Webhook body from the received POST
secret (str): The secret for this Webhook that you saved when you first created it
"""
if int(curr_time) - int(req_time) < 500:
message = 'v0:{}:{}'.format(req_time, body)
calculated_signature = 'v0={}'.format(hmac.new(
bytes(secret, 'latin-1'),
msg=bytes(message, 'latin-1'),
digestmod=hashlib.sha256).hexdigest())
if calculated_signature == signature:
return True
return False
Comments
comment.created
comment.updated
comment.deleted
comment.completed
comment.uncompleted