跳到主要内容

XRP Ledger (Ripple)

XRP Ledger reads for wallets and apps, without running or trusting a single node. Every read is sent to three independent XRPL providers. It is answered only when all three return the same answer for the same validated ledger. If one provider is down, lagging, rate limiting or says something different, you get an error, never one provider's word.

Endpoint​

POST https://mainnet.subfrost.io/v4/YOUR_API_KEY/ripple

The API key is a path segment, or an X-Subfrost-Api-Key header, which takes precedence (see Authentication). The body is rippled's JSON-RPC shape, so any XRPL client that speaks rippled's HTTP API works unchanged:

{ "method": "account_info", "params": [ { "account": "rD86YcZ35wxoTJEhrtmascwW932h2Qa7yE" } ] }

Answers are rippled-shaped too: {"result": {…, "status": "success"}}.

How an answer is agreed​

  1. The edge reads every provider's newest validated ledger and pins your read to the oldest of them, which every provider has.
  2. Your request goes to all three providers at that ledger.
  3. If every answer is identical, it is returned. The only fields removed are the server-specific ones (echoed request, page limit/marker, warnings).

The providers are xrplcluster.com (XRPL Labs, rippled), s2.ripple.com (Ripple, Clio) and honeycluster.io (Clio): three operators, three networks.

Every agreed answer carries headers you can check:

headervalue
X-Subfrost-Quorum3/3 (providers that agreed / providers asked)
X-Subfrost-Quorum-Providersxrplcluster.com,s2.ripple.com,honeycluster.io
X-Subfrost-Ledger-Indexthe validated ledger the answer is from
X-Subfrost-Ledger-Hashits hash, when the answer names one

They are exposed to browsers (Access-Control-Expose-Headers).

Only validated ledgers​

Omit ledger_index, or send "validated", to read the newest ledger every provider has validated. A number works if it is not newer than that. "current" and "closed" are refused (notValidated): those ledgers differ from server to server, so there is nothing to agree on. ledger_hash is refused too; send the index instead.

Methods​

methodnotes
account_infobalance, Sequence, OwnerCount, Flags, account_flags. An unfunded or deleted account is actNotFound at the pinned ledger, naming the account and the ledger (see Missing accounts and objects). queue is not served.
account_linesthe complete list of trust lines in one answer (up to 2,000). Use peer to narrow it. marker is not accepted.
account_objectsthe complete list (up to 2,000); type and deletion_blockers_only work.
account_txlimit 1–200 (default 50), forward, ledger_index_min / ledger_index_max (-1 = all; the max is capped at the pinned ledger), api_version 1 or 2. Page with the marker the answer returns (this endpoint's own marker; pass it back unchanged). binary is not served.
txby hash. Returned only once every provider has it in a validated ledger. Otherwise you get quorumPending: retry after a few seconds. Unknown everywhere: txnNotFound.
ledgerheader, optionally transactions / expand.
ledger_entryany selector, e.g. {"deposit_preauth": {"owner": "r…", "authorized": "r…"}}. A missing object is entryNotFound, naming what was asked and the ledger (see below).
server_infoinfo.validated_ledger (seq, hash, base_fee_xrp, reserve_base_xrp, reserve_inc_xrp) from the agreed ledger and its fee settings, plus load_factor, the highest any provider reports. Nothing else from a single server is included.
submita signed tx_blob, sent to all three providers; one acceptance is enough. The answer lists each provider's verdict in submitted_to. Sign-and-submit (secret, seed, tx_json) is refused: never send a secret to any API.
pingliveness.

Missing accounts and objects​

"This account (or object) does not exist" is an answer like any other: all three providers must say it at the same validated ledger. So that you can tie it to what you asked, an agreed actNotFound (account_info, account_lines, account_objects, account_tx) or entryNotFound (ledger_entry) carries:

fieldvalue
accountthe address you asked about, taken from your request after validation (never from a provider). For ledger_entry, present with an account_root selector.
indexledger_entry only: your index (uppercase), or the AccountRoot index of your account_root
ledger_indexthe validated ledger it was read at (for account_tx, ledger_index_max)
ledger_hashthat ledger's hash, agreed by all three providers
validatedtrue
requestyour request echoed, as rippled does: your params plus command
{ "method": "account_info", "params": [ { "account": "rf1Z17eJnPCaSuxnCCjFQbj5DD1uffxN6z" } ] }
{
"result": {
"status": "error",
"error": "actNotFound",
"error_code": 19,
"error_message": "Account not found.",
"account": "rf1Z17eJnPCaSuxnCCjFQbj5DD1uffxN6z",
"ledger_index": 107663945,
"ledger_hash": "F64C2129C4BB407692236C51B8D60D56D69577113596A4A75BE94E0E6AD506E4",
"validated": true,
"request": { "command": "account_info", "account": "rf1Z17eJnPCaSuxnCCjFQbj5DD1uffxN6z" }
}
}

The X-Subfrost-Quorum: 3/3, X-Subfrost-Ledger-Index and X-Subfrost-Ledger-Hash headers are set on these answers too. Successful answers are unchanged.

Addresses are checked first​

Every address in a request (account, peer, account_root, and account, owner, authorized, destination, accounts inside a ledger_entry selector) must be a classic r… address with a valid checksum. Anything else, including public keys, seeds and X-addresses, is refused with actMalformed (HTTP 400) before any provider is asked.

Common checks​

Deposit status of an address D:

{ "method": "account_tx", "params": [ { "account": "D…", "api_version": 2, "limit": 20 } ] }

lists payments into D (with meta.delivered_amount) and, once it has been swept, the AccountDelete. After the sweep, account_info on D answers actNotFound.

Can a destination receive a payment? Read account_info on it and check account_data.Flags:

flagbitmeaning
lsfRequireDestTag0x00020000a destination tag is required
lsfDepositAuth0x01000000only preauthorized senders: check ledger_entry deposit_preauth
lsfDisallowXRP0x00080000the owner asks not to be sent XRP

A destination that answers actNotFound exists only once it is sent at least the base reserve (server_info → reserve_base_xrp). Trust lines, for issued currencies, are in account_lines.

Errors​

{ "result": { "status": "error", "error": "quorumDisagree", "error_message": "…", "request": { … } } }
errorHTTPwhat to do
quorumMissing503a provider did not answer; retry (Retry-After)
quorumRateLimited503a provider is rate limiting; retry
quorumPending503not yet validated everywhere (tx); retry in a few seconds
quorumDisagree500providers disagree; nothing is returned
notValidated400current / closed asked for
lgrNotFound400ledger newer than the newest validated by every provider, or older than full history
actMalformed400an address in the request is not a valid classic r… address
invalidParams, tooManyEntries, unknownCmd400the request itself

rippled's own answers (txnNotFound, and a submit's engine_result) come back as rippled returns them. actNotFound and entryNotFound come back with the account and ledger added, as described above.