Agent HTTP quickstart
Give an agent a bounded Starkscan HTTP contract without making it guess base paths, auth, or route scope.
Agent HTTP quickstart
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.
Before selecting routes, fetch the caller-specific /v1/meta/capabilities contract. Use its operation index, scopes, rate-limit classes, and OpenAPI references instead of copying a stale route list or probing errors.
Canonical setup
Use one base-path pattern only:
export STARKSCAN_API_KEY="YOUR_STARKSCAN_API_KEY"
export STARKSCAN_CHAIN="SN_MAIN"
# Optional: only set this for preview or self-hosted hosts.
# export STARKSCAN_BASE_URL="https://preview.example.com/api"Hosted requests then always look like:
${STARKSCAN_BASE_URL:-https://api.starkscan.co}/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.
Same key, explicit surface labels
Use one Starkscan API key across RPC, REST, SDK, CLI, and hosted MCP. Keep the label attached to the surface so agents do not confuse package release state, route certification, and RPC provider scope.
| 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 | stable | Use @starkscan/sdk by default or exact @starkscan/[email protected] for unattended typed integrations. |
| Agent CLI | stable | Use @starkscan/cli by default or exact @starkscan/[email protected] for shell workflows, JSON output, and local exports. |
| Hosted MCP | hosted beta / stable launcher | Use https://api.starkscan.co/mcp on the API domain or {appBaseUrl}/api/mcp on an app-origin deployment; if STARKSCAN_BASE_URL already ends with /api, do not append another /api. Use @starkscan/mcp by default or exact @starkscan/[email protected] in unattended agent configs; 18 tools are listed: bootstrap, 16 read-only route tools, and one unsigned write-payload builder. |
| Starkscan RPC | authenticated HTTP beta | Hosted production is open to Starkscan API-key holders for reads, calls, events, fee, and simulation-envelope workflows; preview/self-hosted deployments may require batch or utility scope unless configured open. Signed transaction submission requires a write-scoped key. Selected trace methods require a separate operator-issued trace entitlement. Keep your existing provider for WebSockets, archive/history, and full-provider replacement. |
One-command conformance smoke
Before handing a key to an agent (or after a deploy), sanity-check the host, auth, and reachability with the published CLI and a status call:
npx -y @starkscan/[email protected] doctor
# or a raw check:
curl -i -H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/status"doctor checks the base URL, auth mode, API reachability, and hosted MCP. A 200 with chain status confirms the key and host are wired; send a deliberately bad key to confirm a 401 (see Your first error for the full error/header contract).
JSON-RPC provider beta
For the product-level node URL, server endpoint, and partner migration checklist, start with Starkscan RPC. This section keeps the same contract in a bounded agent-friendly shape.
Use this surface with a Starkscan API key when a client needs Starknet JSON-RPC method names instead of the REST, SDK, CLI, or hosted MCP surfaces. Hosted production authenticated RPC beta access covers read, batch, call, event, fee, and simulation-envelope workflows for Starkscan API-key holders; preview and self-hosted deployments may require batch or utility scope unless configured open. Signed transaction submission requires a write-scoped key.
For higher-capacity access or write-scoped signed-payload submission, use your Starkscan partner or support channel and include:
- app or workspace name
- mainnet use case
- expected requests per second, batch size, and concurrency
- whether your client can send
X-Starkscan-Api-Keyheaders - whether you need
nodeUrlcompatibility for SDKs/tools that cannot attach headers - whether you need write forwarding for already-signed transactions
Starkscan JSON-RPC has current mainnet wallet-app evidence for read, call,
event, fee, and simulation-envelope workflows through the dedicated mainnet
gateway path. The signed-write lane also has mainnet boundary certification for
already-signed starknet_addInvokeTransaction,
starknet_addDeclareTransaction, and starknet_addDeployAccountTransaction
requests through the rpc_write lane. Keep your existing Starknet RPC provider
for WebSockets, broad tracing, archive/history, unrestricted public writes, and
full-provider replacement until Starkscan documents and proves those lanes
separately.
Agents can read the current machine-readable RPC beta contract from
GET https://api.starkscan.co/v1/meta/capabilities under rpcProvider, including the spec-version
floor, supported block tags, quota classes, write-beta methods, trace-beta
methods, and excluded surfaces. Check rpcProvider.writeBeta.enabled and
rpcProvider.writeBeta.status before attempting write methods. Check
rpcProvider.traceBeta.methods, rpcProvider.traceBeta.quotaClass, and its
operator-issued scope policy before attempting a trace call.
export STARKSCAN_RPC_API_URL="https://api.starkscan.co/v1/SN_MAIN/rpc"
export STARKSCAN_API_KEY="YOUR_STARKSCAN_API_KEY"Header-auth request:
curl "$STARKSCAN_RPC_API_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_API_KEY="YOUR_STARKSCAN_API_KEY"
export STARKSCAN_RPC_NODE_URL="https://starkscan.co/rpc/v0_10/SN_MAIN/$STARKSCAN_API_KEY"For preview or self-hosted deployments, replace starkscan.co with that
deployment's app host so the URL-token secret is not sent to the wrong origin.
Then pass the URL directly:
import { RpcProvider } from "starknet";
const provider = new RpcProvider({
nodeUrl: process.env.STARKSCAN_RPC_NODE_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 Starkscan key per app or environment for this URL. It carries
the same RPC scopes as the header-auth key: read and batch for normal
authenticated RPC beta traffic, write only when the key is explicitly
write-scoped for signed-payload submission, and trace only when an operator
has deliberately issued that entitlement for the two documented trace methods.
Do not reuse an admin or shared 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_getStorageProof, starknet_getClass, starknet_getClassHashAt, starknet_getClassAt, starknet_getCompiledCasm, starknet_getNonce |
rpc_read_history | starknet_getBlockWithTxHashes, starknet_getBlockWithTxs, starknet_getBlockWithReceipts, starknet_getBlockTransactionCount, starknet_getTransactionByBlockIdAndIndex, starknet_getTransactionByHash, starknet_getTransactionReceipt, starknet_getTransactionStatus, starknet_getMessagesStatus, starknet_getStateUpdate, starknet_getEvents |
rpc_simulation | starknet_simulateTransactions, starknet_estimateFee, starknet_estimateMessageFee |
rpc_write | Signed-payload submission for write-scoped keys: starknet_addInvokeTransaction, starknet_addDeclareTransaction, starknet_addDeployAccountTransaction |
Limits that agents should treat as contract:
- Batch JSON-RPC is supported, capped at 50 items and a 16 MiB aggregate serialized response.
starknet_blockHashAndNumberis the correct method name. Do not callstarknet_getBlockHashAndNumber.starknet_getEventsmust use bounded numericfrom_blockandto_block,chunk_size <= 1000, and a block span of at most 10,000. Starkscan accepts both the named filter shapeparams: {"filter":{"from_block":{"block_number":N},"to_block":{"block_number":N},"chunk_size":100}}and the direct filter shapeparams: {"from_block":{"block_number":N},"to_block":{"block_number":N},"chunk_size":100}. Prefer the namedfilterwrapper in generated clients; do not mix a nestedfilterobject with top-level filter keys.starknet_calltoken probes must use Starknet entry-point selectors, not EVM-style method IDs or truncated fixtures. For ERC20decimals, use selector0x004c4fb1ab068f6039d5780c68dd0fa2f8742cceb3426d19667778ca7f3518a9. For balance reads, prefer the certified RESTtoken/{token}/balance-of/{address}route unless you have verified the exact Starknetbalance_oforbalanceOfselector for that token.- Write forwarding requires an explicit
write-scoped key, accepts only already-signed payloads, does not custody or generate private keys, and must not be blindly retried by clients. Onlystarknet_traceTransactionandstarknet_traceBlockTransactionsuse the separate operator-issuedtracescope or enrolled trace-certified partner policy, boundedrpc_tracequota, and 16 MiB serialized item cap; trace never inherits read, batch, write, or prove authority. Keys without the required entitlement, malformed or unsigned write probes, and HTTP WebSocket-subscription calls return JSON-RPC errors with explicit quota classes such asrpc_write,rpc_trace, orrpc_ws; they must not return success. starknet_getStorageProofis a bounded proof beta method. Prefer a concreteblock_numberorblock_hash;latestis accepted, butpendingandpre_confirmedare rejected. Keep requests within 8class_hashes, 8contract_addresses, 8contracts_storage_keysentries, 16 storage keys per contract, and 32 total proof targets. The 32-target total isclass_hashes + contract_addresses + all individual storage_keys;contracts_storage_keysentries are capped separately. Split requests if you seestorage_proof_response_too_large.starknet_getCompiledCasmis capped at a 4 MiB serialized JSON-RPC item. Split or fall back to a partner-supported archive path if you seecompiled_casm_response_too_large.- JSON-RPC
id,result, and upstreamerrorenvelopes are preserved. Starkscan metadata stays in headers orerror.data. - For RPC issue reports, log HTTP status, full JSON-RPC
resultorerror,X-Request-Id,X-Starkscan-Rpc-Class, andX-Ratelimit-*headers. REST routes useX-Starkscan-Route-Class; RPC routes useX-Starkscan-Rpc-Class.
Smoke-test the RPC path with the public JSON-RPC calls shown above: confirm an unauthenticated request is rejected, authenticated starknet_chainId, starknet_specVersion, starknet_blockNumber, and starknet_blockHashAndNumber return results, a known-good starknet_call returns a value, bounded starknet_getEvents returns an event page, bounded starknet_getStorageProof, starknet_getMessagesStatus, and starknet_getCompiledCasm probes exercise their documented success or bounded-error contracts, malformed write probes return errors or rpc_write rate limits without success, and batch requests stay within the 50-item and 16 MiB aggregate caps. For an operator-approved trace canary, use a dedicated trace-scoped key, call exactly one of starknet_traceTransaction or starknet_traceBlockTransactions with a bounded known fixture, confirm the rpc_trace response class and request ID, and separately prove a non-trace key is rejected without upstream forwarding. Never use a trace probe as a broad-tracing or archive certification claim.
Provider-migration readiness is validated before Starkscan JSON-RPC is offered
as a migration target. The current dedicated mainnet gateway evidence covers
provider identity, token starknet_call reads, wallet state reads,
transaction/receipt/status/events reads, simulation/fee envelope forwarding,
the starknet_specVersion floor (at least 0.10.2), and request-id,
rpc-class, and rate-limit headers. The signed-write lane has separate mainnet
boundary certification for already-signed payload forwarding.
Wallet/app migration stability
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
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.
Wallet/app Voyager migration map
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} | Rows are newest-first by (blockNumber, txIndex, logIndex, transferIndex). Use direction=any, in, or out relative to the wallet; any dedupes self-transfers. Pass the exclusive nextCursor back unchanged. |
| 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 still an authenticated
HTTP beta rather than a full-provider replacement. Route tier/package naming remains
beta even though the public SDK/CLI/MCP packages are published under the
Starkscan scope. Use documented REST routes for the certified REST set; keep
your existing Starknet RPC provider for WebSockets, broad tracing,
archive/history, unscoped writes, and full-provider replacement until those
lanes have their own certification.
Smallest safe route set
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 a utility or batch-scope key) |
| 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 asset candidates | GET /v1/{chain}/address/{address}/assets/discovery |
| block-pinned wallet state | POST /v1/{chain}/query/wallet-state |
| 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.
For portfolio pagination, typed price failures, the retired holdings route, Wallet-plan full-range event certification, and partner access, use the Wallets guide. Wallet builders and infrastructure providers can contact Omar when they need an issued Wallet-plan key or selector-position certification.
First working checks
1. Verify the host and key
curl \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/status"2. Verify one tx detail and one tx trace
curl \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/tx/<tx_hash>"
curl \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/tx/<tx_hash>/trace"3. Verify one block path
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:-https://api.starkscan.co}/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}. The block response also includes nullable header metadata such as stateRoot, sequencerAddress, gas prices, L1 data availability mode, and Starknet version when indexed from the canonical block payload. 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:-https://api.starkscan.co}/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.
4. Verify one wallet-state path
Use discovery when the wallet does not already have a reviewed token list:
curl \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/address/<owner>/assets/discovery?scope=discovered_plus_registry&limit=25"Then verify a bounded wallet snapshot at one immutable block:
curl -X POST \
-H "Content-Type: application/json" \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
-d '{"ownerAddress":"0x...","mode":"require_complete","scope":"discovered_plus_registry","limit":25,"blockPreference":"latest_accepted_l2"}' \
"${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/query/wallet-state"Use balance-of only when you already know the exact token contract:
curl \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"${STARKSCAN_BASE_URL:-https://api.starkscan.co}/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:-https://api.starkscan.co}/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:-https://api.starkscan.co}/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.
Contract caveats agents must obey
block_refaccepts a block number or block hash.- Token and contract read
block_tagacceptslatest,pending, a block number, or a block hash. Use an exact block for correctness comparisons. - Timestamp-to-block resolution accepts Unix seconds or RFC3339 timestamps with timezone. Do not send timezone-less calendar strings.
- If you need the current head block, read
GET /v1/{chain}/statusfirst and then reuse the returned block number or hash. - For
block/{number}/txs, use a numeric block number. If you started from a block hash, resolveblockNumberfirst. - Pass returned
nextCursorvalues back unchanged. Do not build block cursors yourself. GET /v1/{chain}/search?q=...is identifier-first search for recognized hashes, block references, and addresses. It is not ticker, symbol, or free-text search and its response has onlyblocks,transactions, andaddresses—not a genericresultsfield.- Discovery returns candidate evidence and coverage, never balances.
completeWithinScope=trueis not a global asset-universe claim. - In wallet state, trust balances only when their item status is
ok; every successful item is read at the echoedblock.blockHash. require_completefails visibly instead of substituting indexed data or interpreting an RPC error as zero.- Use
GET /v1/{chain}/address/{address}/transactionswhen the agent wants one row per tx. - Use
GET /v1/{chain}/address/{address}/transferswhen a migration adapter needs transfer-granular wallet rows from the public transfer index; do not treat UIactivitycopy as a public API route. GET /v1/{chain}/contract/{address}/readrequires a raw Starknetselector, not a function name.GET /v1/{chain}/contract/{address}/entrypointsis broader thanread; forread, prefer selectors withstateMutability=viewand pass required calldata.POST /v1/{chain}/tx/previewsexpects{"hashes":[...]}.tx/previewsis compact by default. Ask forincludeLogCounts=trueorincludeLogs=truebefore you infer thatlogCount=0orlogs=[]means “no logs”.
If the agent still needs concrete route shapes, use Route examples before guessing response semantics.
Error contract
| 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.
Bug report template
When an agent reports a Starkscan issue, include:
- exact base URL and chain
- exact route and query string
- request body for
POSTroutes - auth mode used (
X-Starkscan-Api-Key) - response status
- response body snippet
X-Request-IdX-Starkscan-Route-Class- relevant rate-limit headers if present
- expected result
- actual result
Copy-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: