Webhooks
On this page
Add an endpoint in Settings → Developers → Webhooks (owners and admins). It must be a public HTTPS address. Choose which events it receives: leave All events on (this includes events added to Pellio later), or turn it off and pick the events you want. Pellio shows the endpoint’s signing secret once.
Each endpoint lists the events it receives, with these actions:
- Edit events changes which events it receives. Save events applies the change straight away.
- Send test sends a
webhook.testevent to that endpoint, whatever events it receives. - Deliveries shows the last 50 attempts (pending, delivered or failed) and their responses.
- Rotate secret replaces the signing secret. The new one is shown once and the old one stops working immediately, so update your endpoint straight away.
- Remove stops sending to the endpoint.
Through the API: POST /v1/webhooks takes url and events (an empty list means all events), PATCH /v1/webhooks/{id} changes events, and POST /v1/webhooks/{id}/rotate-secret returns a new secret.
Events
Every request body is { "id", "event", "createdAt", "data" }:
| event | When | data |
|---|---|---|
video.created |
A video is created by upload, recording or import from a URL. | id, title |
video.ready |
A video has processed, including after a replace or a trim. | id, title, status, version, durationSeconds, width, height, errorMessage |
video.failed |
A new video couldn’t be processed. | as video.ready |
video.deleted |
A video is moved to Trash (trashed: true) or deleted for good. |
id, title, trashed |
video.watched |
An identified viewer (from an email form, an ?email= link or your WordPress site) starts a video, passes 25%, 50% or 75%, or finishes it (90% watched, across visits). Once per viewer, video and milestone. |
video (id, title), viewer (email, name), progress (0, 25, 50, 75, 100), milestone (started, 25%, 50%, 75%, completed), completed |
lead.captured |
Someone submitted an email form. | id, email, name, fields, video (id, title), createdAt |
Delivery
Pellio sends a POST with the header User-Agent: Pellio-Webhooks/1 and waits up to 10 seconds. Any 2xx response counts as delivered. Redirects aren’t followed, so a 3xx counts as a failure. Failed deliveries are tried 6 times in total, waiting 20 seconds before the first retry and doubling up to 320 seconds.
Verifying signatures
Each request has a Pellio-Signature header: t=<unix time>,v1=<hex HMAC-SHA256 of "t.body">, using your endpoint’s secret. Verify it against the raw request body:
import { createHmac, timingSafeEqual } from 'node:crypto';
function verify(header, rawBody, secret) {
const { t, v1 } = Object.fromEntries(header.split(',').map((p) => p.split('=')));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; // 5-minute tolerance
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}
Was this article helpful?
Related articles
- API keys and the REST APIAuthenticate, upload and manage videos from your own code.
- Player APIControl the player and listen for its events, with postMessage or the web component.
- AI assistants (MCP)Connect Claude, ChatGPT, Cursor or Claude Code to Pellio with its MCP server.
- WordPress pluginA fast, private video player for any WordPress site, and Pellio hosting when you connect an account.