Skip to content
Back to API docs
Webhooks · 19 events

Webhook reference

Subscribe to events from your workspace — Byro POSTs a signed JSON payload to your endpoint whenever the event fires. Configure endpoints in /admin/webhooks.

Delivery
HTTP POST · application/json · 10-second timeout. Idempotent — same event ID won't fire twice.
Retries
Failed deliveries (non-2xx response or timeout) retry with exponential backoff: 30s, 2m, 10m, 1h, 6h, 24h. After 6 failures the endpoint is auto-paused.
Signing
Every request includes X-Byro-Signature — an HMAC-SHA256 of the raw body using your endpoint secret. Verify it before processing.

Event catalog

pr (6)
pr.submittedPR submitted
{
  "event": "pr.submitted",
  "data": {
    "prId": "clx123",
    "amount": 4500,
    "currency": "AED",
    "submittedBy": "ahmed@acme.com"
  },
  "deliveredAt": "2026-05-22T09:30:00Z"
}
pr.approvedPR approved
{
  "event": "pr.approved",
  "data": {
    "prId": "clx123",
    "amount": 4500,
    "currency": "AED",
    "approvedBy": "sara@acme.com"
  },
  "deliveredAt": "2026-05-22T09:30:00Z"
}
pr.rejectedPR rejected
pr.receivedPR received
pr.closedPR closed
pr.cancelledPR cancelled
po (1)
po.issuedPO issued
{
  "event": "po.issued",
  "data": {
    "poId": "clx456",
    "prId": "clx123",
    "supplier": "Apple FZE",
    "amount": 4500
  },
  "deliveredAt": "2026-05-22T09:30:00Z"
}
asset (3)
asset.assignedAsset assigned
{
  "event": "asset.assigned",
  "data": {
    "assetId": "ast789",
    "tag": "BYR-LAP-001",
    "employeeId": "emp123",
    "assignedAt": "2026-05-22T09:30:00Z"
  },
  "deliveredAt": "2026-05-22T09:30:00Z"
}
asset.unassignedAsset unassigned
asset.createdAsset created
{
  "event": "asset.created",
  "data": {
    "assetId": "ast789",
    "tag": "BYR-LAP-001",
    "category": "Laptop",
    "purchaseCost": 4500
  },
  "deliveredAt": "2026-05-22T09:30:00Z"
}
employee (2)
employee.createdEmployee created
{
  "event": "employee.created",
  "data": {
    "employeeId": "emp123",
    "code": "ACM-001",
    "name": "Ahmed Khan",
    "department": "Engineering"
  },
  "deliveredAt": "2026-05-22T09:30:00Z"
}
employee.offboardedEmployee offboarded
inventory (1)
inventory.low_stockInventory low stock
{
  "event": "inventory.low_stock",
  "data": {
    "itemId": "inv321",
    "sku": "USB-C-1M",
    "qty": 3,
    "minQty": 10
  },
  "deliveredAt": "2026-05-22T09:30:00Z"
}
expense (3)
expense.submittedExpense submitted
expense.approvedExpense approved
{
  "event": "expense.approved",
  "data": {
    "claimId": "exp654",
    "amount": 230,
    "currency": "AED",
    "category": "TRAVEL"
  },
  "deliveredAt": "2026-05-22T09:30:00Z"
}
expense.rejectedExpense rejected
leave (3)
leave.submittedLeave submitted
leave.approvedLeave approved
{
  "event": "leave.approved",
  "data": {
    "requestId": "lvr987",
    "employeeId": "emp123",
    "days": 5,
    "startDate": "2026-06-01"
  },
  "deliveredAt": "2026-05-22T09:30:00Z"
}
leave.rejectedLeave rejected

Verifying signatures

Always verify the X-Byro-Signature header before processing a webhook. Use constant-time comparison to prevent timing attacks.

// Verify the X-Byro-Signature header (Node.js)
import crypto from "node:crypto";

function verify(body, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(body)
    .digest("hex");
  // Constant-time compare — never use === for HMAC.
  return crypto.timingSafeEqual(
    Buffer.from(signature, "hex"),
    Buffer.from(expected, "hex"),
  );
}

// In your Express handler:
app.post("/webhook", (req, res) => {
  const sig = req.header("X-Byro-Signature");
  const ok = verify(req.rawBody, sig, process.env.BYRO_WEBHOOK_SECRET);
  if (!ok) return res.status(401).send("invalid signature");
  // ... process req.body
  res.status(200).send("ok");
});

Ready to subscribe? Configure your first endpoint in the admin panel.

Go to /admin/webhooks