Webhooks

Overview

Firework Webhooks notify your application in real time when events occur on the platform. Instead of polling for changes, your server receives HTTP POST callbacks as events happen.

How It Works

┌──────────────┐         Event occurs         ┌──────────────┐
│   Firework   │  ──────────────────────────▶  │  Your Server │
│   Platform   │   HTTP POST with signed JSON  │  (Webhook    │
│              │                               │   Endpoint)  │
│              │  ◀──────────────────────────  │              │
│              │   2xx response                │              │
└──────────────┘                               └──────────────┘
  1. An event occurs on Firework (e.g., video finishes processing)

  2. Firework sends an HTTP POST request to your configured callback URL

  3. The request includes a JSON payload describing the event and an HMAC signature for verification

  4. Your server processes the event and responds with a 2xx status code

Available Event Types

This document covers video-related events only. Additional event types (e.g., livestream) may be documented separately.

Event Type
Description

video_created

Video created — transcoding complete or failed

video_updated

Video metadata or state changed after creation

video_import_failed

Async URL import failed (download error, validation error)


Configuration

Webhook endpoints are not self-service at this time. To set up webhooks for your business:

Contact the Firework IS team and provide:

Information
Description
Example

Callback URL

The HTTPS endpoint on your server that will receive webhook events

https://yourapp.com/webhooks/firework

Event types

Which event types you want to subscribe to

video_created, video_updated, video_import_failed

Business ID

Your Firework business identifier

AbCdEfG

After configuration, the IS team will provide you with:

Important: Store your endpoint secret securely. If you suspect it has been compromised, contact the IS team to rotate it.


Delivery

Delivery Mechanics

Property
Value

HTTP Method

POST

Content-Type

application/json

Timeout

30 seconds per delivery attempt

Signature

HMAC-SHA256 in FW-Webhooks-Signature header

Success Criteria

A delivery is considered successful when your server responds with:

Status Code
Meaning

200

OK

202

Accepted

204

No Content

Any other status code (or a timeout) is treated as a failure and triggers a retry.

Retry Policy

Failed deliveries are retried with increasing backoff:

Attempt
Backoff

1–3

1 hour

4–6

24 hours

Maximum 6 attempts per event delivery. After all attempts are exhausted, the event is dropped.


Signature Verification

Every webhook request includes an FW-Webhooks-Signature header. You must verify this signature before processing the payload to ensure the request is authentic.

Header Format

Component
Description

t

Unix timestamp in milliseconds when the signature was generated

v1

Base64-encoded HMAC-SHA256 signature

Verification Steps

  1. Extract the t (timestamp) and v1 (signature) values from the header

  2. Construct the signed payload string: {t}.{raw_request_body}

  3. Compute HMAC-SHA256 of the signed payload using your endpoint secret

  4. Base64-encode the result

  5. Compare your computed signature with v1 using a constant-time comparison

Worked Example

Given:

  • Endpoint secret (provided by IS team): a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2

  • Signature header received:

  • Raw request body received:

Step 1 — Parse the header:

Step 2 — Concatenate t + . + raw request body:

Step 3 — HMAC-SHA256 this string using your endpoint secret as the key.

Step 4 — Base64-encode the HMAC result.

Step 5 — Compare your Base64 result with v1. If they match, the webhook is authentic.

Important: Use the raw request body exactly as received (do not re-serialize the JSON). JSON key ordering and whitespace must match exactly for the signature to verify.

Tip: Optionally check the timestamp t to reject stale requests (e.g., older than 5 minutes) to prevent replay attacks.

Example: Python

Example: Node.js

Example: Elixir


Event Payload

Envelope Schema

All webhook events share the same envelope structure:

Field
Type
Description

event_type

string

Event type identifier (e.g., "video_created")

version

string

Payload schema version (currently "2023-06-06")

created

integer

Unix timestamp (seconds) when the event was generated

business_id

string

Encoded ID of the business that owns the resource

data

object

Event-specific payload — varies by event type (see Section 6)

Video Data Object

Used by video_created and video_updated events. The payload mirrors GET /api/v1/videos/{id} with additional webhook-specific fields (status, import_id), so consumers do not need a follow-up GET call.

Field
Type
Nullable
Description

id

string

Encoded video ID

status

string

Current video status (see status values below)

import_id

string

Encoded import job ID. Present only for videos created via async URL import.

access

string

Video visibility: "public" or "private"

audio_disabled

boolean

Whether the video audio is muted

caption

string

Video title/caption

description

string

Video description

hashtags

string[]

List of hashtags (empty array if none)

archived_at

string

ISO 8601 timestamp if archived, null otherwise

product_ids

string[]

List of encoded product IDs tagged on the video (empty array if none)

custom_fields

object

Key-value map of custom metadata fields (empty object if none)

display_social_attributions

boolean

Whether to display social attribution overlays

external_media

object

External media source info (see below), or null

External Media Object

Present only when the video was imported from an external source.

Field
Type
Description

source

string

Platform name (e.g., "instagram")

username

string

Original creator's username

url

string

Original content URL

Video Status Values

Status
Description

pending

Video is being transcoded — not yet ready

approved

Transcoding complete — video is ready for playback

errored

Transcoding failed

Note: video_created fires with "approved" status on successful transcoding, or "errored" status on transcoding failure. video_updated only fires for videos that have already received a video_created event.

Import Data Object

Used by video_import_failed events. No video record exists when this event fires. Use GET /api/v1/videos/imports/{import_id} to fetch import job details.

Field
Type
Nullable
Description

import_id

string

Encoded import job ID

reason

string

Machine-readable failure code (see table below)

Import Failure Reason Values

Reason
Description

download_failed

Could not download the file (timeout, 404, network error)

invalid_format

File is not a supported video format

duration_out_of_range

Video shorter than 3s or longer than 1h

file_size_exceeded

File exceeds 5GB limit

internal_error

Unexpected server-side error


Video Events

video_created

Fired when a video's transcoding completes (successfully or with failure). The data field contains the full video resource (same fields as GET /api/v1/videos/{id}).

When it fires:

  • After transcoding completes and the video status transitions to "approved" — the video is ready for playback

  • After transcoding fails and the video status transitions to "errored"

Example — file upload / S3 key:

Example — async URL import:

If the status is "approved", the video is ready for playback. If the status is "errored", transcoding failed. If import_id is present, you can also check GET /api/v1/videos/imports/{import_id} for import job details.

Example — transcoding failed:

video_updated

Fired when a video's state or metadata changes after a video_created event has been sent. The data field contains the full video resource after the update (same fields as GET /api/v1/videos/{id}), so consumers do not need a follow-up GET call.

When it fires:

  • After a metadata update (caption, description, access, hashtags, products, poster, etc.)

  • After any other video state change (admin actions, automations, AICC, etc.)

This event only fires for videos that have already received a video_created event (i.e., videos with "approved" status). It does not fire for transcoding failures — those are covered by video_created with "errored" status.

Example — metadata update via PATCH:

If import_id is present, you can also check GET /api/v1/videos/imports/{import_id} for import job details.

video_import_failed

Fired when an async URL import fails before a video record is created. This covers failures during download, URL validation, or file validation.

When it fires:

  • Download from the source URL fails (timeout, 404, network error)

  • Downloaded file fails validation (invalid format, duration out of range, file size exceeded)

This event only applies to async URL imports (POST /api/v1/videos with "async": true). It does not fire for transcoding failures — those are covered by video_created with "errored" status.

Example — download failed:

Example — invalid file:

Use GET /api/v1/videos/imports/{import_id} to fetch the import job details.


Best Practices

Respond Quickly

Your webhook endpoint should return a 2xx response within 30 seconds. If you need to perform lengthy processing, acknowledge the webhook immediately and process asynchronously.

Verify Signatures

Always verify the FW-Webhooks-Signature header before processing webhook payloads. This protects against spoofed requests. See Section Signature Verification for implementation details.

Handle Duplicates

In rare cases, the same event may be delivered more than once. Design your handler to be idempotent — processing the same event twice should not cause issues.

Deduplication key: event_type + data.id + created (for video_import_failed, use data.import_id instead of data.id)

Use HTTPS

Always use an HTTPS callback URL. Firework will not deliver webhooks to plain HTTP endpoints.

Last updated

Was this helpful?