
Time travel on our public Algorand API, powered by dt-algorand
Our public Algorand API answers questions about the past. Add ?round= to a read and you get the ledger as it stood at the end of that round. It works on MainNet and TestNet, with no key. It is free for now: from 1 January 2027, MainNet history needs a paid plan (Boost, Unlimited or Enterprise), and TestNet stays free.
The answers come from nodes running dt-algorand, D13’s community fork of go-algorand. Its README describes “a node that keeps the value of every account, asset, app and box at every round since genesis, and serves the REST API and transaction simulation at any past round”.
What you can do with it
Each section below has commands you can paste. You need curl and jq, and xxd for the sixteen rounds. There is no key, and nothing here signs or sends a transaction. Every output is real, from 2026-11-06. Paste the blocks in order into one shell: later blocks reuse $API and $CALL.
Read the chain at any past round
Ask for an asset, account, app or box as it stood at a given round. USDC was created at round 8,874,561, on 2020-09-04 at 20:49 UTC. One round earlier, the asset does not exist.
API=https://mainnet-api.4160.nodely.dev
curl -s -w 'HTTP %{http_code}\n' "$API/v2/assets/31566704?round=8874560"# {"message":"asset does not exist"}# HTTP 404
curl -s -w 'HTTP %{http_code}\n' "$API/v2/assets/31566704?round=8874561"# {"index":31566704,"params":{"creator":"2UEQTE5QDNXPI7M3TU44G6SYKLFWLPQO7EBZM7K7MHMQQMFI4QJPLHQFHM","decimals":6,"default-frozen":false,"freeze":"3ERES6JFBIJ7ZPNVQJNH2LETCBQWUPGTO4ROA6VFUR25WFSYKGX3WBO5GE","manager":"37XL3M57AXBUJARWMT5R7M35OERXMH3Q22JMMEFLBYNDXXADGFN625HAL4","name":"USDC","name-b64":"VVNEQw==","reserve":"2UEQTE5QDNXPI7M3TU44G6SYKLFWLPQO7EBZM7K7MHMQQMFI4QJPLHQFHM","total":18446744073709551615,"unit-name":"USDC","unit-name-b64":"VVNEQw==","url":"https://www.centre.io/usdc","url-b64":"aHR0cHM6Ly93d3cuY2VudHJlLmlvL3VzZGM="}}# HTTP 200
curl -s "$API/v2/assets/31566704/versions"# {"round":66706337,"versions":[{"deleted":false,"round":8874561,"timestamp":1599252577}]}In /versions, the outer round is the latest round when you ask. A stock node ignores round and answers as of the latest round, so dt-algorand marks its answers:
curl -s -D - -o /dev/null "$API/v2/assets/31566704?round=8874561" | grep -i x-algod-tt-round# x-algod-tt-round: 8874561Dry-run a transaction in the past
POST /v2/transactions/simulate takes a round. Nothing is signed, sent or committed. For example, you can pay 1,000 ALGO into the Tinyman v2 ALGO/USDC pool at round 40,000,000 and call its swap, from a stand-in account. The answer is 134.710140 USDC out, run on 2026-11-06.
A smaller example you can paste: whether the fee sink could opt in to USDC at the same two rounds, with no signature.
for R in 8874560 8874561; do curl -s "$API/v2/transactions/simulate" -H 'Content-Type: application/json' -d '{ "round": '$R', "allow-empty-signatures": true, "txn-groups": [{"txns": [{"txn": { "type": "axfer", "xaid": 31566704, "fee": 1000, "fv": 8874000, "lv": 8874999, "snd": "Y76M3MSY6DKBRHBL7C3NNDXGS5IIMQVQVUAB6MP4XEMMGVF2QWNPL226CA", "arcv": "Y76M3MSY6DKBRHBL7C3NNDXGS5IIMQVQVUAB6MP4XEMMGVF2QWNPL226CA", "gen": "mainnet-v1.0", "gh": "wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=" }}]}] }' | jq -c '{round: .["last-round"], failure: .["txn-groups"][0]["failure-message"]}'done# {"round":8874560,"failure":"transaction 45TZNH7OSHMFCSASPJ5VATZLO5RBAKVKO6QUXQHF6UCTJHYXKCUQ: asset 31566704 does not exist or has been deleted"}# {"round":8874561,"failure":null}Run one query across many rounds
POST /v2/query runs one read-only program at many rounds in a single request. Sixteen is today’s limit for one request, as GET /v2/capabilities reports. This program works out what 1,000 ALGO would fetch at the same pool, every 2,500,000 rounds from 28.5 M to 66 M. Each figure is computed from the pool’s state at that round: no trade took place, and it is not a forecast.
The output is in microunits, with lines cut here for length.
CALL='{"accounts":["2PIFZW53RHCSFSYMCFUBW4XOCXOMB7XOYQSQ6KGT3KVGJTL4HM6COZRNMM"],"foreign-apps":[1002541853]}'SWAPOUT=DDYcAYGdpobeA4AQYXNzZXRfMl9yZXNlcnZlc2NINQA2HAGBnaaG3gOAEGFzc2V0XzFfcmVzZXJ2ZXNjSDUBNhwBgZ2mht4DgA90b3RhbF9mZWVfc2hhcmVjSDUCgYCU69wDNAILgY9OCIGQTgo1A4GAlOvcAzQDCTUENAQ0AR00ADQECJcWsIEBQw==ROUNDS=28500000,31000000,33500000,36000000,38500000,41000000,43500000,46000000,48500000,51000000,53500000,56000000,58500000,61000000,63500000,66000000
curl -s "$API/v2/query" -H 'Content-Type: application/json' \ -d '{"program":"'$SWAPOUT'","calls":['$CALL'],"rounds":['$ROUNDS']}' \ | jq -r '.rounds[] | "\(.round) \(.calls[0].logs[0])"' \ | while read R V; do echo "$R $(( 0x$(echo $V | base64 -d | xxd -p) ))"; done# 28500000 197796800# 31000000 106770062# ...# 63500000 81627916# 66000000 107496929We timed seven runs of each on 2026-11-06, from our workstation: the read at round 8,874,561 took 0.15 to 0.22 s, the sixteen-round query 0.15 to 0.20 s.
Run new code against old state
POST /v2/query can also run an old round under later rules, “as if an upgrade to it had taken effect right after that round”. At round 27,000,000 a 66-byte AVM 12 program is refused under "protocol": "round", because that round only supports version 8. Under "protocol": "latest" it runs and logs the pool’s two reserves. The answer also lists what changed: 24 consensus parameters, EnablePQSchemeFalcon1024 among them.
The two logs below are big-endian integers in microunits: 5,069,191.410026 ALGO and 1,279,872.455062 USDC.
RESERVES=DDYcAYGdpobeA4AQYXNzZXRfMl9yZXNlcnZlc2NIFrA2HAGBnaaG3gOAEGFzc2V0XzFfcmVzZXJ2ZXNjSBawgQFD
for P in round latest; do curl -s "$API/v2/query" -H 'Content-Type: application/json' \ -d '{"program":"'$RESERVES'","calls":['$CALL'],"rounds":[27000000],"protocol":"'$P'"}' \ | jq -c '.rounds[0].calls[0]'done# {"cost":0,"error":"check failed on ApprovalProgram: program version 12 greater than protocol supported version 8","logs":[]}# {"cost":16,"logs":["AAAEnENacWo=","AAABKf5X0ZY="]}What to know before you rely on it
dt-algorand is a community fork, not an official Algorand release. In the README’s words: “It changes no consensus rule, but it is not an official Algorand release: the node answers questions a standard node cannot, and some historical answers are approximations”.
- Approximations. One of the limitations in the time travel README: “Simulating at an old round detects duplicate txids and leases only against transactions still in the txtail (about the last 1,000 rounds), and knocks offline only the absent or expired accounts the simulated transactions touch.”
- No future. A round not written yet is refused. The read answers 400 and simulate 500. The README says: “Block headers after R can’t be read, as on chain, where block R+1 isn’t there yet”.
- Removed options. dt-algorand v5.0.5-dt5, live on our API on 2026-11-06 at 08:11 UTC (09:11 CET), removed simulate’s
rounds,rewrite-validity-windowandprotocol. They now answer 400 and point toPOST /v2/query. Simulate at a singleroundstill works. - Not for validators. The repo’s main README says “the fork is not audited for running validators”, so on mainnet, testnet and betanet the node refuses participation keys unless its config says otherwise.
- Not the Analytics DB. Our pricing page lists “Time travel to any block height” under Analytics DB. That is a separate product.
Who built it
The fork is D13’s, and the credit is theirs. You may know D13 from the explorers Algo.Surf and Flow. On mainnet the history takes about 70 GB, and a node that keeps it can prune about 3.5 TB of old block bodies and certificates. The code is open source and anyone can run it. We run it for you on our public API.
