From b200dfe9630eb6bd95871cb9fec9411fe6496d0f Mon Sep 17 00:00:00 2001 From: Kaan Kacar Date: Tue, 8 Sep 2026 02:13:58 +0000 Subject: [PATCH 1/6] Document the response differences between Horizon and RPC The migration guide maps each Horizon endpoint to an RPC method, but it never said that the two responses have different shapes. That gap is the one people hit first: Horizon aggregates an account with its trustlines and formats amounts to seven decimal places, while getLedgerEntries returns one raw ledger entry per key with amounts as int64 stroops. Add a Response Differences section that compares GET /accounts/{address} with getLedgerEntries side by side, using real Testnet responses. It covers response shape, raw amounts, XDR encoding, the flags and thresholds fields, and the fact that a missing entry is a 200 rather than a 404. Also link the migration guide from the APIs overview, which had no inbound link to it. --- docs/data/apis/README.mdx | 2 + .../data/apis/migrate-from-horizon-to-rpc.mdx | 138 +++++++++++++++++- 2 files changed, 139 insertions(+), 1 deletion(-) diff --git a/docs/data/apis/README.mdx b/docs/data/apis/README.mdx index 4b680028f7..7e8f030716 100644 --- a/docs/data/apis/README.mdx +++ b/docs/data/apis/README.mdx @@ -31,6 +31,8 @@ RPC is the recommended API for accessing and interacting with Stellar network da Horizon is nearing end-of-life and will eventually be deprecated in favor of Stellar RPC and [Portfolio APIs](../indexers/README.mdx#portfolio-apis). While it will continue to receive updates to maintain compatibility with upcoming protocol releases, it won't receive new feature development. +If your application already uses Horizon, see [Migrate from Horizon to RPC](./migrate-from-horizon-to-rpc.mdx). + ::: Horizon is an API for accessing and interacting with Stellar network data. diff --git a/docs/data/apis/migrate-from-horizon-to-rpc.mdx b/docs/data/apis/migrate-from-horizon-to-rpc.mdx index e73423d12d..dfe6530e1a 100644 --- a/docs/data/apis/migrate-from-horizon-to-rpc.mdx +++ b/docs/data/apis/migrate-from-horizon-to-rpc.mdx @@ -14,6 +14,141 @@ RPC's JSON-RPC API uses JSON-RPC 2.0 to communicate with clients. Requests to th Both formats utilise JSON for the overall structure which are relatively simple and do not require any special client code, although there are client [SDKs] available. Some values contained within are XDR encoded and can be decoded using Stellar [SDKs]. +## Response Differences + +The [endpoint mapping](#endpoint-mapping) below pairs each Horizon endpoint with an RPC method, but the two responses do not have the same shape. Horizon curates the ledger for you. RPC hands you the ledger entry as the protocol stores it. Plan for these differences before you swap one call for the other. + +| Concern | Horizon | RPC | +| --- | --- | --- | +| Shape | One aggregated resource per endpoint | One ledger entry per requested key | +| Amounts | Decimal string with seven places, such as `"1252.7872975"` | Signed 64-bit integer of stroops, such as `"12527872975"` | +| Encoding | Parsed JSON fields | Base64 XDR, or JSON when you pass `xdrFormat` | +| Flags and thresholds | Named booleans and named thresholds | A raw `uint32` bitmask and a four-byte hex string | +| Entry not found | HTTP `404` | HTTP `200`, and the key is absent from `entries` | +| Collections | HAL `_links` and a `paging_token` for paging | No paging, and a limit of 200 keys per call | + +### Example: Account Balances + +Horizon's [`GET /accounts/{address}`] response is an aggregation. It joins the account entry with the account's trustline entries. The [`AccountEntry`] structure holds no trustlines of its own. It holds only a count of the account's sub-entries. So one Horizon call becomes one [`getLedgerEntries`] call with an account key plus one trustline key per asset, and you must already know each asset. + +The example below uses a Testnet account. A [Testnet data reset](../../networks/README.mdx#testnet-and-futurenet-data-reset) clears it, so use your own account and asset to follow along. This Horizon request returns both balances at once: + +```bash +curl "https://horizon-testnet.stellar.org/accounts/GA2242THTLFWPCW2SF3TTLDWJ3C543UUNFTFIMDJUZYXNW2EMEAXZBRH" +``` + +Horizon answers with one resource. The response below is trimmed to the fields this comparison uses: + +```json +{ + "subentry_count": 1, + "thresholds": { + "low_threshold": 0, + "med_threshold": 0, + "high_threshold": 0 + }, + "flags": { + "auth_required": false, + "auth_revocable": false, + "auth_immutable": false, + "auth_clawback_enabled": false + }, + "balances": [ + { + "balance": "1252.7872975", + "limit": "922337203685.4775807", + "is_authorized": true, + "asset_type": "credit_alphanum4", + "asset_code": "USDC", + "asset_issuer": "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5" + }, + { + "balance": "9009.2998203", + "asset_type": "native" + } + ], + "signers": [ + { + "weight": 1, + "key": "GA2242THTLFWPCW2SF3TTLDWJ3C543UUNFTFIMDJUZYXNW2EMEAXZBRH", + "type": "ed25519_public_key" + } + ] +} +``` + +The same data over RPC takes two keys. The first key is the account, the second is the USDC trustline. See [Building ledger keys](./rpc/api-reference/methods/getLedgerEntries.mdx#building-ledger-keys) for how to build each one. + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "getLedgerEntries", + "params": { + "keys": [ + "AAAAAAAAAAA1rmpnmstnitqRdzmsdk7F3m6UaWZUMGmmcXbbRGEBfA==", + "AAAAAQAAAAA1rmpnmstnitqRdzmsdk7F3m6UaWZUMGmmcXbbRGEBfAAAAAFVU0RDAAAAAEI+fQXy7K+/7BkrIVo/G+lq7bjY5wJUq+NBPgIH3lay" + ], + "xdrFormat": "json" + } +} +``` + +RPC answers with one entry per key. This is the `result` object of that response, trimmed the same way: + +```json +{ + "entries": [ + { + "dataJson": { + "account": { + "balance": "90092998203", + "num_sub_entries": 1, + "flags": 0, + "thresholds": "01000000", + "signers": [] + } + }, + "lastModifiedLedgerSeq": 1397061 + }, + { + "dataJson": { + "trustline": { + "balance": "12527872975", + "limit": "9223372036854775807", + "flags": 1 + } + }, + "lastModifiedLedgerSeq": 3657583 + } + ], + "latestLedger": 4561910 +} +``` + +Both responses describe the same account. Read them side by side: + +- Horizon's `native` balance of `9009.2998203` is the account entry's `balance` of `90092998203` stroops. +- Horizon's USDC balance of `1252.7872975` is the trustline entry's `balance` of `12527872975` stroops. It is a separate entry, so it needs a separate key. +- Horizon's `limit` of `922337203685.4775807` is the trustline entry's `limit` of `9223372036854775807`, the largest value a 64-bit amount can hold. +- Horizon's `thresholds` object splits the entry's four-byte `thresholds` string. That string is `[weight of master|low|medium|high]`, so `"01000000"` means a master key weight of `1` and no other threshold set. +- Horizon's `signers` array adds the master key, which the raw account entry never lists. +- Horizon's `flags` booleans expand the entry's `flags` bitmask. The trustline's `flags` value of `1` is `AUTHORIZED_FLAG`, which Horizon reports as `is_authorized`. + +:::note + +Pass `"xdrFormat": "json"` to read an entry without an SDK, as the responses above do. Do not build an application on that JSON. The [`getLedgerEntries`] specification warns that its shape changes whenever the underlying XDR changes. Decode the default base64 XDR with one of the [SDKs] instead. + +::: + +### Amounts Are Raw Integers + +Every classic amount on the ledger is a signed 64-bit integer of stroops. Horizon divides it by ten million and returns a string with seven decimal places. RPC returns the integer itself. Divide it in your own code, and use a big-number type so you do not lose precision. See [Amount precision](../../learn/fundamentals/stellar-data-structures/assets.mdx#amount-precision). + +### A Missing Entry Is Not an Error + +Horizon answers `404` when a resource does not exist. RPC answers `200` and leaves the key out of `entries`, so a request for two keys can return one entry. Match each returned entry back to its own key rather than to the position you sent it in. + ## Endpoint Mapping Applications that use the following Horizon endpoints can typically migrate directly to the RPC using the referenced methods. @@ -41,7 +176,7 @@ Endpoints without mappings do not have a direct replacement in the RPC API. To b | [`GET /operations/{id}/effects`] | No direct RPC equivalent | Retrieve the operation by ID (as above) and then parse its associated transaction and events for effects. | [Effects](../analytics/hubble/analyst-guide/queries-for-horizon-like-data.mdx#effects) | | [`GET /fee_stats`] | [`getFeeStats`] [`simulateTransaction`] | Indexed data not recommended. | [Fee Stats](../analytics/hubble/analyst-guide/queries-for-horizon-like-data.mdx#fee-stats) | | [`GET /accounts`] | No direct RPC equivalent | Ingest all ledger history via [`getLedgers`] to build and maintain a complete list of accounts. | [Accounts](../analytics/hubble/analyst-guide/queries-for-horizon-like-data.mdx#accounts) | -| [`GET /accounts/{address}`] | [`getLedgerEntries`] | Use [`getLedgerEntries`] for a specific account address. Note: RPC will not provide trust line information associated with the account directly, as Horizon does. You will need to derive this from ledger entries. | [Accounts](../analytics/hubble/analyst-guide/queries-for-horizon-like-data.mdx#accounts) | +| [`GET /accounts/{address}`] | [`getLedgerEntries`] | Use [`getLedgerEntries`] for a specific account address. Note: RPC will not provide trust line information associated with the account directly, as Horizon does. You will need to derive this from ledger entries. See [Example: Account Balances](#example-account-balances). | [Accounts](../analytics/hubble/analyst-guide/queries-for-horizon-like-data.mdx#accounts) | | [`GET /claimable_balances`] | No direct RPC equivalent | Ingest all ledger history via [`getLedgers`] to build and maintain a complete list of claimable balances. | [Claimable Balances](../analytics/hubble/analyst-guide/queries-for-horizon-like-data.mdx#claimable-balances) | | [`GET /claimable_balances/{id}`] | [`getLedgerEntries`] | Use [`getLedgerEntries`] to retrieve a specific claimable balance by ID. | [Claimable Balances](../analytics/hubble/analyst-guide/queries-for-horizon-like-data.mdx#claimable-balances) | | [`GET /claimable_balances/{id}/transactions`] | No direct RPC equivalent | Trace transactions that interact with the specific claimable balance ID from their historical ledger data. | [Claimable Balances](../analytics/hubble/analyst-guide/queries-for-horizon-like-data.mdx#claimable-balances) | @@ -78,6 +213,7 @@ That is still narrower than Horizon's effects. Anything CAP-67 does not model, s ::: [CAP-67]: https://github.com/stellar/stellar-protocol/blob/master/core/cap-0067.md +[`AccountEntry`]: https://github.com/stellar/stellar-xdr/blob/v28.0/Stellar-ledger-entries.x#L190 [Horizon]: ./horizon/README.mdx [RPC]: ./rpc/README.mdx [Horizon's REST-like API]: ./horizon/api-reference/README.mdx From 1a4f59a8fe3156023e4dcc02dfd61c0acd4f7741 Mon Sep 17 00:00:00 2001 From: Kaan Kacar Date: Tue, 8 Sep 2026 03:07:48 +0000 Subject: [PATCH 2/6] Show the entry key in the RPC example and fix the ledger key link --- .../data/apis/migrate-from-horizon-to-rpc.mdx | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/docs/data/apis/migrate-from-horizon-to-rpc.mdx b/docs/data/apis/migrate-from-horizon-to-rpc.mdx index dfe6530e1a..6e118e5296 100644 --- a/docs/data/apis/migrate-from-horizon-to-rpc.mdx +++ b/docs/data/apis/migrate-from-horizon-to-rpc.mdx @@ -77,7 +77,7 @@ Horizon answers with one resource. The response below is trimmed to the fields t } ``` -The same data over RPC takes two keys. The first key is the account, the second is the USDC trustline. See [Building ledger keys](./rpc/api-reference/methods/getLedgerEntries.mdx#building-ledger-keys) for how to build each one. +The same data over RPC takes two keys. The first key is the account, the second is the USDC trustline. See [Building ledger keys](./rpc/api-reference/methods/getLedgerEntries.mdx#types-of-ledgerkeys) for how to build each one. ```json { @@ -94,12 +94,17 @@ The same data over RPC takes two keys. The first key is the account, the second } ``` -RPC answers with one entry per key. This is the `result` object of that response, trimmed the same way: +RPC answers with one entry per key. Each entry repeats the key it answers, in the `keyJson` field. This is the `result` object of that response, trimmed the same way: ```json { "entries": [ { + "keyJson": { + "account": { + "account_id": "GA2242THTLFWPCW2SF3TTLDWJ3C543UUNFTFIMDJUZYXNW2EMEAXZBRH" + } + }, "dataJson": { "account": { "balance": "90092998203", @@ -112,6 +117,17 @@ RPC answers with one entry per key. This is the `result` object of that response "lastModifiedLedgerSeq": 1397061 }, { + "keyJson": { + "trustline": { + "account_id": "GA2242THTLFWPCW2SF3TTLDWJ3C543UUNFTFIMDJUZYXNW2EMEAXZBRH", + "asset": { + "credit_alphanum4": { + "asset_code": "USDC", + "issuer": "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5" + } + } + } + }, "dataJson": { "trustline": { "balance": "12527872975", @@ -147,7 +163,7 @@ Every classic amount on the ledger is a signed 64-bit integer of stroops. Horizo ### A Missing Entry Is Not an Error -Horizon answers `404` when a resource does not exist. RPC answers `200` and leaves the key out of `entries`, so a request for two keys can return one entry. Match each returned entry back to its own key rather than to the position you sent it in. +Horizon answers `404` when a resource does not exist. RPC answers `200` and leaves the key out of `entries`, so a request for two keys can return one entry. Match each returned entry back to its own key with the entry's `keyJson` field, or `key` in the default base64 format. Do not match on the position you sent it in. ## Endpoint Mapping From 5e0dd14fbe2adfb4d3d41c396a88409f72807205 Mon Sep 17 00:00:00 2001 From: Kaan Kacar Date: Tue, 8 Sep 2026 03:12:57 +0000 Subject: [PATCH 3/6] Say that RPC sends stroop amounts as strings, and use trustline --- docs/data/apis/migrate-from-horizon-to-rpc.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/data/apis/migrate-from-horizon-to-rpc.mdx b/docs/data/apis/migrate-from-horizon-to-rpc.mdx index 6e118e5296..579b7cf8f0 100644 --- a/docs/data/apis/migrate-from-horizon-to-rpc.mdx +++ b/docs/data/apis/migrate-from-horizon-to-rpc.mdx @@ -21,7 +21,7 @@ The [endpoint mapping](#endpoint-mapping) below pairs each Horizon endpoint with | Concern | Horizon | RPC | | --- | --- | --- | | Shape | One aggregated resource per endpoint | One ledger entry per requested key | -| Amounts | Decimal string with seven places, such as `"1252.7872975"` | Signed 64-bit integer of stroops, such as `"12527872975"` | +| Amounts | Decimal string with seven places, such as `"1252.7872975"` | Signed 64-bit integer of stroops, sent as a string, such as `"12527872975"` | | Encoding | Parsed JSON fields | Base64 XDR, or JSON when you pass `xdrFormat` | | Flags and thresholds | Named booleans and named thresholds | A raw `uint32` bitmask and a four-byte hex string | | Entry not found | HTTP `404` | HTTP `200`, and the key is absent from `entries` | @@ -159,7 +159,7 @@ Pass `"xdrFormat": "json"` to read an entry without an SDK, as the responses abo ### Amounts Are Raw Integers -Every classic amount on the ledger is a signed 64-bit integer of stroops. Horizon divides it by ten million and returns a string with seven decimal places. RPC returns the integer itself. Divide it in your own code, and use a big-number type so you do not lose precision. See [Amount precision](../../learn/fundamentals/stellar-data-structures/assets.mdx#amount-precision). +Every classic amount on the ledger is a signed 64-bit integer of stroops. Horizon divides it by ten million and returns a string with seven decimal places. RPC returns the stroop count itself. It is a JSON string, not a JSON number, because a 64-bit integer does not fit a JSON number safely. Divide it in your own code, and use a big-number type so you do not lose precision. See [Amount precision](../../learn/fundamentals/stellar-data-structures/assets.mdx#amount-precision). ### A Missing Entry Is Not an Error @@ -192,7 +192,7 @@ Endpoints without mappings do not have a direct replacement in the RPC API. To b | [`GET /operations/{id}/effects`] | No direct RPC equivalent | Retrieve the operation by ID (as above) and then parse its associated transaction and events for effects. | [Effects](../analytics/hubble/analyst-guide/queries-for-horizon-like-data.mdx#effects) | | [`GET /fee_stats`] | [`getFeeStats`] [`simulateTransaction`] | Indexed data not recommended. | [Fee Stats](../analytics/hubble/analyst-guide/queries-for-horizon-like-data.mdx#fee-stats) | | [`GET /accounts`] | No direct RPC equivalent | Ingest all ledger history via [`getLedgers`] to build and maintain a complete list of accounts. | [Accounts](../analytics/hubble/analyst-guide/queries-for-horizon-like-data.mdx#accounts) | -| [`GET /accounts/{address}`] | [`getLedgerEntries`] | Use [`getLedgerEntries`] for a specific account address. Note: RPC will not provide trust line information associated with the account directly, as Horizon does. You will need to derive this from ledger entries. See [Example: Account Balances](#example-account-balances). | [Accounts](../analytics/hubble/analyst-guide/queries-for-horizon-like-data.mdx#accounts) | +| [`GET /accounts/{address}`] | [`getLedgerEntries`] | Use [`getLedgerEntries`] for a specific account address. Note: RPC will not provide trustline information associated with the account directly, as Horizon does. You will need to derive this from ledger entries. See [Example: Account Balances](#example-account-balances). | [Accounts](../analytics/hubble/analyst-guide/queries-for-horizon-like-data.mdx#accounts) | | [`GET /claimable_balances`] | No direct RPC equivalent | Ingest all ledger history via [`getLedgers`] to build and maintain a complete list of claimable balances. | [Claimable Balances](../analytics/hubble/analyst-guide/queries-for-horizon-like-data.mdx#claimable-balances) | | [`GET /claimable_balances/{id}`] | [`getLedgerEntries`] | Use [`getLedgerEntries`] to retrieve a specific claimable balance by ID. | [Claimable Balances](../analytics/hubble/analyst-guide/queries-for-horizon-like-data.mdx#claimable-balances) | | [`GET /claimable_balances/{id}/transactions`] | No direct RPC equivalent | Trace transactions that interact with the specific claimable balance ID from their historical ledger data. | [Claimable Balances](../analytics/hubble/analyst-guide/queries-for-horizon-like-data.mdx#claimable-balances) | From 964c565948d9d257a4ef8e7077fe7b396d635ce8 Mon Sep 17 00:00:00 2001 From: Kaan Kacar Date: Tue, 8 Sep 2026 03:19:04 +0000 Subject: [PATCH 4/6] Say that entries is empty when no requested key exists --- docs/data/apis/migrate-from-horizon-to-rpc.mdx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/data/apis/migrate-from-horizon-to-rpc.mdx b/docs/data/apis/migrate-from-horizon-to-rpc.mdx index 579b7cf8f0..43641d4464 100644 --- a/docs/data/apis/migrate-from-horizon-to-rpc.mdx +++ b/docs/data/apis/migrate-from-horizon-to-rpc.mdx @@ -24,7 +24,7 @@ The [endpoint mapping](#endpoint-mapping) below pairs each Horizon endpoint with | Amounts | Decimal string with seven places, such as `"1252.7872975"` | Signed 64-bit integer of stroops, sent as a string, such as `"12527872975"` | | Encoding | Parsed JSON fields | Base64 XDR, or JSON when you pass `xdrFormat` | | Flags and thresholds | Named booleans and named thresholds | A raw `uint32` bitmask and a four-byte hex string | -| Entry not found | HTTP `404` | HTTP `200`, and the key is absent from `entries` | +| Entry not found | HTTP `404` | HTTP `200`, and the key is absent from `entries`, which is empty when no key exists | | Collections | HAL `_links` and a `paging_token` for paging | No paging, and a limit of 200 keys per call | ### Example: Account Balances @@ -163,7 +163,9 @@ Every classic amount on the ledger is a signed 64-bit integer of stroops. Horizo ### A Missing Entry Is Not an Error -Horizon answers `404` when a resource does not exist. RPC answers `200` and leaves the key out of `entries`, so a request for two keys can return one entry. Match each returned entry back to its own key with the entry's `keyJson` field, or `key` in the default base64 format. Do not match on the position you sent it in. +Horizon answers `404` when a resource does not exist. RPC answers `200` and leaves the key out of `entries`, so a request for two keys can return one entry. If no key exists, `entries` is empty. The specification requires only `latestLedger` in the result, so read `entries` defensively. + +Match each returned entry back to its own key with the entry's `keyJson` field, or `key` in the default base64 format. Do not match on the position you sent it in. ## Endpoint Mapping From 2da35bbedd97b9837724117dba3035cff346e34a Mon Sep 17 00:00:00 2001 From: Kaan Kacar Date: Tue, 8 Sep 2026 03:23:55 +0000 Subject: [PATCH 5/6] Say RPC returns an entry for each key it finds --- docs/data/apis/migrate-from-horizon-to-rpc.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data/apis/migrate-from-horizon-to-rpc.mdx b/docs/data/apis/migrate-from-horizon-to-rpc.mdx index 43641d4464..d8cad64efa 100644 --- a/docs/data/apis/migrate-from-horizon-to-rpc.mdx +++ b/docs/data/apis/migrate-from-horizon-to-rpc.mdx @@ -20,7 +20,7 @@ The [endpoint mapping](#endpoint-mapping) below pairs each Horizon endpoint with | Concern | Horizon | RPC | | --- | --- | --- | -| Shape | One aggregated resource per endpoint | One ledger entry per requested key | +| Shape | One aggregated resource per endpoint | One ledger entry for each requested key that exists | | Amounts | Decimal string with seven places, such as `"1252.7872975"` | Signed 64-bit integer of stroops, sent as a string, such as `"12527872975"` | | Encoding | Parsed JSON fields | Base64 XDR, or JSON when you pass `xdrFormat` | | Flags and thresholds | Named booleans and named thresholds | A raw `uint32` bitmask and a four-byte hex string | @@ -94,7 +94,7 @@ The same data over RPC takes two keys. The first key is the account, the second } ``` -RPC answers with one entry per key. Each entry repeats the key it answers, in the `keyJson` field. This is the `result` object of that response, trimmed the same way: +RPC answers with one entry for each key it finds. Each entry repeats the key it answers, in the `keyJson` field. This is the `result` object of that response, trimmed the same way: ```json { From 3103cda8658c8de9a080cb7b092f56a9e2a42b83 Mon Sep 17 00:00:00 2001 From: Kaan Kacar Date: Tue, 8 Sep 2026 03:28:38 +0000 Subject: [PATCH 6/6] Note that the RPC column describes the decoded entry --- docs/data/apis/migrate-from-horizon-to-rpc.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/data/apis/migrate-from-horizon-to-rpc.mdx b/docs/data/apis/migrate-from-horizon-to-rpc.mdx index d8cad64efa..1b50dff5bb 100644 --- a/docs/data/apis/migrate-from-horizon-to-rpc.mdx +++ b/docs/data/apis/migrate-from-horizon-to-rpc.mdx @@ -27,6 +27,8 @@ The [endpoint mapping](#endpoint-mapping) below pairs each Horizon endpoint with | Entry not found | HTTP `404` | HTTP `200`, and the key is absent from `entries`, which is empty when no key exists | | Collections | HAL `_links` and a `paging_token` for paging | No paging, and a limit of 200 keys per call | +The RPC column describes the decoded ledger entry. A default response holds those fields inside the base64 XDR, so you see them only after you decode it, or after you ask for the JSON view with `xdrFormat`. + ### Example: Account Balances Horizon's [`GET /accounts/{address}`] response is an aggregation. It joins the account entry with the account's trustline entries. The [`AccountEntry`] structure holds no trustlines of its own. It holds only a count of the account's sub-entries. So one Horizon call becomes one [`getLedgerEntries`] call with an account key plus one trustline key per asset, and you must already know each asset.