API families
Analytics, immutable history downloads, Horizon and Stellar RPC serve different jobs and data boundaries.
Check service readiness and interpret measured counts
Use the health endpoint for combined service readiness and the metrics endpoint for measured publication and archive counts. These observations do not establish complete chain history or replace a query’s coverage checks.
curl --fail-with-body --connect-timeout 5 --max-time 10 \
--write-out 'HTTP %{http_code}\n' \
'https://api.stellaratlas.io/v1/public-goods/health' --output health.jsoncurl --fail-with-body --connect-timeout 5 --max-time 10 \
--write-out 'HTTP %{http_code}\n' \
'https://api.stellaratlas.io/v1/public-goods/metrics' --output metrics.jsonEach command limits connection time to five seconds and total time to ten seconds, without automatic retries. It prints the HTTP status separately and saves the JSON body. On HTTP 503, curl reports failure but still saves the response body: inspect it to learn which checks or sources failed. A local timeout can leave an incomplete file; it does not prove data absence or that server work stopped.
Health returns HTTP 200 with status: ready only when its ClickHouse, publication and archive checks pass. HTTP 503 with status: not_ready can report stale, empty, incomplete or unavailable evidence. Read each check’s status and observation time. This combines service signals; it does not say every dataset window or archive history is complete.
Metrics returns HTTP 200 when both metric sources were read, even when health is not ready. A required metric source failure returns HTTP 503 with unavailable values left null. Keep null distinct from zero and inspect observation times; an HTTP 200 metrics response is not a readiness certificate. These observations are not intended to be cached as a permanent success.
These synthetic examples illustrate the same stale publication and incomplete archive inventory. They are not a live status report. The health example is HTTP 503:
{
"generatedAt": "2026-01-02T00:00:00.000Z",
"status": "not_ready",
"checks": {
"clickhouse": {
"status": "ready",
"observedAt": "2026-01-02T00:00:00.000Z"
},
"publication": {
"status": "stale",
"observedAt": "2026-01-02T00:00:00.000Z",
"latestCompletedAt": "2025-12-31T23:00:00.000Z"
},
"archive": {
"status": "incomplete",
"observedAt": "2026-01-02T00:00:00.000Z",
"knownRoots": 300,
"checkedRoots": null,
"checkedRootWindowHours": 24,
"complete": false
}
}
}The metrics example is HTTP 200, with unknown counts retained as null:
{
"generatedAt": "2026-01-02T00:00:00.000Z",
"publication": {
"observedAt": "2026-01-02T00:00:00.000Z",
"configuredDatasets": 2,
"publishedDatasets": 1,
"completedBatches": "2",
"failedBatches": "0",
"startedBatches": "0",
"records": "9007199254740993",
"latestCompletedAt": "2025-12-31T23:00:00.000Z",
"maximumLedger": "100"
},
"archives": {
"observedAt": "2026-01-02T00:00:00.000Z",
"knownRoots": 300,
"checkedRoots": null,
"checkedRootWindowHours": 24,
"rootObjectsVerified": null,
"rootObjectsFailed": null,
"oldestEvidenceAt": null,
"newestEvidenceAt": null,
"complete": false
}
}| Field | Meaning and limit |
|---|---|
publication.records | Projected rows recorded by completed ingestion manifests, not unique transactions, unique ledgers or physical database rows. |
publication.publishedDatasets | Configured datasets with nonzero measured active rows, not datasets with complete historical coverage. |
archives.checkedRoots | Sources observed within the reported window, including failed observations, not fully verified archive histories. |
archives.rootObjectsVerified | Verified root-state objects, not verification of every checkpoint or all historical data. |
archives.complete | Whether the source inventory used for these counts is complete and untruncated, not whether chain history is complete. |
Keep decimal strings such as records, batch counts and maximumLedger as strings; JavaScript Number can round large values. The example’s 9007199254740993 is illustrative and exact. Converting to Number or treating null as zero changes the evidence.
Parsed analytics: REST and GraphQL
/v1/analytics and /graphql query parsed ClickHouse data with completed-batch visibility and explicit coverage. Use them for historical analysis, entity relationships and aggregation.
StellarAtlas uses Stellar ETL/Hubble table schemas, but the catalog does not promise full Hubble feature parity or complete chain history. Follow the published coverage and each response’s semantics.
Recognize a saved API response
Some public REST reads can return saved data when the live service is unavailable. Check the HTTP status and headers before parsing the body. This balance request prints both:
curl --include --fail-with-body --connect-timeout 5 --max-time 30 'https://api.stellaratlas.io/v1/analytics/accounts/GCX7LOMYJM54CXJPNTDZPMFSTQTQJTR5XR4DKZXLSWJG3R4B7GOADWXZ/balances?limit=25'X-StellarAtlas-Fallback: snapshot identifies the saved response path, including errors. If present, X-StellarAtlas-Snapshot gives the capture time. Compare it with the current time to estimate the age of the capture. Treat the age as unknown if the timestamp is missing, invalid or in the future. Capture time does not tell you how recent the underlying ledger observations are. A missing fallback header does not establish freshness.
Saved balance responses can include capturedAt, semantics and watermark.snapshotPinned: true. Check coverage and keep saved data separate from live results. A saved response does not provide current ledger state, complete history or live SCP observations.
A saved 503 can mean the requested data or query was not captured; it is unavailable, not an empty result. A saved 404 means the record was not found in the saved data. It does not establish absence on the current chain. A 409 for a cursor from a different capture means you should restart from the first page. Keep cursors with their filters and data source; do not reuse them across live and saved responses or across captures.
GraphQL POSTs, writes, requests with an Authorization header, WebSocket upgrades and live server-sent event streams still require the live service. A saved page or a successful saved REST read does not mean these operations are available.
Immutable history downloads
For offline analysis, start with the history catalogue for published coverage, then list batches for one dataset. These requests read metadata without downloading artifacts.
curl --fail-with-body --connect-timeout 5 --max-time 10 'https://api.stellaratlas.io/v1/history-data/catalog'
curl --fail-with-body --connect-timeout 5 --max-time 10 'https://api.stellaratlas.io/v1/history-data/batches?dataset=ledgers&limit=1'Use the returned nextBeforeLedger as beforeLedger with the same dataset and limit to continue; stop when it is null. Check each output’s byteCount, mediaType and schemaVersion before choosing its returned downloadPath. The HEAD endpoint inspects headers without an artifact body.
When you download an artifact, compare the complete file’s SHA-256 with sha256 or X-Content-SHA256. A byte range cannot validate that complete-file digest. Use the embedded Parquet schema with its version; published batch coverage does not establish complete chain history or an arbitrary-ledger state witness.
Inspect one complete local file
Use Python 3.11+ with a maintained PyArrow release already available; the recipe was qualified with PyArrow 26.0.0. Versions below 14.0.1 are rejected. If the reader is missing, follow the PyArrow prerequisite instructions deliberately before rerunning. The command installs nothing.
From a repository checkout, run the inspection script with an already-downloaded complete Parquet file and a saved JSON object containing only its selected output descriptor, including byteCount, sha256, recordCount, mediaType, dataset and schemaVersion. Keep the local file unchanged throughout inspection.
python3 scripts/inspect_history_parquet.py \
/path/to/complete-ledgers.parquet /path/to/selected-output.json --preview 5The script streams the complete SHA-256 and exact byte count before opening the footer. It compares the footer row count with the descriptor and reports physical/converted/logical types, Arrow schema and footer metadata. The descriptor’s schema-version label is separate from embedded metadata, which may be empty. Readers can normalize legacy converted annotations; inspect the logical types and Arrow schema as well.
The ledger preview displays at most 5 rows (hard cap 10), selecting unsigned ledger_sequence and signed total_coins/ fee_pool as exact decimal strings, including values above 2^53. No float, dataframe or JavaScript Number conversion is used. Reader page/column decoding can exceed the displayed rows; this is not a byte-I/O cap. Use --preview 0 for metadata-only inspection of another dataset, then choose its columns deliberately.
Horizon-compatible reads
GET https://api.stellaratlas.io/horizon/ is a read-only proxy to the configured Horizon service. Follow its HAL links for accounts and other Horizon resources. State-changing methods are rejected.
Horizon uses its own upstream state and pagination. It is not an alternate URL for the ClickHouse analytics warehouse; its freshness and history limits can differ.
Stellar RPC
POST https://api.stellaratlas.io/rpc forwards JSON-RPC to the configured Stellar RPC service. Check the JSON-RPC result or error, not just HTTP 200.
curl --fail-with-body 'https://api.stellaratlas.io/rpc' \
-H 'Content-Type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"getHealth"}'RPC availability and retained ledger history are independent of analytics coverage. A catching-up RPC service can return a health error even while parsed analytics reads work.
Network monitoring and archive evidence
The node, organization and archive views describe observed network state and source-file evidence. Their archive scan/proof totals do not measure the size or completeness of the analytics warehouse.
See the node archive-evidence reference for source findings, the endpoint directory for other APIs, and status for current service telemetry.