curl --request GET \
--url https://api-sandbox.ledgersyncappv2.com/v3/statements/{statement_id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://api-sandbox.ledgersyncappv2.com/v3/statements/{statement_id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api-sandbox.ledgersyncappv2.com/v3/statements/{statement_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-sandbox.ledgersyncappv2.com/v3/statements/{statement_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api-sandbox.ledgersyncappv2.com/v3/statements/{statement_id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api-sandbox.ledgersyncappv2.com/v3/statements/{statement_id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-sandbox.ledgersyncappv2.com/v3/statements/{statement_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"id": "stmt_FINICITY_551",
"statement_date": "2023-12-25",
"account_id": "<string>",
"source": "FINICITY",
"download_url": "<string>",
"exported_to": "<string>"
}{
"error": {
"code": "unknown_api_key",
"message": "The API key you presented doesn't match any active key.",
"type": "auth_error",
"doc_url": "https://portal.ledgersyncappv2.com/errors/unknown_api_key",
"category": "AUTH_ERROR",
"is_user_actionable": true,
"source_diagnostic_code": "FIN-103",
"param": "client.email",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"errors": [
{
"param": "client.email",
"message": "must be a valid email address",
"code": "invalid_email"
}
]
}
}{
"error": {
"code": "unknown_api_key",
"message": "The API key you presented doesn't match any active key.",
"type": "auth_error",
"doc_url": "https://portal.ledgersyncappv2.com/errors/unknown_api_key",
"category": "AUTH_ERROR",
"is_user_actionable": true,
"source_diagnostic_code": "FIN-103",
"param": "client.email",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"errors": [
{
"param": "client.email",
"message": "must be a valid email address",
"code": "invalid_email"
}
]
}
}Get a statement
Returns the statement metadata plus, when available, a
download_url for the original PDF. That URL is a relative
/v3 path scoped to your API key, not a signed link: join
it to the API host and send your Authorization header. It
carries no signature and does not expire, so handing it to a
browser tab on its own returns 401. For FDE connections this
is the document the user uploaded; for bank-sourced statements
it’s the bank’s published file.
curl --request GET \
--url https://api-sandbox.ledgersyncappv2.com/v3/statements/{statement_id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://api-sandbox.ledgersyncappv2.com/v3/statements/{statement_id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api-sandbox.ledgersyncappv2.com/v3/statements/{statement_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-sandbox.ledgersyncappv2.com/v3/statements/{statement_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api-sandbox.ledgersyncappv2.com/v3/statements/{statement_id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api-sandbox.ledgersyncappv2.com/v3/statements/{statement_id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-sandbox.ledgersyncappv2.com/v3/statements/{statement_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"id": "stmt_FINICITY_551",
"statement_date": "2023-12-25",
"account_id": "<string>",
"source": "FINICITY",
"download_url": "<string>",
"exported_to": "<string>"
}{
"error": {
"code": "unknown_api_key",
"message": "The API key you presented doesn't match any active key.",
"type": "auth_error",
"doc_url": "https://portal.ledgersyncappv2.com/errors/unknown_api_key",
"category": "AUTH_ERROR",
"is_user_actionable": true,
"source_diagnostic_code": "FIN-103",
"param": "client.email",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"errors": [
{
"param": "client.email",
"message": "must be a valid email address",
"code": "invalid_email"
}
]
}
}{
"error": {
"code": "unknown_api_key",
"message": "The API key you presented doesn't match any active key.",
"type": "auth_error",
"doc_url": "https://portal.ledgersyncappv2.com/errors/unknown_api_key",
"category": "AUTH_ERROR",
"is_user_actionable": true,
"source_diagnostic_code": "FIN-103",
"param": "client.email",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"errors": [
{
"param": "client.email",
"message": "must be a valid email address",
"code": "invalid_email"
}
]
}
}Authorizations
Pass your secret key in the Authorization header as a Bearer
token: Authorization: Bearer sk_test_... (sandbox) or
Bearer sk_live_... (production).
Keys are created in the developer portal and the plaintext secret is shown exactly once at creation. Treat them like passwords — never embed them in mobile apps or front-end code.
Path Parameters
Query Parameters
The Client (cli_…) to scope the read to. Required on account,
transaction, and statement reads — LedgerSync's backend data APIs
are scoped per end-user, so these resources are resolved within a
single Client.
Response
The Statement, with a signed download URL when one exists.
"stmt_FINICITY_551"
The owning account id. Populated when listing an account's statements; null on single get-by-id (the backend statement record carries no fin-account id to map back).
Financial-data source backing an account. Aggregator sources
(FINICITY, MX) and FDE back a Connection; PDF does not.
Values:
FINICITY— Finicity aggregationMX— MX aggregationFDE— Financial Document Extraction (LedgerSync proprietary)PDF— Uploaded bank statements. Read-only: exposed on/accountsand/transactions(statements are not served for PDF), and never as a Connection (PDF accounts haveconnection_id: null).
FINICITY, MX, FDE, PDF Relative v3 URL to download the statement PDF, auth-scoped to your API key. Resolves to GET /statements/{statement_id}/download; GET it to stream the PDF bytes.
Accounting platform the statement was exported to, if any.
