14 KiB
📚 status-backend API Reference
Practical API reference for building agents/bots and integrations with status-backend.
For architecture overview and how to read the source code, see README.md.
📍 HTTP Endpoints
GET /health
Health check. Returns HTTP 200 with {"version": "..."} if operational.
POST /statusgo/InitializeApplication
Initialize the application. Must be called before login or account creation.
Request:
{"dataDir": "/path/to/data"}
Response:
{
"accounts": [
{"key-uid": "0xabc...", "name": "MyBot", "identicon": "..."}
]
}
accounts: list of existing accounts in the data directory.- An empty
accountsarray means this is a fresh installation and you need to create an account.
POST /statusgo/CreateAccountAndLogin
Create a new account and log in. Generates a BIP39 mnemonic internally.
Request:
{
"rootDataDir": "/path/to/data",
"displayName": "MyBot",
"password": "...",
"customizationColor": "primary"
}
Response: {"error": ""} on success.
Note
The
keyUIDis NOT in the HTTP response — it arrives via thenode.loginsignal event, or can be read fromsettings_getSettingsafter login.
Signal: Fires node.login signal asynchronously.
POST /statusgo/LoginAccount
Log in to an existing account.
Request:
{"keyUID": "0xabc...", "password": "..."}
Response: {"error": ""} — but this can be misleading. The HTTP response may contain an error if request parsing or validation failed. However, a successful HTTP response ({"error": ""}) does not mean login succeeded — the actual login result comes asynchronously via the node.login WebSocket signal.
Important
Always wait for the
node.loginsignal and check itserrorfield. Do NOT trust the HTTP response alone.
Important
Calling
LoginAccountwhen already logged in returns{"error": "node is already running"}or may crash the backend. Always checksettings_getSettingsfor apublic-keyfield first to determine if already logged in.
POST /statusgo/CallRPC
JSON-RPC gateway to all status-go services.
Request:
{"jsonrpc": "2.0", "id": 1, "method": "wakuext_methodName", "params": [...]}
Response:
{"jsonrpc": "2.0", "id": 1, "result": "...", "error": {"code": -32000, "message": "..."}}
Note
The
idfield is required — omitting it causes empty or broken responses.
Note
JSON-RPC errors are objects
{code, message}, while HTTP API errors (InitializeApplication,LoginAccount) are strings. Handle both formats in your client.
📡 WebSocket Signals
Connection
Connect to ws://<host>:<port>/signals as the first step before any other API calls.
Important
status-backenddoes NOT respond to WebSocket pings. Disable keepalive/ping in your WebSocket client or the connection will be dropped.
Signal Format
{"type": "signal.name", "event": {...}}
Key Signals
| Signal | When | Key event fields |
|---|---|---|
node.login |
After LoginAccount or CreateAccountAndLogin completes |
error, settings, account |
node.started |
Node process started | — |
node.ready |
Node fully initialized | — |
messages.new |
New messages received | messages[] — array of message objects |
mediaserver.started |
Media server ready | — |
mailserver.changed |
Connected to mailserver | — |
mailserver.available |
Mailserver available | — |
history.request.started |
Fetching message history | — |
history.request.completed |
History fetch done | — |
envelope.sent |
Message envelope sent via Waku | — |
node.login Signal Details
{
"type": "node.login",
"event": {
"error": "",
"settings": {...},
"account": {...}
}
}
Special error values:
""(empty) — login successful."node is already running"— can be treated as success (already logged in)."failed to get account kdf iterations..."— thekeyUIDdoesn't exist in the data directory.
🔧 RPC Methods
All methods are called via POST /statusgo/CallRPC with JSON-RPC format.
settings_getSettings
Get current account settings.
Params: []
Result:
{
"public-key": "0x04abc...",
"display-name": "MyBot",
"key-uid": "0xabc...",
...
}
Usage: Check if result["public-key"] exists to determine whether the backend is logged in.
wakuext_startMessenger
Start the Waku messenger service. Must be called after login.
Params: []
Behavior:
- Typically completes in several seconds.
- Subsequent calls return immediately ("already started").
- Will return an error if something went wrong.
The standard approach is to call it synchronously (blocking). If you need to do other work in parallel, you can call it asynchronously as a workaround — in that case, poll readiness by calling wakuext_joinedCommunities until it stops returning "does not exist" errors.
wakuext_joinedCommunities
List communities the user has joined.
Params: []
Result:
[{
"id": "0x03abc...",
"name": "Community Name",
"joined": true,
"isMember": true,
"verified": true,
"members": {
"0x04pubkey...": {"roles": [1]}
},
"chats": {
"chat-uuid": {
"name": "general",
"canPost": true
}
}
}]
⚠️ joined vs isMember
This distinction is critical for bot developers:
| Field | Meaning | Set by |
|---|---|---|
joined |
"I want to be in this community" (local intent) | Local joinCommunity call |
isMember |
"My public key is in the community's Members map" (network state) | Community control node (owner) |
joined: true + isMember: false means the bot expressed intent to join locally, but the community owner's node hasn't added the bot to the members list yet (or the updated community description hasn't propagated via Waku).
Only isMember: true allows posting messages. The canPost field on a channel requires isMember: true at the community level.
Note
The
joinCommunityAPI is deprecated and planned for removal (see #7381). Once removed,joinedandisMemberwill converge into a single field.
wakuext_fetchCommunity
Fetch a community description from the Waku network.
Params:
[{
"communityKey": "0x03abc...",
"tryDatabase": true,
"waitForResponse": true
}]
Result: Community object (description, name, members, chats, etc.)
Usage: Call before joining to ensure the local node has the community description. Without this, requestToJoinCommunity may fail with "community not found".
wakuext_spectateCommunity
Subscribe to a community's Waku pubsub topics without joining. This allows reading community messages before becoming a member.
Params: ["0xcommunityId"]
Note
Spectating is not required for joining a community. The join request and acceptance are exchanged via the default Waku topic, not community-specific topics. However, spectating can be useful to read community messages while waiting for membership approval.
wakuext_requestToJoinCommunity
Send a join request to the community's control node via Waku.
Params:
[{
"communityId": "0x03abc...",
"addressesToReveal": ["0xWalletAddress"],
"airdropAddress": "0xWalletAddress"
}]
What it does:
- Validates request parameters.
- Checks if already a member (returns error if so).
- Creates a
CommunityRequestToJoinprotobuf message. - Sends the request to the community control node via Waku pubsub.
- For open communities: control node auto-accepts.
- For closed communities: control node queues for manual approval.
addressesToReveal: Required. Pass at least one wallet address from accounts_getAccounts. Even for open communities without token gates, the protocol expects addresses to be revealed.
Important
Do NOT use
wakuext_joinCommunityfor joining communities. That method is local-only — it setsjoined: truebut never contacts the control node.isMemberwill remainfalseand you won't be able to post. Always userequestToJoinCommunity. See #7381.
wakuext_joinCommunity
Warning
Deprecated. This method is planned for removal — see #7381. Use
wakuext_requestToJoinCommunityinstead.
LOCAL-ONLY. Sets joined: true in local database but does NOT send any network request.
Params: ["0xcommunityId"]
What it does:
- Sets
joined = truein local DB. - Initializes community chats and filters.
- Does NOT contact the community owner.
- Does NOT add the user to the Members map.
wakuext_sendChatMessage
Send a text message to a chat/channel.
Params:
[{
"chatId": "<chatId>",
"text": "Hello!",
"contentType": 1
}]
Chat ID formats:
-
Community channel: concatenation of community ID and chat UUID without separator:
0x03ab2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b28a805944-9f5d-4219-a104-5d2047f5572a -
1:1 chat: the other user's public key:
0x0416afecc10e3a1ab4c4c7efe03d845c5511f783542e36b1d56bff454214726c6035b8632c012d4fba1bbcd311e39ba33357d3b93bce64c1b176ca0a2f85f0f701
Common error: "can't post message type '1' on chat '...'" — this means canPost is false on the channel, usually because isMember is false at the community level. See the Community Join Sequence section.
wakuext_chatMessages
Read message history for a chat.
Params: [chatId, cursor, limit]
chatId: string (communityId + chatUUID)cursor: string (empty string for first page)limit: number
wakuext_leaveCommunity
Leave a community.
Params: ["0xcommunityId"]
wakuext_communities
List ALL communities (joined + known but not joined).
Params: []
accounts_getAccounts
List wallet accounts and addresses.
Params: []
Result:
[
{"address": "0xabc...", "wallet": true, "chat": false, "type": "generated"},
{"address": "0xdef...", "wallet": false, "chat": true, "type": "key"}
]
Usage: Find the wallet address (wallet: true) for the addressesToReveal parameter in requestToJoinCommunity.
🚀 Startup Sequence
The correct order of operations for a bot:
1. Connect WebSocket to /signals
2. POST /statusgo/InitializeApplication → get existing accounts
3. Login or Create Account:
a. If you have a stored keyUID → POST /statusgo/LoginAccount
b. If accounts exist in response → LoginAccount with first account's key-uid
c. Otherwise → POST /statusgo/CreateAccountAndLogin
4. Wait for node.login signal (check the error field!)
5. POST /statusgo/CallRPC with wakuext_startMessenger
6. RPC methods are now available
Tip
Store the
keyUIDafter first account creation so you can useLoginAccounton subsequent startups.
🏘️ Community Join Sequence
The correct order for joining a community:
1. Get wallet address: accounts_getAccounts → find the entry with wallet: true
2. Fetch community description: wakuext_fetchCommunity
3. Request to join: wakuext_requestToJoinCommunity with addressesToReveal
4. Wait for community owner to accept (open communities: auto-accept)
5. isMember becomes true → wakuext_sendChatMessage now works
Tip
Optionally call
wakuext_spectateCommunitybefore step 3 to read community messages while waiting for approval.
Common Mistakes
-
Using
wakuext_joinCommunityinstead ofrequestToJoinCommunity—joinCommunityis local-only and will never result inisMember: true. See #7381. -
Skipping
fetchCommunity— without fetching the community description first,requestToJoinCommunitymay fail with"community not found". -
Not waiting for membership — after
requestToJoinCommunity, the bot must wait for the community owner's control node to process the request. For open communities this is automatic but not instant.
❌ Error Reference
| Error | Meaning | Resolution |
|---|---|---|
"does not exist" |
RPC handler not registered yet | Wait for startMessenger to complete |
"node is already running" |
LoginAccount called on a running node |
Check settings_getSettings for public-key before logging in |
"can't post message type '1'" |
isMember is false, canPost is false |
Use requestToJoinCommunity, wait for membership confirmation |
"community already joined" |
joinCommunity called when already joined |
Skip, or use requestToJoinCommunity |
"community not found" |
Community description not yet fetched | Call fetchCommunity first |
"method handler crashed" |
Internal RPC handler error | Retry after delay; ensure messenger is started |
"failed to get account kdf iterations" |
keyUID doesn't exist in data directory |
Use a different keyUID or create a new account |
"ErrPermissionToJoinNotSatisfied" |
Wallet doesn't meet token requirements | Check community's token gate requirements |
⚠️ Common Gotchas
-
LoginAccountis asynchronous — The HTTP response returns immediately with{"error": ""}even on failure. Always wait for thenode.loginWebSocket signal and check itserrorfield. -
LoginAccounton a running node crashes — Always check if already logged in viasettings_getSettingsbefore callingLoginAccount. -
WebSocket pings are not supported —
status-backenddoes not respond to WebSocket ping frames. Disable keepalive/ping in your WebSocket client. -
JSON-RPC
idfield is required — Omitting theidfield inCallRPCrequests causes empty or broken responses. -
Two error formats — HTTP API endpoints return
{"error": "string"}. JSON-RPC returns{"error": {"code": -32000, "message": "string"}}. Handle both in your client.