New videos, sent to your own server.
CapSend sends a signed JSON POST to your URL when a video arrives. Send it on to your asset manager, an editing queue, a spreadsheet, or anything else that takes a request.
POST https://example.com/hooks/capsend
x-capsend-signature: t=1792843200,v1=887372fa20f16861d0b3401e7452652855de42f1e1a3bb5542371b8c8c9ad3ff
x-capsend-event: submission.received
{
"data": {
"duration_ms": 94200,
"quality_merged": true,
"recipient_name": "Priya Shah",
"request_title": "Customer stories, Q4",
"submission_id": "3f6c1d2a-8b7e-4c55-9a10-2e4f7b9c0d18",
"video_id": "a71e0c94-52d3-4b8f-9e66-0b1c3d5e7f20",
"warnings": []
},
"event": "submission.received",
"image_url": "https://capsend.app/m/p/SFMyNTY…",
"sent_at": "2026-10-24T12:00:00Z",
"text": "Customer stories, Q4",
"title": "Priya Shah sent a video",
"url": "https://capsend.app/o/acme/submissions/3f6c1d2a-8b7e-4c55-9a10-2e4f7b9c0d18"
}
What gets posted
CapSend posts to your URL when something needs your team’s attention, not for every click. Each post links straight to the video or request in CapSend.
- A new video arrives With a thumbnail and any quality warnings.
- Everyone has sent a video
- A video has quality warnings When the checks finish after the video arrived.
- Post for every request, or pick the ones this integration covers.
- Private requests are never posted, wherever they’d otherwise go.
- Pause and resume without losing the setup, and send a test to check it.
- Failed posts are retried, and the last error shows in Settings.
Check that it came from CapSend
Every request carries an
x-capsend-signature
header in the form t=<unix time>,v1=<signature>.
The signature is a hex HMAC-SHA256 of the timestamp, a period, and the raw body, keyed
with your webhook's signing secret.
- Sign the body exactly as it arrived, before parsing the JSON.
- Reject old timestamps, so a captured request can't be replayed.
-
Route on the
x-capsend-eventheader or theeventfield. - Answer with any 2xx status. Other responses are retried a few times.
import crypto from "node:crypto";
// rawBody: the request body exactly as received.
// header: the x-capsend-signature header.
export function verify(rawBody, header, secret) {
if (typeof header !== "string") return false;
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const t = Number(parts.t);
if (!Number.isInteger(t) || !/^[0-9a-f]{64}$/.test(parts.v1 ?? "")) return false;
if (Math.abs(Date.now() / 1000 - t) > 300) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(`${parts.t}.${rawBody}`)
.digest();
return crypto.timingSafeEqual(expected, Buffer.from(parts.v1, "hex"));
}
Set it up
Any HTTPS endpoint that accepts a JSON POST will do. You need to be an owner of your CapSend organization.
-
1
In CapSend, open Settings → Integrations and choose Webhook.
-
2
Paste your endpoint's URL, which must start with https://, and click Connect. CapSend sends an integration.test event right away.
-
3
Copy the signing secret that now shows with the webhook, and store it on your server.
-
4
Once your server checks signatures, click Send test to send another integration.test event, signed like the rest.
Other integrations
All integrationsHear about it when they hit send.
Webhooks are on the Team plan. Start with a request, then connect your endpoint.