CAIP-25: Wallet Create Session JSON-RPC Method

Author Pedro Gomes, Hassan Malik, Alex Donesky, Jiexi Luan
Discussions-To https://github.com/ChainAgnostic/CAIPs/pull/25
Status Review
Type Standard
Created 2020-10-14
Updated 2025-08-11
Requires 2, 10, 171, 217, 285, 311, 312

Simple Summary

CAIP-25 defines an authorization procedure for a chain agnostic provider to interface with a wallet as part of their initialization and/or “handshake” protocol.

Abstract

This proposal defines a standard procedure for decentralized applications to interface with chain agnostic cryptocurrency wallets and other user agents that govern identities (including accounts) across multiple cryptographic systems. It specifies a lightweight protocol for negotiating and persisting authorizations during a session managed either by an in-DOM provider construct, by a securely-addressed browser extensions, or by a distinct user-agent.

Motivation

The absence of standardized interfaces and abstractions for reading from and writing to blockchains such as consistent account models and JSON-RPC method specifications has fragmented application and wallet interactions. CAIP-25 resolves this by defining a unified, session-based interface that standardizes communication between applications and wallets.

Specification

Language

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” are interpreted as described in RFC-2119.

Definition

Session Lifecycle

The session is proposed by a caller and accepted by the respondent. The respondent may return a sessionId which both parties then persist along with session properties and authorization scopes. See CAIP-316 for guidance on session lifecycles with and without sessionIds.

If a wallet does not return a sessionId, it MUST track session data internally. The caller is not required to persist any session state but may query or revoke sessions via wallet_getSession, wallet_revokeSession, or receive updates via wallet_sessionChanged.

Subsequent wallet_createSession calls may:

  • Update an existing session by including the same sessionId
  • Create a new session if no sessionId is provided (discouraged)

Session updates initiated by the wallet must notify the caller using wallet_sessionChanged.

Callers may revoke sessions using wallet_revokeSession, passing the sessionId parameter if it was returned by the initial response.

Session Data and Metadata

Authorization requests are expressed as a top-level object scopes containing keyed scopeObjects.

Each scopeObject is keyed by a CAIP-2 or CAIP-104 identifiers. A null reference can be used to refer to a scope that applies to ANY chain within that namespace (eg. eip155:0)

Wallets MAY authorize a subset of scopes or scope properties as requested, and MAY also authorize additional scopes or scope properties. This enables granular control and flexibility on the part of the respondent.

Upon successful negotiation, the response includes a unified scopes object containing all granted scopes. Identically-keyed scopeObjects from multiple requests MUST be merged. No duplicate scopes with identical keys are allowed.

Respondents MUST NOT restructure scope formats (e.g., converting chain-specific keys into namespace-wide keys).

If a connection is rejected, the wallet MAY respond with a generic error or silently ignore the request to minimize fingerprinting risk (see Privacy Considerations).

Request

interface CAIP25JsonRpcRequest {
  id: number;
  jsonrpc: "2.0";
  method: "wallet_createSession";
  params: {
    scopes: {
      [scopeKey: string]: {
        chains?: string[];
        accounts?: string[];
        methods: string[];
        notifications: string[];
      };
    };
    properties?: {
      [propertyKey: string]: any;
    };
  };
}

The scopes object MUST contain one or more scopeObjects.

The properties object MAY be included for global session metadata.

Response

Success

interface CAIP25JsonRpcResponse {
  id: number;
  jsonrpc: "2.0";
  result: {
    scopes: {
      [scopeKey: string]: {
        chains?: string[];
        accounts: string[];
        methods: string[];
        notifications: string[];
        capabilities?: {
          [capabilityKey: string]: any;
        };
      };
    };
    properties?: {
      [propertyKey: string]: any;
    };
  };
}

Each entry within scopes object MAY contain accounts and capabilities as part of its object for success response.

Error Codes

The wallet MAY return generic or specific error messages depending on trust. Trusted responses may include codes like:

  • 5000: Unknown error
  • 5001: User disapproved requested methods
  • 5002: User disapproved requested notifications
  • 5100-5102: Unsupported chains, methods, or notifications
  • 5201-5302: Malformed requests

Examples

Example 1

For request, we define a very simple scope for 10 EVM chains with the exact same scope.

// JSON-RPC REQUEST
{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "wallet_createSession",
  "params": {
    "scopes": {
      "eip155": {
        "chains": [
          "1",
          "10",
          "130",
          "324",
          "2741",
          "8453",
          "42161",
          "59144",
          "534352",
          "747474"
        ],
        "methods": ["eth_sendTransaction", "personal_sign"],
        "notifications": ["accountsChanged", "chainChanged"]
      }
    },
    "properties": {
      "expiry": "2022-12-24T17:07:31+00:00"
    }
  }
}

For response, we also keep it quite simple with no wallet capabilities or special scopes.

// JSON-RPC RESPONSE
{
  "id": 1,
  "jsonrpc": "2.0",
  "result": {
    "scopes": {
      "eip155": {
        "chains": [
          "1",
          "10",
          "130",
          "324",
          "2741",
          "8453",
          "42161",
          "59144",
          "534352",
          "747474"
        ],
        "accounts": ["0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb"],
        "methods": ["eth_sendTransaction", "personal_sign"],
        "notifications": ["accountsChanged", "chainChanged"]
      }
    },
    "properties": {
      "expiry": "2022-12-24T17:07:31+00:00"
    }
  }
}

Example 2

For the request, we define the expectation of 5 EVM chains with similar scope and additonally we have 2 Solana chains with similar scope

// JSON-RPC REQUEST
{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "wallet_createSession",
  "params": {
    "scopes": {
      "eip155": {
        "chains": ["1", "10", "324", "8453", "42161"],
        "methods": [
          "eth_sendTransaction",
          "personal_sign",
          "wallet_grantPermissions",
          "wallet_getAssets",
          "wallet_sendCalls"
        ],
        "notifications": ["accountsChanged", "chainChanged"]
      },
      "solana": {
        "chains": [
          "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
          "4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z"
        ],
        "methods": [
          "solana_signMessage",
          "solana_signTransaction",
          "solana_signAndSendTransaction"
        ],
        "notifications": []
      }
    },
    "properties": {
      "expiry": "2022-12-24T17:07:31+00:00"
    }
  }
}

For the response, we match the same scopes as the request but separate 2 out of 5 EVM chains into individual scopes because of non-overlapping accounts, capabilities or methods.

Additionaly we have the two Solana chains returning the same scopes but returning two different account addresses for each chain including a unique capability for one of the chains

Finally the wallet has provided within properties with its walletInfo per CAIP-372.

// JSON-RPC RESPONSE
{
  "id": 1,
  "jsonrpc": "2.0",
  "result": {
    "sessionId": "0xdeadbeef",
    "scopes": {
      "eip155": {
        "chains": ["1", "10", "324"],
        "accounts": ["0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb"],
        "methods": [
          "eth_sendTransaction",
          "personal_sign",
          "wallet_addEthereumChain",
          "wallet_grantPermissions",
          "wallet_getAssets",
          "wallet_sendCalls"
        ],
        "notifications": ["accountsChanged", "chainChanged"],
        "capabilities": {
          "walletService": "https://wallet-service.example.com/rpc"
        }
      },
      "eip155:8453": {
        "accounts": ["0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb"],
        "methods": [
          "eth_sendTransaction",
          "personal_sign",
          "wallet_grantPermissions",
          "wallet_getAssets",
          "wallet_sendCalls"
        ],
        "notifications": ["accountsChanged", "chainChanged"],
        "capabilities": {
          "atomic": {
            "status": "supported"
          }
        }
      },
      "eip155:42161": {
        "accounts": [
          "0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb",
          "0x0495766cD136138Fc492Dd499B8DC87A92D6685b"
        ],
        "methods": [
          "eth_sendTransaction",
          "personal_sign",
          "wallet_grantPermissions",
          "wallet_getAssets",
          "wallet_sendCalls"
        ],
        "notifications": ["accountsChanged", "chainChanged"],
        "capabilities": {
          "atomic": {
            "status": "supported"
          },
          "paymasterService": {
            "url": "https://...",
            "optional": true
          }
        }
      },
      "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": {
        "accounts": [],
        "methods": [
          "solana_signMessage",
          "solana_signTransaction",
          "solana_signAndSendTransaction"
        ],
        "notifications": [],
        "capabilities": {
          "supportedTransactionVersions": ["legacy", "0"]
        }
      },
      "solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z": {
        "accounts": ["6LmSRCiu3z6NCSpF19oz1pHXkYkN4jWbj9K1nVELpDkT"],
        "methods": [
          "solana_signMessage",
          "solana_signTransaction",
          "solana_signAndSendTransaction"
        ],
        "notifications": [],
        "capabilities": {
          "supportedTransactionVersions": ["legacy"]
        }
      }
    },
    "properties": {
      "expiry": "2022-12-24T17:07:31+00:00",
      "walletInfo": {
        "uuid": "350670db-19fa-4704-a166-e52e178b59d2",
        "name": "Example Wallet",
        "icon": "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'/>",
        "rdns": "com.example.wallet"
      }
    }
  }
}

Security Considerations

To avoid ambiguity in authorizations, scopes MUST retain their original keyed structure using CAIP-2 or CAIP-104 identifiers. This ensures clarity in what is authorized and prevents accidental scope merging or misinterpretation.

Privacy Considerations

To mitigate fingerprinting risks, wallets should prefer uniform or silent failure responses. Avoid leaking timing or error detail that may help malicious actors identify users or wallets. Progressive, minimal scope requests and updates are encouraged.

Changelog

  • 2025-08-07: Remove capababilities from request AND remove CAIP-2 prefix from accounts
  • 2025-08-04: Merged capabilities (fka scopedProperties) into scopeObjects
  • 2025-08-03: Removed Namespace-scoped scopeObjects and retained only Chain-scoped scopeObjects
  • 2025-07-31: Removed requiredScopes and retained only scopes (fka optionalScopes).
  • 2025-07-30: Renamed optionalScopes to scopes, scopedProperties to capabilities and sessionProperties to properties
  • 2024-07-29: Added lifecycle management methods and notification for single session connections
  • 2024-07-16: Redefined scope negotiation behavior
  • 2023-03-29: Refactored scopeObject syntax to CAIP-217
  • 2022-11-26: Introduced mandatory sessionId usage (CAIP-171)
  • 2022-10-26: Updated session param syntax post community gathering
  • CAIP-2 - Chain ID Specification
  • CAIP-10 - Account ID Specification
  • CAIP-104 - Definition of Chain Agnostic Namespaces or CANs
  • CAIP-171 - Session Identifier, i.e. syntax and usage of sessionIds
  • CAIP-217 - Authorization Scopes, i.e. syntax for scopeObjects
  • CAIP-285 - wallet_revokeSession Specification
  • CAIP-312 - wallet_getSession Specification
  • CAIP-311 - wallet_sessionChanged Specification
  • CAIP-316 - Session Lifecycle Management equivalence chart and diagrams
  • CAIP-372 - Wallet Information Metadata Standard
  • RFC-2119 - Key words for use in RFCs to Indicate Requirement Levels

Copyright and related rights waived via CC0.

Citation

Please cite this document as:

Pedro Gomes, Hassan Malik, Alex Donesky, Jiexi Luan, "CAIP-25: Wallet Create Session JSON-RPC Method," Chain Agnostic Improvement Proposals, no. 25, October 2020. [Online serial]. Available: https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-25.md