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