bitlync Docs

Concepts

Webhooks

Bitlync pushes signed events to your HTTPS URL after sync. You can also poll GET /tenants/{id}/connections/events?kind=…. This page is outbound Bitlync→ISV only.

Kinds shipped today

Tickets: ticket.created / updated / noted / closed / reopened — grant psa.ticket.events.

Devices: device.created / updated — grant rmm.device.events.

Companies: company.created / updated — grant psa.company.events.

Register

One pipe: POST /tenants/{tenant_id}/ticket-events/webhook with {"url":"https://…"}. OpenAPI name stays ticket-events; the same registration delivers device and company kinds when those grants are on. There is not a second register route.

register
curl -sS -X POST "$BITLYNC_BASE/tenants/sandbox-mainstreet/ticket-events/webhook" \
  -H "X-API-Key: $BITLYNC_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/bitlync/hooks"}'

Secret

The response returns secret once. Store it. Docs examples redact as whsec_… — never log plaintext.

HMAC

Header Bitlync-Signature: t=<unix>,v1=<hex> over {t}.{body} (HMAC-SHA256 with the secret).

verify (Python)
import hmac, hashlib
parts = dict(p.split("=", 1) for p in header.split(","))
t, v1 = parts["t"], parts["v1"]
expect = hmac.new(secret.encode(), f"{t}.{body}".encode(), hashlib.sha256).hexdigest()
ok = hmac.compare_digest(v1, expect)
verify (Node)
const crypto = require("crypto");
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const expect = crypto.createHmac("sha256", secret)
  .update(`${parts.t}.${body}`).digest("hex");
const ok = crypto.timingSafeEqual(
  Buffer.from(parts.v1), Buffer.from(expect));

Delivery rules

Retry with backoff on tick. Your endpoint returning HTTP 410 disables the webhook. A revoked grant stops delivery for that kind. Nothing is dropped silently.

Missing grant

Without the connection grant, list/push fails with grant_missing. The MSP must grant events on the connection (psa.ticket.events, rmm.device.events, or psa.company.events).

Inbound (vendor→Bitlync)

E3b Halo Ticket inbound is PARTIAL: tickets only, under path-token intake + Basic Auth (fail closed). DirtyFlagBoard → demand-path sync; store unchanged (no body→store parser). Reconciliation poll stays on (webhooks accelerate freshness only). HMAC / X-HALO-SIGNATURE for Halo→URL webhooks is UNKNOWN — not implemented. No Autotask or ConnectWise inbound parsers. Live Halo→Bitlync ingress is UNKNOWN / not proven in prod. HTTP mount is mount-when-wired (POST /webhooks/{vendor}/{intake_token}) — may be absent from the public OpenAPI. Contact create parked. Badge OFF.

Not this page

This chapter stays outbound Bitlync→ISV. Inbound does not invent Autotask or ConnectWise parsers, and it does not claim live real-time PSA push into your product.