aboutsummaryrefslogtreecommitdiffstats
path: root/docs/MESHBAY_HTTP_API.md
blob: 74b9d779bd31baa7c239989e5415c14074e496af (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# MeshBay HTTP API

> **Generated** by `docs/generate_http_api.py` from the routes themselves. Do not
> edit this file: change the route's docstring and run the script again. A test
> fails when the two disagree.

MeshBay has two HTTP APIs: the **hub's**, for accounts, groups and signaling, and
the **node's control API**, which only its own machine reaches. Files, the index
and chat do not use either: they travel between a client and a node over MNP
(`MESHBAY_NODE_PROTOCOL.md`). Why each API is shaped as it is, who may call
what and what the hub must never see are in `MESHBAY_DESIGN.md`; this file lists
what exists.

`examples/` has small Python programs that use both.

## Hub

Under the hub's address, `https://meshbay.org` on the reference deployment. The
hub also serves the web application at `/` and `/app/`, which are not listed.

| Auth | What the request carries |
|---|---|
| none | No session. Any credential is in the request itself, as the route says |
| user | `Authorization: Bearer`, a person's session. A node's token is refused |
| user or node | A person's session, or a node daemon's token from `/v1/nodes/auth` |
| node | A node daemon's token only |
| moderator | A person's session, for an account with the moderator or admin role |
| admin | A person's session, for an account with the admin role |
| peer hub | Another hub's MHP token. Every route answers 503 unless federation is enabled |

### Instance

| Method | Path | Auth | What |
|---|---|---|---|
| GET | `/v1/hub/info` | none | Versions and the instance policy a client needs before signing in. |
| GET | `/v1/hub/pubkey` | none | Hub Ed25519 public key PEM — cached by nodes on first contact. |
| GET | `/v1/hub/version` | none | Version check endpoint for clients to detect updates. |

### Accounts

| Method | Path | Auth | What |
|---|---|---|---|
| POST | `/v1/users/register` | none | Create an account. |
| POST | `/v1/users/verify-email` | none | Verify a registration email with the code received by mail. |
| POST | `/v1/users/me/bundle-pepper` | user | The pepper, for a session that has just been given the passphrase again. |
| POST | `/v1/users/login` | none | Sign in with the auth key derived from the passphrase. |
| POST | `/v1/users/devices` | user | Register a device's hub authentication key. |
| GET | `/v1/users/devices` | user or node | The account's registered devices. |
| DELETE | `/v1/users/devices/{device_id}` | user | Retire a device's hub key. |
| POST | `/v1/users/auth` | none | Sign in with a registered device key. |
| POST | `/v1/users/token/refresh` | none | Exchange a refresh token for a new session. |
| GET | `/v1/users/me` | user or node | The signed-in account: id, name, e-mail, role, status. |
| PATCH | `/v1/users/me` | user | Update the signed-in account. |
| POST | `/v1/users/verify-email-change` | user | Confirm an email change with the code sent to the new address. |
| POST | `/v1/users/logout` | none | End this session on the hub, not only in the browser. |
| POST | `/v1/users/me/sessions/revoke` | user | Sign out everywhere: no refresh token of this account renews any more. |
| POST | `/v1/users/password` | user | Change the passphrase, proving the current one. |
| POST | `/v1/users/password/reset-request` | none | Send a reset code by e-mail, when the username and the address match. |
| POST | `/v1/users/password/reset` | none | Set a new passphrase with the code received by e-mail. |
| GET | `/v1/users/me/preferences` | user or node | The account's stored interface preferences. |
| PUT | `/v1/users/me/preferences/{key:path}` | user | Store one interface preference. |
| DELETE | `/v1/users/me/preferences/{key:path}` | user | Remove one interface preference. |
| PUT | `/v1/users/me/node_key` | user | Link a node daemon's Ed25519 public key to the operator's account. |
| DELETE | `/v1/users/me/node_key` | user or node | Remove the linked node key from the operator's account. |
| DELETE | `/v1/users/me` | user | Erase your own account. |
| GET | `/v1/users/{username}/pubkeys` | user or node | Resolve a username to its account id, and its node's linking key. |

### Nodes

| Method | Path | Auth | What |
|---|---|---|---|
| POST | `/v1/nodes/mnp-token` | user | Mint the short-lived token a member presents to a node in the MNP handshake. |
| POST | `/v1/nodes/auth` | none | Authenticate a node daemon via Ed25519 challenge-response. |
| POST | `/v1/nodes/announce` | user or node | Register a node record. |
| GET | `/v1/nodes/{node_id}` | user or node | A node's public record: owner, key, endpoint hint. |

### Groups

| Method | Path | Auth | What |
|---|---|---|---|
| GET | `/v1/groups/mine` | user or node | List groups the current user belongs to. |
| GET | `/v1/groups/invitations` | user or node | Groups somebody added this account to, waiting for it to say yes. |
| POST | `/v1/groups/{group_id}/invitation/accept` | user | Accept an invitation: the account becomes a member of the group. |
| POST | `/v1/groups/{group_id}/invitation/decline` | user | Decline an invitation to a group. |
| POST | `/v1/groups/{group_id}/activity` | user or node | Bump a group's last_activity_at. |
| GET | `/v1/groups/{group_id}/nodes` | user or node | Return online nodes that serve a group (for WebRTC connection). |
| GET | `/v1/groups` | none | List/search public groups — local and optionally federated. |
| GET | `/v1/groups/{group_id}/members` | user or node | A group's members, for its members only. |
| POST | `/v1/groups/{group_id}/join` | user | Join an open group. |
| POST | `/v1/groups` | user | Create a group, owned by the caller. |
| DELETE | `/v1/groups/{group_id}/members/{username}` | user | Remove someone from a group. |
| POST | `/v1/groups/{group_id}/leave` | user | Leave a group you are a member of. |
| PATCH | `/v1/groups/{group_id}` | user | Change the group's description. |
| POST | `/v1/groups/{group_id}/members/{username}` | user or node | Add an account to a group the caller owns. |
| POST | `/v1/groups/{group_id}/mute` | user | Turn this group's notifications on or off, for this account. |
| DELETE | `/v1/groups/{group_id}` | user | Delete a group. |
| POST | `/v1/groups/{group_id}/invite-notify` | user | Send an invitation email to a member who was just invited. |
| GET | `/v1/groups/{group_id}/hosts` | user | The nodes that host a group or asked to, for its owner. |
| POST | `/v1/groups/{group_id}/hosts/{node_id}` | user | Approve a node that asked to host this group. |
| DELETE | `/v1/groups/{group_id}/hosts/{node_id}` | user | Withdraw an approval, or turn a request down. |

### Invitation links

| Method | Path | Auth | What |
|---|---|---|---|
| POST | `/v1/groups/{group_id}/invite-links` | user or node | Mint the ticket for a link whose node half already exists. |
| GET | `/v1/groups/{group_id}/invite-links` | user or node | The owner's view: the links nobody has used yet, masked. |
| DELETE | `/v1/groups/{group_id}/invite-links/{link_id}` | user or node | Take the ticket back. |
| POST | `/v1/invite-links/preview` | user | What the confirmation screen shows before anyone joins anything. |
| POST | `/v1/invite-links/redeem` | user | Membership for the first account that asks, once — and the same answer again for that account, because a second tab or a reload is the same person. |

### Revocation and the node socket

| Method | Path | Auth | What |
|---|---|---|---|
| WS | `/v1/nodes/ws` | none | Persistent WebSocket connection for nodes, authenticated by the node's token in the first message. |
| POST | `/v1/nodes/{node_id}/incoming` | user or node | Signal a node that a client wants to connect (NAT punch coordination). |
| POST | `/v1/admin/revoke` | admin | Revoke a user or group. |

### Moderation

| Method | Path | Auth | What |
|---|---|---|---|
| POST | `/v1/reports` | user | Report a file of a public group, as a member of that group. |
| GET | `/v1/blocklist` | node | The content blocklist, a page at a time, for a node hosting a public group. |
| GET | `/v1/admin/blocklist` | admin | The content blocklist. |
| POST | `/v1/admin/blocklist` | admin | Add a content hash (BLAKE3) to the blocklist. |
| DELETE | `/v1/admin/blocklist/{content_hash}` | admin | Remove a content hash from the blocklist. |
| GET | `/v1/admin/reports` | moderator | Hashes waiting for a decision, oldest first, with what was said about them. |
| POST | `/v1/admin/reports/{content_hash}/block` | admin | Block reported content and close its reports. |
| POST | `/v1/admin/reports/{content_hash}/dismiss` | admin | Dismiss the reports on a piece of content. |

### Federation (MHP)

| Method | Path | Auth | What |
|---|---|---|---|
| GET | `/mhp/info` | peer hub | Return this hub's identity for peer registration. |
| GET | `/mhp/directory` | peer hub | This hub's public groups, for a peer hub presenting an MHP token. |
| POST | `/mhp/directory` | peer hub | A peer hub's public groups, pushed with a single-use MHP token. |
| POST | `/mhp/revoke` | peer hub | Act on a revocation from a peer hub. |
| POST | `/mhp/peers` | admin | Admin: register a trusted peer hub. |
| GET | `/mhp/peers` | admin | Admin: list registered peer hubs. |

### Health

| Method | Path | Auth | What |
|---|---|---|---|
| GET | `/v1/health` | none | Liveness: database reachable, version, connected nodes. |

### Signaling

| Method | Path | Auth | What |
|---|---|---|---|
| POST | `/v1/nodes/{node_id}/webrtc/offer` | user or node | Browser sends WebRTC SDP offer for a node. |

### Administration

| Method | Path | Auth | What |
|---|---|---|---|
| GET | `/v1/admin/settings` | moderator | Instance-wide policy an admin controls from the panel. |
| PATCH | `/v1/admin/settings` | admin | Change instance policy. |
| GET | `/v1/admin/mail` | moderator | Is the hub still sending, and how much of the hour is left. |
| GET | `/v1/admin/stats` | moderator | Account, group and node counts. |
| GET | `/v1/admin/users` | moderator | Search and list accounts. |
| GET | `/v1/admin/users/{user_id}` | moderator | One account, with its group count. |
| PATCH | `/v1/admin/users/{user_id}` | moderator | Change an account's status, or its role (admin only). |
| DELETE | `/v1/admin/users/{user_id}` | admin | Erase an account, and every group it owns. |
| GET | `/v1/admin/groups` | moderator | List groups with their member counts. |
| PATCH | `/v1/admin/groups/{group_id}` | moderator | Change a group's status. |
| GET | `/v1/admin/nodes` | moderator | Registered nodes, with the address the hub saw them announce from. |
| GET | `/v1/admin/logs` | moderator | The connection log, filtered by account and event. |

### Notifications

| Method | Path | Auth | What |
|---|---|---|---|
| GET | `/v1/notifications` | user or node | The account's notifications, newest first. |
| POST | `/v1/notifications/{notification_id}/read` | user or node | Dismiss one. |
| DELETE | `/v1/notifications/{notification_id}` | user or node | Dismiss one. |
| DELETE | `/v1/notifications` | user or node | Throw them all away. |
| POST | `/v1/notifications/read-all` | user or node | Dismiss every one — the same thing as `DELETE ""`, under the name an older client knows it by. |

## Node control API

`http://127.0.0.1:<ui_port>`, port 18000 unless `ui_port` in `node.toml` says
otherwise, and never on another address. Every request carries the token the
daemon writes to `<data_dir>/ui-token` (`~/.local/share/meshbay/ui-token` on
Linux), as the `X-MeshBay-Token` header or the `t` query parameter. The daemon
draws a new one at each start and deletes the file when it stops.

| Method | Path | What |
|---|---|---|
| GET | `/api/status` | The daemon's state, and what it still needs: a linked key, a group, an operator, a group key. |
| DELETE | `/api/unlink` | Unlink the node's key from its hub account. |
| GET | `/api/groups` | The groups this node hosts, with live status, and whether an operator is paired. |
| POST | `/api/groups/attach` | Host a group that exists on the hub: add it to node.toml with its first folder, then reload. |
| POST | `/api/groups/detach` | Stop hosting a group: remove it from node.toml, then reload. |
| DELETE | `/api/groups/{group_id}/files/{file_id}` | Delete a file from the group's folder on disk. |
| GET | `/api/denylist` | What the node currently refuses. |
| POST | `/api/denylist/clear` | Drop denylist entries: all of them, or one identifier. |
| GET | `/api/index-cache` | Size of the index cache. |
| POST | `/api/index-cache/prune` | Drop index cache rows that no longer match a file on disk. |
| POST | `/api/groups/{group_id}/video/rematch` | Forget the automatic matches of the group's videos, so they are looked up again. |
| GET | `/api/groups/{group_id}/files` | The group's files, from its index. |
| GET | `/api/peers` | The connected peers. |
| GET | `/api/audit` | The audit log, filtered by time, account and event. |
| POST | `/api/operator/pair` | A one-time code that pairs an application as this node's operator. |
| GET | `/api/roster` | The pinned identities, for one group or all. |
| POST | `/api/groups/{group_id}/invites` | An invitation code for one account, for this group. |
| POST | `/api/groups/{group_id}/invite-links` | A whole invitation link: the node's code, then the hub's ticket. |
| DELETE | `/api/groups/{group_id}/invite-links/{invite_id}` | Take an invitation link back, on the node and on the hub. |
| GET | `/api/resolve` | Map a username to an account id, through the hub. |
| POST | `/api/members/{user_id}/revoke` | Stop serving the group key to a member. |
| POST | `/api/members/{user_id}/unpin` | Forget a pinned identity, so the person can pair again with a new key. |
| GET | `/api/groups/{group_id}/chat` | What the operator needs to decide anything about the group's chat. |
| POST | `/api/groups/{group_id}/chat/epoch` | Open a new chat epoch. |
| POST | `/api/groups/{group_id}/chat/encrypt-history` | Re-encrypt the messages written before the group's chat was encrypted. |
| POST | `/api/groups/{group_id}/chat/prune` | Delete chat messages older than a number of days. |
| POST | `/api/groups/{group_id}/gek` | Generate the group key, or rotate it with ?rotate=true. |
| POST | `/api/groups/{group_id}/roots` | Add a folder to a group. |
| PATCH | `/api/groups/{group_id}/roots/{root_name}` | Make a folder writable or removable, or not. |
| PUT | `/api/groups/{group_id}/roots/{root_name}/eject` | Eject a removable folder so its disk can be unplugged. |
| PUT | `/api/groups/{group_id}/roots/{root_name}/plug` | Bring an ejected folder back. |
| DELETE | `/api/groups/{group_id}/roots/{root_name}` | Remove a folder from a group. |
| GET | `/api/groups/{group_id}/index-status` | One group's indexing progress. |
| GET | `/api/index-status` | Every group's indexing progress. |
| PUT | `/api/groups/{group_id}/apps` | Which applications members see for the group. |
| POST | `/api/reload` | Reload node.toml. |
| POST | `/api/shutdown` | Stop the daemon. |
| GET | `/api/node-settings` | The node's effective settings. |
| PUT | `/api/node-settings` | Change node settings, written to roster.db and node.toml. |
| GET | `/api/transfers` | Live transfer leases and queue depth. |
| PUT | `/api/groups/{group_id}/transfer-limits` | How many transfers one member may run at once in this group. |