Base URL (sandbox):
https://api-sandbox.ledgersyncappv2.com/v3 · Auth: Authorization: Bearer sk_test_... · Every response carries an X-LS-Trace-Id header — grab it if you ever open a support ticket.Prefer Postman?
Import our collection and run the whole flow without leaving Postman. The Quickstart folder chains every step below and captures ids for you, so you can run it top-to-bottom.Import the collection
In Postman, Import → Link and paste the hosted URL (or download it and Import → File):It ships folders for every resource — Clients, Connections, Accounts, Transactions, Statements, Operations, Webhooks, Institutions, and more — plus the chained Quickstart folder.
Set two variables
On the collection, set
api_key to your key and point base_url at the environment you’re testing:| Variable | Sandbox | Live |
|---|---|---|
api_key | your sk_test_... | your sk_live_... |
base_url | https://api-sandbox.ledgersyncappv2.com/v3 | https://api.ledgersyncappv2.com/v3 |
The mental model
Four objects, one line of descent. A Client is your record of one end-user. Each Client owns one or more Connections (one per linked bank). Each Connection exposes Accounts, and each Account has Transactions and Statements. Two things to internalize now, because they save debugging later:- You never see bank credentials. The user types them into a LedgerSync-hosted widget. You just open a URL.
- The data source is chosen for you. LedgerSync routes each institution to Finicity, MX, or FDE server-side. There is no
sourceparameter — the id you pass (ins_...) already encodes everything.
Finicity
Broadest US coverage. OAuth where the bank supports it.
MX
Alternate aggregator. Catches banks Finicity misses.
FDE
LedgerSync’s proprietary extraction for banks neither aggregator covers.
Mint a sandbox key
In the portal, open Developers → API keys and create a sandbox key. It starts with Confirm it authenticates:A
sk_test_ — live keys start with sk_live_. Keep test and live strictly separate; they hit different base URLs and different data.Set it in your shell so the snippets below just work:401 means a bad or missing key. See Authentication for the full contract.Register a webhook subscription
Connections finish asynchronously — the user could take thirty seconds or ten minutes inside the widget. Rather than poll forever, subscribe to webhooks and react when The response includes a Verify signatures constant-time and dedupe on
connection.active arrives.The easiest path is the portal Webhooks page — add your endpoint, pick events, and see deliveries and retries visually. To do it over the API, subscribe to all eight event types:signing_secret:event_id. The full recipe (headers, HMAC, retries, the 30-second ack window) is in the Webhooks guide. Want to see a payload land right away? Fire a test:Create a Client
A Client represents one end-user. Set Hold onto
external_id to whatever you use internally (a user id, org id, however you key it) so you can cross-reference without storing our ids everywhere.cli_01HXYZ7ABCDEF... — every read later is scoped to it.Discover the institution
Search the catalog to get the
institution_id you’ll connect to. Each row carries a capabilities block so you know upfront what a bank supports.Initiate the Connection
Create a Connection under the Client with just the You get back Poll the operation until it succeeds:
institution_id. No source, no credentials.202 Accepted and an operation_id. The connection is being set up in the background.Hand off the widget
Open
widget_url in the user’s browser — redirect, iframe, or webview, whatever fits your app. The user searches for their bank, signs in (credentials or the bank’s own OAuth), picks accounts, and closes it. Credentials go to the bank, never through you.A small nuance by source: Finicity and MX show an aggregator widget with a bank search; FDE shows a LedgerSync-hosted connect page with the bank already chosen (no search, since institution_id fixed it).Don’t want to build a picker at all? Use the hosted link instead:
POST /v3/clients/{id}/connect-session returns { url, expires_at } — a LedgerSync-hosted page you email the member. They search, pick, and connect their own bank; you revoke with DELETE /v3/clients/{id}/connect-session/{sid}. See Connect a bank for both flows side by side.Receive connection.active
When the user finishes, LedgerSync fires Persist
connection.active to your webhook. This is your signal that data is flowing and the canonical id is ready.con_FINICITY_41294 against your user. That’s the id you’ll use for every read. (The other statuses — requires_action, failed, disconnected — are covered in the Connection lifecycle guide.)List accounts and transactions
Reads are Client-scoped — pass Then pull transactions for an account, filtered by date:
client_id on every one. Start with the accounts on this connection:That’s the full loop — Client → Connection → Account → Transactions. The ids encode their source (
acc_FINICITY_..., txn_MX_..., txn_FDE_...), but the shapes are identical no matter which aggregator served them.Testing with FinBank
The no-MFA happy path. Search
?q=FinBank and pick the row named exactly FinBank. In the widget, sign in with Banking Userid demo / Banking Password go. It flips to active immediately — no MFA, no OAuth round-trip — and auto-populates accounts, transactions, and statements. To exercise FDE instead, use “Ledgersync Bank” (ins_a7397a8d0656e1b7). The full bank list, plus MFA and OAuth variants and their credentials, lives in the portal Testing playbook.Handling errors
Every error returns the same envelope — branch oncode, not on the HTTP status alone:
| HTTP | Meaning |
|---|---|
| 400 | Validation — something in your request body or params is off |
| 401 | Auth — bad or missing key |
| 404 | Not found |
| 429 | Rate limited — back off and retry |
| 5xx | Server error — retry, and quote X-LS-Trace-Id if it persists |
Where to go next
Connect a bank
The widget flow and the hosted connect-session link, in depth.
Webhooks
Verify signatures, dedupe on event_id, handle retries.
Connection lifecycle
requires_action, active, failed, disconnected — and capability changes.
API reference
Every endpoint, parameter, and response shape.
