LedgerSync API: Webhooks

LedgerSync API: Webhooks

Overview

Bank connections in the LedgerSync API are asynchronous. When a user links their bank, they may finish in seconds or take several minutes. Webhooks let LedgerSync push a notification to your server the instant something changes — so you never have to poll.

The most important event is connection.active. It fires when a user finishes linking and data starts flowing. Its payload carries the canonical connection ID (e.g., con_FINICITY_41294) — the only ID that works on /accounts, /transactions, and /statements.

How to Subscribe

The easiest path is the Webhooks page in the developer portal: paste your endpoint URL, pick the events you want, and copy the signing secret.

To subscribe via API:

curl -X POST https://api-sandbox.ledgersyncappv2.com/v3/webhooks/subscriptions \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/webhooks/ledgersync",
    "event_types": ["connection.active", "connection.failed", "connection.disconnected", "account.refresh.completed"]
  }'

The response includes a signing_secret — shown only once. Save it immediately in a secrets manager. If you lose it, rotate the secret from the portal Webhooks page.

The Eight Event Types

EventWhen it fires
connection.initiatedYou kicked off a link; the user hasn't finished the widget yet.
connection.requires_actionThe connection is waiting on the user (sign-in, MFA, account selection).
connection.activeUser finished linking. Data is flowing. Carries the canonical connection ID.
connection.failedBad credentials or aggregator-reported failure. The link did not complete.
connection.disconnectedUser revoked access, or the connection needs a re-link.
connection.capability_changedA single capability on an active connection flipped working ↔ not-working.
account.refresh.completedA background data refresh for an account finished successfully.
account.refresh.failedA background data refresh for an account failed.

You can also use "*" as the event type to subscribe to all events.

Verifying the Signature

Never trust a delivery without verifying it. Every webhook delivery includes these headers:

  • X-LS-Webhook-Event-Id — unique ID for the event (use for deduplication)
  • X-LS-Webhook-Timestamp — Unix seconds when LedgerSync produced the event
  • X-LS-Webhook-Signature — HMAC-SHA256 signature to verify

The signed payload is: timestamp + "." + raw_body

Compute: hex(HMAC-SHA256(signing_secret, signed_payload)) and compare to X-LS-Webhook-Signature using a constant-time comparison. Also reject deliveries where the timestamp is more than 5 minutes old (replay protection).

Critical: Sign the raw bytes of the body exactly as received. If your framework re-serializes the JSON before you verify, the bytes will change and the signature will not match. Capture the raw body before any JSON middleware processes it.

Retries and Idempotency

  • LedgerSync retries failed deliveries with exponential backoff for up to 24 hours.
  • Return a 2xx response within 30 seconds. Do the minimum (verify, enqueue), then push slow work to a background queue. A slow response looks like a failure and triggers a retry.
  • Dedupe on event_id. The same event can arrive more than once due to retries. Treat event_id as an idempotency key: if you've seen it, acknowledge and skip.
  • Order is not guaranteed under retries. Design handlers to react to the state in data rather than assuming a previous event already arrived.

Testing Your Webhook

Send a real signed test delivery to your endpoint at any time:

curl -X POST \
  https://api-sandbox.ledgersyncappv2.com/v3/webhooks/subscriptions/whsub_01HXYZ.../test \
  -H "Authorization: Bearer sk_test_..."

The test delivery is signed with your real signing secret and bypasses the event type filter, so it exercises your full verification and deduplication logic end-to-end.

Managing Subscriptions

  • List subscriptions: GET /v3/webhooks/subscriptions
  • Update a subscription: Change the URL, event types, or pause/resume delivery (status: active or paused)
  • Rotate the signing secret: The old secret stays valid for a 24-hour grace period so you can deploy your new verifier without dropping deliveries.
  • Delete a subscription: Stops all future deliveries. Past attempts stay in the audit log.

Need Help?

Related Articles

  • LedgerSync API: Getting Started (Quickstart Guide)
  • LedgerSync API Overview: What You Can Build
  • LedgerSync API: Authentication & API Keys
    • Related Articles

    • LedgerSync API — Webhooks & Transaction Deduplication (transactionHash)

      Overview This article is for LedgerSync API partners. The LedgerSync API supports webhook notifications and a stable transaction hash field to help your integration handle real-time events and deduplicate transactions across bank reconnections. ...
    • LedgerSync API: Getting Started (Quickstart Guide)

      Overview This guide walks you through linking your first bank account and pulling real transaction data using the LedgerSync API — from your first sandbox key to a live data response. The full flow takes about 15 minutes in sandbox. Sandbox base URL: ...
    • Building a LedgerSync Integration with AI (Vibe Coding)

      Overview You don't need to be a developer to build a banking data integration with LedgerSync. If you use AI tools like ChatGPT, Claude, or Cursor, you can point them at the LedgerSync API documentation and let the AI write the full integration for ...
    • How to Request Live (Production) API Access

      Overview The LedgerSync API portal operates in two environments: Sandbox and Live (Production). All new API accounts begin in Sandbox mode, which uses test keys and fake data. To use the API with real production traffic, you must request and receive ...
    • LedgerSync Close — Overview and How It Works

      Overview LedgerSync Close is a month-end reconciliation tool that compares your bank statements directly against the transactions recorded in QuickBooks Online (QBO). It automatically identifies missing transactions, duplicate entries, and category ...