Webhooks
Webhooks let you receive real-time updates when certain actions happen in your Samply account—like when an upload finishes or a comment is added. When one of your subscribed events occurs, Samply sends an HTTP POST request to the URL you provide with a JSON payload describing the event.
Create a webhook
This endpoint creates a webhook and returns a webhook object.
Request type POST
Endpoint /webhooks
Attributes
{
label: string,
url: string,
events: string[],
}label string
A name to help you identify the webhook.
url string
The endpoint URL where Samply will send event payloads. Must be an https:// URL on a publicly reachable host, using port 443 or 8443.
events string array
One or more event types to subscribe to. See available events below.
Destination requirements
Destinations must be reachable from the public internet. Samply rejects a webhook with a 400 when the URL:
- uses any scheme other than
https:// - uses a port other than
443or8443 - contains a username or password
- points at a loopback, private, link-local or cloud metadata address, or at a host that resolves to one
Redirects are not followed, so the destination must accept the POST directly.
Delete a webhook
This endpoint deletes a webhook by id.
Request type DELETE
Endpoint /webhooks/:webhookid
Available events
| Event type | Description |
|---|---|
player.created | A new player is created |
player.updated | An existing player is modified |
project.created | A new project is created |
project.updated | An existing project is modified |
comment.created | A new comment is posted |
upload.started | A file begins uploading |
upload.completed | A file has finished uploading |
upload.failed | A file upload fails due to an error |
Webhook object
All webhook actions return a webhook object with the following structure.
{
id: string,
label: string,
events: string[],
url: string,
timeCreated: number,
timeModified: number,
secret: string, // Only returned on create
}id string readonly
Webhook id.
label string readonly
Webhook label.
events string array readonly
Subscribed event types.
url string readonly
Destination URL.
timeCreated number readonly
Time created in millis since Unix epoch.
timeModified number readonly
Time modified in millis since Unix epoch.
secret string readonly
Signing secret used to verify deliveries. Only returned on creation, so store it securely.
Example payload
{
"id": "a459f855-da9f-4dfc-9181-35da2badfdcc",
"type": "comment.created",
"object": "event",
"projectid": "mSg4Nu5vAch9pkCEcgDP",
"boxid": "cd01f0c1-f1b3-4bc9-95c3-e14e5b01fbe1",
"boxName": "Mystery Machine",
"commentid": "uDXE192QibaDfK51eTTN",
"data": {
"after": {
"id": "uDXE192QibaDfK51eTTN",
"object": "comment",
"message": "<p>Scooby Doo Where Are You?</p>",
"creator": {
"displayName": "eschirtz",
"email": null,
"photoURL": null,
"uid": "TlYYwlHzZohpleC8a2Vo1SYY1902"
},
"isReply": false,
"timeCreated": 1750041281427,
"timeModified": 1750041281427
}
},
"timeCreated": 1750041281427,
"uid": "zklUx8RcjHZTqqi4mWoQNoBMsU03"
}Verifying webhooks
Samply signs every delivery using the Standard Webhooks format. Every new webhook has its own signing secret, starting with whsec_. It's returned when you create the webhook, and you can also find it in your Samply preferences.
Every delivery includes these headers:
| Header | Description |
|---|---|
webhook-id | Unique id for the event. The same as id in the payload. Use it to ignore duplicates. |
webhook-timestamp | When the delivery was sent, in seconds since the Unix epoch. |
webhook-signature | v1, followed by a base64 HMAC-SHA256 signature. |
The signature is computed over {webhook-id}.{webhook-timestamp}.{raw request body}, keyed with the base64-decoded part of your secret after whsec_. Always verify against the raw body exactly as received, before parsing it as JSON.
To protect against replays, reject deliveries whose timestamp is more than 5 minutes from your current time, and ignore any webhook-id you've already processed.
The easiest way to verify is with a Standard Webhooks library, such as standardwebhooks for Node.js:
import { Webhook } from "standardwebhooks";
const wh = new Webhook(process.env.SAMPLY_WEBHOOK_SECRET);
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
try {
// Throws if the signature doesn't match or the timestamp is too old
const event = wh.verify(req.body.toString(), req.headers);
// Handle the event...
res.sendStatus(200);
} catch (error) {
res.sendStatus(400);
}
});Webhooks created prior to October 2026 don't have a secret by default, so their deliveries arrive unsigned. To add a secret, open the webhook in your preferences and choose Generate signing secret to start signing them.
Tips
- Test your endpoint with a tool like Webhook.site before going live.
- Use webhooks alongside tools like Zapier or Make to trigger automations.
- You can delete or update webhooks at any time from your Samply preferences.
Need help? Contact support or check out our integration guides.