Webhooks

Get a message at your own URL the moment a connection, application or operation changes.

A URL you give us. When an event you chose happens, we POST a small JSON message there — to keep another system in step, or to trigger a workflow from something that happened in TallyPrime.

Setting one up

  1. 1

    In the dashboard, open Webhooks and choose New webhook.

  2. 2

    Paste the HTTPS address that should receive the messages.

  3. 3

    Tick the events you care about. You can change them later.

  4. 4

    Copy the signing secret shown once, and store it with your receiver.

  5. 5

    Use Send a test on the card to see a message arrive before anything real happens.

The address must be public and use HTTPS
A private-network or localhost address is refused when you save.

What a message looks like

Every message is a POST with a JSON body and these headers:

HeaderMeaning
X-Balancely-EventThe event name, for example connection.connected.
X-Balancely-DeliveryA unique id for this message. The same id is reused when a message is retried.
X-Balancely-Signaturet=<unix seconds>,v1=<signature> — see below.
Content-Typeapplication/json

The body carries the event, when it happened, and the details:

body
{
  "id": "dlv_8f3…",
  "event": "connection.connected",
  "createdAt": "2026-09-04T10:15:00.000Z",
  "data": {
    "connectionId": "…",
    "connectionName": "Acme Traders",
    "companyName": "Acme Traders (2026-27)"
  }
}

Checking a message is really from us

HMAC-SHA256 of t.body with your signing secret must equal v1. Reject a t older than a few minutes so a captured message cannot be replayed.

Node.js example

verify.js
import { createHmac, timingSafeEqual } from 'node:crypto';

function verify(rawBody, signatureHeader, secret) {
  const parts = Object.fromEntries(signatureHeader.split(',').map((p) => p.split('=')));
  const expected = createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex');
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
  return fresh && timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

Retries and timeouts

  • Answer 2xx within 8 seconds. Anything else is tried again, up to 6 attempts in all over about two hours.

  • Deliveries do not count against your plan, however many attempts they take.

  • Every attempt and your server's answer is listed under Recent deliveries.

Answer first, work later
A slow receiver is retried — and handles the same message twice.

Events

connection — TallyPrime linked or unlinked. application — access gained or lost. operation — a request succeeded or failed. The full list, with what each carries, is shown when you create a webhook.

Something missing on this page? Tell us and we will fix it.