Migration skills
Download source-backed SKILL.md artifacts for Voyager migration and accounting point-in-time balances.
Migration skills
Use this page when a client wants an agent to migrate from Voyager-style calls to Starkscan without guessing routes.
The artifacts below are intentionally narrow. They read like executable migration contracts, not generic prompts. Each skill tells the agent which Starkscan routes are certified, beta, experimental, or unsupported, and points back to the published starkscan-openapi.yaml before any code generation.
Downloadable skills
| Skill | Best for | Artifact |
|---|---|---|
| Accounting point-in-time balances | Accountants that need one token balance for one account at a calendar close. | /skills/accounting-point-in-time-balances/SKILL.md |
| Voyager migration | Adapters that need to replace a bounded Voyager workflow with Starkscan REST routes and keep unsupported/RPC gaps explicit. | /skills/voyager-migration/SKILL.md |
Install the artifact by giving the SKILL.md file to Claude, Codex, Cursor, or any agent runtime that supports portable task instructions. If the runtime does not support skills directly, paste only the relevant sections into the migration task and keep the OpenAPI link attached.
Accounting workflow
The current accounting close workflow is already possible with two Starkscan calls:
- Resolve the calendar timestamp to an indexed Starknet block.
- Query the certified token balance route at that exact block.
export STARKSCAN_CHAIN="SN_MAIN"
export STARKSCAN_API_KEY="<api_key>"
STARKSCAN_BASE_URL="${STARKSCAN_BASE_URL:-https://api.starkscan.co}"
export STARKSCAN_TIMESTAMP="2025-12-31T23:59:59Z"
export STARKSCAN_TIMESTAMP_QUERY="2025-12-31T23%3A59%3A59Z"
export STARKSCAN_TOKEN="<token_contract_address>"
export STARKSCAN_ACCOUNT="<account_address>"
curl -sS \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/block-at-timestamp?timestamp=$STARKSCAN_TIMESTAMP_QUERY&closest=before"Use the returned block.blockNumber as the block_tag:
curl -sS \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/token/$STARKSCAN_TOKEN/balance-of/$STARKSCAN_ACCOUNT?block_tag=<block.blockNumber>"For 2025-12-31T23:59:59Z, Starkscan's correctness gate verified block 5007537 against RPC. The helper response also includes previousBlock, nextBlock, and source=indexed_blocks so an accountant can keep the bracket evidence with the report.
Voyager migration matrix
Use this matrix before generating migration code. The state must stay attached to every replaced call so clients know whether they are using a certified REST route, a beta REST route, an experimental RPC provider surface, or no Starkscan replacement yet.
| Voyager-style need | Starkscan replacement | State | Migration note |
|---|---|---|---|
| Health / host reachability | GET /v1/{chain}/status | certified | Use this as the first smoke for every integration. |
| Exact token balance | GET /v1/{chain}/token/{token}/balance-of/{address}?block_tag={block} | certified | Use exact token and account addresses; pass a concrete block for accounting. |
| Timestamp to block | GET /v1/{chain}/block-at-timestamp?timestamp={time}&closest=before | certified | Use as the helper before exact historical balance checks for one known token/account. |
| One transaction | GET /v1/{chain}/tx/{tx_hash} | certified | Use for transaction detail and support links. |
| Contract metadata | GET /v1/{chain}/contract/{address} | beta | Indexed-only class/deployment/token metadata. Nullable token fields mean not identified in indexed token metadata. |
| Address attribution / readable name | GET /v1/{chain}/address/{address}/attribution | beta | Address-oriented alias for indexed contract metadata. Use when a migration starts from an address and needs alias, token-kind, class, deployment, or deployer fields. |
| Wallet transactions | GET /v1/{chain}/address/{address}/transactions?limit={n}&cursor={nextCursor} | beta | Cursor-based; preserve nextCursor exactly. |
| Address token transfers | GET /v1/{chain}/address/{address}/transfers?direction=any&limit={n}&cursor={nextCursor} | beta | Wallet-first transfer rows across all indexed tokens. Use direction=any, in, or out; any dedupes self-transfers while in and out keep the explicit directional view. Direction, token, block, cursor, and limit filters are applied before pagination. |
| Token transfer rows | GET /v1/{chain}/token/{token}/transfers?address={address}&limit={n}&cursor={nextCursor} | beta | Use when the token contract is known. Do not enumerate token contracts client-side for wallet history. |
| Contract event ingestion | GET /v1/{chain}/contract/{address}/events?limit={n}&cursor={nextCursor} | beta | Voyager /events?contract={market}&p={page}&ps=100 migrations should switch to cursor pagination. keys maps to topic0..topic3, transactionHash maps to txHash, name maps to eventName when attributed, and dataDecoded maps to decodedFields when an exact materialized ABI schema matches; inspect decodedFieldsUnavailableReason when fields are omitted. |
| Storage reads, class reads, nonce, calls, fee, simulation | Starkscan JSON-RPC provider beta | beta | Use the authenticated JSON-RPC provider path. REST getStorageAt is not shipped; use JSON-RPC starknet_getStorageAt. |
| Already-signed invoke, declare, deploy-account writes | Starkscan JSON-RPC signed-write beta | beta | Available to write-scoped Starkscan API-key holders. Starkscan forwards already-signed payloads; it does not generate or custody private keys and clients must not blindly retry broadcasts. |
| WebSocket subscriptions, broad Voyager parity | No current-pilot replacement | unsupported | Keep your existing Starknet RPC provider until Starkscan RPC formally launches that surface. |
Route status
| Task | Route | State |
|---|---|---|
| Health check | GET /v1/{chain}/status | certified |
| Timestamp to block | GET /v1/{chain}/block-at-timestamp?timestamp={time}&closest=before | certified |
| Exact token balance | GET /v1/{chain}/token/{token}/balance-of/{address}?block_tag={block} | certified |
| One transaction | GET /v1/{chain}/tx/{tx_hash} | certified |
| Contract metadata | GET /v1/{chain}/contract/{address} | beta |
| Address attribution / readable name | GET /v1/{chain}/address/{address}/attribution | beta |
| Wallet transactions | GET /v1/{chain}/address/{address}/transactions?limit={n}&cursor={nextCursor} | beta |
| Address token transfers | GET /v1/{chain}/address/{address}/transfers?direction=any&limit={n}&cursor={nextCursor} | beta |
| Token transfer rows | GET /v1/{chain}/token/{token}/transfers?address={address}&limit={n}&cursor={nextCursor} | beta |
| Contract event ingestion | GET /v1/{chain}/contract/{address}/events?limit={n}&cursor={nextCursor} | beta |
| Storage reads / class reads / nonce / calls / fee / simulation | Starkscan JSON-RPC provider beta | beta |
| Already-signed invoke / declare / deploy-account writes | Starkscan JSON-RPC signed-write beta | beta |
Current gaps must stay visible in migration plans. A standalone REST storage
route, WebSocket traffic, full archive/history behavior, unrestricted public
writes, strict signed simulation certification, and broad Voyager parity are not
certified launch surfaces. If an agent asks for a route that is not listed here
or in the OpenAPI artifact, it should answer unsupported instead of inventing
an endpoint.
Contract Metadata Example
Use this when a Voyager workflow needs indexed deployment/class/token identity for a known address. This route is beta and indexed-only; it does not probe ABI or RPC on the request path.
curl -sS \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/contract/0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a"{
"chainId": "SN_MAIN",
"address": "0x40337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a",
"classHash": "0x30b8...",
"deployedAtBlock": 9795720,
"deployedAtTx": "0x...",
"createdOnIso": "2026-05-18T00:00:00.000Z",
"deployedByAddress": "0x...",
"isAccount": false,
"isToken": null,
"tokenKind": null,
"alias": null,
"metadataCompleteness": true,
"source": "indexed_read_model"
}Token fields are either identified together (isToken: true, non-null tokenKind) or absent together (isToken: null, tokenKind: null, alias: null).
Address Attribution Example
Use this when a migration starts from an address and needs a readable label or protocol/project attribution.
curl -sS \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/address/0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a/attribution"{
"chainId": "SN_MAIN",
"requestedAddress": "0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a",
"canonicalAddress": "0x40337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a",
"known": true,
"label": "Starknet: Canonical Privacy Pool",
"confidence": "high",
"source": "indexed_protocol_registry",
"protocol": {
"name": "Starknet Privacy Pool",
"kind": "infrastructure"
}
}Agent rules
- Use
X-Starkscan-Api-Key; do not paste the full key into chats, screenshots, tickets, or generated reports. - Use
closest=beforefor "as of this instant" accounting semantics. - Use exact token contract addresses. Do not rely on symbols such as
USDCwhen correctness matters. - Use a concrete block number or block hash for replayable balance checks. Do not use
latestfor historical accounting close. - Treat the certified accounting workflow as one known token contract, one account, and one timestamp. Do not infer a historical portfolio from it.
- Preserve returned cursors exactly. Do not construct pagination cursors client-side.
- Log
X-Request-Id, rate-limit headers, HTTP status, and latency for support. For REST routes includeX-Starkscan-Route-Class; for RPC calls includeX-Starkscan-Rpc-Class. - Read
/starkscan-openapi.yamlbefore generating SDK code or adding a route to a migration matrix.
Smoke before handoff
curl -sS \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/status"
BLOCK_RESPONSE="$(curl -sS \
-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%3A59%3A59Z&closest=before")"
printf '%s\n' "$BLOCK_RESPONSE"
BLOCK_NUMBER="$(printf '%s' "$BLOCK_RESPONSE" | python3 -c 'import json, sys; print(json.load(sys.stdin)["block"]["blockNumber"])')"
curl -sS \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
"${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/token/$STARKSCAN_TOKEN/balance-of/$STARKSCAN_ACCOUNT?block_tag=$BLOCK_NUMBER"TypeScript and CLI smoke
Use the TypeScript SDK for the certified balance route after the timestamp helper resolves the block:
import { createStarkscanClient } from "@starkscan/sdk";
const customBaseUrl = process.env.STARKSCAN_BASE_URL?.trim();
const apiBase = customBaseUrl || "https://api.starkscan.co";
const chainId = process.env.STARKSCAN_CHAIN ?? "SN_MAIN";
const apiKey = process.env.STARKSCAN_API_KEY;
const token = process.env.STARKSCAN_TOKEN;
const account = process.env.STARKSCAN_ACCOUNT;
const timestamp = "2025-12-31T23:59:59Z";
if (!apiKey || !token || !account) {
throw new Error("STARKSCAN_API_KEY, STARKSCAN_TOKEN, and STARKSCAN_ACCOUNT are required");
}
const blockResponse = await fetch(
`${apiBase}/v1/${chainId}/block-at-timestamp?timestamp=${encodeURIComponent(timestamp)}&closest=before`,
{ headers: { "X-Starkscan-Api-Key": apiKey } },
);
const { block } = (await blockResponse.json()) as { block: { blockNumber: number } };
const starkscan = createStarkscanClient({
apiKey,
chainId,
...(customBaseUrl ? { baseUrl: customBaseUrl } : {}),
});
const balance = await starkscan.tokenBalanceOf(token, account, String(block.blockNumber));
console.log({ blockNumber: block.blockNumber, balance });Use the CLI for a package-level smoke after the block number is known:
npx -y @starkscan/cli@0.1.2 \
--chain "$STARKSCAN_CHAIN" \
--api-key "$STARKSCAN_API_KEY" \
doctor
npx -y @starkscan/cli@0.1.2 \
--chain "$STARKSCAN_CHAIN" \
--api-key "$STARKSCAN_API_KEY" \
--output-format json \
token-balance-of "$STARKSCAN_ACCOUNT" "$STARKSCAN_TOKEN" \
--block-tag "$BLOCK_NUMBER"Builder policy
The safe builder behavior is constrained:
- Read the requested Voyager call or accounting task.
- Match it against this page, the downloadable skills, and OpenAPI.
- Emit a
SKILL.md, curl commands, TypeScript SDK notes, Python smoke, and a route-state table only for matched routes. - Mark everything else
unsupported,beta, orexperimentalwith the reason.
This prevents a migration agent from converting "missing docs" into fake Starkscan routes.