Complete REST API reference for GRAIN relay operations.
- GRAIN API Documentation
- Table of Contents
- Base URL
- Client API Endpoints
- Relay Management API
- Configuration Endpoints
- Get Server Configuration
- Get Rate Limit Configuration
- Get Event Purge Configuration
- Get Logging Configuration
- Get MongoDB Configuration
- Get Resource Limits Configuration
- Get Auth Configuration
- Get Event Time Constraints Configuration
- Get Backup Relay Configuration
- Get User Sync Configuration
- Get Whitelist Configuration
- Get Blacklist Configuration
- WebSocket & Protocol Endpoints
- Progressive Web App (PWA) Endpoints
- Quick Reference
- Response Status Codes
- Error Response Format
- Rate Limiting
/api/v1
Web client operations, user management, and Nostr client functionality.
GET /api/v1/sessionReturns information about the current user session.
Response:
{
"publicKey": "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d",
"lastActive": "2024-01-15T12:00:00Z",
"relays": {
"userRelays": ["wss://relay.damus.io", "wss://nos.lol"],
"relayCount": 2
}
}GET /api/v1/cacheReturns cached user data including profile and mailboxes.
Response:
{
"publicKey": "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d",
"npub": "npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6",
"metadata": {
"name": "fiatjaf",
"about": "I made Nostr",
"picture": "https://example.com/pic.jpg"
},
"mailboxes": {
"read": ["wss://relay.damus.io"],
"write": ["wss://nos.lol"],
"both": ["wss://relay.nostr.band"]
}
}POST /api/v1/cache/refreshManually triggers a cache refresh for the current user.
Response:
{
"status": "success",
"message": "Cache refreshed successfully"
}POST /api/v1/auth/login
Content-Type: application/json
{
"publicKey": "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"
}Response:
{
"status": "success",
"publicKey": "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"
}POST /api/v1/auth/logoutResponse:
{
"status": "success",
"message": "Logged out successfully"
}GET /api/v1/auth/amber-callback?event={signed_event}Handles the callback from Amber signer for NIP-55 authentication flow.
GET /api/v1/keys/generateGenerates a new random Nostr keypair.
Response:
{
"private_key": "ee5e36081fe74482ce9085a8e97ee020d6d20a0d1fddc0dd986c5629883b111a",
"public_key": "68027a7931229f043fed19028462df6279fcaf099d33cb75edaf2c5d698b23ad",
"nsec": "nsec1ae0rvzqluazg9n5ssk5wjlhqyrtdyzsdrlwuphvcd3tznzpmzydqzxfym7",
"npub": "npub1dqp857f3y20sg0ldrypggcklvfuletcfn5euka0d4uk966vtywksrs7n24"
}GET /api/v1/keys/derive/<private_key>Derives the public key from a private key. Accepts both hex and nsec formats.
Examples:
Derive from hex private key:
GET /api/v1/keys/derive/ee5e36081fe74482ce9085a8e97ee020d6d20a0d1fddc0dd986c5629883b111aDerive from nsec:
GET /api/v1/keys/derive/nsec1ae0rvzqluazg9n5ssk5wjlhqyrtdyzsdrlwuphvcd3tznzpmzydqzxfym7Parameters:
pubkey(required) - Hex-encoded public key
Response:
{
"public_key": "68027a7931229f043fed19028462df6279fcaf099d33cb75edaf2c5d698b23ad",
"npub": "npub1dqp857f3y20sg0ldrypggcklvfuletcfn5euka0d4uk966vtywksrs7n24"
}GET /api/v1/keys/convert/public/<key>Converts between hex and npub formats. Auto-detects input format.
Examples:
Convert hex to npub:
GET /api/v1/keys/convert/public/3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459dConvert npub to hex:
GET /api/v1/keys/convert/public/npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6Response:
Convert hex to npub:
{
"npub": "npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6"
}Convert npub to hex:
{
"public_key": "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"
}GET /api/v1/keys/convert/private/<key>Converts between hex and nsec formats. Auto-detects input format.
Examples:
Convert hex to nsec:
GET /api/v1/keys/convert/private/ee5e36081fe74482ce9085a8e97ee020d6d20a0d1fddc0dd986c5629883b111aConvert nsec to hex:
GET /api/v1/keys/convert/private/nsec1ae0rvzqluazg9n5ssk5wjlhqyrtdyzsdrlwuphvcd3tznzpmzydqzxfym7Parameters:
pubkey(required) - Hex-encoded public key to validate
Response:
Convert hex to nsec:
{
"nsec": "nsec1ae0rvzqluazg9n5ssk5wjlhqyrtdyzsdrlwuphvcd3tznzpmzydqzxfym7"
}Convert nsec to hex:
{
"private_key": "ee5e36081fe74482ce9085a8e97ee020d6d20a0d1fddc0dd986c5629883b111a"
}GET /api/v1/keys/validate/<key>Validates any key type (hex, npub, or nsec) and returns the key type.
Examples:
Validate hex public key:
GET /api/v1/keys/validate/3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459dValidate npub:
GET /api/v1/keys/validate/npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6Validate nsec:
GET /api/v1/keys/validate/nsec1ae0rvzqluazg9n5ssk5wjlhqyrtdyzsdrlwuphvcd3tznzpmzydqzxfym7Response:
Valid key:
{
"valid": true,
"type": "npub"
}Invalid key:
{
"valid": false,
"type": "unknown",
"error": "Invalid key format"
}Error Response (for all endpoints):
{
"error": "Error message"
}GET /api/v1/ping/{domain}Pings a relay and returns response time and connection status with automatic protocol detection.
Parameters:
{domain}- Relay domain (e.g.,relay.damus.io)
Examples:
GET /api/v1/ping/relay.damus.io
GET /api/v1/ping/nos.lol
GET /api/v1/ping/wheat.happytavern.coResponse:
{
"success": true,
"response_time": 45,
"relay": "wss://relay.damus.io/"
}Failed Response:
{
"success": false,
"response_time": 5000,
"relay": "relay.damus.io",
"error": "Unable to connect via ws:// or wss://"
}POST /api/v1/client/connect/{domain}
POST /api/v1/client/connect/{domain}?read=true&write=falseConnects to a relay with automatic protocol detection and configurable permissions.
Parameters:
{domain}- Relay domain (e.g.,relay.damus.io)read(optional) - Read permission (default:true)write(optional) - Write permission (default:true)
Examples:
POST /api/v1/client/connect/relay.damus.io
POST /api/v1/client/connect/nos.lol?read=true&write=false
POST /api/v1/client/connect/wheat.happytavern.co?read=false&write=trueResponse:
{
"success": true,
"relay": "wss://relay.damus.io/",
"message": "Successfully connected to relay",
"connected": true,
"read": true,
"write": false
}Error Response:
{
"success": false,
"relay": "relay.damus.io",
"error": "Unable to connect via ws:// or wss://"
}POST /api/v1/client/disconnect/{domain}Disconnects from a relay and removes it from the user's relay list.
Parameters:
{domain}- Relay domain (e.g.,relay.damus.io)
Examples:
POST /api/v1/client/disconnect/relay.damus.io
POST /api/v1/client/disconnect/nos.lol
POST /api/v1/client/disconnect/offchain.pubResponse:
{
"success": true,
"relay": "wss://relay.damus.io/",
"message": "Successfully disconnected from relay",
"connected": false
}Error Response:
{
"success": false,
"relay": "relay.damus.io",
"error": "Relay not found in user's relay list"
}GET /api/v1/client/relays
GET /api/v1/client/relays?ping=trueReturns the status of the user's configured client relays with optional ping testing.
Parameters:
ping(optional) - Include latency testing (default:false)
Examples:
GET /api/v1/client/relays
GET /api/v1/client/relays?ping=trueResponse:
{
"relays": [
{
"url": "wss://relay.damus.io/",
"connected": true,
"status": "connected",
"latency": 45,
"last_checked": "2025-07-28T19:34:52Z",
"read": true,
"write": false,
"added_at": "2025-07-28T18:57:58Z"
},
{
"url": "wss://nos.lol/",
"connected": false,
"status": "disconnected",
"last_checked": "2025-07-28T19:34:52Z",
"read": true,
"write": true,
"added_at": "2025-07-28T18:57:58Z"
}
],
"count": 2
}Status Values:
"connected"- Relay is actively connected via core client"disconnected"- Relay not connected via core client"reachable"- Not connected but ping successful (whenping=true)"unreachable"- Not connected and ping failed (whenping=true)
All relay operations automatically detect and use the correct protocol:
- Tries
wss://(secure) first - Falls back to
ws://if needed - Returns the working protocol in responses
Connect operations support granular permissions:
read=true&write=true- Full access (default)read=true&write=false- Read-only accessread=false&write=true- Write-only access- Both
falseis rejected as invalid
All client relay operations require user authentication via session cookies.
⚠️ Note: The publish endpoint is currently in development. The current implementation has limited functionality. Full support for all signing methods and anonymous publishing will be available in the next update.
POST /api/v1/publishPublishes a Nostr event to relays with flexible signing options. Supports both authenticated and anonymous publishing.
Authentication: Optional - works with or without session
Signing Methods Available (Next Update):
Browser Extension Signing (Recommended)
{
"content": "Hello Nostr!",
"kind": 1,
"tags": [],
"signingMethod": "extension",
"relays": ["wss://relay.damus.io", "wss://nos.lol"]
}Amber Signer (Android)
{
"content": "Hello Nostr!",
"kind": 1,
"tags": [],
"signingMethod": "amber",
"relays": ["wss://relay.damus.io"]
}Bunker/Remote Signer
{
"content": "Hello Nostr!",
"kind": 1,
"tags": [],
"signingMethod": "bunker",
"bunkerUri": "bunker://npub1234...@relay.example.com?relay=wss://relay.example.com",
"relays": ["wss://relay.damus.io"]
}Anonymous Random Key
{
"content": "Hello Nostr!",
"kind": 1,
"tags": [],
"signingMethod": "anonymous"
}Manual Private Key (Not Recommended)
{
"content": "Hello Nostr!",
"kind": 1,
"tags": [],
"signingMethod": "manual",
"privateKey": "your_private_key_hex",
"relays": ["wss://relay.damus.io"]
}Request Fields:
content(required): Event content textkind(required): Nostr event kindsigningMethod(required): One of:extension,amber,bunker,anonymous,manualtags(optional): Tag arrays[["e", "event_id"], ["p", "pubkey"]]relays(optional): Custom relay URLsprivateKey(conditional): Required forsigningMethod: "manual"bunkerUri(conditional): Required forsigningMethod: "bunker"
Authentication Behavior:
- With Session: Uses session pubkey and relays
- Without Session: Forces anonymous mode with default relays
Response:
{
"success": true,
"eventId": "1234567890abcdef...",
"pubkey": "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d",
"signingMethod": "extension",
"event": {
"id": "1234567890abcdef...",
"pubkey": "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d",
"created_at": 1704067200,
"kind": 1,
"content": "Hello Nostr!",
"tags": [],
"sig": "abcdef1234567890..."
},
"results": [
{
"relay": "wss://relay.damus.io",
"success": true,
"error": null,
"responseTime": 150
}
],
"summary": {
"successful": 1,
"failed": 0,
"totalRelays": 1,
"successRate": 1.0
}
}Error Response:
{
"success": false,
"error": "User denied signing request",
"signingMethod": "extension",
"code": "SIGNING_DENIED"
}Security Notes:
- Browser extension and remote signers are recommended over manual private keys
- Anonymous mode generates ephemeral keypairs for one-time use
- Manual private key transmission should only occur over HTTPS
- Default relays are used when no session exists
GET /api/v1/events/query?authors=3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d&kinds=1&limit=10Queries events from connected relays using Nostr filters. Uses a 10-second timeout for collecting results.
Query Parameters:
authors: Pubkey values (repeat parameter for multiple:authors=pubkey1&authors=pubkey2)kinds: Event kind numbers (repeat parameter for multiple:kinds=1&kinds=7)limit: Maximum number of events to returnids: Event IDs (repeat parameter for multiple:ids=id1&ids=id2)
Currently Supported Parameters:
- ✅
authors- Filter by pubkey - ✅
kinds- Filter by event kind - ✅
limit- Maximum results - ✅
ids- Filter by event ID
Not Yet Implemented:
- ❌
since- Unix timestamp (planned) - ❌
until- Unix timestamp (planned) - ❌
#e- Event ID tags (planned) - ❌
#p- Pubkey tags (planned)
Example Queries:
Single author, single kind:
GET /api/v1/events/query?authors=3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d&kinds=1&limit=10
Multiple authors and kinds:
GET /api/v1/events/query?authors=pubkey1&authors=pubkey2&kinds=1&kinds=7&limit=20
Specific event IDs:
GET /api/v1/events/query?ids=event_id_1&ids=event_id_2
Response:
{
"events": [
{
"id": "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"pubkey": "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d",
"created_at": 1234567890,
"kind": 1,
"content": "Hello Nostr!",
"tags": [],
"sig": "abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
}
],
"count": 1
}Response Fields:
events: Array of Nostr events matching the filtercount: Number of events returned
Behavior:
- Creates WebSocket subscription to fetch events
- Collects results for up to 10 seconds
- Returns when EOSE (End of Stored Events) received or timeout reached
- Uses connected relays from core client
GET /api/v1/user/profile?pubkey=3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459dFetches user profile metadata (kind 0 event). If no pubkey is provided, uses current session pubkey.
Response:
{
"id": "c43be8b4634298e97dde3020a5e6aeec37d7f5a4b0259705f496e81a550c8f8b",
"pubkey": "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d",
"created_at": 1738588530,
"kind": 0,
"tags": [],
"content": "{\"name\":\"fiatjaf\",\"about\":\"~\",\"picture\":\"https://fiatjaf.com/static/favicon.jpg\",\"nip05\":\"_@fiatjaf.com\",\"lud16\":\"fiatjaf@zbd.gg\",\"website\":\"https://nostr.technology\"}",
"sig": "202a1bf6a58943d660c1891662dbdda142aa8e5bca9d4a3cb03cde816ad3bdda6f4ec3b880671506c2820285b32218a0afdec2d172de9694d83972190ab4f9da"
}GET /api/v1/user/relays?pubkey=3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459dFetches user's relay list (kind 10002 event). If no pubkey is provided, uses current session pubkey.
Response:
{
"read": ["wss://inbox.relays.land/"],
"write": ["wss://pyramid.fiatjaf.com/", "wss://relay.westernbtc.com/"],
"both": null
}Administrative endpoints for relay operators.
GRAIN provides both cached and live endpoints for key management. Use cached endpoints for performance and live endpoints for verification after configuration changes.
GET /api/v1/relay/keys/whitelistReturns all whitelisted pubkeys from cache. Uses cached data - may not reflect recent configuration changes until next cache refresh. This endpoint provides fast responses and is suitable for regular operations.
Cache Refresh Interval: Based on cache_refresh_minutes in whitelist configuration (default: 60 minutes)
Response:
{
"list": [
"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d",
"fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52"
],
"domains": [
{
"domain": "example.com",
"pubkeys": [
"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
]
}
]
}Response Fields:
list: All cached pubkeys from all sources (config + domains)domains: Array of domain objects with their cached pubkeys
GET /api/v1/relay/keys/whitelist/liveReturns all whitelisted pubkeys with fresh domain fetching. Fetches live data - makes HTTP requests to domains for current NIP-05 data. Use this endpoint to verify configuration changes or when you need the most current data.
Performance Note: Slower response due to live HTTP requests to external domains.
Response:
{
"list": [
"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d",
"fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52"
],
"domains": [
{
"domain": "example.com",
"pubkeys": [
"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
]
}
]
}Response Fields:
list: All pubkeys from config + live domain fetchdomains: Array of domain objects with freshly fetched pubkeys
GET /api/v1/relay/keys/blacklistReturns all blacklisted pubkeys organized by source. Uses live mutelist data - fetches current mutelist data for consistent structure with live endpoint.
Response:
{
"permanent": [
"33c74427f3b2b73d5e38f3e6c991c122a55d204072356f71da49a0e209fb6940",
"db0c9b8acd6101adb9b281c5321f98f6eebb33c5719d230ed1870997538a9765"
],
"temporary": [
{
"pubkey": "efgh5678901234567890abcdef1234567890abcdef1234567890abcdef1234",
"expires_at": 1704067200
}
],
"mutelist": {
"16f1a0100d4cfffbcc4230e8e0e4290cc5849c1adc64d6653fda07c031b1074b": [
"a30816b063c858965f032ee5aa50b6e8091225e583970c2b167ac00de6c54ba5",
"cf94884ef3330842f55faeeeec6bb3b0e3f0c63ccf2b9ac5f15c94752f637cda"
],
"3fe0ab6cbdb7ee27148202249e3fb3b89423c6f6cda6ef43ea5057c3d93088e4": [
"0f45cbe562351c7211742fe02cc3e6f91d6cf5b306873c0f3e9fc0c570d3371c",
"d8a6ecf0c396eaa8f79a4497fe9b77dc977633451f3ca5c634e208659116647b"
]
}
}Response Fields:
permanent: Permanently blacklisted pubkeys from configtemporary: Temporarily banned pubkeys with expiration timestamps (null if none)mutelist: Object where keys are mutelist author pubkeys and values are arrays of their muted pubkeys
GET /api/v1/relay/keys/blacklist/liveReturns all blacklisted pubkeys with fresh mutelist fetching. Fetches live data - makes WebSocket requests to local relay for current mutelist data. Use this endpoint to verify recent mutelist changes or when you need the most current data.
Performance Note: Slower response due to live WebSocket requests to fetch mute lists.
Response:
{
"permanent": [
"33c74427f3b2b73d5e38f3e6c991c122a55d204072356f71da49a0e209fb6940",
"db0c9b8acd6101adb9b281c5321f98f6eebb33c5719d230ed1870997538a9765"
],
"temporary": null,
"mutelist": {
"16f1a0100d4cfffbcc4230e8e0e4290cc5849c1adc64d6653fda07c031b1074b": [
"a30816b063c858965f032ee5aa50b6e8091225e583970c2b167ac00de6c54ba5",
"cf94884ef3330842f55faeeeec6bb3b0e3f0c63ccf2b9ac5f15c94752f637cda"
],
"3fe0ab6cbdb7ee27148202249e3fb3b89423c6f6cda6ef43ea5057c3d93088e4": [
"0f45cbe562351c7211742fe02cc3e6f91d6cf5b306873c0f3e9fc0c570d3371c",
"d8a6ecf0c396eaa8f79a4497fe9b77dc977633451f3ca5c634e208659116647b"
]
}
}Response Fields:
permanent: Permanently blacklisted pubkeys from configtemporary: Temporarily banned pubkeys with expiration timestamps (null if none)mutelist: Object where keys are mutelist author pubkeys and values are arrays of their live-fetched muted pubkeys
Use Cached Endpoints When:
- Regular operations and monitoring
- Building dashboards or UIs
- Need structured breakdown by source
- Want to see mutelist author organization
Use Live Endpoints When:
- Verifying configuration changes
- Testing new mutelist author additions
- Debugging blacklist issues
- Need guaranteed current mutelist data
Configuration Notes:
- Both endpoints return the same structure for consistency
- Cached endpoint still fetches live mutelist data for proper grouping
mutelistfield shows which pubkeys came from which mutelist authors- Data is returned regardless of blacklist enabled/disabled state
temporaryfield returnsnullwhen no temporary bans exist
Mutelist Structure:
The mutelist object uses mutelist author pubkeys as keys:
- Key: Mutelist author's pubkey (from
mutelist_authorsconfig) - Value: Array of pubkeys that author has muted (from their kind 10000 events)
This allows you to see which specific mutelist authors contributed which muted pubkeys to your relay's blacklist.
All configuration endpoints are read-only and return current relay settings.
GET /api/v1/relay/config/serverResponse:
{
"read_timeout": 10,
"write_timeout": 10,
"idle_timeout": 120,
"max_subscriptions_per_client": 10,
"implicit_req_limit": 100
}GET /api/v1/relay/config/rate_limitResponse:
{
"ws_limit": 10,
"ws_burst": 5,
"event_limit": 100,
"event_burst": 10,
"req_limit": 50,
"req_burst": 10,
"max_event_size": 65536,
"kind_size_limits": [
{
"kind": 0,
"max_size": 8192
}
],
"category_limits": {
"regular": {
"rate": 100,
"burst": 10
}
},
"kind_limits": [
{
"kind": 1,
"rate": 50,
"burst": 5
}
]
}GET /api/v1/relay/config/event_purgeResponse:
{
"enabled": true,
"disable_at_startup": false,
"keep_interval_hours": 24,
"purge_interval_minutes": 60,
"purge_by_category": {
"regular": true,
"replaceable": false,
"ephemeral": true
},
"purge_by_kind_enabled": true,
"kinds_to_purge": [1, 7],
"exclude_whitelisted": true
}GET /api/v1/relay/config/loggingResponse:
{
"level": "info",
"file": "debug",
"max_log_size_mb": 10,
"structure": false,
"check_interval_min": 10,
"backup_count": 2,
"suppress_components": [
"util",
"conn-manager",
"client",
"mongo-query",
"event-store",
"close-handler"
]
}GET /api/v1/relay/config/mongodbResponse:
{
"uri": "mongodb://localhost:27017",
"database": "grain"
}GET /api/v1/relay/config/resource_limitsResponse:
{
"cpu_cores": 4,
"memory_mb": 1024,
"heap_size_mb": 512
}GET /api/v1/relay/config/authResponse:
{
"enabled": true,
"relay_url": "wss://auth.relay.com"
}GET /api/v1/relay/config/event_time_constraintsResponse:
{
"max_created_at_future_seconds": 900,
"max_created_at_past_seconds": 94608000
}GET /api/v1/relay/config/backup_relayResponse:
{
"enabled": true,
"url": "wss://backup.relay.com"
}GET /api/v1/relay/config/user_syncResponse:
{
"enabled": true,
"interval_hours": 6,
"batch_size": 100
}GET /api/v1/relay/config/whitelistReturns the complete whitelist configuration from whitelist.yml.
Response:
{
"pubkey_whitelist": {
"enabled": false,
"pubkeys": [
"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"
],
"npubs": [
"npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6"
],
"cache_refresh_minutes": 60
},
"kind_whitelist": {
"enabled": false,
"kinds": ["0", "1", "3", "7"]
},
"domain_whitelist": {
"enabled": false,
"domains": ["example.com", "nostr.example.org"],
"cache_refresh_minutes": 120
}
}GET /api/v1/relay/config/blacklistReturns the complete blacklist configuration from blacklist.yml.
Response:
{
"enabled": true,
"permanent_ban_words": ["spam", "scam"],
"temp_ban_words": ["crypto", "airdrop"],
"max_temp_bans": 3,
"temp_ban_duration": 3600,
"permanent_blacklist_pubkeys": [
"abcd1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcd"
],
"permanent_blacklist_npubs": [
"npub1abcd1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
],
"mutelist_authors": ["author_pubkey_1", "author_pubkey_2"],
"mutelist_cache_refresh_minutes": 120
}ws://localhost:8080/
wss://yourdomain.com/
Standard Nostr relay protocol implementation supporting NIPs 1, 2, 9, 11, 40, 42.
GET /
Accept: application/nostr+jsonResponse:
{
"name": "🌾 My GRAIN Relay",
"description": "A community Nostr relay running GRAIN",
"pubkey": "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d",
"contact": "admin@example.com",
"supported_nips": [1, 2, 9, 11, 40, 42],
"software": "https://github.com/0ceanslim/grain",
"version": "0.4.0",
"limitation": {
"max_message_length": 65536,
"max_subscriptions": 10,
"max_filters": 10,
"max_limit": 5000,
"payment_required": false,
"auth_required": false
}
}GET /manifest.jsonReturns the PWA manifest for installable web app functionality.
GET /sw.jsReturns the service worker JavaScript for offline functionality.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/session |
Get current session info |
| GET | /api/v1/cache |
Get cached user data |
| POST | /api/v1/cache/refresh |
Refresh cache manually |
| POST | /api/v1/auth/login |
Login with public key |
| POST | /api/v1/auth/logout |
Logout current session |
| GET | /api/v1/auth/amber-callback |
Amber signer callback |
| GET | /api/v1/keys/generate |
Generate new keypair |
| GET | /api/v1/keys/derive/{private_key} |
Derive public key from private key |
| GET | /api/v1/keys/convert/public/{key} |
Convert between hex and npub |
| GET | /api/v1/keys/convert/private/{key} |
Convert between hex and nsec |
| GET | /api/v1/keys/validate/{key} |
Validate any key type |
| GET | /api/v1/relay/ping |
Ping relay |
| POST | /api/v1/relays/connect |
Connect to relay |
| POST | /api/v1/relays/disconnect |
Disconnect from relay |
| GET | /api/v1/relays/status |
Get relay connection status |
| POST | /api/v1/publish |
Publish Nostr event |
| GET | /api/v1/events/query |
Query events with filters |
| GET | /api/v1/user/profile |
Get user profile |
| GET | /api/v1/user/relays |
Get user relay list |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/relay/keys/whitelist |
Get whitelisted keys (cached) |
| GET | /api/v1/relay/keys/whitelist/live |
Get whitelisted keys (live) |
| GET | /api/v1/relay/keys/blacklist |
Get blacklisted keys (cached) |
| GET | /api/v1/relay/keys/blacklist/live |
Get blacklisted keys (live) |
| GET | /api/v1/relay/config/server |
Get server configuration |
| GET | /api/v1/relay/config/rate_limit |
Get rate limit configuration |
| GET | /api/v1/relay/config/event_purge |
Get event purge configuration |
| GET | /api/v1/relay/config/logging |
Get logging configuration |
| GET | /api/v1/relay/config/mongodb |
Get MongoDB configuration |
| GET | /api/v1/relay/config/resource_limits |
Get resource limits |
| GET | /api/v1/relay/config/auth |
Get auth configuration |
| GET | /api/v1/relay/config/event_time_constraints |
Get time constraints |
| GET | /api/v1/relay/config/backup_relay |
Get backup relay config |
| GET | /api/v1/relay/config/user_sync |
Get user sync config |
| GET | /api/v1/relay/config/whitelist |
Get complete whitelist config |
| GET | /api/v1/relay/config/blacklist |
Get complete blacklist config |
| Method | Endpoint | Description |
|---|---|---|
| WebSocket | / |
Nostr relay WebSocket |
| GET | / |
NIP-11 relay information |
| GET | /manifest.json |
PWA manifest |
| GET | /sw.js |
Service worker |
200 OK- Request successful400 Bad Request- Invalid request parameters401 Unauthorized- Authentication required404 Not Found- Resource not found429 Too Many Requests- Rate limit exceeded500 Internal Server Error- Server error
{
"error": "Error message",
"code": "ERROR_CODE",
"details": "Additional error details"
}API endpoints are subject to rate limiting based on the relay configuration. Rate limit headers are included in responses:
X-RateLimit-Limit: Maximum requests allowedX-RateLimit-Remaining: Remaining requests in current windowX-RateLimit-Reset: Unix timestamp when limit resets