curl --request GET \
--url https://api-sandbox.ledgersyncappv2.com/v3/transactions/{transaction_id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://api-sandbox.ledgersyncappv2.com/v3/transactions/{transaction_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/transactions/{transaction_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/transactions/{transaction_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/transactions/{transaction_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/transactions/{transaction_id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-sandbox.ledgersyncappv2.com/v3/transactions/{transaction_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": "txn_FINICITY_8837",
"account_id": "<string>",
"amount": -28.34,
"iso_currency_code": "USD",
"date": "2023-12-25",
"description": "STARBUCKS #1234 SEATTLE WA",
"external_id": "<string>",
"merchant_name": "<string>",
"category": "<string>",
"pending": true
}{
"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 single transaction
Look up one transaction by id. Useful when a webhook just
fired for a specific transaction_id and you want the
full record.
curl --request GET \
--url https://api-sandbox.ledgersyncappv2.com/v3/transactions/{transaction_id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://api-sandbox.ledgersyncappv2.com/v3/transactions/{transaction_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/transactions/{transaction_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/transactions/{transaction_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/transactions/{transaction_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/transactions/{transaction_id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-sandbox.ledgersyncappv2.com/v3/transactions/{transaction_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": "txn_FINICITY_8837",
"account_id": "<string>",
"amount": -28.34,
"iso_currency_code": "USD",
"date": "2023-12-25",
"description": "STARBUCKS #1234 SEATTLE WA",
"external_id": "<string>",
"merchant_name": "<string>",
"category": "<string>",
"pending": true
}{
"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 Transaction.
"txn_FINICITY_8837"
Signed decimal amount in the account's currency, normalized to one convention across every source - money out negative, money in positive (matches Plaid/Finicity). Sources that report an unsigned magnitude with the direction in a separate field are signed by LedgerSync before they reach this API.
-28.34
ISO-4217 currency code. Defaults to USD when the source omits it.
"USD"
Posted date, the date the transaction cleared (Plaid-style date). A pending charge has not cleared and so has no posted date yet; for those this falls back to the date the bank recorded the charge, and it can change when the charge settles.
"STARBUCKS #1234 SEATTLE WA"
Upstream aggregator's transaction ID (Finicity, MX, etc.) if available.
LedgerSync's normalized category (best-effort across sources).
Whether the bank is still holding this as an authorization rather than a settled charge.
A pending charge is not final. Its amount and its description are both provisional: banks often publish only the card-network entry type while a charge is pending ("PURCHASE", "MAIL/TELEPHONE ORDER") and name the real merchant only once it settles. Treat it as a preview of a charge, never as a booked entry.
When it settles, either of two things happens, and which one is up to the bank. The charge may settle in place, keeping the same id and flipping pending to false. Or the bank may drop it and reissue the settled charge as a new transaction with a different id. So do not assume a pending charge you saw earlier will still be there, or will still carry the same id, on your next call.
LedgerSync withholds pending charges from its own rules engine and from accounting exports until they settle, so a charge returned with pending: true has not been categorized and has not been pushed to QuickBooks or Zoho Books.
Whether pending charges are reported at all depends on the institution, so an account that never returns one is normal.
