Webhooks

Get a message at your own URL as soon as a connection, application or operation changes.

A URL you give us. When an event you chose happens, we POST a small JSON message there. Use it to keep another system up to date, or to start 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 want. You can change them later.

  4. 4

    Copy the signing secret. It is shown once. Keep it with your receiver.

  5. 5

    Click Send a test on the card. A test message arrives before any real event.

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. A retried message keeps the same id.
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. Then a copied message cannot be sent again.

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 about two hours.

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

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

Answer first, work later
A slow receiver gets the message again, and handles it twice. Reply first, then do the work.

Events

connection: TallyPrime linked or unlinked. application: access given or taken away. operation: a request worked or failed. You see the full list, and what each carries, when you create a webhook.

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