Skip to main content
When a bank exposes scanned images of the paper checks written against an account, LedgerSync captures them and serves them alongside that account’s transactions. Checks hang off an account, so every route below is nested under one:
Check images are FDE-only — no other source delivers them. Finicity, MX and PDF accounts have no checks, and asking for theirs returns an empty list rather than an error (see Sources without checks).
There is no back image. LedgerSync captures the front of a check only, so a check is exactly one image and there is no side field to pass or branch on.

Before you start

Your API key needs the read:checks scope. A key minted before check support shipped won’t have it, and every check route will answer 403 insufficient_scope. Tick the scope on a new key in the developer portal, or widen the key you already have — the calling key needs write:api-keys, and {id} is the key’s id from GET /v3/api-keys (not the sk_test_... secret):
Add read:checks to an existing key
PATCH replaces the whole scope list — send every scope the key should keep, not just the new one. The secret itself never changes, so nothing you’ve already deployed stops working.

List an account’s checks

Reads are Client-scoped, so pass client_id every time.
List checks
Response
Check ids are chk_FDE_<id>, source-tagged like every other v3 id. The list paginates with limit and cursor exactly like the rest of the API — see Pagination.

Download the image

download_url on each check is a ready-to-call relative URL — prefer it over building the path yourself:
Download
The response is the raw image, served through the API and auth-scoped to your key — you never handle a storage URL. Content-Type is determined by inspecting the image’s own magic bytes (image/png, image/jpeg or image/gif; application/octet-stream if the bytes match none of those), and Content-Disposition names the file <check_id>.<ext> to match.
Read the format from the Content-Type header, not from a filename — stored objects are not reliably named after their true format, which is exactly why this endpoint sniffs the bytes for you.

Bank-reported vs OCR fields

Every check carries two independent readings of the same piece of paper, and they are deliberately kept apart: The two routinely disagree, and individual ocr fields are often null where recognition failed — as check_number is above. OCR is best-effort on a photograph of handwriting; the bank’s own record is the authoritative one. Treat ocr as a hint (for search, prefill, or reconciliation review), never as ground truth for money movement. The whole ocr object is omitted when nothing at all was recognised.

Sources without checks

Only FDE accounts can have check images, and the API distinguishes “this source has none” from “you asked wrong”:
The non-FDE short-circuit is evaluated before ownership, so listing checks on a non-FDE account you don’t own returns 200 with an empty array rather than 404. It carries no data either way.

Try it in sandbox

The sandbox Ledgersync Bank (ins_a7397a8d0656e1b7) returns real check images, so you can exercise all three routes end-to-end without a live bank:
1

Connect Ledgersync Bank

Follow FDE — Ledgersync Bank. It accepts any username and password.
2

Wait for connection.active

Extraction is asynchronous. Checks land once the connection completes — listen for the connection.active webhook rather than polling immediately.
3

Find the account, then its checks

GET /v3/accounts?client_id=...&connection_id=con_FDE_... gives you the acc_FDE_... id; pass it to the list route above.

Full reference

Every parameter and response field for the three check routes.