LedgerSync API: Getting Started (Quickstart Guide)

LedgerSync API: Getting Started (Quickstart Guide)

Overview

This guide walks you through linking your first bank account and reading its transactions with the LedgerSync API, starting from a sandbox key.

  • Sandbox base URL: https://sandbox-api.ledgersyncappv2.com/v3
  • Auth: Authorization: Bearer sk_test_...

Tip: Every response includes an X-LS-Trace-Id header. Include it in any support request.

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 holds Transactions and Statements.

Two important things to know upfront:

  • You never see bank credentials. The user enters them on a hosted connection screen that you open from a URL. Your app never receives them.
  • The data source is chosen for you. LedgerSync picks the data provider for each bank automatically. You send only the bank's institution_id; there is no source to choose when you connect.

Step 1: Get a Sandbox Key

Log in to the developer portal and create a sandbox key. Sandbox keys start with sk_test_. Set it in your terminal:

export LS_KEY="sk_test_your_key_here"
export LS_BASE="https://sandbox-api.ledgersyncappv2.com/v3"

Confirm authentication:

curl "$LS_BASE/institutions?q=chase" -H "Authorization: Bearer $LS_KEY"

A 401 response means a bad or missing key.

Step 2: Register a Webhook

Bank connections complete asynchronously. Subscribe to webhooks so LedgerSync notifies you when a connection goes active, with no polling required.

curl -X POST "$LS_BASE/webhooks/subscriptions" -H "Authorization: Bearer $LS_KEY" -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. You will use it to verify every incoming delivery: each delivery carries an X-LS-Webhook-Signature header signed with that secret.

Step 3: Create a Client

A Client represents one end-user. Set external_id to your own internal user ID so you can cross-reference without storing LedgerSync IDs everywhere.

curl -X POST "$LS_BASE/clients" -H "Authorization: Bearer $LS_KEY" -H "Content-Type: application/json" -d '{ "external_id": "user_4820", "name": "Example Client" }'

Save the returned id, which starts with cli_. Every later read is scoped to it.

Step 4: Find the Institution

Search the institution catalog to get the institution_id you want to connect. Each result includes a capabilities block showing what the bank supports (transactions, statements, check images).

curl "$LS_BASE/institutions?q=FinBank" -H "Authorization: Bearer $LS_KEY"

For sandbox testing, search for FinBank, a test bank. Use the id from your search result rather than hardcoding one.

Step 5: Initiate the Connection

Create a Connection under your Client with just the institution_id. No source selection, no credentials.

curl -X POST "$LS_BASE/clients/cli_.../connections" -H "Authorization: Bearer $LS_KEY" -H "Content-Type: application/json" -d '{ "institution_id": "ins_..." }'

You receive a 202 Accepted and an operation_id. Poll GET /v3/operations/{operation_id} until status is succeeded, then take the widget_url from the result.

Important: The connection ID at this stage is a placeholder (con_ followed by a long random ID). Do not use it to read data. The canonical ID (con_ followed by a source code and a number) is only available after the user completes the widget and connection.active fires.

Step 6: Open the Widget

Open the widget_url in the user's browser. The user signs in to their bank and authorizes their accounts. You never see their credentials.

Don't want to build a bank picker? Use the hosted connect link instead: POST /v3/clients/{id}/connect-session returns a LedgerSync-hosted URL you can email to the user. They search, pick, and connect their own bank with no front-end work on your side.

Step 7: Receive the Webhook and Read Data

When the user finishes, LedgerSync sends connection.active to your webhook endpoint with the canonical connection ID. Save that ID against your user record. If you cannot run a webhook handler, list the Client's connections with GET /v3/clients/{id}/connections, which only returns canonical IDs.

Then read accounts and transactions:

# List accounts
curl "$LS_BASE/accounts?client_id=cli_...&connection_id=con_..." -H "Authorization: Bearer $LS_KEY"

# List transactions
curl "$LS_BASE/accounts/acc_.../transactions?client_id=cli_...&from=2026-01-01" -H "Authorization: Bearer $LS_KEY"

Use connection and account IDs exactly as LedgerSync returns them.

Error Handling

Every error returns the same envelope. Branch on code, not just the HTTP status:

  • 400: Validation error. Something in your request body or params is incorrect.
  • 401: Authentication error. 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.

Related Articles

  • LedgerSync API Overview: What You Can Build
  • LedgerSync API: Authentication & API Keys
  • LedgerSync API: Webhooks
  • How to Request Live (Production) API Access