Developer guides
Build on the shipped contract
Overview depth for the six surfaces lives on Features. Deep IA is H2. Below: webhooks, idempotency, and error codes generated from the same registries the API uses.
Webhooks — signed & replayable
10 event types. Header: Snipy-Signature: t=<ts>,v1=<hmac>. Replay re-queues delivery — it never re-mints the event.
- link.created
- link.updated
- link.clicked
- qr.created
- qr.scanned
- sale.completed
- ppv.purchased
- subscriber.created
- form.submitted
- pass.subscribed
import { createHmac } from "node:crypto";
function verifySnipySignature(secret, body, header, nowSec = Math.floor(Date.now()/1000)) {
const parts = Object.fromEntries(header.split(",").map((p) => {
const [k, ...rest] = p.trim().split("=");
return [k, rest.join("=")];
}));
const t = Number(parts.t);
const v1 = parts.v1;
if (!Number.isFinite(t) || !v1) return false;
if (Math.abs(nowSec - t) > 300) return false; // reject stale
const expected = createHmac("sha256", secret)
.update(`${t}.${body}`, "utf8")
.digest("hex");
return expected === v1;
}Idempotency-Key on /v1 writes
Send Idempotency-Key on POST/PATCH. Replay returns the stored response. Same key with a different body returns 409 idempotency_key_reused. Every response echoes x-request-id.
Error-code reference
Closed set from API_ERROR_CODES — registry-diff tested so this page cannot lie.
- bad_request
- unauthorized
- forbidden
- insufficient_scope
- not_found
- conflict
- idempotency_key_reused
- rate_limited
- unavailable
- internal
OpenAPI: Developers hub · Feature overview: Developer pillar