# JSON-RPC API

The Fast network exposes a JSON-RPC 2.0 API through its proxy service. This is the low-level interface that the SDK uses internally. Most developers should use the SDK instead — it handles serialization, signing, and error recovery automatically.

This page is for developers who need direct access to the protocol-level endpoints.

***

### Endpoints

<table><thead><tr><th width="105.70703125">Network</th><th width="639.171875">Proxy RPC</th></tr></thead><tbody><tr><td><strong>Mainnet</strong></td><td><code>https://api.fast.xyz/proxy</code></td></tr><tr><td><strong>Testnet</strong></td><td><code>https://testnet.api.fast.xyz/proxy</code></td></tr></tbody></table>

<table><thead><tr><th width="105.70703125">Network</th><th width="155.9609375">Fee Token Name</th><th>Token ID</th></tr></thead><tbody><tr><td><strong>Mainnet</strong></td><td><code>USDC</code></td><td><a href="https://explorer.fast.xyz/asset/0xc655a12330da6af361d281b197996d2bc135aaed3b66278e729c2222291e9130">c655a12330da6af361d281b197996d2bc135aaed3b66278e729c2222291e9130</a></td></tr><tr><td><strong>Testnet</strong></td><td><code>testUSDC</code></td><td><a href="https://testnet.explorer.fast.xyz/asset/0xd73a0679a2be46981e2a8aedecd951c8b6690e7d5f8502b34ed3ff4cc2163b46">d73a0679a2be46981e2a8aedecd951c8b6690e7d5f8502b34ed3ff4cc2163b46</a></td></tr></tbody></table>

All requests are `POST` with `Content-Type: application/json`.

#### Request

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "<method_name>",
  "params": { ... }
}
```

#### Responses

All responses have HTTP code 200. Success and error responses are differentiated by their structure.

Success Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    ...
  }
}
```

Error Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": "<error_code>",
    "message": "<error_message>",
    "data": "<additional_data>"
  }
}
```

***

### Methods

| Method                    | Purpose                                                         |
| ------------------------- | --------------------------------------------------------------- |
| `proxy_submitTransaction` | Submit a signed transaction — returns a certificate on success  |
| `proxy_getAccountInfo`    | Query account balance, nonce, token holdings, and certificates  |
| `proxy_getTokenInfo`      | Look up token metadata (name, decimals, supply, admin, minters) |

***

#### `proxy_submitTransaction`

Submit a signed transaction to the network. The proxy handles the full settlement lifecycle: it broadcasts the transaction to all validators, collects their signatures, assembles a certificate once quorum is reached, and submits the certificate back to validators for settlement.

**Parameters:**

| Field         | Type                  | Description                                           |
| ------------- | --------------------- | ----------------------------------------------------- |
| `transaction` | `Transaction`         | The transaction to submit                             |
| `signature`   | `SignatureOrMultiSig` | Ed25519 signature over the BCS-serialized transaction |

**Returns:** `ProxySubmitTransactionResult`

* `{ "Success": TransactionCertificate }` — transaction settled, certificate returned
* `{ "IncompleteMultiSig": [...] }` — multisig transaction stored, awaiting additional signatures

<details>

<summary>Example request</summary>

```bash
curl -X POST 'https://testnet.api.fast.xyz/proxy' \
  --header 'Content-Type: application/json' \
  --data '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "proxy_submitTransaction",
    "params": {
      "transaction": {
        "network_id": "fast:testnet",
        "sender": [54,128,54,206,88,243,124,101,147,238,105,180,78,172,190,12,193,195,118,236,177,124,79,251,192,63,114,196,255,73,74,81],
        "nonce": 0,
        "timestamp_nanos": 1769705752161000000,
        "claim": {
          "TokenTransfer": {
            "recipient": [75,164,223,195,221,101,117,31,251,60,194,50,41,1,83,17,79,28,61,165,140,36,12,127,122,60,161,218,118,145,112,210],
            "token_id": [250,87,94,112,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
            "amount": "ffff",
            "user_data": null
          }
        },
        "archival": false
      },
      "signature": {
        "Signature": [228,162,180,83,46,167,133,230,176,100,60,110,57,65,23,113,101,204,242,193,125,59,88,232,122,6,90,118,41,159,94,108,20,181,224,234,57,42,35,95,4,186,62,128,68,213,212,46,214,155,241,163,147,120,155,69,201,1,29,63,106,22,75,15]
      }
    }
  }'
```

</details>

<details>

<summary>Example response</summary>

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "Success": {
      "envelope": {
        "transaction": {
          "network_id": "fast:mainnet",
          "sender": [54,128,54,206,...],
          "nonce": 0,
          "timestamp_nanos": 1769705752161000000,
          "claim": {
            "TokenTransfer": {
              "recipient": [75,164,223,195,...],
              "token_id": [250,87,94,112,0,...],
              "amount": "ffff",
              "user_data": null
            }
          },
          "archival": false
        },
        "signature": {
          "Signature": [228,162,180,83,...]
        }
      },
      "signatures": [
        [[223,165,168,37,...], [95,227,196,114,...]],
        [[236,249,103,252,...], [80,65,124,70,...]],
        [[150,20,92,12,...], [26,229,199,218,...]]
      ]
    }
  }
}
```

</details>

***

#### `proxy_getAccountInfo`

Query account information from a validator known to the proxy.

**Parameters:**

| Field                   | Type                        | Description                                                           |
| ----------------------- | --------------------------- | --------------------------------------------------------------------- |
| `address`               | `Array<uint8; 32>`          | The account's Ed25519 public key                                      |
| `token_balances_filter` | `Array<TokenId>` or `null`  | Which token balances to return. `null` = none; `[]` = all tokens held |
| `state_key_filter`      | `Array<StateKey>` or `null` | Which state fields to return. `null` = none; `[]` = all               |
| `certificate_by_nonce`  | `NonceRange` or `null`      | Currently not unabled                                                 |

**Returns:** `AccountInfoResponse`

<details>

<summary>Example request</summary>

```bash
curl -X POST 'https://testnet.api.fast.xyz/proxy' \
  --header 'Content-Type: application/json' \
  --data '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "proxy_getAccountInfo",
    "params": {
      "address": [54,128,54,206,88,243,124,101,147,238,105,180,78,172,190,12,193,195,118,236,177,124,79,251,192,63,114,196,255,73,74,81],
      "token_balances_filter": [],
      "state_key_filter": null,
      "certificate_by_nonce": null
    }
  }'
```

</details>

<details>

<summary>Example response</summary>

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "sender": [54,128,54,206,...],
    "balance": "de0b6b3a7640000",
    "next_nonce": 3,
    "pending_confirmation": null,
    "requested_state": [],
    "requested_certificates": null,
    "requested_validated_transaction": null,
    "token_balance": [
      [[250,87,94,112,0,...], "de0b6b3a7640000"]
    ]
  }
}
```

</details>

***

#### `proxy_getTokenInfo`

Look up metadata for one or more tokens.

**Parameters:**

| Field       | Type                      | Description          |
| ----------- | ------------------------- | -------------------- |
| `token_ids` | `Array<Array<uint8; 32>>` | Token IDs to look up |

**Returns:** `TokenInfoResponse`

<details>

<summary>Example request</summary>

```bash
curl -X POST 'https://testnet.api.fast.xyz/proxy' \
  --header 'Content-Type: application/json' \
  --data '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "proxy_getTokenInfo",
    "params": {
      "token_ids": [
        [250,87,94,112,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
      ]
    }
  }'
```

</details>

<details>

<summary>Example response</summary>

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "requested_token_metadata": [
      [
        [250,87,94,112,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        {
          "update_id": 0,
          "admin": [0,0,...],
          "token_name": "SET",
          "decimals": 18,
          "total_supply": "52b7d2dcc80cd2e4000000",
          "mints": []
        }
      ]
    ]
  }
}
```

</details>

***

### Transaction Signing

To submit a transaction, you must sign it locally before sending it to the proxy.

#### 1. Serialize

Serialize the `Transaction` struct using [BCS (Binary Canonical Serialization)](https://github.com/zefchain/bcs).

BCS libraries:

* **TypeScript/JavaScript:** [`@mysten/bcs`](https://www.npmjs.com/package/@mysten/bcs)
* **Rust:** [`bcs`](https://github.com/zefchain/bcs) (as a `serde` backend)

**Special rule:** Numerical string fields (`Amount` / `Balance`) are encoded as little-endian unsigned 256-bit integers (32 bytes) during BCS serialization.

#### 2. Prefix

Prepend the UTF-8 string `"Transaction::"` to the serialized bytes.

#### 3. Sign

Sign the prefixed bytes with Ed25519 using the sender's private key:

```
signature = ed25519_sign(private_key, "Transaction::" + BCS(transaction))
```

#### 4. Hash

The transaction hash is the keccak256 digest of the BCS-serialized transaction (without the prefix):

```
tx_hash = keccak256(BCS(transaction))
```

#### 5. Submit

Wrap the signature in a `SignatureOrMultiSig` envelope and call `proxy_submitTransaction`.

***

### Data Encoding

| Concept                   | Format                                                         | Example                     |
| ------------------------- | -------------------------------------------------------------- | --------------------------- |
| **Addresses**             | 32-byte Ed25519 public key, as JSON array of unsigned integers | `[54,128,54,206,...,74,81]` |
| **User-facing addresses** | bech32m with `fast` prefix (SDK only, not used in RPC)         | `fast1qxy2kgdy...`          |
| **Amounts**               | Hex-encoded unsigned 256-bit integer (no `0x` prefix)          | `"de0b6b3a7640000"`         |
| **Timestamps**            | `uint128` nanoseconds since Unix epoch                         | `1769705752161000000`       |
| **Nonces**                | `uint64`, auto-incrementing per account, starting at 0         | `0`, `1`, `2`, ...          |

***

### Data Types

#### Transaction

The core unit submitted to the network.

| Field             | Type                | Description                                                                           |
| ----------------- | ------------------- | ------------------------------------------------------------------------------------- |
| `network_id`      | `string`            | The id of the network (e.g., "fast:mainnet", "fast:testnet"). Follows CAIP-2 standard |
| `sender`          | `Array<uint8; 32>`  | Sender's Ed25519 public key                                                           |
| `nonce`           | `uint64`            | Sequence number — must match the account's `next_nonce`                               |
| `timestamp_nanos` | `uint128`           | Nanoseconds since Unix epoch                                                          |
| `claim`           | `ClaimType`         | The operation to perform                                                              |
| `archival`        | `boolean`           | Currently disabled                                                                    |
| `fee_token`       | `TokenId` or `null` | The fee token to use to pay for this transaction. See more details below.             |

> **Fee token**
>
> You can specify a `fee_token` field in your `Transaction` to indicate what token you want to pay the network fee with. If omitted, then the default token is used (currently USDC). Currently, only USDC is supported as the fee token. More tokens could be supported in the future.

#### ClaimType

Determines the operation packed into a transaction.

| Variant           | Type              | Description                                    |
| ----------------- | ----------------- | ---------------------------------------------- |
| `TokenTransfer`   | `TokenTransfer`   | Transfer tokens to the recipient               |
| `TokenCreation`   | `TokenCreation`   | Create a new custom token                      |
| `TokenManagement` | `TokenManagement` | Modify a custom token (admin, minters)         |
| `Mint`            | `Mint`            | Mint additional supply of a custom token       |
| `Burn`            | `Burn`            | Burn an amount of a custom token               |
| `ExternalClaim`   | `ExternalClaim`   | Submit arbitrary data with verifier signatures |
| `Batch`           | `OperationBundle` | Bundle multiple operations in one transaction  |

#### TokenTransfer

| Field       | Type                         | Description                      |
| ----------- | ---------------------------- | -------------------------------- |
| `recipient` | `Array<uint8; 32>`           | Recipient address                |
| `token_id`  | `Array<uint8; 32>`           | Token ID to transfer             |
| `amount`    | `Amount`                     | Amount in raw units (hex string) |
| `user_data` | `Array<uint8; 32>` or `null` | Optional arbitrary data          |

#### TokenCreation

| Field            | Type                         | Description                              |
| ---------------- | ---------------------------- | ---------------------------------------- |
| `token_name`     | `string`                     | Human-readable name                      |
| `decimals`       | `uint8`                      | Decimal places (0–18)                    |
| `initial_amount` | `Amount`                     | Initial supply, credited to the creator  |
| `mints`          | `Array<Array<uint8; 32>>`    | Addresses authorized to mint more supply |
| `user_data`      | `Array<uint8; 32>` or `null` | Optional arbitrary data                  |

The token ID is derived from the keccak256 hash of the BCS-serialized transaction that creates the token.

#### TokenManagement

| Field       | Type                                       | Description                                          |
| ----------- | ------------------------------------------ | ---------------------------------------------------- |
| `token_id`  | `Array<uint8; 32>`                         | Token to manage                                      |
| `update_id` | `uint64`                                   | Sequencing counter — must increment by 1 each update |
| `new_admin` | `Array<uint8; 32>` or `null`               | New admin address, or `null` to keep current         |
| `mints`     | `Array<[AddressChange, Array<uint8; 32>]>` | Minter addresses to add or remove                    |
| `user_data` | `Array<uint8; 32>` or `null`               | Optional arbitrary data                              |

`AddressChange` is either `{ "Add": [...] }` or `{ "Remove": [...] }`.

#### Mint

Sender must be an authorized minter for the token.

| Field       | Type               | Description       |
| ----------- | ------------------ | ----------------- |
| `recipient` | `Array<uint8; 32>` | Recipient address |
| `token_id`  | `Array<uint8; 32>` | Token to mint     |
| `amount`    | `Amount`           | Amount to mint    |

#### Burn

| Field      | Type               | Description    |
| ---------- | ------------------ | -------------- |
| `token_id` | `Array<uint8; 32>` | Token to burn  |
| `amount`   | `Amount`           | Amount to burn |

#### ExternalClaim

Submit arbitrary data verified by a set of external verifiers.

| Field                | Type                      | Description                              |
| -------------------- | ------------------------- | ---------------------------------------- |
| `verifier_committee` | `Array<Array<uint8; 32>>` | Verifier public keys                     |
| `verifier_quorum`    | `uint64`                  | Minimum verifier signatures required     |
| `claim_data`         | `Array<uint8>`            | Arbitrary data payload                   |
| `signatures`         | `Array<VerifierSig>`      | Verifier signatures over the transaction |

Each `VerifierSig` contains `verifier_addr` (public key) and `sig` (Ed25519 signature over the `Transaction` struct without verifier signatures).

#### OperationBundle

An array of `Operation` objects. Each `Operation` is one of: `TokenTransfer` (with explicit `recipient`), `TokenCreation`, `TokenManagement`, `ExternalClaim`, `Mint` (with explicit `recipient`), or `Burn`.

The `TokenTransfer` and `Mint` variants inside a bundle include a `recipient` field, since the bundle allows operations targeting different recipients within a single transaction.

***

#### Response Types

**AccountInfoResponse**

| Field                    | Type                                      | Description                                 |
| ------------------------ | ----------------------------------------- | ------------------------------------------- |
| `sender`                 | `Array<uint8; 32>`                        | Account address                             |
| `balance`                | `Balance`                                 | Native SET balance (hex string)             |
| `next_nonce`             | `uint64`                                  | Next valid nonce for this account           |
| `pending_confirmation`   | `ValidatedTransaction` or `null`          | Transaction validated but not yet confirmed |
| `requested_state`        | `Array<[StateKey, State]>`                | Requested state fields                      |
| `requested_certificates` | `Array<TransactionCertificate>` or `null` | Certificates in the requested nonce range   |
| `token_balance`          | `Array<[TokenId, Balance]>`               | Custom token balances                       |

**TokenInfoResponse**

| Field                      | Type                              | Description               |
| -------------------------- | --------------------------------- | ------------------------- |
| `requested_token_metadata` | `Array<[TokenId, TokenMetadata]>` | Token ID → metadata pairs |

`TokenMetadata` fields: `update_id`, `admin`, `token_name`, `decimals`, `total_supply`, `mints`.

**TransactionCertificate**

| Field        | Type                                 | Description                             |
| ------------ | ------------------------------------ | --------------------------------------- |
| `envelope`   | `TransactionEnvelope`                | The transaction + sender's signature    |
| `signatures` | `Array<[PublicKeyBytes, Signature]>` | Validator signatures forming the quorum |

`TransactionEnvelope` contains `transaction` (`Transaction`) and `signature` (`SignatureOrMultiSig`).

**ProxySubmitTransactionResult**

| Variant              | Payload                  | Description                                           |
| -------------------- | ------------------------ | ----------------------------------------------------- |
| `Success`            | `TransactionCertificate` | Transaction settled successfully                      |
| `IncompleteMultiSig` | `array`                  | Multisig transaction stored, awaiting more signatures |

***

#### Primitive Types

| Type                  | Format                                                               | Description                                                            |
| --------------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| `Amount`              | Hex string (unsigned 256-bit)                                        | Token amount in raw units. Example: `"de0b6b3a7640000"` = 10¹⁸ = 1 SET |
| `Balance`             | Hex string (signed 257-bit)                                          | Like Amount, but may be negative (prefixed with `-`)                   |
| `Nonce`               | `uint64`                                                             | Sequence number                                                        |
| `NonceRange`          | `{ start: Nonce, limit: uint }`                                      | Range query for certificates                                           |
| `PublicKeyBytes`      | `Array<uint8; 32>`                                                   | Ed25519 public key                                                     |
| `Signature`           | `Array<uint8; 64>`                                                   | Ed25519 signature                                                      |
| `SignatureOrMultiSig` | `{ "Signature": [...] }` or `{ "MultiSig": { config, signatures } }` | Single or multisig authentication                                      |
| `TokenId`             | `Array<uint8; 32>`                                                   | Unique token identifier                                                |
| `StateKey`            | `Array<uint8; 32>`                                                   | Account state field key                                                |
| `State`               | `Array<uint8; 32>`                                                   | Account state field value                                              |
| `UserData`            | `Array<uint8; 32>` or `null`                                         | Optional arbitrary data attached to a transaction                      |

***

#### MultiSig

For accounts controlled by multiple signers.

**MultiSigConfig** — determines the multisig account address:

| Field                | Type                    | Description                                                      |
| -------------------- | ----------------------- | ---------------------------------------------------------------- |
| `authorized_signers` | `Array<PublicKeyBytes>` | Accounts that may sign                                           |
| `quorum`             | `uint64`                | Minimum signatures required                                      |
| `nonce`              | `uint64`                | Distinguishes multiple multisig accounts with the same committee |

**MultiSig** — authentication envelope:

| Field        | Type                                 | Description                          |
| ------------ | ------------------------------------ | ------------------------------------ |
| `config`     | `MultiSigConfig`                     | The account's multisig configuration |
| `signatures` | `Array<[PublicKeyBytes, Signature]>` | Signatures from authorized signers   |

***

### Error Codes

Standard JSON-RPC 2.0 error codes plus application-specific codes:

| Code     | Message          | Description                                                                                                                          |
| -------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `-32700` | Parse error      | Malformed JSON in request body                                                                                                       |
| `-32601` | Method not found | The requested method does not exist                                                                                                  |
| `-32602` | Invalid params   | Missing or invalid parameters                                                                                                        |
| `-32014` | Unexpected Nonce | The nonce of the transaction is incorrect                                                                                            |
| `-32015` | Invalid Request  | The transaction exceeds various limits (size, number of signatures, token name length, number of minters, number of claims in batch) |
| `-32000` | General Error    | Other general errors                                                                                                                 |

***

### Architecture Note

The proxy is a convenience layer — it is not part of the trust model. It relays messages, aggregates signatures, and assembles certificates, but it cannot forge signatures or alter transactions. Anyone can run a proxy.

In the current network configuration, validators are not directly accessible. All traffic routes through the proxy service. This is a temporary operational decision to prevent DDoS attacks — not a protocol requirement. The protocol itself is fully functional with direct client-to-validator communication.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.fast.xyz/api-reference/json-rpc-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
