Skip to main content

Message Format

The Nitro RPC protocol uses a compact, efficient message format for all communication between clients and a clearnode.


General Structure

Every Nitro RPC message consists of a compact JSON array format:

[requestId, method, params, timestamp]
Compact Format

This array-based format reduces message overhead by approximately 30% compared to traditional JSON-RPC, making it ideal for high-frequency state channel operations.

Components

ComponentTypeDescription
requestIduint64Unique identifier for the request, used to correlate responses
methodstringRemote method name to be invoked
paramsobjectMethod-specific parameters as a JSON object
timestampuint64Server-provided timestamp in milliseconds

requestId

  • Purpose: Correlate requests with their responses
  • Type: Unsigned 64-bit integer
  • Generation: Client-generated, must be unique per connection
  • Range: 0 to 2^64-1
  • Example: 1, 42, 9876543210

method

  • Purpose: Specify which RPC method to invoke
  • Type: String
  • Format: snake_case (e.g., create_channel, not createChannel)
  • Examples: auth_request, transfer, create_app_session

params

timestamp

  • Purpose: Request ordering and replay attack prevention
  • Type: Unsigned 64-bit integer (Unix milliseconds)
  • Generation: Client-provided on requests; server-provided on responses
  • Example: 1699123456789 (November 5, 2023, 01:57:36 UTC)

Request Message

A complete request message wraps the payload array and includes signatures.

Structure

{
"req": [requestId, method, params, timestamp],
"sig": [signature1, signature2, ...]
}

Fields

req

The request payload as a 4-element array containing:

  • Request ID
  • Method name
  • Parameters object
  • Timestamp

sig

Array of ECDSA signatures, one or more depending on the operation:

  • Single signature: Most operations (signed by client's session key)
  • Multiple signatures: Multi-party operations (e.g., app session creation)

Signature Format

Each signature is:

  • Format: 0x-prefixed hex string
  • Length: 65 bytes (130 hex characters + "0x" prefix)
  • Components: r (32 bytes) + s (32 bytes) + v (1 byte)
  • Algorithm: ECDSA over secp256k1 curve
  • Hash: keccak256 of the exact req array bytes

Example Signature:

0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef01
EVM-Specific Format

This signature format (ECDSA over secp256k1 with keccak256 hashing) is specific to EVM-compatible chains. If the protocol extends to support non-EVM chains in the future, signature formats may need to be adapted to match those chains' native cryptographic primitives.

Signature Security

Signatures are computed over the keccak256 hash of the JSON-encoded req array. The JSON encoding MUST be consistent (same key ordering, no extra whitespace) to ensure signature validity.

Complete Example

{
"req": [
1,
"auth_request",
{
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"session_key": "0x9876543210fedcba9876543210fedcba98765432",
"application": "trading-dex",
"allowances": [
{"asset": "usdc", "amount": "1000.0"},
{"asset": "eth", "amount": "0.5"}
],
"scope": "transfer,app.create",
"expires_at": 1762417328123
},
1699123456789
],
"sig": [
"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef01"
]
}

Response Message

The clearnode sends response messages with the same structure, replacing params with result.

Structure

{
"res": [requestId, method, result, timestamp],
"sig": [signature1, ...]
}

Fields

res

The response payload as a 4-element array:

  • Same requestId (to correlate with request)
  • method (response method name)
    • Usually matches the request method
    • Exception: auth_request → response has auth_challenge method
    • Exception: Errors → response has error method
  • result (method-specific response data, replaces params)
  • timestamp (server response time)

sig

The clearnode's signature(s) over the response:

  • Proves response authenticity
  • Verifies response hasn't been tampered with
  • Enables non-repudiation

Complete Example

{
"res": [
1,
"auth_challenge",
{
"challenge_message": "550e8400-e29b-41d4-a716-446655440000"
},
1699123457000
],
"sig": [
"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890ab"
]
}

Error Response

When an error occurs, the clearnode sends an error response with method set to "error".

Structure

{
"res": [
requestId,
"error",
{
"error": "Error description message"
},
timestamp
],
"sig": ["0xServerSignature..."]
}

The result object at position 2 contains a single "error" field with a descriptive error message string.

Error Examples

Authentication Required:

{
"res": [
5,
"error",
{
"error": "Authentication required: session not established"
},
1699123456789
],
"sig": ["0xServerSignature..."]
}

Insufficient Balance:

{
"res": [
12,
"error",
{
"error": "Insufficient balance: required 100 USDC, available 75 USDC"
},
1699123456790
],
"sig": ["0xServerSignature..."]
}

Method Not Found:

{
"res": [
8,
"error",
{
"error": "Method not found: 'invalid_method'"
},
1699123456791
],
"sig": ["0xServerSignature..."]
}
Error Handling

Check the response method field (position 1 in res array). If it equals "error", extract the error message from the result object's error field. The error message provides human-readable context about what went wrong.


Payload Hash Computation

Every RPC message (request or response) is signed over the exact serialized req or res array bytes.

What is Signed

  • Requests: The req array [requestId, method, params, timestamp] exactly as sent
  • Responses: The res array [requestId, method, result, timestamp] exactly as received

Hash Formula

payloadHash = keccak256(<exact JSON bytes of req or res>)

Use the same bytes you transmit (or receive) when computing/verifying the hash; do not re-serialize with different spacing or key ordering.

Example

Request Payload:

[42,"create_app_session",{"definition":{...},"allocations":[...]},1699123456789]

Hash that exact byte string, then sign it (client for requests, clearnode for responses).


Message Flow Diagram

The following diagram illustrates the complete request-response cycle:


Signature Verification Process

Both clients and a clearnode MUST verify signatures on all messages.

Client Verifying a Clearnode Response

  1. Extract Response: Get res array from response
  2. Compute Hash: hash = keccak256(<exact res bytes>)
  3. Recover Address: Use sig to recover signer address
  4. Verify: Confirm recovered address matches the clearnode's known address

A Clearnode Verifying Client Request

  1. Extract Request: Get req array from request
  2. Compute Hash: hash = keccak256(<exact req bytes>)
  3. Recover Address: Use sig to recover signer address
  4. Verify: Confirm recovered address matches authenticated user or registered session key
Signature Verification Requirements

Most messages MUST be cryptographically signed and verified. All state-changing operations (channel creation/closure, transfers, app sessions) and authenticated methods require valid signatures. However, some query methods (such as get_config) may be accessed without signatures. Refer to individual method specifications for signature requirements.


JSON Encoding Consistency

To ensure signature validity, JSON encoding MUST be consistent across all implementations.

Requirements

  1. Key Ordering: Object keys MUST be in a deterministic order
  2. No Whitespace: Remove all unnecessary whitespace
  3. No Trailing Commas: Standard JSON (no trailing commas)
  4. UTF-8 Encoding: Use UTF-8 character encoding
  5. Number Format: Numbers as strings for large integers (avoid precision loss)

Canonical Example

Consistent (valid for signing):

[1,"transfer",{"amount":"100","asset":"usdc","destination":"0x..."},1699123456]

Inconsistent (would produce different hash):

[  1,  "transfer",  { "destination": "0x...", "amount": "100", "asset": "usdc" },  1699123456  ]
Implementation Note

Use a JSON library that supports canonical JSON serialization, or implement strict key ordering and whitespace removal before computing hashes.


Next Steps

Now that you understand the message format, explore how it's used in practice:

For a high-level overview, return to Off-Chain RPC Overview.