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