Every XE node exposes the same JSON HTTP API. By default it listens on
http://127.0.0.1:8080 (--api is on by default; change the port and bind
address with --api-port and --api-bind). The playground below targets the
live London testnet node at https://ldn.core.test.network through a local docs
proxy, so requests work from this site without browser CORS issues.
Conventions
- Amounts are micro-units. 1 XE = 1 XUSD = 1,000,000 micro-units, and every
amount, balance, and weight in the API is an integer micro-unit count. A
balance of
100000000is 100 XUSD. - The API is self-describing.
GET /returns a manifest of every route with its method and a one-line description — the same list the node uses to register its handlers. - Authentication is per-endpoint. Most reads are open. Four endpoints are
operator-only, gated behind an admin bearer token
(
Authorization: Bearer <XE_API_ADMIN_TOKEN>;403when no token is configured,401when it is wrong):POST /lease/request,POST /lease/{hash}/renew, the parameterlessGET /chat/eventsfirehose and the parameterless node-wideGET /chat/contactslist. Reading a specific account's chat (/chat/messages,/chat/contacts?account=,/chat/events?account=) requires an ownership proof: fetch a challenge fromGET /chat/auth/challenge(valid 120 s, single-use, bound to the issuing node), signsha256("xe/chat-read-auth/v1\0" || challenge)with the account key, and passaccount,pub_key,challengeandsigas query parameters.pub_keyis required — an address issha256("xe/account/v1" || pubkey)and so cannot verify its own signature. - Retryable errors. A rejected block returns
{"error":"block rejected: …","retryable":<bool>}:400withretryable: falsefor a deterministically invalid block (bad signature or PoW, structural or value validation),503withretryable: truefor a transient failure (a dependency this node has not synced yet, a frontier race). Branch on the flag, not the prose. - Rate limits on the node are per-IP with three classes: reads (GET) at
200 requests/second (burst 1,000), writes (POST) at 10 requests/second
(burst 50), and probes (
/health,/ready) at 20 requests/second (burst 100) in a bucket of their own. Exceeding a bucket returns429. Throughhttps://test.network/apievery response also carriesRateLimit-PolicyandRateLimitheaders (plus the olderRateLimit-Limit/-Remaining/-Reset) so a client can throttle itself, and a429addsRetry-After— see rate limits. Bodies are capped at 1 MiB; lists take?offset=N&limit=M(default 100, max 1,000). - Versioning. The proxied API is versioned in the URL path: pin
https://test.network/api/v1;https://test.network/apiis an alias of the current major and every response carriesX-API-Version. Changes within a major are additive only, and deprecations are announced withDeprecationandSunsetheaders at least 90 days ahead — see versioning. The machine-readable contract is the OpenAPI 3.1 document.
LIVE TESTNET API
Executable endpoint directory
https://ldn.core.test.networkGET
List all accounts
Returns accounts known by the node with balances and frontier hashes. Balances are micro-units (1 XE = 1 XUSD = 1,000,000 micro-units).
Select an endpoint and run it against the live testnet.
cURL
curl 'https://ldn.core.test.network/accounts'
Notes
- Most
GETendpoints run immediately. Chat reads need the ownership proof described above, and lease-scoped lookups need a real lease hash — the samples come fromGET /leaseson the live network and go stale when it is wiped, at which point those entries return 404 until they are refreshed. POSTendpoints include editable starter JSON showing the exact shape the node decodes. Block submissions must be fully formed: valid signature, block hash, post-blockbalance, and proof-of-work nonce. The node does not sign or complete blocks for you.- Entries marked as reference-only (
/lease/request, the TCP tunnel) cannot run from the browser; the panel explains what each needs instead. - Sample account and block identifiers are refreshed from the live network
with
node scripts/refresh-playground-samples.mjs— rerun it after a testnet wipe.