Webhooks
Get told when a take finishes instead of polling.
Events
| Event | When |
|---|---|
take.completed | The file is ready. |
take.failed | No file, the charge was refunded. error says why. |
Delivery
We POST JSON { event, created_at, take } to the take's webhook_url with headers X-Takes-Event, X-Takes-Delivery, X-Takes-Signature and the three Standard Webhooks headers below. Any 2xx within 10 s counts. Otherwise we retry after 30 s, 1 m, 2 m and so on, 8 attempts in total. Each take sends each event once.
Verify the signature
The header is t=UNIX_SECONDS,v1=HEX, where HEX is HMAC-SHA256 of t + "." + raw body with your signing secret (Developers page). Reject old timestamps to stop replays.
import crypto from "node:crypto";
export function verify(rawBody, header, secret, toleranceS = 300) {
const [, t, v1] = header.match(/^t=(\d+),v1=([0-9a-f]+)$/) ?? [];
if (!t || Math.abs(Date.now() / 1000 - Number(t)) > toleranceS) return false;
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}import hashlib, hmac, re, time
def verify(raw_body: bytes, header: str, secret: str, tolerance_s=300) -> bool:
m = re.match(r"^t=(\d+),v1=([0-9a-f]+)$", header or "")
if not m or abs(time.time() - int(m[1])) > tolerance_s:
return False
expected = hmac.new(secret.encode(), f"{m[1]}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, m[2])Standard Webhooks
Every delivery is also signed to the Standard Webhooks spec, so you can verify it with a ready library in most languages. Use the whsec_ form of your signing secret: whsec_ followed by the base64 of the secret shown on the Developers page. webhook-id stays the same on retries of one delivery, so you can drop duplicates.
import { Webhook } from "standardwebhooks";
const wh = new Webhook(process.env.TAKES_WEBHOOK_WHSEC); // whsec_...
// Throws if the signature or timestamp is wrong.
const event = wh.verify(rawBody, {
"webhook-id": req.get("webhook-id"),
"webhook-timestamp": req.get("webhook-timestamp"),
"webhook-signature": req.get("webhook-signature"),
});webhook_url. Run a draft take to see a real delivery arrive.