API guide

Receive and verify webhook events

Subscribe to what you need

Create an HTTPS webhook endpoint and choose event types. Test and live endpoints are separate. Save the signing secret securely; during secret rotation, verify against the active secret while the overlap completes.

Events contain id, version (currently 1), type, at, livemode and data. The OpenAPI components define the envelope and event data schemas. Return 2xx only after durable acceptance. Delivery is at least once: deduplicate by id and tolerate duplicates or events arriving out of order.

Verify before parsing

Buddy-Signature contains t=<unix timestamp> and one or more v1=<hex signature> entries. Compute HMAC-SHA256(secret, timestamp + '.' + raw body). Use a constant-time comparison against any v1 value and reject timestamps more than five minutes from your clock.

Verify the exact raw bytes before parsing JSON. Do not stringify an already-parsed object; whitespace and key order affect the signature. Keep your server clock synchronized.

Recover failed deliveries

The dashboard shows delivery attempts and lets you resend after fixing your receiver. Buddy retries failures with backoff and pauses delivery after three days of failures. A 410 Gone response disables the endpoint immediately. Both are reversible: fix the receiver, then PATCH the endpoint with status: enabled. Events are retained for 30 days, including events emitted while delivery is disabled. List matching events with GET /webhook_endpoints/{id}/events?since=RFC3339_TIMESTAMP and follow cursor pagination. Resend each event through POST /webhook_endpoints/{id}/events/{event_id}/resend. Deduplicate by event ID so replay cannot apply the same action twice.

Related API operations

Verification examples

Choose your language and verify the original request body before processing an event.

Node · Webhook signature verification
import { Buddy } from "@usebuddy/sdk";

// Call this before your framework parses the body. Persist event.id in your
// durable deduplication store before processing and returning a 2xx response.
export async function verifyBuddyRequest(request: Request) {
  const signature = request.headers.get("Buddy-Signature");
  const secret = process.env.BUDDY_WEBHOOK_SECRET;
  if (!signature || !secret) throw new Error("Missing signature or signing secret");
  const rawBody = new Uint8Array(await request.arrayBuffer());
  const event = Buddy.webhooks.verify(rawBody, signature, secret);
  if (!event || typeof event !== "object" || !("id" in event) || typeof event.id !== "string") {
    throw new Error("Invalid webhook event");
  }
  return event;
}