Skip to main content

Overview

Every validator can serve an HTTP API (default devnet port 4000, set by rpc_port in the validator config). The cowboy CLI and SDKs are wrappers over this API; anything they do, you can do with plain HTTP.
curl http://localhost:4000/height
# {"height": 12345}
With COWBOY_DEV_MODE set on the node, a Swagger UI is served at /swagger-ui and the machine-readable spec at /api-docs/openapi.json. That spec is the exhaustive, always-current endpoint list; this page covers the conventions and the endpoints developers use most.

Conventions

  • Addresses are 20-byte hex strings (0x-prefixed accepted). Invalid addresses return 400.
  • Pagination: list endpoints take offset and limit query params (limit defaults to 50, capped at 1,000) and return total_count with the echoed offset/limit; the actor storage/mailbox endpoints use cursor pagination (next_cursor).
  • Rate limits: global sliding window (default 100 req/s, RPC_GLOBAL_RATE_LIMIT_PER_SEC); the faucet is limited separately (default 5 req/min). Exceeding returns 429.
  • Errors are JSON with an HTTP status plus a numeric code (table below).
  • Body size: requests are capped at 1 MB globally; /submit and /submit_wait enforce a tighter 512 KB.
  • Amounts (balances, fees) are integers in CBY base units (1 CBY = 10⁹).

Transactions

EndpointMethodPurpose
/submitPOSTSubmit a batch of signed transactions
/submit_waitPOSTSubmit and block until receipts are available (timeout 100–10,000 ms)
/transaction/{hash}GETTransaction by hash
/transaction/{hash}/receiptGETReceipt: status, cycles_used/cells_used, events, revert reason
/mempool/transaction/{hash}GETA still-pending transaction
The submission body is binary CBOR, not JSON: a Submission::Transactions([...]) envelope of signed transactions (max 50 per batch). In practice you produce it with the CLI (cowboy transaction submit) or an SDK rather than by hand; the wallet’s transaction encoding is byte-compatible with the node’s deterministic CBOR. /submit_wait returns per-transaction results including status, block_height, gas used, and revert_reason when execution failed.

Accounts

EndpointMethodPurpose
/account/{address}GETNonce and balance
/account/{address}/delegationsGETThe account’s runner stake delegations (CIP-13)
curl http://localhost:4000/account/0x7a3B...F92E
# {"address":"0x7a3b...","nonce":7,"balance":4999000000000}

Actors

EndpointMethodPurpose
/actor/{address}GETActor summary: code hash, balance, nonce, mailbox count, manifest
/actor/{address}/codeGETDeployed code
/actor/{address}/manifestGETEntitlements manifest
/actors/{address}/storageGETStorage entries (cursor-paginated; note the plural prefix)
/actors/{address}/storage/countGETStorage entry count
/actors/{address}/mailboxGETPending messages (plural prefix)
/actor/{address}/logsGETEvent log (topic + data per event)
/actor/{address}/timersGETPending timers
/actor/{address}/upgrade-historyGETCode upgrade history
/actor/readPOSTRead-only execution of a handler — no state mutation allowed
/actor/read runs a handler against current state without a transaction — the workhorse for UIs and polling:
curl -X POST http://localhost:4000/actor/read \
  -H 'Content-Type: application/json' \
  -d '{"actor": "0x...", "handler": "get_count", "payload_text": ""}'
# {"result":"<base64>", "cycles_used":1234, "cells_used":0, "block_height":42, "state_root":"0x..."}
The payload can be given as payload (base64 bytes), payload_text (UTF-8 string), or payload_json (JSON value); optional max_cycles/max_cells bound the execution. A handler that attempts a state write is rejected (error 5003).

Blocks and chain state

EndpointMethodPurpose
/heightGETCurrent chain height
/block/{hash}GETBlock by hash, by height, or the literal latest
/chain-infoGETchain_id and network name
/basefeeGETCurrent dual basefee + suggested max fees (numeric strings)
/healthGETLiveness ({"status":"ok"})
/health/detailedGETComponent-level health (blockchain, mempool, storage)
/metricsGETPrometheus metrics

Tokens (CIP-20)

EndpointMethodPurpose
/tokensGETList tokens (paginated)
/token/{token_id}GETMetadata: name, symbol, decimals, supply, owner
/token/{token_id}/balance/{address}GETBalance (uint128 as string)
/token/{token_id}/allowance/{owner}/{spender}GETAllowance

Runners and jobs (CIP-2)

Read endpoints useful when integrating with off-chain compute:
EndpointMethodPurpose
/runners/activeGETActive runners with reputation, rate card, stake
/runner/{address}GETOne runner’s registration info
/job/{job_id}GETJob spec
/job/{job_id}/statusGETpending / assigned / completed / failed / cancelled (verification is exposed via /job/{id}/verified)
/job/{job_id}/resultsGETSubmitted results (paginated)
/job/{job_id}/verifiedGETThe verified result
The runner daemon itself uses signed POST flows (/runner/{address}/heartbeat, /runner/{address}/job_result, …): each has a companion *_payload GET that returns the exact message_to_sign_base64, so signatures are computed over server-canonical bytes.

Proofs (CIP-15/17)

/proof/receipt/{tx_hash}, /proof/tx/{tx_hash}, /proof/account/{address}, /proof/actor/{address}, /proof/storage/{address}/{key}, and batch /proof/multi (POST) return Merkle proofs against the block state root, for light-client-style verification. /state/{actor}/{key_hex} returns a storage value together with its proof.

Faucet (devnet only)

curl -X POST http://localhost:4000/faucet \
  -H 'Content-Type: application/json' \
  -d '{"address": "0x..."}'
The route exists only when the validator runs with the faucet enabled (404 otherwise); with the faucet enabled on a non-dev chain (chain id other than 1 or 100) it returns 403. Rate-limited per minute.

Other endpoint families

FamilyPrefixSpec
Storage relays / volumes (RAS)/ras/... (delegation-token auth via X-Cbfs-Delegation header)CIP-9
Secrets/cbss/...CIP-24 (Secrets Manager)
Governance/governance/params, /governance/proposals, /governance/proposal/{id}CIP-12
Entitlements registry/entitlements/registry, /entitlements/validate-manifestEntitlements
Libraries/library/{publisher}/{name}CIP-26
State sync/state/snapshot, /state/operations (per-IP rate-limited)CIP-4
Consult /api-docs/openapi.json (dev mode) for the full schemas of these families.

Error codes

Numeric codes accompany HTTP errors so clients can branch reliably:
RangeDomainNotable codes
1000–1004General1000 internal, 1002 not found, 1003 timeout
2000–2017Transactions2001 invalid signature, 2003/2004 nonce too low/high, 2005 out of gas, 2009 deferred tx rejected, 2011 basefee too low, 2016 admission busy (429), 2017 admission retry (500)
3000–3001Accounts3000 not found, 3001 invalid address
4000–4001Blocks
5000–5004Actors5002 handler not found, 5003 read-only violation, 5004 read limits exceeded
6000–6002Storage / serialization
7000–7005Runners/jobs7000 runner not found, 7002 job not found
8000Faucet disabled
9000Library not found (CIP-26)
Execution-level failures inside a committed transaction surface as E-codes in the receipt instead — see the error reference.

Further reading