Channels (peer)
What a viewer (a web page or another app) calls after opening a share link `https://<provider>/s/<id>#k=<secret>`. The fragment `k` never reaches the server; the viewer derives `authKey` from it to join.
What a viewer reads before joining. meta is sealed with encKey, so only someone holding the link can read it. Public and rate-limited (20 requests per IP per minute by default).
id*stringServer-generated, base64url (16 random bytes → 22 characters).
^[A-Za-z0-9_-]{8,64}$Channel status, sealed meta and the channel public key.
application/json- response
status*ChannelStatus"open""closed""expired"meta*XChaCha20-Poly1305 sealed JSON. n = 24-byte random nonce, c = ciphertext ‖ 16-byte tag. Open it with open() from @pku-harness/cloud-protocol and validate the result.
chanPub*Key3232 bytes, base64url (Ed25519 or X25519 public key, hash).
^[A-Za-z0-9_-]{43}$expiresAt*MsUnix time in milliseconds.
0 <= valueownerOnline*booleancurl -X GET 'https://cloud.example.org/v1/c/string'{ "status": "open", "meta": { "v": 1, "n": "string", "c": "stringstringstringstri" }, "chanPub": "string", "expiresAt": 0, "ownerOnline": true}Claims a seat. The server checks sha256(authKey) against the channel's joinHash and
enforces maxPeers: when the channel is full the answer is 409 conflict, so a forwarded
link is useless once the first viewer claimed it. peerPub is the viewer's ephemeral X25519
key.
id*stringServer-generated, base64url (16 random bytes → 22 characters).
^[A-Za-z0-9_-]{8,64}$application/json- body
authKey*Key3232 bytes, base64url (Ed25519 or X25519 public key, hash).
^[A-Za-z0-9_-]{43}$peerPub*Key3232 bytes, base64url (Ed25519 or X25519 public key, hash).
^[A-Za-z0-9_-]{43}$The peer id and a peer token for the socket, SSE stream, send and mailbox endpoints.
application/json- response
peerId*PeerId^[A-Za-z0-9_-]{4,64}$peerToken*string16 <= lengthexpiresAt*MsUnix time in milliseconds.
0 <= valuecurl -X POST 'https://cloud.example.org/v1/c/string/join' \ -H 'Content-Type: application/json' \ -d '{ "authKey": "string", "peerPub": "string"}'{ "peerId": "string", "peerToken": "stringstringstri", "expiresAt": 0}Upgrades to a WebSocket for a joined peer.
- Server → peer:
PeerInFrame(hello,owneronline state,extended,msg,closed,error,pong). - Peer → server:
PeerOutFrame(msg,ping).
id*stringServer-generated, base64url (16 random bytes → 22 characters).
^[A-Za-z0-9_-]{8,64}$t*stringThe peerToken from POST /v1/c/{id}/join.
16 <= lengthSwitching to the WebSocket protocol. Frames are described by the PeerInFrame and PeerOutFrame schemas.
curl -X GET 'https://cloud.example.org/v1/c/string/ws?t=stringstringstri'Fallback for webviews without WebSocket (WeChat). Each data: line is one PeerInFrame as JSON. Send with POST /v1/c/{id}/send.
id*stringServer-generated, base64url (16 random bytes → 22 characters).
^[A-Za-z0-9_-]{8,64}$t*stringThe peerToken from POST /v1/c/{id}/join.
16 <= lengthServer-sent events.
text/event-stream- response
Server → peer frame (WebSocket message or SSE data: line).
t*stringpeerId*PeerId^[A-Za-z0-9_-]{4,64}$ownerOnline*booleanexpiresAt*MsUnix time in milliseconds.
0 <= valuecurl -X GET 'https://cloud.example.org/v1/c/string/events?t=stringstringstri'{ "t": "hello", "peerId": "string", "ownerOnline": true, "expiresAt": 0}The body is one PeerOutFrame, as it would be sent on the WebSocket.
peerTokenAuthorizationBearer <token>peerToken from POST /v1/c/{id}/join, as Authorization: Bearer. The WebSocket and SSE endpoints take it as the t query parameter (any token may be passed that way).
id*stringServer-generated, base64url (16 random bytes → 22 characters).
^[A-Za-z0-9_-]{8,64}$application/json- body
Peer → server frame (WebSocket message, or the body of POST /v1/c/{id}/send).
t*stringenv*XChaCha20-Poly1305 sealed JSON. n = 24-byte random nonce, c = ciphertext ‖ 16-byte tag. Open it with open() from @pku-harness/cloud-protocol and validate the result.
Accepted.
application/json- response
ok*booleancurl -X POST 'https://cloud.example.org/v1/c/string/send' \ -H 'Content-Type: application/json' \ -d '{ "t": "msg", "env": { "v": 1, "n": "string", "c": "stringstringstringstri" }}'{ "ok": true}Batch mode. The sealed blobs the owner left in the channel's mailbox.
peerTokenAuthorizationBearer <token>peerToken from POST /v1/c/{id}/join, as Authorization: Bearer. The WebSocket and SSE endpoints take it as the t query parameter (any token may be passed that way).
id*stringServer-generated, base64url (16 random bytes → 22 characters).
^[A-Za-z0-9_-]{8,64}$Mailbox slots.
application/json- response
items*array<>curl -X GET 'https://cloud.example.org/v1/c/string/mailbox'{ "items": [ { "slot": "string", "env": { "v": 1, "n": "string", "c": "stringstringstringstri" }, "expiresAt": 0 } ]}Channels (owner)
End-to-end encrypted relay channels opened by a device, used for live sharing with people who open a share link. The owner talks to its peers over a WebSocket; the server only forwards envelopes.
Share links and pages
Public redirects and static viewer pages for people without the app.