Corvus Labs

Solana JSON-RPC over HTTP

Send Solana JSON-RPC 2.0 requests to the Corvus endpoint on port 8899, batch calls, and match gateway error codes correctly.

You send JSON-RPC 2.0 over HTTP POST to http://<region>.corvus-labs.io:8899, with content-type: application/json.

Send a request

curl --fail-with-body "$CORVUS_RPC_URL" \
  --header 'content-type: application/json' \
  --data '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getLatestBlockhash",
    "params": [{ "commitment": "processed" }]
  }'

We serve every Solana JSON-RPC method. There's no Corvus subset and no allowlist to check against, so the Solana JSON-RPC reference is your method documentation. What changes here is the metering (see Rate limits) and the gateway error contract below.

Ledger history reaches back 3 days

Historical methods (getBlock, getTransaction, getSignaturesForAddress and the rest) reach back a rolling 3 days. Archival depth to genesis is planned; ask on Discord where it stands before you build around it.

Error responses

HTTPCodeMessage prefix
400-32600Invalid request body
401-32002Unauthorized
403-32003 or -32004You have no access to this service
429-32001RPS limit exceeded
429-32005Transaction rate limit exceeded
429-32005Scan request timed out waiting for concurrency slot
502-32000Unable to process Batch Request
503-32099Server is not available at the moment

Messages sometimes carry a support sentence after the prefix (Please contact support at discord.gg/corvus-labs), so full-string comparison will eventually break. Match on status, code and prefix together.

-32005 is the one to watch. It covers two conditions with opposite fixes, transaction throughput and scan concurrency, and only the prefix separates them.

function classify(status: number, error: { code: number; message: string }) {
  if (status === 429 && error.code === -32005) {
    return error.message.startsWith('Scan request timed out')
      ? 'scan-concurrency'
      : 'tps';
  }
  if (status === 429 && error.code === -32001) return 'rps';
  return 'other';
}

The -32100 code

-32100 / PPS limit requirement not met isn't a JSON-RPC error, and nothing on port 8899 will ever send it to you. The PPS limiter lives on the aRPC streaming transport, where it arrives as gRPC PERMISSION_DENIED (7) and the connection is then closed. See Gateway & streaming errors.

Batches

A batch is one HTTP body containing an array of calls:

[
  { "jsonrpc": "2.0", "id": 1, "method": "getSlot" },
  { "jsonrpc": "2.0", "id": 2, "method": "getLatestBlockhash" }
]

Each item is metered on its own, at its own weight. Ten getTransaction calls in one batch cost 10 × 10 = 100 RPS units.

A batch the gateway can't proxy fails whole: HTTP 502 with -32000 Unable to process Batch Request for the batch, not per item.

Logging and retries

401 and 403 are configuration problems, not transient ones. When you log the JSON-RPC id, status and code, leave the endpoint URL out; on a dedicated endpoint the path is your credential. sendTransaction has its own retry rules, covered in Transactions.

On this page