SNAP Protocol
Decentralized agent-to-agent communication with self-sovereign identity.
Identity
Every agent is identified by a Bitcoin P2TR (Pay-to-Taproot) address derived from a private key using BIP-341 taproot tweak.
P2TR address rules:
-
Exactly 62 characters
-
Prefix: bc1p (mainnet) or tb1p (testnet)
-
Bech32m encoded, witness version 1
-
Encodes the BIP-341 tweaked output key (not the internal key)
Key derivation flow:
Private Key (32 bytes) ├─→ Internal Key (P) → hex pubkey (used by Nostr) └─→ Internal Key (P) → Taproot Tweak → Output Key (Q) → Bech32m → P2TR address
Important: publicKeyToP2TR() and p2trToPublicKey() are NOT inverses. The taproot tweak is irreversible — you cannot recover the Nostr pubkey from a P2TR address.
Message Format
Every SNAP message is a JSON object with these fields:
Field Type Description
id
string Unique message ID (1-128 chars, [a-zA-Z0-9_-] )
version
string Protocol version, must be "0.1"
from
string Sender P2TR address
to
string Recipient P2TR address. Optional — omit for Agent-to-Service (e.g. service/call ).
type
string request , response , or event
method
string Method name (e.g. message/send )
payload
object Method-specific data (max 1 MB, max depth 10)
timestamp
integer Unix seconds (UTC), must be within ±60s of current time
sig
string 128 hex chars (64-byte BIP-340 Schnorr signature, signs with tweaked key)
Authentication
Messages are signed using BIP-340 Schnorr signatures with the taproot-tweaked private key. The signature covers a canonical JSON serialization of all message fields (excluding sig ).
Verification steps:
-
Extract tweaked output key Q from the from P2TR address
-
Reconstruct canonical signing payload from message fields
-
Verify BIP-340 Schnorr signature against Q
Methods
Method Type Description
message/send
request-response Single message exchange
message/stream
streaming Streaming response (chunks)
tasks/send
request-response Create a new task
tasks/get
request-response Get task status
tasks/cancel
request-response Cancel a running task
tasks/resubscribe
streaming Resume a task stream
service/call
Agent→Service Call an HTTP service capability
agent/card
request-response Get agent's capability card
agent/ping
request-response Health check
Custom methods MAY be used as long as they match ^[a-z]+/[a-z_]+$ .
Task States
submitted → working → completed → failed → canceled → input_required → working (after user responds)
State Description
submitted
Queued, not yet started
working
Currently processing
input_required
Waiting for user input
completed
Finished successfully
failed
Finished with error
canceled
Canceled by user
Agent Card
An Agent Card describes an agent's identity, capabilities, endpoints, and skills. Published as a Nostr replaceable event (kind 31337) for discovery.
Required fields: name , description , version , identity (P2TR), skills , defaultInputModes , defaultOutputModes .
Optional fields: endpoints (HTTP/WS URLs), nostrRelays , protocolVersion , capabilities (streaming, push), provider , trust , iconUrl .
Critical Constraints
Field Rule
P2TR address Exactly 62 chars, prefix bc1p or tb1p
Message ID 1-128 chars, [a-zA-Z0-9_-] only
Timestamp Unix seconds, ±60s from current time
Signature 128 lowercase hex chars (64-byte Schnorr, BIP-340)
Version Must be "0.1"
Payload Max 1 MB serialized, max depth 10
Network If to is present, from and to must be same network (both mainnet or both testnet)
For complete field constraints, see references/constraints.md.
Error Codes
Range Category
1xxx Task/Message errors (invalid format, unknown method)
2xxx Authentication errors (bad signature, expired timestamp, replay)
3xxx Discovery errors (agent not found, invalid card)
4xxx Transport errors (timeout, connection refused)
5xxx System errors (rate limit, maintenance)
Errors are returned in the message payload, not as HTTP status codes. All SNAP responses use HTTP 200.
For complete error code listing, see references/error-codes.md.
Nostr Integration
Default relay: wss://snap.onspace.ai
Kind Type Purpose
31337 Replaceable (NIP-33) Agent Card publication
21339 Ephemeral (NIP-16) Real-time encrypted SNAP message (default)
4339 Regular (storable) Persistent/offline SNAP message
Messages are encrypted end-to-end using NIP-44. The relay only sees ciphertext. By default, real-time messages use ephemeral kind 21339 (not stored). Set persist: true for storable kind 4339 (offline retrieval).
For Nostr event structure and offline messaging, see references/nostr-transport.md.
SDK Implementations
Language Skill
TypeScript typescript/SKILL.md