syntax = "proto3"; package nostr.v1; option go_package = "northwest.io/nostr-grpc/api/nostr/v1;nostrv1"; // Core Nostr event as defined in NIP-01 message Event { string id = 1; string pubkey = 2; int64 created_at = 3; int32 kind = 4; repeated Tag tags = 5; string content = 6; string sig = 7; // Optional: only populated if client requests verification // Contains exact canonical JSON bytes that were signed optional bytes canonical_json = 8; } // Tag is an array of strings (e.g., ["e", "event_id", "relay_url"]) message Tag { repeated string values = 1; } // Nostr filter for querying events (REQ) message Filter { repeated string ids = 1; repeated string authors = 2; // pubkeys repeated int32 kinds = 3; repeated string e_tags = 4; // #e tag values repeated string p_tags = 5; // #p tag values optional int64 since = 6; optional int64 until = 7; optional int32 limit = 8; // Extension: support for arbitrary tag filters map tag_filters = 9; } // Filter for arbitrary tags message TagFilter { repeated string values = 1; } // Request to publish a single event message PublishEventRequest { Event event = 1; } // Response after publishing an event message PublishEventResponse { bool accepted = 1; string message = 2; // Error message or "duplicate" or "success" // Always include canonical JSON so client can verify // what the relay stored bytes canonical_json = 3; } // Request to subscribe to events matching filters message SubscribeRequest { repeated Filter filters = 1; // If true, include canonical_json in streamed Event messages // Allows client-side signature verification // Default: false (most clients trust the relay) bool include_canonical_json = 2; // Optional client-provided subscription ID for tracking string subscription_id = 3; } // Request to unsubscribe from an active subscription message UnsubscribeRequest { string subscription_id = 1; } // Batch publish request message PublishBatchRequest { repeated Event events = 1; } // Batch publish response message PublishBatchResponse { repeated PublishEventResponse results = 1; } // Paginated query request message QueryRequest { repeated Filter filters = 1; bool include_canonical_json = 2; // Pagination string cursor = 3; // Opaque cursor from previous response int32 page_size = 4; // Default: 100 } // Paginated query response message QueryResponse { repeated Event events = 1; string next_cursor = 2; // Empty if no more results int32 total_count = 3; // Optional: total matching events } // Event count request (NIP-45) message CountRequest { repeated Filter filters = 1; } // Event count response message CountResponse { int64 count = 1; } // Empty message message Empty {} // Main relay service service NostrRelay { // Publish a single event rpc PublishEvent(PublishEventRequest) returns (PublishEventResponse); // Subscribe to events matching filters (streaming) rpc Subscribe(SubscribeRequest) returns (stream Event); // Unsubscribe from an active subscription rpc Unsubscribe(UnsubscribeRequest) returns (Empty); // gRPC-specific: batch publish rpc PublishBatch(PublishBatchRequest) returns (PublishBatchResponse); // gRPC-specific: paginated query (non-streaming) rpc QueryEvents(QueryRequest) returns (QueryResponse); // Event counts (NIP-45) rpc CountEvents(CountRequest) returns (CountResponse); } // Admin service (optional, secured separately) service RelayAdmin { rpc GetStats(Empty) returns (RelayStats); rpc GetConnections(Empty) returns (ConnectionList); rpc BanPublicKey(BanRequest) returns (Empty); rpc GetStorageInfo(Empty) returns (StorageStats); } // Relay statistics message RelayStats { int64 total_events = 1; int64 total_subscriptions = 2; int64 connected_clients = 3; int64 events_per_second = 4; int64 uptime_seconds = 5; } // List of active connections message ConnectionList { repeated Connection connections = 1; } // Single connection info message Connection { string client_id = 1; string protocol = 2; // "websocket" or "grpc" int64 connected_at = 3; int32 active_subscriptions = 4; } // Request to ban a public key message BanRequest { string pubkey = 1; int64 until = 2; // Unix timestamp, 0 for permanent string reason = 3; } // Storage statistics message StorageStats { int64 total_bytes = 1; int64 total_events = 2; int64 db_size_bytes = 3; }