curl --request POST \
--url https://api.range.org/v2/reconciliation/multi-source \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: <api-key>' \
--data '
{
"account_ids": [
"a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"b2c3d4e5-f6a7-8901-bcde-f12345678901"
],
"start_time": "2026-09-01T00:00:00Z",
"end_time": "2026-09-30T00:00:00Z",
"assets": [
"USDC"
],
"reporting_currency": "USD",
"show_all": false
}
'import requests
url = "https://api.range.org/v2/reconciliation/multi-source"
payload = {
"account_ids": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890", "b2c3d4e5-f6a7-8901-bcde-f12345678901"],
"start_time": "2026-09-01T00:00:00Z",
"end_time": "2026-09-30T00:00:00Z",
"assets": ["USDC"],
"reporting_currency": "USD",
"show_all": False
}
headers = {
"X-API-KEY": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-KEY': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
account_ids: ['a1b2c3d4-e5f6-7890-abcd-ef1234567890', 'b2c3d4e5-f6a7-8901-bcde-f12345678901'],
start_time: '2026-09-01T00:00:00Z',
end_time: '2026-09-30T00:00:00Z',
assets: ['USDC'],
reporting_currency: 'USD',
show_all: false
})
};
fetch('https://api.range.org/v2/reconciliation/multi-source', 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.range.org/v2/reconciliation/multi-source",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'account_ids' => [
'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
'b2c3d4e5-f6a7-8901-bcde-f12345678901'
],
'start_time' => '2026-09-01T00:00:00Z',
'end_time' => '2026-09-30T00:00:00Z',
'assets' => [
'USDC'
],
'reporting_currency' => 'USD',
'show_all' => false
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-KEY: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.range.org/v2/reconciliation/multi-source"
payload := strings.NewReader("{\n \"account_ids\": [\n \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n \"b2c3d4e5-f6a7-8901-bcde-f12345678901\"\n ],\n \"start_time\": \"2026-09-01T00:00:00Z\",\n \"end_time\": \"2026-09-30T00:00:00Z\",\n \"assets\": [\n \"USDC\"\n ],\n \"reporting_currency\": \"USD\",\n \"show_all\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-KEY", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.range.org/v2/reconciliation/multi-source")
.header("X-API-KEY", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"account_ids\": [\n \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n \"b2c3d4e5-f6a7-8901-bcde-f12345678901\"\n ],\n \"start_time\": \"2026-09-01T00:00:00Z\",\n \"end_time\": \"2026-09-30T00:00:00Z\",\n \"assets\": [\n \"USDC\"\n ],\n \"reporting_currency\": \"USD\",\n \"show_all\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.range.org/v2/reconciliation/multi-source")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-KEY"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"account_ids\": [\n \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n \"b2c3d4e5-f6a7-8901-bcde-f12345678901\"\n ],\n \"start_time\": \"2026-09-01T00:00:00Z\",\n \"end_time\": \"2026-09-30T00:00:00Z\",\n \"assets\": [\n \"USDC\"\n ],\n \"reporting_currency\": \"USD\",\n \"show_all\": false\n}"
response = http.request(request)
puts response.read_body{
"requested_period": {
"start_time": "2026-07-01T00:00:00.000Z",
"end_time": "2026-08-01T00:00:00.000Z"
},
"reporting_currency": "USD",
"holding": {
"chain_account_id": "<string>",
"custodian_account_id": "<string>",
"ledger_account_id": "<string>"
},
"accounts": [
{
"account_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "ok",
"declared_gaps": [
{
"reason": "trade_quote_leg_unattributed",
"asset": "USDC",
"quantity": "500.00",
"transaction_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
],
"label": "custodian",
"effective_period": {
"start_time": "2026-07-01T00:00:00.000Z",
"end_time": "2026-08-01T00:00:00.000Z"
},
"unreconcilable_reason": "network_reconciliation_unsupported"
}
],
"assets": [
{
"asset": "USDC",
"per_account": [
{
"account_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "ok",
"label": "custom",
"unreconcilable_reason": "network_reconciliation_unsupported",
"declared_gap_reason": "trade_quote_leg_unattributed",
"opening_quantity": "100000",
"movements_quantity": "-2500",
"computed_closing_quantity": "97500",
"actual_closing_quantity": "97500",
"difference": "0",
"tie_out_status": "tied",
"opening_usd": "100000.00",
"closing_usd": "97500.00"
}
],
"agreement_status": "agreed",
"likely_cause": "none",
"unmatched_movements": [
{
"account_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"asset": "USDC",
"quantity": "25",
"missing_on": [
"b2c3d4e5-f6a7-8901-bcde-f12345678901"
],
"tx_hash": "0xabc...",
"source_ref": "ptx-1"
}
]
}
],
"unmatched_assets": []
}Multi-source reconciliation
Compares a custodian account with an on-chain account over one period. Addresses do not have to match. An optional connection with type custom is a stand-in ledger. Runs each account’s roll-forward and returns them side-by-side per asset. Each asset block carries an agreement_status, a closed likely_cause tag, and any unmatched_movements (tx_hash then source_ref; SELF legs included). Unlike roll-forward this is a POST with a JSON body, and end_time is optional (defaults to and echoes server now). USD figures are display-only snapshots taken independently per tape, and agreement is on quantities.
curl --request POST \
--url https://api.range.org/v2/reconciliation/multi-source \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: <api-key>' \
--data '
{
"account_ids": [
"a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"b2c3d4e5-f6a7-8901-bcde-f12345678901"
],
"start_time": "2026-09-01T00:00:00Z",
"end_time": "2026-09-30T00:00:00Z",
"assets": [
"USDC"
],
"reporting_currency": "USD",
"show_all": false
}
'import requests
url = "https://api.range.org/v2/reconciliation/multi-source"
payload = {
"account_ids": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890", "b2c3d4e5-f6a7-8901-bcde-f12345678901"],
"start_time": "2026-09-01T00:00:00Z",
"end_time": "2026-09-30T00:00:00Z",
"assets": ["USDC"],
"reporting_currency": "USD",
"show_all": False
}
headers = {
"X-API-KEY": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-KEY': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
account_ids: ['a1b2c3d4-e5f6-7890-abcd-ef1234567890', 'b2c3d4e5-f6a7-8901-bcde-f12345678901'],
start_time: '2026-09-01T00:00:00Z',
end_time: '2026-09-30T00:00:00Z',
assets: ['USDC'],
reporting_currency: 'USD',
show_all: false
})
};
fetch('https://api.range.org/v2/reconciliation/multi-source', 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.range.org/v2/reconciliation/multi-source",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'account_ids' => [
'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
'b2c3d4e5-f6a7-8901-bcde-f12345678901'
],
'start_time' => '2026-09-01T00:00:00Z',
'end_time' => '2026-09-30T00:00:00Z',
'assets' => [
'USDC'
],
'reporting_currency' => 'USD',
'show_all' => false
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-KEY: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.range.org/v2/reconciliation/multi-source"
payload := strings.NewReader("{\n \"account_ids\": [\n \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n \"b2c3d4e5-f6a7-8901-bcde-f12345678901\"\n ],\n \"start_time\": \"2026-09-01T00:00:00Z\",\n \"end_time\": \"2026-09-30T00:00:00Z\",\n \"assets\": [\n \"USDC\"\n ],\n \"reporting_currency\": \"USD\",\n \"show_all\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-KEY", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.range.org/v2/reconciliation/multi-source")
.header("X-API-KEY", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"account_ids\": [\n \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n \"b2c3d4e5-f6a7-8901-bcde-f12345678901\"\n ],\n \"start_time\": \"2026-09-01T00:00:00Z\",\n \"end_time\": \"2026-09-30T00:00:00Z\",\n \"assets\": [\n \"USDC\"\n ],\n \"reporting_currency\": \"USD\",\n \"show_all\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.range.org/v2/reconciliation/multi-source")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-KEY"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"account_ids\": [\n \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n \"b2c3d4e5-f6a7-8901-bcde-f12345678901\"\n ],\n \"start_time\": \"2026-09-01T00:00:00Z\",\n \"end_time\": \"2026-09-30T00:00:00Z\",\n \"assets\": [\n \"USDC\"\n ],\n \"reporting_currency\": \"USD\",\n \"show_all\": false\n}"
response = http.request(request)
puts response.read_body{
"requested_period": {
"start_time": "2026-07-01T00:00:00.000Z",
"end_time": "2026-08-01T00:00:00.000Z"
},
"reporting_currency": "USD",
"holding": {
"chain_account_id": "<string>",
"custodian_account_id": "<string>",
"ledger_account_id": "<string>"
},
"accounts": [
{
"account_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "ok",
"declared_gaps": [
{
"reason": "trade_quote_leg_unattributed",
"asset": "USDC",
"quantity": "500.00",
"transaction_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
],
"label": "custodian",
"effective_period": {
"start_time": "2026-07-01T00:00:00.000Z",
"end_time": "2026-08-01T00:00:00.000Z"
},
"unreconcilable_reason": "network_reconciliation_unsupported"
}
],
"assets": [
{
"asset": "USDC",
"per_account": [
{
"account_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "ok",
"label": "custom",
"unreconcilable_reason": "network_reconciliation_unsupported",
"declared_gap_reason": "trade_quote_leg_unattributed",
"opening_quantity": "100000",
"movements_quantity": "-2500",
"computed_closing_quantity": "97500",
"actual_closing_quantity": "97500",
"difference": "0",
"tie_out_status": "tied",
"opening_usd": "100000.00",
"closing_usd": "97500.00"
}
],
"agreement_status": "agreed",
"likely_cause": "none",
"unmatched_movements": [
{
"account_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"asset": "USDC",
"quantity": "25",
"missing_on": [
"b2c3d4e5-f6a7-8901-bcde-f12345678901"
],
"tx_hash": "0xabc...",
"source_ref": "ptx-1"
}
]
}
],
"unmatched_assets": []
}Authorizations
Authorization method required to allow user to access the api endpoints.
Body
A custodian account and an on-chain account, plus an optional custom connection as a stand-in ledger. Between 2 and 4 account ids (UUIDs). Addresses do not have to match. At most one of each tape.
[
"a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"b2c3d4e5-f6a7-8901-bcde-f12345678901"
]
Period start A (ISO 8601). Must be before the effective end.
"2026-09-01T00:00:00Z"
Period end B (ISO 8601). Omit for the live period — the server fills and echoes the instant used (now).
"2026-09-30T00:00:00Z"
Restrict the comparison to these display symbols (catalogue-normalised). A symbol that is not in the catalogue is rejected. Omit to compare every asset held across the accounts. At most 50.
["USDC"]
Display currency. Only 'USD' is supported today.
"USD"
Bypass the workspace token whitelist on both sides of every line, same meaning as on the roll-forward endpoint.
Response
Echoes the period; end_time is the instant actually used.
Show child attributes
Show child attributes
"USD"
Show child attributes
Show child attributes
Every requested account. An id outside the workspace, a duplicate role, or a tape this comparison does not accept is rejected before this list is built, so a missing tape is a 400 rather than a shorter list.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Requested display symbols that matched no line on any tape. Empty when assets was omitted or every requested symbol appeared.
[]
Was this page helpful?