Agent HTTP quickstart
Give an agent a bounded Starkscan HTTP contract without making it guess base paths, auth, or route scope.
Give an agent a bounded Starkscan HTTP contract without making it guess base paths, auth, or route scope.
Use this page when you are giving an agent direct Starkscan HTTP access instead of MCP or the CLI.
This page is intentionally narrower than the full API guide. It covers a bounded route set, one canonical base-path shape, and the minimum issue-report contract. Agents and SDK generators should read the host-local OpenAPI file at /starkscan-openapi.yaml before guessing query params or enums.
Use one base-path pattern only:
export STARKSCAN_BASE_URL="https://<your-starkscan-host>/api"
export STARKSCAN_API_KEY="mzk_live_your_key_here"
export STARKSCAN_CHAIN="SN_MAIN"
Hosted requests then always look like:
$STARKSCAN_BASE_URL/v1/$STARKSCAN_CHAIN/...
Do not paste full API keys into agent chats, tickets, screenshots, PR comments, or shared prompts. Store the key in an environment variable or secrets manager. Rotate immediately if the full value appears in chat or logs.
Use one Starkscan API key across REST, SDK, CLI, and hosted MCP. Keep the label attached to the surface so agents do not treat an alpha package as a certified protocol route.
| Surface | Public label | Agent guidance |
|---|---|---|
| REST core API | certified | Start here for direct HTTP. The certified launch set is status, block detail, timestamp-to-block, transaction detail, token total supply, and token balance-of. |
| TypeScript SDK | alpha | Use @starkscan/sdk@alpha when application code needs typed responses over the same REST contract. |
| Agent CLI | alpha | Use @starkscan/cli@alpha for shell workflows, JSON output, and local exports. |
| Hosted MCP | beta hosted / alpha launcher | Use /api/mcp for hosted HTTP MCP. Use @starkscan/mcp@alpha as the launcher; 18 tools are listed: bootstrap plus 17 route tools. |
| Starkscan RPC | provider pilot, not migration-ready | Do not replace an existing Starknet RPC provider with Starkscan yet. The route exists for gated partner/operator proof, but customer use waits for a dedicated mainnet RPC upstream and provider-readiness attestation with starknet_specVersion >= 0.10.2. |
For a repo checkout, run the smoke before handing a key to an agent or after a preview deploy:
STARKSCAN_BASE_URL="https://<host>/api" \
STARKSCAN_API_KEY="$STARKSCAN_API_KEY" \
rust-exp/scripts/agent-api-conformance-smoke.sh
The script never prints the full key. It verifies host auth, JSON error shape, request-id mirroring, status, address transactions, holdings completeness fields, token metadata fields, and the published OpenAPI error/header contract. If STARKSCAN_API_KEY is unset, it still checks invalid-key behavior and OpenAPI.
If both new STARKSCAN_* env vars and hidden legacy aliases are present, they must match exactly; the smoke fails before making network calls when they differ.
Do not use this surface as a customer migration target yet. Starkscan JSON-RPC is a gated provider pilot until a dedicated mainnet RPC upstream passes the provider-readiness gate and records attested evidence. Keep existing Alchemy, Infura, Juno, Pathfinder, or other provider paths in production until that proof exists.
Use the shape below only for partner/operator readiness testing.
export STARKSCAN_RPC_URL="https://<host>/api/v1/SN_MAIN/rpc"
export STARKSCAN_API_KEY="mzk_live_your_key_here"
Header-auth request:
curl "$STARKSCAN_RPC_URL" \
-H "Content-Type: application/json" \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
--data '{"jsonrpc":"2.0","id":1,"method":"starknet_blockNumber","params":[]}'
starknet.js clients that can attach headers should use the same URL and X-Starkscan-Api-Key.
If a client only accepts a bare nodeUrl, use the compatibility URL-token path:
export STARKSCAN_RPC_COMPAT_KEY="mzk_live_rpc_compat_key_here"
export STARKSCAN_RPC_URL="https://<host>/rpc/v0_10/SN_MAIN/$STARKSCAN_RPC_COMPAT_KEY"
Then pass the URL directly:
import { RpcProvider } from "starknet";
const provider = new RpcProvider({
nodeUrl: process.env.STARKSCAN_RPC_URL,
});
Treat this full URL as a secret. Prefer header auth for servers, never paste the URL-token form into chats, tickets, screenshots, PR comments, or source code, and rotate the key if the full URL appears in logs. Use a dedicated RPC compatibility key for this URL. In the current closed beta, that key needs the same partner/batch RPC access as header-auth RPC because simulation and fee methods are part of phase one; do not reuse a primary account or admin key in a URL.
Phase-one methods are read and simulation oriented:
| Class | Methods |
|---|---|
rpc_read_light | starknet_chainId, starknet_specVersion, starknet_blockNumber, starknet_blockHashAndNumber, starknet_syncing |
rpc_read_state | starknet_call, starknet_getStorageAt, starknet_getClass, starknet_getClassHashAt, starknet_getClassAt, starknet_getNonce |
rpc_read_history | starknet_getBlockWithTxHashes, starknet_getBlockWithTxs, starknet_getBlockWithReceipts, starknet_getBlockTransactionCount, starknet_getTransactionByBlockIdAndIndex, starknet_getTransactionByHash, starknet_getTransactionReceipt, starknet_getTransactionStatus, starknet_getStateUpdate, starknet_getEvents |
rpc_simulation | starknet_simulateTransactions, starknet_estimateFee, starknet_estimateMessageFee |
Limits that agents should treat as contract:
starknet_getEvents must use bounded numeric from_block and to_block, chunk_size <= 1000, and a block span of at most 10,000.rpc_write, rpc_trace, or rpc_ws.id, result, and upstream error envelopes are preserved. Starkscan metadata stays in headers or error.data.After provider-readiness is green, run this smoke before giving an agent the RPC URL:
STARKSCAN_RPC_URL="https://<host>/api/v1/SN_MAIN/rpc" \
STARKSCAN_API_KEY="$STARKSCAN_API_KEY" \
rust-exp/scripts/starkscan-rpc-provider-smoke.sh
For the nodeUrl-compatible path, omit the header variable:
STARKSCAN_RPC_COMPAT_KEY="mzk_live_rpc_compat_key_here" \
STARKSCAN_RPC_URL="https://<host>/rpc/v0_10/SN_MAIN/$STARKSCAN_RPC_COMPAT_KEY" \
rust-exp/scripts/starkscan-rpc-provider-smoke.sh
On /api/v1, it validates unauthenticated rejection before the authenticated calls. In both auth modes, it validates starknet_chainId, batch chainId + blockNumber, planned write rejection, and the batch-size cap without printing the full key.
For preview-main or disposable branch-validation evidence, run the broader pilot gate:
python3 rust-exp/scripts/starkscan-rpc-provider-pilot-gate.py \
--rpc-url "https://<host>/api/v1/SN_MAIN/rpc" \
--api-key "$STARKSCAN_API_KEY" \
--external-no-key-url "https://<host>/api/v1/SN_MAIN/rpc" \
--reference-rpc-url "https://starknet-rpc.publicnode.com" \
--max-reference-lag-blocks 80 \
--chain SN_MAIN \
--report-dir /tmp/starkscan-rpc-provider-gate
That gate checks read-state and read-history method matrices plus simulation/fee JSON-RPC forwarding envelopes. Simulation and fee fixtures are deliberately invalid until partner-signed fixtures exist, so upstream JSON-RPC errors are acceptable only when the gateway preserves the envelope and reports rpc_simulation.
Partner wallet/app provider-migration readiness is validated internally with a
bounded workload bench before Starkscan JSON-RPC is offered as a migration
target. That validation covers provider identity, token starknet_call reads,
wallet state reads, transaction/receipt/status/events reads, simulation/fee
envelope forwarding, the workload-required starknet_specVersion floor (at
least 0.10.2, matching the captured OpenRPC matrix), request IDs, route-class
headers, rate-limit headers, and p50/p95/p99 latency.
For partner wallet/app migrations that loop exact-token balance-of calls, the
launch bar for a bounded wallet fixture is zero unexplained 5xx responses,
zero unexpected non-2xx responses, and no missing X-Request-Id or
X-Starkscan-Route-Class headers. These bounded workloads are validated
internally before a host is declared migration-ready.
The full Voyager replacement set for a wallet/app migration is three routes:
exact-token balance-of, tx/{hash} with inline tokenTransfers, and
address/{address}/transactions cursor rows. A migration is ready only when all
three return correct shapes with request-id, route-class, and rate-limit headers
and no unexplained 5xx or unexpected non-2xx responses.
Use this table for a wallet/app Voyager migration. It is intentionally narrow and does not imply full Voyager parity across every Starkscan route.
| Voyager need | Starkscan route | Notes |
|---|---|---|
| exact token balance | GET /v1/{chain}/token/{token}/balance-of/{address}?block_tag=latest | Certified for exact-token reads. Use a concrete block number or hash instead of latest when replayable correctness matters. |
| accounting timestamp to block | GET /v1/{chain}/block-at-timestamp?timestamp={time}&closest=before | Certified helper for calendar-close workflows. Use the returned block.blockNumber as the balance-of block_tag. |
| transaction detail | GET /v1/{chain}/tx/{tx_hash} | Includes tokenTransfers; use this before adding a separate transfer lookup. |
| transactions to/from a wallet | GET /v1/{chain}/address/{address}/transactions?limit={n}&cursor={nextCursor} | Cursor-based, not page-number based. Pass nextCursor back unchanged. |
| transfer-granular wallet rows | GET /v1/{chain}/address/{address}/transfers?direction=any&limit={n}&cursor={nextCursor} | Use direction=any, in, or out relative to the wallet. any returns sender or recipient rows and dedupes self-transfers; in and out keep the explicit directional view. |
| indexed contract metadata | GET /v1/{chain}/contract/{address} | Indexed-only class/deployment/token metadata. Nullable token fields mean not identified in indexed token metadata. |
| canonical transaction UI link | https://starkscan.co/tx/{tx_hash} | Same hash as the API route. |
| canonical contract/account UI link | https://starkscan.co/contract/{address} | Use for wallets and contracts shown in support/debug output. |
Current gaps must stay explicit in client plans: getStorageAt is not part of
the certified REST launch set, and Starkscan JSON-RPC is not a migration-ready
provider until a mainnet 0.10.2+ upstream proof and provider
attestation. Route tier/package naming remains beta even though the public
SDK/CLI/MCP packages are published under the Starkscan scope. Use documented
REST routes now; keep existing JSON-RPC providers for storage, simulation, fee,
and broad provider workflows until the provider gate passes.
Start with the smallest route set that answers the task:
| Job | Route |
|---|---|
| health / host reachability | GET /v1/{chain}/status |
| latest blocks | GET /v1/{chain}/blocks |
| one block | GET /v1/{chain}/block/{block_ref} |
| block transaction list | GET /v1/{chain}/block/{number}/txs |
| tx list scan | GET /v1/{chain}/txs |
| one tx | GET /v1/{chain}/tx/{tx_hash} |
| one tx trace | GET /v1/{chain}/tx/{tx_hash}/trace |
| compact tx batch | POST /v1/{chain}/tx/previews (advanced utility — needs utility key tier) |
| wallet activity | GET /v1/{chain}/address/{address}/activity |
| wallet transactions | GET /v1/{chain}/address/{address}/transactions |
| wallet transfer rows | GET /v1/{chain}/address/{address}/transfers |
| wallet holdings | GET /v1/{chain}/address/{address}/token-holdings |
| exact token balance | GET /v1/{chain}/token/{token}/balance-of/{address} |
| token transfer history | GET /v1/{chain}/token/{token}/transfers |
| indexed contract metadata | GET /v1/{chain}/contract/{address} |
| contract read | GET /v1/{chain}/contract/{address}/read |
| contract selectors | GET /v1/{chain}/contract/{address}/entrypoints |
| identifier lookup | GET /v1/{chain}/search |
Stay on this set unless you already know you need a published advanced utility.
curl \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"$STARKSCAN_BASE_URL/v1/$STARKSCAN_CHAIN/status"
curl \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"$STARKSCAN_BASE_URL/v1/$STARKSCAN_CHAIN/tx/<tx_hash>"
curl \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"$STARKSCAN_BASE_URL/v1/$STARKSCAN_CHAIN/tx/<tx_hash>/trace"
Use block/{block_ref} when the agent starts from a block number or block hash:
curl \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"$STARKSCAN_BASE_URL/v1/$STARKSCAN_CHAIN/block/<block_number_or_hash>?tx_limit=3"
Use child routes when the task needs canonical block contents. If you start from a block hash, resolve blockNumber first with GET /v1/{chain}/block/{block_ref}. If you need the current head block, read GET /v1/{chain}/status first and then call the block route with the returned number or hash:
curl \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"$STARKSCAN_BASE_URL/v1/$STARKSCAN_CHAIN/block/<block_number>/txs?limit=25"
If you need per-transaction execution or receipt context for a block, walk the txs page and then read GET /v1/{chain}/tx/{tx_hash} or GET /v1/{chain}/tx/{tx_hash}/trace per transaction.
Use token-holdings for wallet screening:
curl \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"$STARKSCAN_BASE_URL/v1/$STARKSCAN_CHAIN/address/<owner>/token-holdings"
Use balance-of only when you already know the exact token contract:
curl \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"$STARKSCAN_BASE_URL/v1/$STARKSCAN_CHAIN/token/<token>/balance-of/<owner>?block_tag=latest"
For reproducible balance checks, pass a concrete block number or hash instead
of latest.
For accounting close, resolve the timestamp first, then pass the returned block
number into balance-of:
curl \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"$STARKSCAN_BASE_URL/v1/$STARKSCAN_CHAIN/block-at-timestamp?timestamp=2025-12-31T23:59:59Z&closest=before"
curl \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"$STARKSCAN_BASE_URL/v1/$STARKSCAN_CHAIN/token/<token>/balance-of/<owner>?block_tag=<blockNumber>"
Use closest=before for "as of this instant" semantics. The response includes
the selected block plus inclusive previous/next indexed bounds so accountants
can verify that the selected block brackets the requested timestamp.
block_ref accepts a block number or block hash.block_tag accepts latest, pending, a block number, or a block hash. Use an exact block for correctness comparisons.GET /v1/{chain}/status first and then reuse the returned block number or hash.block/{number}/txs, use a numeric block number. If you started from a block hash, resolve blockNumber first.nextCursor values back unchanged. Do not build block cursors yourself.GET /v1/{chain}/search?q=... is identifier-first search. It is not ticker or symbol search.token-holdings as complete only when exact=true, truncated=false, and completeness.reasonCode="complete".normalizedTokenAddress, symbol, name, and decimals from holdings rows when present; do not infer token identity from raw felts.GET /v1/{chain}/address/{address}/transactions when the agent wants one row per tx.GET /v1/{chain}/transfers?address={address} when a migration adapter needs transfer-granular rows from the public transfer index; do not treat UI activity copy as a public API route.GET /v1/{chain}/contract/{address}/read requires a raw Starknet selector, not a function name.GET /v1/{chain}/contract/{address}/entrypoints is broader than read; for read, prefer selectors with stateMutability=view and pass required calldata.POST /v1/{chain}/tx/previews expects {"hashes":[...]}.tx/previews is compact by default. Ask for includeLogCounts=true or includeLogs=true before you infer that logCount=0 or logs=[] means “no logs”.If the agent still needs concrete route shapes, use Route examples before guessing response semantics.
| Status | Meaning | Client action |
|---|---|---|
401 | key missing or invalid | stop and fix auth |
403 | valid key, wrong scope or route tier | stop and fix key tier |
429 | rate limit hit for the current route class | honor Retry-After and back off |
503 | temporary unavailability | retry with backoff and honor Retry-After when present |
Error responses use a JSON envelope:
{
"code": "rate_limited",
"message": "Rate limit exceeded; retry shortly",
"docSlug": "api/rate-limits",
"requestId": "mzk-..."
}
For route-class budgets and headers, see Rate limits. Agents should log X-Starkscan-Route-Class, Retry-After, and X-Request-Id when present.
When an agent reports a Starkscan issue, include:
POST routesX-Starkscan-Api-Key)X-Request-IdX-Starkscan-Route-ClassCopy-paste template:
Host:
Chain:
Route:
Query params:
Request body:
Auth mode:
Status:
X-Request-Id:
X-Starkscan-Route-Class:
Rate-limit headers:
Response snippet:
Expected:
Actual: