Astralane's GitBook docs cover a real, technically serious product (low-latency Solana transaction submission and shred streaming) and ship agent-friendly niceties like llms.txt and .md page exports — but the reference content contradicts itself on tier limits, encodings, and even which city its own servers are in, and the flagship code examples don't compile. Note: the audit request pointed at a Medium blog post; the actual documentation surface audited is https://astralane.gitbook.io/docs.
1. Free-tier bundle access contradicts itself on the same page (critical)
Problem: The fee-tier table gives the Free tier "0 TPS" for the "bundle txn method". Two screens down, the FAQ answers "How do i get access to sendBundle?" with: "Available in the Free tier. This feature is available for all users at different TPS according to the current tier." Both statements cannot be true — either free users can send bundles or they can't.
Consequence: A developer evaluating Astralane on the free tier either wastes time integrating sendBundle and gets rate-limited to zero, or skips a feature they actually have. An AI agent reading the page has no way to resolve the conflict and will assert whichever half it read last.
The fix: Reconcile the table and FAQ. If free-tier bundles are allowed at some low TPS, put that number in the table; if not, correct the FAQ.
Problem: The parameters table specifies "Array of base64-encoded serialized transactions. Maximum batch size is 25 transactions." The TypeScript example on the same page annotates the same parameter as transactions: string[], // base58-encoded serialized Solana transactions.
Consequence: Encoding is exactly the kind of detail developers copy from the nearest code comment. A base58-encoded batch will be rejected (or worse, mis-parsed) with only a generic -32600 Transaction sanitization errors to debug from. Coding agents extracting the typed signature will generate base58 pipelines wholesale.
The fix: Pick the actual wire encoding, fix the comment, and add an note to the sendBatch request example like the sendTransaction section has.
Code verification
Runtime snippet checks
Run the public examples from this audit in an isolated sandbox and attach the pass, fixed, skipped, and failed counts to the report.
Problem: The primary Rust example (a) references client and url variables that are never defined or passed in, (b) calls .send().await inside a non-asyncfn send_tx_tipped, (c) passes tx by value to bincode::serialize(tx) where &tx is required, (d) ends with a stray extra }, and (e) authenticates with .header("api_key", "xxx") — while the URI-params table directly above it says api-key is a mandatory query parameter. The declared params astralane_txn_sender is also never used.
Consequence: This is the first code a new integrator copies. It fails to compile on four separate counts, and the header-vs-query-param confusion means even a repaired version may authenticate incorrectly. Agents asked to "integrate Astralane sendTransaction" will reproduce the phantom api_key header.
The fix: Replace with a complete, compiling example (imports, async fn, defined client/url, &tx) that authenticates via the documented ?api-key= query parameter.
4. The same server IP is in Los Angeles on one page and San Francisco on three others (significant)
Problem: Endpoints and Configs lists "Los Angeles: http://la.gateway.astralane.io … IPv4 : 74.118.142.151". The QUIC page lists the identical IP 74.118.142.151:7000 as "San Francisco"; the WebSocket page labels wss://la.gateway.astralane.io:5500 "San Francisco"; the Postpacks page labels la.gateway.astralane.io/postpack-pay "San Francisco".
Consequence: For a latency product where users are told to "broadcast to the closest endpoint," region labels are load-bearing. A trader colocated in one metro can't tell which label is wrong, and ~500 km of fiber is real microseconds in this market.
The fix: Decide where the box actually is and use one region label (and one host naming convention) across all four pages.
5. sendPaladin is listed and cross-referenced but documented nowhere (significant)
Problem: The Endpoints page lists sendPaladin among six available calls, and the Tip Refunds page says "Other methods like sendBundle and sendPaladin and sendIdeal also quality for Tip rebates". No page in the docs (per the complete llms.txt index) documents sendPaladin's parameters, tip requirements, or behavior. Meanwhile sendBatch — which has a full reference on Submit Transactions — is missing from the Endpoints page's "Available calls" list entirely.
Consequence: Developers discover a method exists, then hit a dead end; the only path is Discord. The two method inventories disagree, so neither can be trusted as the canonical API surface.
The fix: Add a sendPaladin section to Submit Transactions (or remove it from the list until it's documented) and sync the "Available calls" list with the documented method set.
6. Postpacks page contradicts its own headline and ships copy-paste leftovers from the Shreds page (significant)
Problem: The page subtitle declares Postpacks "The fastest transaction feed on Solana", but the comparison table on the same page rates Postpacks' Latency: High against Preconfs' "Lower" — the opposite of the headline (the row reads as inverted). The endpoints table below is titled "ShredPay endpoints" although every URL is /postpack-pay, and the sentence "Send your POST request" links to an anchor that only exists on the Shreds page — on Postpacks it's a dead link.
Consequence: A reader comparing Postpacks vs Shreds vs Preconfs — the entire point of the page — gets a table that says the opposite of the marketing line. The ShredPay heading makes it genuinely ambiguous whether postpack tips should go to /shred-pay or /postpack-pay.
The fix: Fix the Latency row (or define what "High/Lower/Slowest" mean), rename the heading "PostpackPay endpoints", and point the anchor at the on-page pricing section.
7. Ghost QUIC submission points at a :6000 listener that has no documented host (significant)
Problem: The QUIC section requires "a dedicated ghost-enabled QUIC listener … :6000 - Ghost QUIC listener", and warns "Sending a ghost frame to a standard QUIC listener will cause the frame to be interpreted as a normal transaction and dropped." But the example connects to the placeholder "host:6000" and no page lists any ghost-enabled host or IP — the QUIC endpoints table only documents :7000 and :9000 listeners. The page's first curl example is also corrupted: the code fence begins // Some codecurl --location …, an editor placeholder fused onto the command.
Consequence: The failure mode is the worst kind: a ghost frame sent to the documented :7000 listeners is silently dropped as a malformed normal transaction — no error, no signature, just a missing trade. And the very first copy-paste example on the page won't run as written.
The fix: Publish the ghost-enabled endpoint list (or state explicitly that the address is issued per-account on whitelisting), and remove the "// Some code" artifact from the curl fence.
8. Five different API-key spellings across the product surface (significant)
Problem: Authentication is spelled differently per page: ?api-key= query param (HTTP endpoints), ?api_key= query param (WebSocket examples), an api_key: HTTP header (getHealth JSON-RPC curl and the Rust sendTransaction example), x-token: header (Postpacks and Deshreds), and authorization: Bearer (Deshreds alternative). Nothing explains which forms are interchangeable on which service.
Consequence: Hyphen-vs-underscore auth bugs are invisible until a request 401s — and on fire-and-forget transports there isn't even a 401 to see. Agents pattern-matching from one page will apply the wrong spelling to another service.
The fix: Add one Authentication page defining the canonical parameter/header per transport, and make every example conform to it.
9. Live tip_floor endpoint returns all-null percentiles; the null case is undocumented (significant)
Problem: The docs show GET /tip_floor returning populated percentiles ("landed_tips_50th_percentile": 21000 …). A live probe during this audit returned HTTP 200 with every percentile null and a stale timestamp: [{"time":"2026-09-25T09:00:40Z","landed_tips_25th_percentile":null,…}]. The page never mentions that fields can be null or that the snapshot can go stale.
Consequence: The page tells users to size tips off these buckets ("Anything below the 25th is likely too low to land"). Code written to the documented shape does arithmetic on null — a runtime crash or, worse, a zero-lamport tip on a live trading system.
The fix: Document the null/stale-snapshot case and the recommended fallback tip; fix or status-flag the feed itself.
10. The advertised "indexed data" product has no docs — its old section 404s while still ranking in search (significant)
Problem: The Welcome page sells "global RPC and indexed data", and the company's blog (the audit's entry point) pitches a full data-indexing pipeline product. But the docs' llms.txt index contains no data/indexing section, and the former Data Pipelines pages (e.g. the Websocket Token Price API at wss://ws.price.astralane.io/price-by-token) now return a GitBook "Page Not Found" body — served with HTTP 200 and no redirect — while search engines still return the full old page content.
Consequence: Developers arriving from the blog or a search result for Astralane's price API land on a dead page with no pointer to a replacement. The 200-status soft-404 means crawlers and agents keep the ghost pages ranked indefinitely.
The fix: Either restore/relocate the Data Pipelines docs with redirects, or remove "indexed data" from the Welcome pitch and serve real 404s for the retired section.
11. sendBundle section: mislabeled example, response that doesn't match the request (minor)
Problem: The "Golang" tab is captioned "Code example for sendIdeal endpoint usage in Go" while the code calls sendBundle. The request example submits three transactions; the paired response ("List of signatures for your transaction") shows exactly one signature. The revertProtection description refers to a nonexistent "sentTransaction pipeline".
Consequence: Readers can't tell whether bundles return one signature or one per transaction, and the sendIdeal caption sends people studying the wrong method.
The fix: Correct the caption and typo and show a three-signature response for the three-transaction request.
12. Changelog has three entries and stops before most of the current product surface shipped (minor)
Problem: The entire changelog is three lines (7 Aug, 12 Aug, 23 Sept 2025 — including the typo "firewal throttling"). Features documented elsewhere — WebSocket submission, sendBatch, Ghost Transactions, Postpacks, the MCP server — have no changelog entries at all.
Consequence: Users of a latency product can't audit when endpoints, tip wallets, or methods changed; the 23 Sept entry retiring an IP is exactly the kind of change they'd need to catch, and there's no evidence later changes are recorded anywhere.
The fix: Log every endpoint/method/tip-wallet change with dates, or drop the page rather than imply the record is complete.
13. Official QUIC client's install instruction only works inside the repo checkout (minor)
Problem: The README's Cargo.toml snippet is astralane-quic-client = { path = "../astralane-quic-client" } — a local relative-path dependency, with no published crates.io version or git = ... alternative shown.
Consequence: Everyone copy-pasting the documented install line gets "failed to load source for dependency" unless they happen to have cloned the repo as a sibling directory; nothing tells them to.
The fix: Publish the crate (or show the git dependency form) and update the README and docs page accordingly.
What they do well
llms.txt plus .md exports of every page and an llms-full.txt corpus — the docs are genuinely agent-fetchable.
The QUIC page documents server limits, application-level error codes, and the silent rate-limit drop behavior in clean tables — the best-specified surface in the docs.
Deshreds ships the full protobuf inline with filter semantics ("without at least one filter, the stream stays silent"), which is exactly the operational detail streaming users need.
Top 3 recommendations
Do a single-source-of-truth pass on the API surface: one method inventory, one encoding per method, one auth spelling per transport, one region label per host — and fix the fee-tier table/FAQ conflict.
Make every code example compile and run as pasted (fix the Rust sendTransaction snippet, the // Some codecurl artifact, the local-path Cargo dependency), ideally with CI that extracts and builds doc snippets.
Close the ghost surfaces: publish or gate the :6000 ghost QUIC hosts, document tip_floor's null case, and redirect or properly 404 the retired Data Pipelines pages.