# REST API

> Complete NeuroChain REST API reference — every node and gateway endpoint grouped by area, with request fields, signed-operation targets, query parameters, conventions for amounts and errors, and rate limits.

Source: https://docs.nro.world/reference/rest

Two HTTP services expose the chain:

| Service | Default | Use |
|---------|---------|-----|
| **Gateway** (Node.js) | `http://localhost:3000` | What dApps and the web app call. Proxies the node, adds WebSocket, AI tooling and caching |
| **Node RPC** (Rust) | `http://localhost:9933` | The source of truth. Some operator endpoints exist only here |

Most paths are the same on both. The tables below mark endpoints that exist on only one of them. Examples use `$GATEWAY` and `$NODE_RPC` — see [Start here](/learn/start-here).

## Conventions

### Amounts

- On-chain amounts are **integers in uNRO** (`1 NRO = 1 000 000 uNRO`).
- Responses add a formatted **`*_human`** string next to each amount (`balance_human`, `value_human`, `stake_human`, …). Display those; do not convert in the client.
- In request bodies, send amounts as **JSON numbers** in uNRO unless the endpoint says otherwise.

### Signed operations

Every endpoint that changes state needs a signature. Two kinds:

| Kind | Signed message | `nonce` |
|------|----------------|---------|
| **Transaction** (`POST /api/v1/transactions`) | `nc-tx-v2|from|to|value|nonce` | Account nonce: last confirmed + pending + 1 |
| **Operation** (everything else) | `nc-tx-v2|actor|<target>|<value>|nonce` | Milliseconds timestamp, strictly increasing per address |

The *target* is a reserved system address naming the operation; the tables give it in the **Signs for** column. Each request carries `signature` (hex), `public_key` (hex ML-DSA-65) and `nonce`. See [Wallet → Signed operations](/learn/wallet#signed-operations).

With `CHAIN_ENV=mainnet` (the default), a missing or invalid signature is refused with **401**. With `CHAIN_ENV=testnet` the node logs a warning instead — for local development only.

Most operations are **applied in consensus**: the response says `"status": "pending"` and returns a `tx_hash`; the effect is visible once that transaction is in a block.

### Errors

Errors are JSON: `{"error": "<message>"}`, sometimes with `hint` or extra fields. HTTP codes used:

| Code | Meaning |
|------|---------|
| 200 | Success — but some older endpoints also return `{"error": …}` with 200; always check for `error` |
| 400 | Bad request, failed validation, Sentinel rejection |
| 401 | Missing or invalid signature, key not bound to the address |
| 403 | Forbidden in this mode (faucet on mainnet, write call without consensus on mainnet), deploy refused by VMGuardian |
| 404 | Not found |
| 409 | Name already taken |
| 429 | Rate limited |
| 502 / 503 | Gateway cannot reach the node |

### Pagination

List endpoints take `limit` and `offset` (some also `page`). Each endpoint caps `limit` (typically 100 or 200).

### Rate limits and CORS

| Where | Default | Variable |
|-------|---------|----------|
| Node RPC, per IP | 100 requests/s | `NEUROCHAIN_RPC_RATE_LIMIT` |
| Gateway, per IP | 200 requests/s | `GLOBAL_RL_MAX_RPS` |
| Gateway AI endpoints (`/contracts/audit`, `/contracts/generate`, …), per IP | 10 requests/min | `AI_RL_MAX_RPM` |

Allowed origins: `CORS_ALLOWED_ORIGINS` on both services (default `*`).

---

## Network and node

| Method | Path | Notes |
|--------|------|-------|
| GET | `/health` | `status`, `height`, `round`, `mempool`, `peers`, `tps`, `total_txs`, `validator_count`, `bft_quorum`, `bft_ready` |
| GET | `/status`, `/api/v1/status` | Node only. Height, validators, shards, network name |
| GET | `/api/v1/network/status` | Gateway only. Network summary for the explorer |
| GET | `/metrics` | Prometheus text format — see [Run a node](/operate/node) |
| GET | `/api/v1/shards` | Per-shard heights and roots |
| GET | `/api/v1/state/root` | `global_root`, `shard_roots`, `height`, `root_height`, `n_shards` |
| GET | `/api/v1/state/snapshot` | Node only. Full signed state snapshot for bootstrapping a node |
| GET | `/api/v1/checkpoints` | Signed checkpoints. `offset`, `limit` |
| GET | `/peers` | Node only. Connected peers |
| GET | `/api/v1/gas/estimate` | `base_fee`, gas per operation, `total_burned`, `nft_transfer_fee` — see [Gas & fees](/learn/gas) |
| GET | `/api/v1/wasm/version` | Gateway only. Version manifest of the browser WASM module |

## Blocks

| Method | Path | Notes |
|--------|------|-------|
| GET | `/api/v1/blocks` | `limit` (≤ 100, default 20), `offset`, `page`. Newest first |
| GET | `/api/v1/blocks/latest` | Gateway only. `{ "block": … }` |
| GET | `/api/v1/blocks/:height` | One block: `height`, `hash`, `parent_hash`, `proposer`, `tx_root`, `state_root`, `tx_count`, `gas_used`, `base_fee`, `fees_burned`, `shard`, `round`, `timestamp` |
| GET | `/api/v1/blocks/:height/transactions` | Transactions in the block |

## Transactions

| Method | Path | Signs for | Notes |
|--------|------|-----------|-------|
| POST | `/api/v1/transactions` | the transaction itself | Body below |
| GET | `/api/v1/transactions` | — | `address`, `hash`, `type` (`staking` to list staking operations), `limit` (≤ 200), `offset`, `page` |
| GET | `/api/v1/transactions/:hash` | — | One transaction with `status`, `gas`, `fee`, `fee_human`, `value_human` |
| GET | `/api/v1/tx/:hash/proof` | — | Merkle inclusion proof: `leaf_index`, `proof`, `tx_root`, `block_height` |
| POST | `/api/v1/transactions/:hash/confirm` | `neuro:system.trust` | Confirm a held transfer (owner's main key only) — see [Sentinel](/ai/sentinel) |
| POST | `/api/v1/transactions/:hash/cancel` | `neuro:system.trust` | Cancel a held transfer |
| GET | `/api/v1/held/:address` | — | Held transfers of an address |
| GET | `/api/v1/cross-shard/queue` | — | Cross-shard relays. `status`, `limit`, `offset` |

**`POST /api/v1/transactions` body**

| Field | Type | Required | Meaning |
|-------|------|----------|---------|
| `from` | string | yes | Sender address |
| `to` | string | yes | Recipient, contract, or `neuro:system.deploy` |
| `value` | number | yes | uNRO |
| `nonce` | number | yes | Next account nonce |
| `signature` | string | yes | ML-DSA-65 over `nc-tx-v2|from|to|value|nonce`, hex |
| `public_key` | string | yes | ML-DSA-65 public key, hex |
| `gas_price` | number | no | uNRO per gas unit; must be ≥ the base fee |
| `data` | string | no | Contract call or deploy as a JSON string (hex also accepted) — see [ABI](/build/abi), [Deploy](/build/deploy) |

Response: `tx_hash`, `status: "pending"`, `estimated_block`; plus `sentinel_score` and `sentinel_warning` when Sentinel flags it, or `held` details when the policy layer holds it.

## Accounts

| Method | Path | Notes |
|--------|------|-------|
| GET | `/api/v1/accounts/:address` | `balance`, `balance_human`, `nonce`, … |
| GET | `/api/v1/accounts/:address/transactions` | History. `limit`, `offset` |
| GET | `/api/v1/accounts/:address/token-transfers` | Token (NRC-20) transfers involving the address |
| GET | `/api/v1/accounts/:address/totals` | Node only. Totals sent and received |
| POST | `/api/v1/faucet` | Test networks only (`CHAIN_ENV=testnet`). Body: `address`, `public_key`, `amount` (uNRO, optional) |
| POST | `/api/v1/wallet/derive-address` | Body: `words`. Derives the `.human` address from a phrase — **sends the phrase to the server**. Off on mainnet; on test networks only with `NEUROCHAIN_ALLOW_SERVER_DERIVE=true` |

## Names and NFTs

| Method | Path | Signs for | Body / notes |
|--------|------|-----------|--------------|
| POST | `/api/v1/addresses/human` | `neuro:system.name` | Node only. `name`, `owner`, + signed fields. Registers a custom `.human` name |
| GET | `/api/v1/addresses/human/price` | — | Node only. `?name=` → price by length |
| POST | `/api/v1/nodes/register` | `neuro:system.node` | `name`, `owner`, optional `node_address` (to register `.app` / `.vault`), + signed fields |
| GET | `/api/v1/nodes` | — | Registered nodes |
| GET | `/api/v1/nodes/:address` | — | One node record |
| PUT/POST | `/api/v1/nodes/:address/profile` | `neuro:system.node` | `description`, `website`, `commission_bps`, `p2p_endpoint`, `rpc_endpoint` |
| POST | `/api/v1/nodes/:address/unjail` | `neuro:system.node` | Re-enter the set after the jail period (owner signs) |
| POST | `/api/v1/nft/transfer` | the NFT address | `nft_address`, `from` (current owner), `to`, + signed fields. Fee 100 uNRO |
| GET | `/api/v1/nft/:address` | — | NFT record and transfer history |
| GET | `/api/v1/nft/owner/:address` | — | NFTs owned by an address |
| POST | `/api/v1/agents/register` | `neuro:system.agent` | `name`, `owner`, + signed fields. Registers a `.agent` |
| GET | `/api/v1/agents/:address` | — | Agent record |

## Staking

| Method | Path | Signs for | Body / notes |
|--------|------|-----------|--------------|
| POST | `/api/v1/staking/stake` | `neuro:system.stake` | `address`, `amount`, + signed fields |
| POST | `/api/v1/staking/unstake` | `neuro:system.stake` | `address`, + signed fields |
| POST | `/api/v1/staking/delegate` | the validator address | `delegator`, `validator`, `amount`, + signed fields |
| POST | `/api/v1/staking/undelegate` | the validator address | `delegator`, `validator`, + signed fields |
| GET | `/api/v1/staking/info/:address` | — | Stake, lock, rewards of an address |
| GET | `/api/v1/staking/validators` | — | Validators with stake and delegations |
| GET | `/api/v1/staking/delegations/:validator` | — | Delegations to a validator |
| GET | `/api/v1/staking/my-delegations/:address` | — | Delegations made by an address |
| GET | `/api/v1/staking/rewards/:address` | — | Reward history; `source=stake|delegation|commission` |
| GET | `/api/v1/validators` | — | Consensus validators with `stake`, `trust_score`, `blocks_proposed`, `votes_cast`, `last_active` |
| GET | `/api/v1/slashing/history` | — | Node only. Slashes. `limit` |

See [Staking & delegation](/learn/staking).

## Governance

| Method | Path | Signs for | Body / notes |
|--------|------|-----------|--------------|
| POST | `/api/v1/governance/propose` | `neuro:system.governance` | `proposer`, `title`, `description`, `kind` (`text` / `PARAM_CHANGE`), `payload`, `voting_duration`, + signed fields |
| POST | `/api/v1/governance/:id/vote` | `neuro:system.governance` | `voter`, `accept` (bool), + signed fields |
| GET | `/api/v1/governance/proposals` | — | `status`, `limit` (≤ 100), `offset` |
| GET | `/api/v1/governance/:id` | — | One proposal with votes |
| GET | `/api/v1/governance/params` | — | Every parameter with value and description |

See [Governance](/learn/governance).

## Vaults (multi-signature)

| Method | Path | Signs for | Body / notes |
|--------|------|-----------|--------------|
| GET | `/api/v1/vault/:addr/config` | — | `threshold`, `members` |
| GET | `/api/v1/vault/:addr/proposals` | — | Payout proposals |
| GET | `/api/v1/vault/member/:addr` | — | Vaults an address belongs to |
| POST | `/api/v1/vault/:addr/proposals` | the vault address | `proposer`, `to`, `amount`, `description`, + signed fields |
| POST | `/api/v1/vault/:addr/proposals/:id/sign` | the vault address | `signer`, + signed fields. Pays out when signatures reach the threshold |
| POST | `/api/v1/vault/:addr/members` | the vault address | `member`, `requester`, + signed fields |
| POST | `/api/v1/vault/:addr/threshold` | the vault address | `threshold`, `requester`, + signed fields |

::: warning Experimental
Vault operations are currently applied by the node that receives the request, not in consensus. Use a single node for a vault until this moves into consensus.
:::

## Contracts

| Method | Path | Signs for | Body / notes |
|--------|------|-----------|--------------|
| GET | `/api/v1/contracts` | — | `owner`, `limit`, `offset` |
| GET | `/api/v1/contracts/:address` | — | Metadata, `security_score`, owner, code hash |
| GET | `/api/v1/contracts/:address/token-info` | — | Gateway only. NRC-20 name, symbol, decimals, supply |
| POST | `/api/v1/contracts/:address/call` | — | `function`, `args`, `dry_run`, `gas_limit`, `caller`. Read with `dry_run: true`; writes refused on mainnet |
| POST | `/api/v1/contracts/deploy` | `neuro:system.deploy` | Node only. `owner`, `bytecode_hex` or `base64_wasm`, `name`, `description`, `template`, + signed fields |
| POST | `/api/v1/contracts/analyze` | — | Node only. `bytecode_hex` → `risk_score`, `security_score`, `ml_score`, `model`, `violations` |
| POST | `/api/v1/contracts/attest` | — | `bytecode_hex` → analysis signed with ML-DSA-65: `score`, `bytecode_hash`, `timestamp`, `signature`, `pubkey` |
| POST | `/api/v1/contracts/audit` | — | Gateway only. `bytecode_hex` → node analysis (source code is not accepted) |
| POST | `/api/v1/contracts/reaudit` | — | Gateway only. `address` → re-run analysis of a deployed contract |
| POST | `/api/v1/contracts/generate` | — | Gateway only. Contract template generation (SmartForge) |
| POST | `/api/v1/contracts/certify` | `neuro:system.cert` | Issue a security certificate (VMGuardian operator) |
| POST | `/api/v1/contracts/whitelist` | `neuro:system.whitelist` | Node only. `bytecode_hash` — trusted template bytecode |
| PATCH | `/api/v1/contracts/:address/score` | `neuro:system.score` | Node only. `security_score` |
| GET | `/api/v1/certificates` | — | `owner`, `limit`, `offset` |
| GET | `/api/v1/certificates/:id` | — | One certificate |
| GET | `/api/v1/certificates/contract/:address` | — | Certificate of a contract |
| GET | `/api/v1/templates` | — | Registered contract templates |
| GET | `/api/v1/templates/:id` | — | One template with ABI |
| POST | `/api/v1/templates/register` | `neuro:system.templates` | `author` (a `.node`), `name`, `description`, `category`, `bytecode_hex`, `abi_json`, `fee_unro`, + signed fields |
| POST | `/api/v1/templates/deprecate` | `neuro:system.templates` | Node only. `template_id`, `author`, `delete`, + signed fields |

## AI and models

| Method | Path | Notes |
|--------|------|-------|
| GET | `/api/v1/ai/status` | Gateway only. Status of the AI models |
| POST | `/api/v1/sentinel/score` | Score a transaction shape: `value`, `gas_price`, `nonce`, `last_nonce`, `balance`, `tx_count_last_10`, `recipient_tx_count`, `is_self_transfer` → `score`, `anomalous`, `category` |
| GET | `/api/v1/oracle/log` | AI decision log. `model`, `kind`, `subject`, `limit`, `offset` |
| GET | `/api/v1/oracle/log/:id` | One decision |
| GET | `/api/v1/models/registry` | On-chain model registry. `limit`, `offset` |
| GET | `/api/v1/models/registry/:id` | One model version |
| POST | `/api/v1/models/register` | Validators only; signs for `neuro:models.registry`. `from`, `name`, `version`, `weights_hash`, `architecture`, `params_count`, `accuracy`, + signed fields |
| GET | `/api/v1/ai/export/{blocks,txs,validators,oracle}` | Training-data export (JSON Lines) |
| POST | `/api/v1/assistant/ask`, GET `/api/v1/assistant/health` | Gateway only. Documentation assistant (off unless `ASSISTANT_ENABLED=1`) |

## Sentinel trust list

| Method | Path | Signs for | Body |
|--------|------|-----------|------|
| POST | `/api/v1/trust/add` | `neuro:system.trust` | `owner`, `recipient`, + signed fields |
| POST | `/api/v1/trust/remove` | `neuro:system.trust` | `owner`, `recipient`, + signed fields |
| GET | `/api/v1/trust/:owner` | — | Trusted recipients, with activation height |

## Account abstraction

| Method | Path | Signs for | Body |
|--------|------|-----------|------|
| POST | `/api/v1/session/grant` | `neuro:system.session` | `account`, `session_pk`, `scope`, `cap`, `expiry_block`, + signed fields |
| POST | `/api/v1/session/revoke` | `neuro:system.session` | `account`, `session_pk`, + signed fields |
| GET | `/api/v1/session/list/:account` | — | Session keys of an account |
| POST | `/api/v1/sponsor/deposit` | `neuro:system.sponsor` | `address`, `amount`, + signed fields |
| POST | `/api/v1/sponsor/withdraw` | `neuro:system.sponsor` | `address`, `amount`, + signed fields |
| GET | `/api/v1/sponsor/:address` | — | Sponsor pool balance |

See [Account abstraction](/ai/account-abstraction).

## Identity and recovery

These sign their own messages (for example `nc-rotate|addr|add|remove|nonce`) rather than `nc-tx-v2`; see [Identity](/ai/identity).

| Method | Path | Body |
|--------|------|------|
| POST | `/api/v1/identity/rotate` | `owner`, `add`, `remove`, + signed fields |
| POST | `/api/v1/identity/recovery/setup` | `owner`, `guardians`, `threshold`, `timelock`, + signed fields |
| POST | `/api/v1/identity/recovery/request` | `target`, `new_key`, + signed fields |
| POST | `/api/v1/identity/recovery/approve` | `target`, `guardian`, + signed fields |
| POST | `/api/v1/identity/recovery/reject` | `target`, `guardian`, + signed fields |
| POST | `/api/v1/identity/recovery/withdraw` | `target`, + signed fields |
| POST | `/api/v1/identity/recovery/cancel` | `owner`, + signed fields |
| GET | `/api/v1/identity/:addr` | Keys and version |
| GET | `/api/v1/identity/recovery/:addr` | Recovery configuration and any open request |
| GET | `/api/v1/identity/guardian-of/:addr` | Identities this address guards |

## Native assets and exchange

| Method | Path | Body / notes |
|--------|------|--------------|
| GET | `/api/v1/assets` | Issued assets |
| GET | `/api/v1/assets/:id` | One asset |
| GET | `/api/v1/assets/check-symbol` | `?symbol=` — is the ticker free and valid |
| GET | `/api/v1/assets/balances/:addr` | Asset balances |
| POST | `/api/v1/assets/issue` | `from`, `name`, `symbol`, `decimals`, `initial`, `max_supply`, `reissuable`, `reissue_unlock_height`, `issue_nonce`, + signed fields. Fee `asset_issue_fee` |
| POST | `/api/v1/assets/transfer` | `from`, `to`, `asset_id`, `amount`, + signed fields |
| GET | `/api/v1/dex/pools`, `/api/v1/dex/pools/:id` | Pools |
| POST | `/api/v1/dex/pools` | `from`, `asset_x`, `asset_y`, `amount_x`, `amount_y`, + signed fields |
| POST | `/api/v1/dex/liquidity/add` | `from`, `pool_id`, `max_a`, `max_b`, + signed fields |
| POST | `/api/v1/dex/liquidity/remove` | `from`, `pool_id`, `shares`, + signed fields |
| GET | `/api/v1/dex/quote` | Swap quote |
| POST | `/api/v1/dex/swap` | `from`, `pool_id`, `asset_in`, `amount_in`, `min_out`, `deadline_height`, + signed fields. Cleared in a batch when the next block commits |
| GET | `/api/v1/dex/window` | Current batch window |
| POST | `/api/v1/dex/deposit`, `/api/v1/dex/withdraw` | Move funds between the main balance and the exchange balance |
| GET | `/api/v1/dex/balances/:addr`, `/dex/positions/:addr`, `/dex/activity/:addr`, `/dex/transactions` | Exchange balances, LP positions, activity |

All asset and exchange operations sign for `neuro:system.assets` and are applied in consensus.

::: warning Test networks only for now
In consensus, these operations also require a second signature over the exact payload (`_psig`, message `nc-asset-op-v1|op|from|fields|nonce`) when the node runs with `CHAIN_ENV=mainnet`. The REST endpoints do not accept that signature yet, so on mainnet every asset and exchange operation is refused; on `CHAIN_ENV=testnet` they apply without the payload check.
:::

## IBC v2 <Badge type="warning" text="experimental" /> {#ibc-v2}

| Method | Path | Body / notes |
|--------|------|--------------|
| POST | `/api/v1/ibc/channel/open` | `from`, `channel`, `port`, `counterparty_chain`, `allowed_denoms`, + signed fields |
| POST | `/api/v1/ibc/channel/pause` | `from`, `channel`, `paused`, + signed fields |
| POST | `/api/v1/ibc/transfer` | `from`, `channel`, `dest_chain`, `receiver`, `denom`, `amount`, + signed fields |
| POST | `/api/v1/ibc/recv` | `from`, `packet_id`, `receiver`, `denom`, `amount`, + signed fields |
| POST | `/api/v1/ibc/ack` | `from`, `id`, + signed fields |
| POST | `/api/v1/ibc/redeem` | `from`, `channel`, `dest_chain`, `receiver`, `denom`, `amount`, + signed fields |
| POST | `/api/v1/ibc/client/update`, `/api/v1/ibc/attest` | Light-client update and attestation (relayer) |
| GET | `/api/v1/ibc/channels`, `/ibc/packets`, `/ibc/denoms`, `/ibc/client/:chainId`, `/ibc/header/latest`, `/ibc/voucher/:addr`, `/ibc/pq/test-vector` | State and test vectors |

All IBC v2 operations sign for `neuro:system.ibc`; `recv`, `ack`, channel and client operations are limited to IBC operator keys. See [IBC v2 & sharding](/operate/ibc).
