Logo
New RPC users get 35% off their first monthView the offer
RPC Assistant

Solana HTTP API: How Do You Connect, Sign, and Debug JSON-RPC Calls?

Summary

The Solana HTTP API is the JSON-RPC interface your app uses to read accounts, submit transactions, and query the cluster over standard HTTPS. You send a POST request with a JSON body to an RPC endpoint, and the node returns a JSON result or an error object. This article covers the request shape, the methods you will use most, and how to debug the failures that show up in real Solana apps. It also explains when a shared public endpoint is enough and when a dedicated Solana node is the better fit for production traffic.

The Solana HTTP API is the JSON-RPC interface your application uses to talk to a Solana node over HTTPS. Every wallet balance lookup, account read, transaction submission, and block query goes through a POST request to an RPC endpoint. If you are building on Solana, this is the layer you will debug most often.

This page focuses on the practical side: the request shape, the methods you will actually call, how commitment levels change results, and how to read the errors that come back. It also helps you decide whether a shared endpoint is enough or whether your workload needs a dedicated Solana node.

Which endpoint should you start with?

Start with the official OnFinality public endpoint for Solana mainnet:

https://solana.api.onfinality.io/public

That endpoint is fine for local development, scripts, and low-volume reads. Move to a dedicated or private endpoint when you hit any of these signals:

  • You are submitting transactions at a steady rate and seeing intermittent 429 responses.
  • You need consistent access to historical account state or large getProgramAccounts scans.
  • You run indexers, bots, or backends that poll the same accounts every few seconds.
  • You need WebSocket subscriptions for account or slot changes alongside HTTP calls.

If your workload is read-heavy and bursty, a shared RPC plan usually covers it. If your workload is continuous and latency-sensitive, a dedicated Solana node gives you isolated capacity. You can compare options on the RPC pricing page and see the full list of supported RPC networks.

The request shape

Every Solana HTTP API call is a JSON-RPC 2.0 POST. The body has four fields: jsonrpc, id, method, and params.

curl https://solana.api.onfinality.io/public \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getBalance",
    "params": [
      "83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri"
    ]
  }'

The response returns a result object on success, or an error object with a code and message on failure. The id you send is echoed back, which matters when you batch requests.

A few things that trip people up:

  • params is always an array, even for a single argument.
  • Some methods take an options object as the second element, for example {"commitment": "confirmed"}.
  • The Content-Type header must be application/json.

Methods you will call most

You do not need to memorize the full method list. Most Solana apps use a small set repeatedly.

MethodWhat it doesTypical caller
getBalanceReturns the lamport balance of an accountWallets, dashboards
getAccountInfoReturns the data and owner of an accountPrograms, indexers
getLatestBlockhashReturns a recent blockhash for transaction buildingAny transaction sender
sendTransactionSubmits a signed transactionWallets, bots, backends
getSignatureStatusesChecks confirmation status of signaturesTransaction senders
getTransactionReturns a confirmed transaction by signatureExplorers, support tools
getProgramAccountsReturns accounts owned by a programIndexers, analytics
getSlotReturns the current slotHealth checks, monitors

getProgramAccounts deserves a warning. It can be expensive on large programs and is often the first call to time out or get rate limited on shared endpoints. If you rely on it, plan for a dedicated node or an indexed data source.

Commitment levels change what you get back

Solana does not have a single "confirmed" state. You choose a commitment level per request, and it changes both the result and the latency.

CommitmentMeaningTrade-off
processedNode has seen the slotFastest, can be rolled back
confirmedSupermajority of stake has votedBalanced default for most apps
finalizedRooted, cannot be rolled backSlowest, safest for settlement

For a wallet showing a balance, confirmed is usually right. For anything that moves funds or triggers irreversible business logic, wait for finalized. If you mix commitment levels across calls, you can get inconsistent reads, for example a balance that appears before the transaction that changed it.

Reading errors instead of guessing

When a Solana HTTP API call fails, the error object tells you where to look. The table below maps common symptoms to the likely cause and the next step.

SymptomLikely causeNext step
HTTP 429Rate limit on a shared endpointBack off, batch reads, or move to a dedicated node
-32602 invalid paramsWrong param shape or missing options objectCheck the method signature and array order
-32002 transaction simulation failedTransaction would fail on-chainRun simulateTransaction and read the logs
Blockhash not foundBlockhash expired before submissionFetch a fresh blockhash right before sending
Empty result on getTransactionNot yet confirmed or wrong commitmentRetry with confirmed or finalized
Timeout on getProgramAccountsResult set too largeAdd filters or use a dedicated node

A useful habit is to log the full error object, not just the message. The data field often contains logs from the failed transaction, which usually points straight at the program error.

Building and sending a transaction

The HTTP API does not sign transactions for you. You build and sign locally, then submit the signed bytes. A minimal JavaScript flow looks like this:

import { Connection, PublicKey, Transaction, SystemProgram } from "@solana/web3.js";

const connection = new Connection("https://solana.api.onfinality.io/public", "confirmed");

const from = new PublicKey("<YOUR_WALLET_PUBLIC_KEY>");
const to = new PublicKey("<RECIPIENT_PUBLIC_KEY>");

const { blockhash } = await connection.getLatestBlockhash("confirmed");

const tx = new Transaction().add(
  SystemProgram.transfer({ fromPubkey: from, toPubkey: to, lamports: 1_000_000 })
);
tx.recentBlockhash = blockhash;
tx.feePayer = from;

// Sign with your wallet adapter or keypair, then:
const signature = await connection.sendRawTransaction(tx.serialize());
await connection.confirmTransaction(signature, "confirmed");

Two details matter here. First, always fetch a fresh blockhash immediately before sending, because blockhashes expire. Second, confirm the signature rather than assuming submission equals success.

HTTP versus WebSocket

HTTP is request-response. WebSocket is a persistent connection that pushes updates. Use HTTP for reads and transaction submission. Use WebSocket when you need to react to changes without polling.

const subId = connection.onAccountChange(
  new PublicKey("<ACCOUNT_PUBLIC_KEY>"),
  (accountInfo) => {
    console.log("Account changed:", accountInfo.lamports);
  },
  "confirmed"
);

OnFinality exposes WebSocket transport for Solana alongside HTTP, so you can keep both on the same provider. If your app polls the same account every few seconds, switching to a subscription usually reduces load and improves reaction time.

When to move off a public endpoint

A public endpoint is a starting point, not a production plan. The decision usually comes down to three questions:

  1. Is your traffic continuous or occasional? Continuous traffic needs isolated capacity.
  2. Do you depend on expensive calls like getProgramAccounts or historical reads? Those need headroom.
  3. Do you need predictable behavior under load? Shared endpoints are best-effort by nature.

If you answer yes to more than one, look at a dedicated node. Dedicated infrastructure gives your app its own capacity, which removes the noisy-neighbor problem and makes rate-limit behavior predictable. OnFinality provides both RPC API access and dedicated node options, so you can start shared and move up without changing your integration.

For devnet and testing, use the Solana Devnet RPC page to set up a separate endpoint so test traffic never competes with production.

Operational checks before you ship

Before you point real users at your Solana HTTP API setup, confirm these basics:

  • Your endpoint is configurable through an environment variable, not hardcoded.
  • You have a fallback endpoint or provider for failover.
  • You log request IDs and error codes for support.
  • You monitor getSlot or getHealth on a schedule to detect stalls early.
  • You batch independent reads instead of firing them one at a time.
  • You handle 429 responses with exponential backoff.

A simple health probe looks like this:

curl -s https://solana.api.onfinality.io/public \
  -X POST -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"getHealth"}'

If getHealth returns "ok", the node is responding. Pair that with a slot check to confirm the node is actually advancing.

Key Takeaways

  • The Solana HTTP API is JSON-RPC over HTTPS: POST a JSON body, get a JSON result or error.
  • params is always an array, and options like commitment go in a second element.
  • Commitment level changes both latency and safety; use finalized for irreversible actions.
  • Expensive calls like getProgramAccounts are the first to fail on shared endpoints.
  • Use HTTP for reads and submission, WebSocket for subscriptions.
  • Move to a dedicated node when traffic is continuous or latency-sensitive.

Frequently Asked Questions

Is the Solana HTTP API the same as JSON-RPC?

Yes. When people say Solana HTTP API, they mean the JSON-RPC interface served over HTTPS. The transport is HTTP, the payload format is JSON-RPC 2.0.

What is the default commitment level?

If you do not pass a commitment option, most methods default to finalized. Many apps explicitly set confirmed for faster reads.

Why do I get 429 responses?

A 429 means you hit a rate limit, which is common on shared public endpoints. Reduce request volume, batch reads, or move to a dedicated node.

Can I use the same endpoint for mainnet and devnet?

No. Mainnet and devnet are separate clusters with separate endpoints. Keep them in separate configuration so test traffic never touches production.

Do I need WebSocket if I already use HTTP?

Only if you need push updates. If you poll the same account repeatedly, a WebSocket subscription is usually more efficient.

How do I debug a failed transaction?

Run simulateTransaction and read the logs in the error data field. The program error code usually identifies the cause.

Next steps

If you are still evaluating, start with the public endpoint above and measure your request patterns for a week. If you see rate limits, timeouts on large queries, or a need for WebSocket subscriptions, review RPC pricing and the Solana network page to pick a plan that matches your workload. For teams running continuous traffic, a dedicated node removes the shared-capacity ceiling and keeps your Solana HTTP API calls predictable.

RPC Knowledge Base

Related RPC details

Never Worry about Infrastructure Again

OnFinality takes away the heavy lifting of DevOps so you can build smarter and faster.

Get Started