diff --git a/src/content/docs/developer/integrations/http-api.md b/src/content/docs/developer/integrations/http-api.md
index 5415fbb..1a2ff1d 100644
--- a/src/content/docs/developer/integrations/http-api.md
+++ b/src/content/docs/developer/integrations/http-api.md
@@ -1,18 +1,18 @@
---
title: HTTP API
-description: Query nodes, broadcast transactions, and subscribe to real-time events using RUES over HTTP and WebSocket.
+description: Query chain data, call contracts, broadcast transactions, and subscribe to node events over HTTP and WebSocket.
---
:::tip[Prefer W3sper First]
For application integrations, prefer the [W3sper SDK](/developer/integrations/w3sper). It wraps transaction building, proving, submission, and common node interactions.
:::
-The Rusk Universal Event System (RUES) is the public interface exposed by Dusk nodes.
+Dusk nodes expose two main low-level HTTP surfaces:
-This page covers the common low-level HTTP and WebSocket surface. Treat it as an implementation guide, not as a frozen protocol spec.
+- **GraphQL** for chain, block, transaction, mempool, archive, and other node-indexed queries.
+- **RUES-style `/on/...` routes** for transaction submission, contract calls, node operations, proof generation, driver management, and event subscriptions.
-- Use **HTTP `POST`** for request/response calls (query node state, submit transactions, generate proofs, etc.).
-- Use **WebSocket + HTTP `GET`/`DELETE`** for real-time event subscriptions.
+Use this page as an implementation guide for direct node integrations. Application code should normally use W3sper or another SDK layer unless it needs low-level node access.
You can also [download the Postman collection](/dusk_api_postman_collection.json) and import it into Postman.
@@ -23,9 +23,19 @@ You can also [download the Postman collection](/dusk_api_postman_collection.json
All endpoints below are relative to one of these base URLs.
+## Choosing the Right Surface
+
+Use **GraphQL** when you need chain, block, transaction, mempool, archive, or other node-indexed data that is not part of a contract ABI.
+
+Use **`/on/contracts:/`** when you are querying a method exposed by a contract ABI.
+
+Use **other `/on/...` routes** for node operations such as transaction submission, proof generation, driver management, and event subscriptions.
+
+Some legacy `/on/...` shortcut routes still work for compatibility, but are deprecated. Prefer the replacement routes documented below.
+
## Request and Response Encoding
-RUES endpoints accept both binary and text payloads.
+RUES-style `/on/...` endpoints accept both binary and text payloads.
### Request body
@@ -41,49 +51,121 @@ Some endpoints return binary data. By default, binary responses are returned as
- To force a raw binary response, set `Accept: application/octet-stream`.
-## Version Headers (Optional)
+## Version Headers
Nodes include a `Rusk-Version` header in responses.
Clients can optionally send:
-- `Rusk-Version`: a semver requirement string (example: `^1.4.0`).
+- `Rusk-Version`: a semver requirement string, for example `^1.4.0`.
- `Rusk-Version-Strict`: if present, the node requires `Rusk-Version` and performs a strict version check.
If the requested version is incompatible, the node rejects the request.
## GraphQL Queries
-**Endpoint**: `/on/graphql/query`
-**Method**: `POST`
-**Body**: a GraphQL query string.
+**Endpoint**: `/graphql`
+**Method**: `POST`
+**Body**: a GraphQL-over-HTTP JSON request.
+
+Use GraphQL for chain, block, transaction, mempool, archive, and other node-indexed data.
:::note
Archive-only GraphQL fields such as `moonlightHistory`, `fullMoonlightHistory`, and `finalizedEvents` require an archive-enabled node.
:::
-### Get the schema (SDL)
+### Query example: latest block
-Send an empty body to retrieve the schema:
+```sh
+curl -s -X POST "https://nodes.dusk.network/graphql" \
+ -H "Content-Type: application/json" \
+ --data-raw '{"query":"{ block(height: -1) { header { height hash } } }"}' | jq .
+```
+
+### Query example: with variables
```sh
-curl -s -X POST "https://nodes.dusk.network/on/graphql/query"
+curl -s -X POST "https://nodes.dusk.network/graphql" \
+ -H "Content-Type: application/json" \
+ --data-raw '{
+ "query": "query ($height: Int!) { block(height: $height) { header { height hash } } }",
+ "variables": { "height": -1 }
+ }' | jq .
```
-### Query example: latest block
+### Legacy raw-query endpoint
+
+`POST /on/graphql/query` is the legacy RUES GraphQL route. It accepts a raw GraphQL query string, and an empty body returns the schema SDL.
+
+Prefer `/graphql` for new integrations.
```sh
curl -s -X POST "https://nodes.dusk.network/on/graphql/query" \
- --data-raw 'query { block(height: -1) { header { height hash } } }'
+ --data-raw 'query { block(height: -1) { header { height hash } } }' | jq .
```
-:::note
-GraphQL variables can be passed via request headers using the prefix `rusk-gqlvar-`, for example: `rusk-gqlvar-height: 123`.
-:::
+Legacy GraphQL variables can be passed through request headers using the `rusk-gqlvar-` prefix, for example `rusk-gqlvar-height: 123`.
+
+## Route Model and Deprecated Shortcuts
+
+New integrations should avoid legacy shortcut routes when the same data is available through GraphQL, a contract ABI query, or contract metadata.
+
+### Current route model
+
+- `/graphql` is the canonical GraphQL endpoint for chain, mempool, block, transaction, and archive queries.
+- `/on/contracts:/` is the contract ABI query/call surface.
+ - `POST` executes a read/query call.
+ - `GET` and `DELETE` on the same path subscribe and unsubscribe from contract events, using `Rusk-Session-Id`.
+ - With `Content-Type: application/json`, Rusk uses the contract data driver to encode input and decode output.
+- `/on/contract:/` is the contract metadata and driver-management surface.
+ - Common topics: `metadata`, `download_driver`, and `upload_driver`.
+- `/on/driver:/` is the data-driver utility surface.
+
+### Deprecated routes
+
+The following routes still work, but emit deprecation headers and are scheduled for removal:
+
+- `/on/account:/status`
+- `/on/contract:/status`
+- `/on/contract_owner:/`
+
+Deprecated responses include:
+
+```text
+deprecation: true
+deprecation-note: This endpoint is deprecated and scheduled for removal
+```
+
+`/on/contract_owner:/` also advertises its successor:
+
+```text
+Link: /metadata>; rel="successor-version"
+```
+
+### Migration summary
+
+| Deprecated route | Use instead | Notes |
+|---|---|---|
+| `/on/account:/status` | `POST /on/contracts:0100000000000000000000000000000000000000000000000000000000000000/account` | Returns committed `balance` and `nonce`. It does not return the old mempool-aware `next_nonce`. |
+| `/on/contract:/status` | `POST /on/contracts:0100000000000000000000000000000000000000000000000000000000000000/contract_balance` | Returns the scalar balance directly instead of `{ "balance": ... }`. |
+| `/on/contract_owner:/` | `POST /on/contract:/metadata` | Read `contract_owner` from the metadata response. The legacy `{topic}` segment was ignored. |
+
+The transfer genesis contract ID used for account and contract-balance queries is:
+
+```text
+0100000000000000000000000000000000000000000000000000000000000000
+```
+
+To inspect the transfer contract query surface directly, use its data driver schema:
+
+```sh
+curl -s -X POST \
+ "https://nodes.dusk.network/on/driver:0100000000000000000000000000000000000000000000000000000000000000/get_schema" | jq .
+```
## Common HTTP Endpoints
-All endpoints below are **HTTP `POST`** calls.
+All endpoints in this section are **HTTP `POST`** calls.
### Node
@@ -99,20 +181,22 @@ curl -s -X POST "https://nodes.dusk.network/on/node/info" | jq .
### Network
-- **Peers** (request body: number of peers): `/on/network/peers`
+- **Peers**: `/on/network/peers`
+ - Request body: number of peers to return.
- **Peers Location**: `/on/network/peers_location`
Example:
```sh
-curl -s -X POST "https://nodes.dusk.network/on/network/peers" --data-raw '5' | jq .
+curl -s -X POST "https://nodes.dusk.network/on/network/peers" \
+ --data-raw '5' | jq .
```
### Gas and Fees
- **Gas Price Statistics**: `/on/blocks/gas-price`
-Optional request body: max number of mempool transactions to consider (defaults to all).
+Optional request body: max number of mempool transactions to consider. Defaults to all.
```sh
curl -s -X POST "https://nodes.dusk.network/on/blocks/gas-price" | jq .
@@ -120,15 +204,13 @@ curl -s -X POST "https://nodes.dusk.network/on/blocks/gas-price" | jq .
### Transactions
-- **Preverify** (validate tx without broadcasting): `/on/transactions/preverify`
-- **Propagate** (broadcast tx): `/on/transactions/propagate`
-- **Simulate** (estimate gas): `/on/transactions/simulate`
+- **Preverify**: `/on/transactions/preverify`
+- **Propagate**: `/on/transactions/propagate`
+- **Simulate**: `/on/transactions/simulate`
-:::note[Important]
-For `preverify`, `propagate` and `simulate`, send the serialized transaction as bytes (for example as a `0x...` hex string).
-:::
+For `preverify`, `propagate`, and `simulate`, send the serialized transaction as bytes, for example as a `0x...` hex string.
-Example (format only; replace with a real tx):
+Example format:
```sh
curl -s -X POST "https://nodes.dusk.network/on/transactions/preverify" \
@@ -137,41 +219,113 @@ curl -s -X POST "https://nodes.dusk.network/on/transactions/preverify" \
### Accounts
-- **Account Status**: `/on/account:/status`
+:::warning[Deprecated shortcut]
+`/on/account:/status` is deprecated. Use the transfer contract `account` query instead.
+:::
+
+Use the transfer genesis contract to query committed account state:
+
+**Endpoint**: `/on/contracts:0100000000000000000000000000000000000000000000000000000000000000/account`
+
+```sh
+curl -s -X POST \
+ "https://nodes.dusk.network/on/contracts:0100000000000000000000000000000000000000000000000000000000000000/account" \
+ -H "Content-Type: application/json" \
+ --data-raw '""' | jq .
+```
-Returns:
+Response:
```json
-{ "balance": 0, "nonce": 0, "next_nonce": 1 }
+{
+ "nonce": "7",
+ "balance": "1000"
+}
```
-Example:
+The deprecated account shortcut also returned `next_nonce`. That value was derived from pending mempool transactions and has no exact one-call successor.
+
+For most clients, use `Number(nonce) + 1`. If you need mempool-aware nonce allocation, derive it client-side using GraphQL mempool data.
+
+### Contracts
+
+#### Contract ABI calls
+
+To query a contract method:
+
+**Endpoint**: `/on/contracts:/`
+**Method**: `POST`
+
+- If you send `Content-Type: application/octet-stream`, the request body is treated as raw bytes.
+- If you send `Content-Type: application/json`, and the node has a data driver for the contract, the request body is treated as JSON input and encoded automatically.
+
+Example format:
```sh
-curl -s -X POST "https://nodes.dusk.network/on/account:/status" | jq .
+curl -s -X POST \
+ "https://nodes.dusk.network/on/contracts:/" \
+ -H "Content-Type: application/json" \
+ --data-raw '' | jq .
```
-### Contracts
+#### Contract metadata and drivers
-- **Contract Balance**: `/on/contract:/status`
- **Contract Metadata**: `/on/contract:/metadata`
- **Download Data Driver**: `/on/contract:/download_driver`
-- **Upload Data Driver**: `/on/contract:/upload_driver` (requires a `sign` header)
+- **Upload Data Driver**: `/on/contract:/upload_driver`
+ - Requires a `sign` header.
-#### Contract Calls (Queries)
+The deprecated `/on/contract_owner:/` route has been replaced by contract metadata. Read `contract_owner` from the metadata response.
-To query a contract method:
+Example:
+
+```sh
+curl -s -X POST \
+ "https://nodes.dusk.network/on/contract:/metadata" | jq .
+```
-**Endpoint**: `/on/contracts:/`
+Example response:
-- If you send `Content-Type: application/octet-stream`, the request body is treated as raw bytes.
-- If you send `Content-Type: application/json` and the node has a data driver for the contract, the request body is treated as JSON input and encoded automatically.
+```json
+{
+ "owner": "",
+ "contract_owner": "",
+ "driver_available": true,
+ "driver_signature": "",
+ "created_at": null
+}
+```
+
+#### Contract balance
+
+:::warning[Deprecated shortcut]
+`/on/contract:/status` is deprecated. Use the transfer contract `contract_balance` query instead.
+:::
+
+Use the transfer genesis contract to query a contract balance:
+
+**Endpoint**: `/on/contracts:0100000000000000000000000000000000000000000000000000000000000000/contract_balance`
+
+```sh
+curl -s -X POST \
+ "https://nodes.dusk.network/on/contracts:0100000000000000000000000000000000000000000000000000000000000000/contract_balance" \
+ -H "Content-Type: application/json" \
+ --data-raw '""'
+```
+
+Replacement response:
+
+```json
+"123456"
+```
+
+The replacement route returns the scalar balance value directly. The deprecated route wrapped that same value as `{ "balance": ... }`.
-#### Data Drivers
+#### Data drivers
-Drivers allow encoding/decoding contract data.
+Drivers allow encoding and decoding contract data.
-**Endpoint**: `/on/driver:/[:]`
+**Endpoint**: `/on/driver:/`
Common methods:
@@ -182,6 +336,13 @@ Common methods:
- `decode_output_fn:`
- `decode_event:`
+Example:
+
+```sh
+curl -s -X POST \
+ "https://nodes.dusk.network/on/driver:/get_schema" | jq .
+```
+
### Blobs
- **Blob by commitment**: `/on/blobs:/commitment`
@@ -189,66 +350,87 @@ Common methods:
To retrieve a JSON sidecar instead of raw bytes, set `Content-Type: application/json`.
+Example:
+
+```sh
+curl -s -X POST \
+ "https://nodes.dusk.network/on/blobs:/hash" \
+ -H "Content-Type: application/json" | jq .
+```
+
### Stats
-- **Active public accounts (archive)**: `/on/stats/account_count`
-- **Finalized tx count (archive)**: `/on/stats/tx_count`
+Archive-enabled nodes expose:
+
+- **Active public accounts**: `/on/stats/account_count`
+- **Finalized transaction count**: `/on/stats/tx_count`
+
+Example:
+
+```sh
+curl -s -X POST "https://nodes.dusk.network/on/stats/tx_count" | jq .
+```
## Prover Endpoints
- **Prove**: `/on/prover/prove`
-Send proof input as bytes (for example as a `0x...` hex string). The response is proof bytes (binary).
+Send proof input as bytes, for example as a `0x...` hex string. The response is proof bytes.
+
+```sh
+curl -s -X POST "https://nodes.dusk.network/on/prover/prove" \
+ --data-raw '0x...' \
+ --output proof.bin
+```
## Event Subscriptions
-Subscriptions are a 2-step process:
+Subscriptions are a two-step process:
1. Open a WebSocket connection to `wss:///on`.
-2. Use the session ID from that WebSocket to `GET`/`DELETE` subscriptions over HTTP.
+2. Use the session ID from that WebSocket to `GET` or `DELETE` subscriptions over HTTP.
### WebSocket session
Connect to:
-```
+```text
wss://nodes.dusk.network/on
```
-The node sends the **session ID as the first WebSocket text message** (16 bytes, hex-encoded). Use that value in the `Rusk-Session-Id` header.
+The node sends the **session ID as the first WebSocket text message**. Use that value in the `Rusk-Session-Id` header.
### Event URI format
-```
+```text
/on/[:]/
```
-- `component` and `topic` are case-insensitive (normalized to lowercase).
-- `entity` is optional for `blocks` and `transactions` (wildcard subscription), but required for `contracts`.
+- `component` and `topic` are case-insensitive and normalized to lowercase.
+- `entity` is optional for `blocks` and `transactions`, which allows wildcard subscriptions.
+- `entity` is required for `contracts`.
Common topics:
- `blocks`: `accepted`, `statechange`, `reverted`
- `transactions`: `included`, `removed`, `executed`
-- `contracts`: contract-specific event topics (emitted event names)
+- `contracts`: contract-specific event topics, usually emitted event names
Examples:
- All accepted blocks: `/on/blocks/accepted`
- A specific block: `/on/blocks:/accepted`
-- All executed txs: `/on/transactions/executed`
+- All executed transactions: `/on/transactions/executed`
- Contract events: `/on/contracts:/`
-### Subscribe / Unsubscribe
-
-Subscribe:
+### Subscribe
```sh
curl -i -X GET "https://nodes.dusk.network/on/blocks/accepted" \
-H "Rusk-Session-Id: "
```
-Unsubscribe:
+### Unsubscribe
```sh
curl -i -X DELETE "https://nodes.dusk.network/on/blocks/accepted" \
@@ -257,15 +439,16 @@ curl -i -X DELETE "https://nodes.dusk.network/on/blocks/accepted" \
On success, the node returns `200 OK` with an empty body. Events are delivered over the WebSocket connection.
-If the session ID is missing/invalid, the node returns `424 Failed Dependency`.
+If the session ID is missing or invalid, the node returns `424 Failed Dependency`.
-## Event Payload Format (WebSocket)
+## Event Payload Format
Events are sent as WebSocket **binary messages**:
1. `u32` little-endian: length of the JSON header.
-2. JSON header bytes (includes `Content-Location`).
-3. Raw event data bytes (format depends on the event).
+2. JSON header bytes, including `Content-Location`.
+3. Raw event data bytes. The format depends on the event.
If you need historical data, use an archive-enabled node and GraphQL queries such as `moonlightHistory`, `fullMoonlightHistory`, and `finalizedEvents`.
+
See: [Retrieve historical events](/developer/integrations/historical_events).