Skip to content

Webhooks

Endpoints

GET    /api/v1/webhooks                  list
POST   /api/v1/webhooks                  create   { url, events[] }
DELETE /api/v1/webhooks/:id              delete
POST   /api/v1/webhooks/:id/test         fire a test event

Webhook fields

typescript
{
  user: ObjectId,
  team_id: ObjectId | null,
  url: string,                       // your endpoint
  events: string[],                  // subscribed event types
  secret: string,                    // never returned after creation
  active: boolean,
  failure_count: number,
  last_dispatched_at: Date | null,
  last_failure_at: Date | null,
}

Signing

Every outbound webhook carries a X-Sosyabot-Signature header — the HMAC-SHA256 of the raw body, hex-encoded, signed with the registered secret. Verify on your end:

js
import crypto from "node:crypto";

function verify(req, secret) {
  const sig = req.headers["x-sosyabot-signature"];
  const expected = crypto.createHmac("sha256", secret).update(req.rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}

Retry

Failed deliveries (non-2xx response, or no response within timeout) increment failure_count. The dispatcher backs off exponentially; persistent failures eventually disable the webhook (active: false).

Common events

post.published, post.failed, account.refresh_failed, billing.invoice.paid, billing.payment_failed, marketplace.order.created, team.invitation.accepted. The exact list is in the source for the dispatcher.