Mainly

Call a program (read-only)

Execute a read-only program call and get its return value — no transaction, no fee, no keys.

POST /programs/{programId}/view

How calling programs works on Solana

Coming from Ethereum, expect two differences:

  1. Writes are transactions. There is no separate "contract call" API for state changes — you build an instruction, sign it, and submit it via send.
  2. Most reads don't need a call at all. Program state lives in accounts, so the usual way to "read a contract" is just reading accounts — Get an account or List program accounts.

The remaining case: programs (especially Anchor programs) expose view functions that compute a value on-chain — an oracle price, a quote, an entitlement check. This endpoint executes one via simulation and hands you the return value. Nothing lands on-chain, nothing is signed, nothing costs a network fee.

Request body

FieldTypeRequiredDescription
datastringYesThe instruction data, base64-encoded (for Anchor: the view method's discriminator + args, as produced by your program's client library).
accountsarrayYesThe accounts the instruction reads, in the order the program expects: { "address": "...", "writable": false, "signer": false }.
payerstringNoAddress to simulate as fee payer. Defaults to a funded placeholder — only set this if the program checks the payer's identity.

Example

Calling a lending program's view function that returns a wallet's current deposit value:

curl -X POST https://api.sarg.am/v1/solana/programs/LendZqTs7gn5CjSJJT3zXcTQyEN2BSK9BbA6iDgc4Fj/view \
  -H "Authorization: Bearer $MAINLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "data": "Y2FsY3VsYXRlX3VzZXJfZGVwb3NpdA==",
    "accounts": [
      { "address": "7Xq3mZvUkPqRSPY2ZRegjxUmjcSDCBL8HbGyWjcJt2gV", "writable": false, "signer": false },
      { "address": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM", "writable": false, "signer": false }
    ]
  }'
{
  "success": true,
  "returnData": {
    "base64": "AOH1BQAAAAA=",
    "programId": "LendZqTs7gn5CjSJJT3zXcTQyEN2BSK9BbA6iDgc4Fj"
  },
  "computeUnits": 8420,
  "logs": [
    "Program LendZqTs7gn5CjSJJT3zXcTQyEN2BSK9BbA6iDgc4Fj invoke [1]",
    "Program return: LendZqTs7gn5CjSJJT3zXcTQyEN2BSK9BbA6iDgc4Fj AOH1BQAAAAA=",
    "Program LendZqTs7gn5CjSJJT3zXcTQyEN2BSK9BbA6iDgc4Fj success"
  ]
}

Response fields

FieldTypeDescription
successbooleanWhether the call executed without error. Failures return success: false with an error object and logs, same as simulate.
returnData.base64string | nullThe program's return value. Decoding it requires the program's IDL — it's your program's type, not ours. null if the program returned nothing.
computeUnitsnumberCompute consumed by the call.
logsarrayFull program log output.

Decoding tip: for Anchor programs, deserialize returnData.base64 with the return type from your IDL. In this example, AOH1BQAAAAA= is a little-endian u64100000000, i.e. 100 USDC at 6 decimals.

Errors

codeWhen
invalid_addressThe program ID or an account address isn't valid base58.
invalid_parameterdata isn't valid base64, or accounts is malformed.
not_foundThe address isn't a program.

Under the hood

Builds a throwaway transaction around your instruction, runs simulateTransaction with signature verification off and a fresh blockhash, and extracts the returnData — the pattern Anchor's .view() uses, minus the client-side setup.

On this page