App Session Methods
App sessions enable multi-party applications with custom governance rules, allowing complex interactions on top of payment channels.
Overview
App sessions are off-chain channels built on top of the unified balance, intended for app developers to create application-specific interactions. They act as a "box" or shared account where multiple participants can transfer funds and execute custom logic with governance rules.
Key Features
Multi-Party Governance: Define custom voting weights and quorum rules for state updates.
Application-Specific State: Store arbitrary application data (game state, escrow conditions, etc.).
Flexible Fund Management: Transfer, redistribute, add, or withdraw funds during session lifecycle.
Instant Updates: All state changes happen off-chain with zero gas fees.
App sessions are specifically designed for app developers building trustless multi-party applications like games, prediction markets, escrow, and collaborative finance.
Protocol Versions
App sessions support multiple protocol versions for backward compatibility.
Version Comparison
| Feature | NitroRPC/0.2 (Legacy) | NitroRPC/0.4 (Current) |
|---|---|---|
| State Updates | Basic only | Intent-based (OPERATE, DEPOSIT, WITHDRAW) |
| Add Funds to Active Session | ❌ No | ✅ Yes (DEPOSIT intent) |
| Remove Funds from Active Session | ❌ No | ✅ Yes (WITHDRAW intent) |
| Fund Redistribution | ✅ Yes | ✅ Yes (OPERATE intent) |
| Error Handling | Basic | Enhanced validation |
| Modify Total Funds | Must close & recreate | Can update during session |
| Recommended For | Legacy support only | All new implementations |
The protocol version is specified in the app definition during creation and cannot be changed for an existing session. Always use NitroRPC/0.4 for new app sessions.
create_app_session
Name
create_app_session
Usage
Creates a new virtual application session on top of the unified balance. An app session is a "box" or shared account where multiple participants can transfer funds and execute application-specific logic with custom governance rules. The app definition specifies participants, their voting weights, quorum requirements for state updates, and the protocol version. Funds are transferred from participants' unified balance accounts to a dedicated App Session Account for the duration of the session. App sessions enable complex multi-party applications like games, prediction markets, escrow, and collaborative finance—all operating off-chain with instant state updates and zero gas fees.
When to Use
When multiple participants need to interact with shared funds and application state in a trustless manner. Examples include turn-based games, betting pools, escrow arrangements, DAOs, prediction markets, and any application requiring multi-signature state management.
Prerequisites
- All participants with non-zero initial allocations must be authenticated
- All such participants must have sufficient available balance
- All such participants must sign the creation request
- Protocol version must be supported (NitroRPC/0.2 or NitroRPC/0.4)
Request
Common structures: AppDefinition • Allocation
| Parameter | Type | Required | Description | See Also |
|---|---|---|---|---|
definition | AppDefinition | Yes | Configuration defining the app session rules and participants | ↓ Structure |
allocations | Allocation[] | Yes | Initial funds to transfer from participants' unified balance accounts | ↓ Structure |
session_data | string | No | Application-specific initial state (JSON string, max 64KB recommended) This is application-specific; protocol doesn't validate content | — |
Session Identifier
app_session_id is derived deterministically from the entire App definition:
appSessionId = keccak256(JSON.stringify({
application: "...",
protocol: "NitroRPC/0.4",
participants: [...],
weights: [...],
quorum: 100,
challenge: 86400,
nonce: 123456
}))
- Includes
application,protocol,participants,weights,quorum,challenge, andnonce - Does not include
chainIdbecause sessions live entirely off-chain - Client can recompute locally to verify clearnode responses
nonceuniqueness is critical: same definition ⇒ same ID
Implementation reference: clearnode/app_session_service.go.
AppDefinition
| Field | Type | Required | Description | Default | Allowed Values | Notes |
|---|---|---|---|---|---|---|
protocol | string | Yes | Protocol version for this app session | — | "NitroRPC/0.2" | "NitroRPC/0.4" | Version cannot be changed after creation; use 0.4 for new sessions |
participants | address[] | Yes | Array of all participant wallet addresses | — | Min: 2 participants | Order is important - indices used for signatures and weights Last participant often represents the application/judge |
weights | int64[] | Yes | Voting power for each participant | — | — | Length must match participants array Order corresponds to participants array Absolute values matter for quorum; don't need to sum to 100 |
quorum | uint64 | Yes | Minimum total weight required to approve state updates | — | — | Sum of signers' weights must be ≥ quorum |
challenge | uint64 | No | Challenge period in seconds for disputes | 86400 (24 hours) | — | Only relevant if app session state is ever checkpointed on-chain |
nonce | uint64 | Yes | Unique identifier | — | — | Typically timestamp; ensures uniqueness |
Example:
{
"protocol": "NitroRPC/0.4",
"participants": ["0x742d35Cc...", "0x8B3192f2...", "0x456789ab..."],
"weights": [50, 50, 100],
"quorum": 100,
"challenge": 3600,
"nonce": 1699123456789
}
Allocation
| Field | Type | Required | Description |
|---|---|---|---|
participant | address | Yes | Participant wallet address (must be in definition.participants) |
asset | string | Yes | Asset identifier (e.g., "usdc") |
amount | string | Yes | Amount in human-readable format (e.g., "100.0") |
Example:
[
{"participant": "0x742d35Cc...", "asset": "usdc", "amount": "100.0"},
{"participant": "0x8B3192f2...", "asset": "usdc", "amount": "100.0"},
{"participant": "0x456789ab...", "asset": "usdc", "amount": "0.0"}
]
Note: Participants with zero allocation don't need to sign creation.
Response
| Parameter | Type | Description | Format/Structure | Example | Notes |
|---|---|---|---|---|---|
app_session_id | string | Unique identifier for the created app session | 0x-prefixed hex string (32 bytes) | "0x9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba" | Use this for all subsequent operations on this session |
status | string | App session status | "open" | "open" | Values: "open" or "closed" |
version | number | Current state version | 1 | 1 | Always starts at 1 |
The Go service returns only these fields on creation. To fetch full metadata (application, participants, quorum, weights, session_data, protocol, challenge, nonce, timestamps), call get_app_sessions after creation.
Governance Models
App sessions support flexible governance through custom weights and quorum configurations.
Example 1: Simple Two-Player Game
Participants: [Alice, Bob]
Weights: [1, 1]
Quorum: 2
Result: Both players must sign every state update
Use case: Chess, poker, betting between two parties
Governance: Cooperative - both parties must agree to all changes.
Example 2: Game with Judge
Participants: [Alice, Bob, Judge]
Weights: [0, 0, 100]
Quorum: 100
Result: Only judge can update state
Use case: Games where application determines outcome
Governance: Authoritative - application/judge has full control.
Example 3: Multi-Party Escrow
Participants: [Buyer, Seller, Arbiter]
Weights: [40, 40, 50]
Quorum: 80
Result: Any 2 parties can approve
- Buyer + Seller (80)
- Buyer + Arbiter (90)
- Seller + Arbiter (90)
Use case: Escrowed transactions with dispute resolution
Governance: Flexible 2-of-3 - any two can proceed, preventing single-party blocking.
Example 4: DAO-like Voting
Participants: [User1, User2, User3, User4, Contract]
Weights: [20, 25, 30, 25, 0]
Quorum: 51
Result: Majority of weighted votes required (51 out of 100)
Use case: Collaborative funds management
Governance: Weighted majority - decisions require majority approval by stake.
Example 5: Watch Tower
Participants: [Alice, Bob, WatchTower]
Weights: [40, 40, 100]
Quorum: 80
Result:
- Normal operation: Alice + Bob (80)
- Emergency: WatchTower alone (100)
Use case: Automated monitoring and intervention
Governance: Dual-mode - normal requires cooperation, emergency allows automated action.
By adjusting weights and quorum, you can implement any governance model from fully cooperative (all must sign) to fully authoritative (single party controls) to complex weighted voting systems.
Fund Transfer Mechanics
When an app session is created, funds are transferred from the unified balance account to a dedicated App Session Account:
Balance State Changes:
Before Creation:
Alice's Unified Account:
Balance: 200 USDC
After Creating Session with 100 USDC:
Alice's Unified Account:
Balance: 100 USDC
App Session Account:
Balance: 100 USDC (Beneficiary: Alice)
Signature Requirements
All participants with non-zero initial allocations MUST sign the create_app_session request. The clearnode validates that:
- All required signatures are present
- Signatures are valid for respective participants
- Total weight of signers >= quorum (must be met for creation)
submit_app_state
Name
submit_app_state
Usage
Submits a state update for an active app session. State updates can redistribute funds between participants (OPERATE intent), add funds to the session (DEPOSIT intent), or remove funds from the session (WITHDRAW intent). The intent system is only available in NitroRPC/0.4; version 0.2 sessions only support fund redistribution without explicit intent. Each state update increments the version number, and must be signed by participants whose combined weights meet the quorum requirement. The allocations field always represents the FINAL state after the operation, not the delta.
When to Use
During app session lifecycle to update the state based on application logic. Examples include recording game moves, updating scores, reallocating funds based on outcomes, adding stakes, or partially withdrawing winnings.
Prerequisites
- App session must exist and be in "open" status
- Signers must meet quorum requirement
- For DEPOSIT intent: Depositing participant must sign (in addition to quorum)
- For DEPOSIT intent: Depositing participant must have sufficient available balance
- For WITHDRAW intent: Session must have sufficient funds to withdraw
- NitroRPC/0.4:
versionmust be exactly current_version + 1 - NitroRPC/0.2: omit
intentandversion(service rejects them); only OPERATE-style redistribution is supported - If using a session key, spending allowances for that key are enforced
Request
| Parameter | Type | Required | Description | Format | Example | Notes / See Also |
|---|---|---|---|---|---|---|
app_session_id | string | Yes | Identifier of the app session to update | 0x-prefixed hex string (32 bytes) | "0x9876543210fedcba..." | - |
intent | string | Yes for v0.4, No for v0.2 | Type of operation (NitroRPC/0.4 only) | Allowed: "operate" | "deposit" | "withdraw" | "operate" | Omit for NitroRPC/0.2 sessions (treated as operate) |
version | number | Yes | Expected next version number | - | 2 | Must be exactly currentVersion + 1; prevents conflicts |
allocations | Allocation[] | Yes | FINAL allocation state after this update ⚠️ IMPORTANT: This is the target state, NOT the delta | See Allocation above | After operate from [100, 100] where Alice loses 25 to Bob:[{"participant": "0xAlice", "asset": "usdc", "amount": "75.0"}, {"participant": "0xBob", "asset": "usdc", "amount": "125.0"}] | Clearnode validates based on intent rules (see below) |
session_data | string | No | Updated application-specific state | JSON string | "{\"currentMove\":\"e2e4\",\"turn\":\"black\"}" | Can be updated independently of allocations |
Response
| Parameter | Type | Description | Format/Structure | Example | Notes |
|---|---|---|---|---|---|
app_session_id | string | Session identifier (echoed) | - | - | - |
version | number | Confirmed new version number | - | 2 | - |
status | string | Updated session status | "open" | "open" | Minimal response (no metadata echoed) |
The Go handler returns an AppSessionResponse type, but for state submissions it only includes app_session_id, version, and status (and does not echo session metadata). Use get_app_sessions to read the full session record.
Intent System (NitroRPC/0.4)
The intent system defines the type of operation being performed. Each intent has specific validation rules.
Intent: OPERATE (Redistribute Existing Funds)
Purpose: Move funds between participants without changing total amount in session.
Rules:
- Sum of allocations MUST equal sum before operation
- No funds added or removed from session
- Quorum requirement MUST be met
- Depositing participant signature NOT required
Example:
Current state (version 1):
Alice: 100 USDC
Bob: 100 USDC
Total: 200 USDC
Update (version 2, intent: "operate"):
Allocations: [
{"participant": "0xAlice", "asset": "usdc", "amount": "75.0"},
{"participant": "0xBob", "asset": "usdc", "amount": "125.0"}
]
Result:
Alice: 75 USDC (-25)
Bob: 125 USDC (+25)
Total: 200 USDC (unchanged) ✓
Validation: Sum before (200) == Sum after (200) ✓
Use Cases:
- Record game outcome (winner gets opponent's stake)
- Update prediction market positions
- Rebalance shared pool
- Penalize or reward participants
Use OPERATE for simple fund redistributions within the session. The total amount remains constant—funds just move between participants.
Intent: DEPOSIT (Add Funds to Session)
Purpose: Add funds from a participant's unified balance into the session.
Rules:
- Sum of allocations MUST be greater or equal to sum before operation
- Increase MUST come from available balance of depositing participant
- Depositing participant MUST sign (even if quorum is met without them)
- Quorum requirement MUST still be met
- Allocations show FINAL amounts (not delta)
- If signed via a session key, spending caps for that key are enforced
Example:
Current state (version 1):
Alice: 100 USDC
Bob: 100 USDC
Total: 200 USDC
Alice's Unified Balance:
Available: 50 USDC
Update (version 2, intent: "deposit"):
Allocations: [
{"participant": "0xAlice", "asset": "usdc", "amount": "150.0"},
{"participant": "0xBob", "asset": "usdc", "amount": "100.0"}
]
Signatures: [AliceSig, QuorumSigs...]
Calculation:
Alice deposit amount = 150 (new) - 100 (old) = 50 USDC
Result:
Alice: 150 USDC (100 + 50 deposited)
Bob: 100 USDC (unchanged)
Total: 250 USDC (+50) ✓
Alice's Unified Balance After:
Available: 0 USDC (50 transferred to App Session Account)
App Session Account After:
Balance: 250 USDC (increased by 50)
Validation:
- Sum after (250) > Sum before (200) ✓
- Alice signed ✓
- Alice had 50 available ✓
Use Cases:
- Top up game stake mid-game
- Add collateral to escrow
- Increase position in prediction market
- Buy into ongoing game
Critical Understanding: The allocations array shows FINAL amounts, not the deposit amount. The clearnode calculates the deposit by comparing previous and new allocations for each participant.
Intent: WITHDRAW (Remove Funds from Session)
Purpose: Remove funds from session back to a participant's unified balance.
Rules:
- Sum of allocations MUST be less or equal to sum before operation
- Decrease is returned to participant's available balance
- Withdrawing participant signature NOT specifically required (quorum sufficient)
- Quorum requirement MUST be met
- Allocations show FINAL amounts (not delta)
Example:
Current state (version 1):
Alice: 150 USDC
Bob: 100 USDC
Total: 250 USDC
Update (version 2, intent: "withdraw"):
Allocations: [
{"participant": "0xAlice", "asset": "usdc", "amount": "150.0"},
{"participant": "0xBob", "asset": "usdc", "amount": "75.0"}
]
Signatures: [QuorumSigs...]
Calculation:
Bob withdrawal amount = 100 (old) - 75 (new) = 25 USDC
Result:
Alice: 150 USDC (unchanged)
Bob: 75 USDC (100 - 25 withdrawn)
Total: 225 USDC (-25) ✓
Bob's Unified Balance After:
Available: +25 USDC
App Session Account After:
Balance: 225 USDC (decreased by 25)
Validation:
- Sum after (225) < Sum before (250) ✓
- Quorum met ✓
Use Cases:
- Cash out partial winnings mid-game
- Remove collateral when no longer needed
- Take profits from shared investment
- Reduce stake in ongoing game
Version Management
- NitroRPC/0.4: each update MUST be exactly
previous_version + 1, or it is rejected. - NitroRPC/0.2: omit
intentandversion; providing either results in"incorrect request: specified parameters are not supported in this protocol".
Quorum Validation
For every update, the clearnode validates quorum:
Validation Logic:
totalWeight = sum of weights for all signers
if (totalWeight >= definition.quorum) {
✓ Update accepted
} else {
✗ Reject: "Quorum not met"
}
Example (using Game with Judge scenario):
Participants: [Alice, Bob, Judge]
Weights: [0, 0, 100]
Quorum: 100
Valid signature combinations:
- Judge alone: weight = 100 >= 100 ✓
- Alice + Bob: weight = 0 >= 100 ✗
- Alice + Bob + Judge: weight = 100 >= 100 ✓
close_app_session
Name
close_app_session
Usage
Closes an active app session and distributes all funds from the App Session Account according to the final allocations. Once closed, the app session cannot be reopened; participants must create a new session if they want to continue. The final allocations determine how funds are returned to each participant's unified balance account. Closing requires quorum signatures. The final session_data can record the outcome or final state of the application. All funds in the App Session Account are released immediately.
When to Use
When application logic has completed and participants want to finalize the outcome and retrieve their funds. Examples include game ending, escrow condition met, prediction market settled, or any application reaching its natural conclusion.
Prerequisites
- App session must exist and be in "open" status
- Signers must meet quorum requirement
- Final allocations must not exceed total funds in session
- Sum of final allocations must equal total session funds
Request
| Parameter | Type | Required | Description | Format/Structure | Example | Notes |
|---|---|---|---|---|---|---|
app_session_id | string | Yes | Identifier of the app session to close | 0x-prefixed hex string (32 bytes) | "0x9876543210fedcba..." | - |
allocations | Allocation[] | Yes | Final distribution of all funds in the session IMPORTANT: Must account for ALL funds; sum must equal session total Structure (per allocation): • participant (address) - Participant wallet address• asset (string) - Asset identifier• amount (string) - Final amount for this participant | See structure | 200 USDC total, winner takes most:[{"participant": "0xAlice", "asset": "usdc", "amount": "180.0"}, {"participant": "0xBob", "asset": "usdc", "amount": "15.0"}, {"participant": "0xJudge", "asset": "usdc", "amount": "5.0"}] | Can allocate zero to participants (they get nothing) |
session_data | string | No | Final application state or outcome record | JSON string | "{\"result\":\"Alice wins\",\"finalScore\":\"3-1\"}" | Useful for recording outcome for history/analytics |
Response
| Parameter | Type | Description | Format/Structure | Example | Notes |
|---|---|---|---|---|---|
app_session_id | string | Session identifier (echoed) | - | - | - |
status | string | Final status | Value: "closed" | "closed" | Minimal response |
version | number | New session version | - | 2 | Incremented on close |
The handler returns an AppSessionResponse type in Go, but on close it only populates app_session_id, status, and version. For full metadata after closure, query get_app_sessions.
Fund Distribution on Closure
When an app session closes, funds return to participants' unified balances:
Before Closure:
Alice's Unified Account:
Balance: 100 USDC
App Session Account 0x98765:
Alice: 100 USDC
Bob: 100 USDC
Total: 200 USDC
Close with final allocations:
Alice: 180 USDC
Bob: 20 USDC
After Closure:
Alice's Unified Account:
Balance: 280 USDC (100 + 180 received from session)
Bob's Unified Account:
Balance: 20 USDC (received from session)
App Session Account 0x98765:
Closed (Balance: 0 USDC)
Allocation Rules
-
Must Sum to Total:
sum(final_allocations) MUST equal sum(current_allocations)- Clearnode validates this; cannot create or destroy funds during close
-
Can Be Zero:
- Participants can receive zero in final allocation (lost everything)
- Example: Losing player in a winner-takes-all game
-
Accounting for Participants:
- It is recommended to include an entry for every participant (use zero for losers).
- If you omit a participant, the service treats them as receiving zero, as long as per-asset totals still match the session balance.
-
Can Include Non-Financial Participants:
- Example: Judge/application can receive commission
{"participant": "0xJudge", "asset": "usdc", "amount": "5.0"}
Closure Examples
Example 1: Chess Game
Initial:
White: 100 USDC
Black: 100 USDC
Judge: 0 USDC
Total: 200 USDC
Final (White wins):
White: 190 USDC (won 90)
Black: 0 USDC (lost 100)
Judge: 10 USDC (5% commission)
Total: 200 USDC ✓
Example 2: Escrow (Buyer Satisfied)
Initial:
Buyer: 100 USDC
Seller: 0 USDC
Arbiter: 0 USDC
Total: 100 USDC
Final (Successful delivery):
Buyer: 0 USDC
Seller: 99 USDC (payment)
Arbiter: 1 USDC (fee)
Total: 100 USDC ✓
Example 3: Escrow (Dispute, Buyer Refunded)
Initial:
Buyer: 100 USDC
Seller: 0 USDC
Arbiter: 0 USDC
Total: 100 USDC
Final (Arbiter ruled for buyer):
Buyer: 95 USDC (refund minus fee)
Seller: 0 USDC
Arbiter: 5 USDC (dispute fee)
Total: 100 USDC ✓
Example 4: Prediction Market
Initial:
User1: 50 USDC (bet YES)
User2: 50 USDC (bet YES)
User3: 40 USDC (bet NO)
Oracle: 0 USDC
Total: 140 USDC
Final (Outcome: YES):
User1: 68.25 USDC (split pot proportionally)
User2: 68.25 USDC
User3: 0 USDC (lost)
Oracle: 3.50 USDC (2.5% fee)
Total: 140 USDC ✓
All participants receive funds according to the final allocations, whether they won, lost, or served as neutral parties (judges, arbiters, oracles). The total is always preserved.
Implementation Notes
State Management:
- Always use
intent: "operate"for simple redistributions - Always specify FINAL allocations, never deltas
- The clearnode computes deltas internally by comparing with previous state
- Version numbers must be strictly sequential
- The session_data field can be updated in any intent
Performance:
- Updates are instant (< 1 second) and off-chain
- Zero gas fees for all operations
- All updates are logged for audit trail
Notifications:
- Participants are notified on all active connections of state changes
- Closed sessions remain queryable for history
Irreversibility:
- Closure is instant and atomic
- All funds released simultaneously
- Once closed, cannot be reopened
- To continue, create a new session
Next Steps
Explore other protocol features:
- Queries & Notifications - Query session history and receive real-time updates
- Transfers - Move funds between unified balances
- Channel Methods - Manage underlying payment channels
For foundational concepts:
- Message Format - Understand request/response structure
- Authentication - Manage session keys and security