E2EE relay
36 routes. Paths are relative to https://api.intersink.com/v1.
- GET/e2ee/blobsThe account's backups
- POST/e2ee/blobsStart an encrypted blob upload
- GET/e2ee/blobs/{id}Download link for a finished blob
- DELETE/e2ee/blobs/{id}Delete a blob (sender's delete for everyone, or one's own backup)
- POST/e2ee/blobs/{id}/abortResumable blob upload: give up and drop the stored parts
- POST/e2ee/blobs/{id}/completeFinish a blob upload
- POST/e2ee/blobs/{id}/partsResumable blob upload: part URLs and the parts already stored
- POST/e2ee/calls/{call_id}/cancelStop the ring: the caller hung up, or the callee answered or declined on one device (the others stop)
- POST/e2ee/calls/{call_id}/ringRing the callee's phones for a call (APNs VoIP / FCM high priority; call id and expiry only)
- GET/e2ee/certificateA 24-hour sealed-sender certificate for this device
- GET/e2ee/channels/{channelId}/pushWhich push credentials are set (never the secrets)
- PUT/e2ee/channels/{channelId}/pushSet APNs / FCM credentials and the wake alert text ("" clears)
- GET/e2ee/devicesMy devices
- POST/e2ee/devicesRegister this device (first = 1; others need link_token). With no bearer: a device linked from the phone (bound link_token + provisioning_address) is registered and signed in
- DELETE/e2ee/devices/{device_id}Remove a device with its queue and keys
- PUT/e2ee/devices/{device_id}/keyAdd a device key to a device from before device keys (linked session of that device, or a sign-in within 10 minutes), or replace it (device token of the current key)
- PUT/e2ee/devices/{device_id}/pushSet this device's push token (apns / apns_voip / fcm)
- DELETE/e2ee/devices/{device_id}/pushRemove this device's push token (apns / apns_voip / fcm), e.g. on sign-out or when calls are turned off
- POST/e2ee/devices/{device_id}/tokenProve this device with its device key (signed ts + single-use nonce) → a device token for this session
- POST/e2ee/devices/link-tokenA single-use 10-minute token to link a new device (device 1 only); optionally bound to the new device's provisioning address
- POST/e2ee/directory/lookupUsername → account id (30/hour; 404 when not discoverable)
- GET/e2ee/gateway/deliveriesDeliveries
- PUT/e2ee/gateway/liveGateway: report devices whose client proved it is there ({ devices }, each lasts 40 s); devices that disconnected go in { gone }
- PUT/e2ee/keysUpload pre-keys (one-time keys replace the unused ones)
- GET/e2ee/keys/{account_id}/{device_id}Pre-key bundle(s); consumes one-time keys (bearer or uak)
- GET/e2ee/keys/countUnused one-time keys of this device (replenish under 20)
- GET/e2ee/messagesQueued envelopes of this device, oldest first
- PUT/e2ee/messages/{account_id}Send envelopes to every device of an account (bearer or sealed sender)
- DELETE/e2ee/messages/{guid}Acknowledge (delete) an envelope; 404 when already gone
- PUT/e2ee/profileStore an encrypted profile version and the access key
- GET/e2ee/profile/{account_id}/{version}An encrypted profile version (bearer or uak)
- POST/e2ee/provisioningNew device: a one-use provisioning address (10 minutes) to show as a QR
- GET/e2ee/provisioning/{address}New device, long-poll fallback: waits up to ?timeout= s (default 25, max 55) → { body } or { body: null, expires }
- PUT/e2ee/provisioning/{address}Primary device: deliver the sealed provisioning message (once; the address is then burned)
- GET/e2ee/provisioning/{address}/streamNew device: SSE; one `provisioning.message` event { body }, then the stream ends
- PUT/e2ee/username/discoverableCan others find me by username?
The account's backups
GET/e2ee/blobs
Needs a signed-in user (Bearer token or access_token cookie).
?purpose=backup&latest=1 → the current backup { id, size, created, completed } or null (only a finished backup is ever the latest). ?purpose=backup → every backup of the account, newest first, each with its delete_token.
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| purposerequired | string, query | |
| latestrequired | string, query |
Response
200. data is object[]. Without latest: the account's backups. With latest=1: one backup or null.
| Field | Type | Description |
|---|---|---|
| idrequired | string | |
| statusrequired | string | One of: "pending", "ready". |
| sizerequired | number | |
| currentrequired | boolean | The backup a new phone restores |
| createdrequired | number | |
| completedrequired | number | |
| expiresrequired | number | |
| delete_tokenrequired | string |
Start an encrypted blob upload
POST/e2ee/blobs
Needs a signed-in user (Bearer token or access_token cookie).
Single PUT (default): { id, upload_url, expires, delete_token, status }. With resumable: true a multipart upload: { id, upload_token, delete_token, status, size, part_size, parts, expires, max_parallel }; then POST /e2ee/blobs/:id/parts and /complete. Errors: 400 BLOB_SIZE_INVALID, IDEMPOTENCY_KEY_INVALID, RESUMABLE_DISABLED; 409 IDEMPOTENCY_CONFLICT, BACKUP_IN_PROGRESS; 413 BLOB_TOO_LARGE (details.max_bytes); 429 RATE_LIMITED, UPLOAD_BUDGET_EXCEEDED (details.resets_at), TOO_MANY_PENDING_UPLOADS; 503 STORAGE_UNAVAILABLE; 507 MEDIA_STORAGE_FULL.
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| Idempotency-Key | string, header | A UUID per upload; a replay with the same body answers 200 with the same blob |
Request body application/json
| Field | Type | Description |
|---|---|---|
| sizerequired | number | Exact ciphertext size in bytes (a whole number, at least 1) |
| purposerequired | string | One of: "attachment", "avatar", "backup". |
| resumable | boolean | true: a resumable upload in parts (POST /e2ee/blobs/:id/parts, /complete) instead of one presigned PUT |
Response
201. data is object (BlobCreatedDto).
| Field | Type | Description |
|---|---|---|
| idrequired | string | |
| statusrequired | string | One of: "pending". |
| upload_url | string | Single PUT: the presigned URL (PUT exactly size bytes, application/octet-stream) |
| upload_token | string | Resumable: the write capability for parts, complete and abort |
| delete_token | string | The sender's delete capability (DELETE with X-Delete-Token) |
| size | number | |
| part_size | number | Bytes per part (every part but the last) |
| parts | number | Number of parts |
| expiresrequired | number | Epoch ms: single PUT URL expiry, or the resumable upload's deadline |
| max_parallel | number | Parts to send at once (advice) |
Download link for a finished blob
GET/e2ee/blobs/{id}
Needs a signed-in user (Bearer token or access_token cookie).
{ id, url, expires, size, accept_ranges }. The URL takes Range (206 / 416) and If-Range; when it expires (403) ask again and resume at the same byte. Errors: 404 BLOB_NOT_FOUND; 409 BLOB_NOT_READY (Retry-After); 429 RATE_LIMITED; 503 STORAGE_UNAVAILABLE.
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| idrequired | string, path |
Response
200. data is object (BlobLinkDto).
| Field | Type | Description |
|---|---|---|
| idrequired | string | |
| urlrequired | string | Download URL; takes Range (206/416), expires with 403 |
| expiresrequired | number | Epoch ms |
| sizerequired | number | |
| accept_rangesrequired | boolean |
Delete a blob (sender's delete for everyone, or one's own backup)
DELETE/e2ee/blobs/{id}
Needs a signed-in user (Bearer token or access_token cookie).
Removes the object, the row and the edge copy. Idempotent: a valid token for a blob already gone answers ok. Errors: 404 BLOB_NOT_FOUND (wrong token, someone else's backup); 429 RATE_LIMITED; 503 STORAGE_UNAVAILABLE.
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| idrequired | string, path | |
| X-Delete-Token | string, header | delete_token from POST /e2ee/blobs |
Response
200. data is object (BlobOkDto).
| Field | Type | Description |
|---|---|---|
| okrequired | boolean |
Resumable blob upload: give up and drop the stored parts
POST/e2ee/blobs/{id}/abort
Needs a signed-in user (Bearer token or access_token cookie).
Errors: 404 UPLOAD_NOT_FOUND; 409 BLOB_ALREADY_READY (use DELETE).
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| idrequired | string, path |
Request body application/json
| Field | Type | Description |
|---|---|---|
| upload_tokenrequired | string | upload_token from POST /e2ee/blobs with resumable: true At most 200 characters. |
Response
200. data is object (BlobOkDto).
| Field | Type | Description |
|---|---|---|
| okrequired | boolean |
Finish a blob upload
POST/e2ee/blobs/{id}/complete
Needs a signed-in user (Bearer token or access_token cookie).
Resumable: checks every part is stored at its exact size, then joins them. Single PUT: checks the object arrived. Safe to repeat: a ready blob answers the same body. Errors: 404 UPLOAD_NOT_FOUND; 409 BLOB_PARTS_INCOMPLETE (details: missing, wrong_size, unexpected), BLOB_NOT_UPLOADED, BLOB_SIZE_MISMATCH; 410 UPLOAD_EXPIRED.
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| idrequired | string, path |
Request body application/json
| Field | Type | Description |
|---|---|---|
| upload_token | string | upload_token from POST /e2ee/blobs (required for a resumable upload; a single PUT needs none) At most 200 characters. |
Response
200. data is object (BlobReadyDto).
| Field | Type | Description |
|---|---|---|
| idrequired | string | |
| statusrequired | string | One of: "ready". |
| sizerequired | number | |
| expiresrequired | number | Epoch ms when the blob expires; null for a current backup or a referenced avatar |
Resumable blob upload: part URLs and the parts already stored
POST/e2ee/blobs/{id}/parts
Needs a signed-in user (Bearer token or access_token cookie).
{ upload_token, parts: [1, 2, ...] (at most 100), ttl_s?, md5? }. PUT each part to its url with the headers given and exactly size bytes; a 403 from storage means the URL expired: ask again. parts: [] after a restart answers what storage holds (uploaded). Errors: 400 BLOB_PARTS_INVALID; 404 UPLOAD_NOT_FOUND (wrong id or token); 410 UPLOAD_EXPIRED; 429 RATE_LIMITED.
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| idrequired | string, path |
Request body application/json
| Field | Type | Description |
|---|---|---|
| upload_tokenrequired | string | upload_token from POST /e2ee/blobs with resumable: true At most 200 characters. |
| parts | number[] | Part numbers (1-based) to get upload URLs for, at most 100; empty: status only |
| ttl_s | number | Seconds the part URLs live, 300..86400 (default 3600), clipped to the upload deadline |
| md5 | object | Part number → base64 MD5 of that part; signed into its URL so storage refuses a corrupted body |
Response
200. data is object (BlobPartsResultDto).
| Field | Type | Description |
|---|---|---|
| idrequired | string | |
| statusrequired | string | One of: "pending", "ready". |
| sizerequired | number | |
| part_sizerequired | number | |
| partsrequired | number | |
| uploadedrequired | object[] | Parts storage holds at their exact size |
| uploaded[].partrequired | number | |
| uploaded[].sizerequired | number | |
| urlsrequired | object[] | |
| urls[].partrequired | number | |
| urls[].sizerequired | number | |
| urls[].urlrequired | string | |
| urls[].methodrequired | string | One of: "PUT". |
| urls[].headersrequired | object | |
| urls[].expiresrequired | number | Epoch ms |
| expiresrequired | number | Epoch ms: the upload's deadline |
Stop the ring: the caller hung up, or the callee answered or declined on one device (the others stop)
POST/e2ee/calls/{call_id}/cancel
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| call_idrequired | string, path |
Request body application/json
| Field | Type | Description |
|---|---|---|
| reason | string | Why the ring ends (default hangup) One of: "hangup", "timeout", "answered", "declined", "busy". |
Response
200. The payload in data is not described in the spec yet.
Ring the callee's phones for a call (APNs VoIP / FCM high priority; call id and expiry only)
POST/e2ee/calls/{call_id}/ring
Needs a signed-in user (Bearer token or access_token cookie).
The call itself goes end to end encrypted as relay messages; this only rings. The push says nothing about the caller: the app shows who is calling from the decrypted call offer. Only a caller with the callee's access_key (unidentified-access key) rings, and only when neither has blocked the other; otherwise the answer is the same and nothing rings. Re-sending the same call id to the same callee rings again. Limits (429): 10 rings a minute and 60 an hour per caller, 3 in 2 minutes to the same person. Into one callee at most 6 a minute and 30 an hour ring; past that nothing rings, with the same answer. 409 CALL_ID_IN_USE: another caller or callee holds this id. 503: the block check failed, nothing rang.
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| call_idrequired | string, path |
Request body application/json
| Field | Type | Description |
|---|---|---|
| torequired | string | The callee's account id on this channel |
| access_keyrequired | string | The callee's unidentified-access key (16 bytes, base64), the one a contact holds from the callee's profile key and uses for sealed-sender sends. Only a holder can ring the callee; with a wrong key the answer is the same and nothing rings At most 32 characters. |
| ttl_seconds | number | How long it rings, 10 to 60 seconds (default 45) Minimum 10, maximum 60. |
| caller_blob | string | Opaque caller details sealed by the app (base64url, at most 1024 characters), for the callee's ringing screen. Passed through untouched as cb in the VoIP and FCM ring push of every callee device; never logged, never stored, not sent with cancels. 400 CALLER_BLOB_INVALID when it is not base64url or too long At most 1024 characters. |
Response
200. The payload in data is not described in the spec yet.
A 24-hour sealed-sender certificate for this device
GET/e2ee/certificate
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header |
Response
200. The payload in data is not described in the spec yet.
Which push credentials are set (never the secrets)
GET/e2ee/channels/{channelId}/push
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| channelIdrequired | string, path |
Response
200. The payload in data is of type object.
Set APNs / FCM credentials and the wake alert text ("" clears)
PUT/e2ee/channels/{channelId}/push
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| channelIdrequired | string, path |
Request body application/json
| Field | Type | Description |
|---|---|---|
| apns_key | string | APNs .p8 key (PEM) At most 4096 characters. |
| fcm_service_account | string | FCM service-account JSON At most 8192 characters. |
| alert_title | string | Wake alert title (default: channel title) At most 60 characters. |
| alert_body | string | Wake alert body (default: New message) At most 120 characters. |
| apns_key_id | string | |
| apns_team_id | string |
Response
200. The payload in data is of type object.
My devices
GET/e2ee/devices
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header |
Response
200. The payload in data is not described in the spec yet.
Register this device (first = 1; others need link_token). With no bearer: a device linked from the phone (bound link_token + provisioning_address) is registered and signed in
POST/e2ee/devices
Public: no sign-in needed.
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| x-ref | string, header | channel id (required without a bearer token) |
Request body application/json
| Field | Type | Description |
|---|---|---|
| registration_idrequired | number | Minimum 1, maximum 16380. |
| identity_keyrequired | string | base64url, 33 bytes At most 64 characters. |
| name_ct | string | encrypted device name (opaque) At most 1024 characters. |
| provisioning_address | string | The provisioning address this device showed as a QR. Required with a link_token bound to it, and to register without signing in (the response then also carries tokens). |
| reregister | boolean | Replace every device and the identity key (lost primary). Needs a session signed in within the last 10 minutes. |
| device_key | object | This device's own signing key. Optional until the device-key grace ends, required afterwards. A keyed device is acted for only with a device token. |
| device_key.algrequired | string | One of: "ed25519", "p256". |
| device_key.public_keyrequired | string | base64url public key: Ed25519 32 bytes; P-256 65 bytes uncompressed (or 33 compressed) At most 96 characters. |
| device_key.signaturerequired | string | base64url signature by this key over "kodkila-e2ee-device-key-v1\n<channel_id>\n<account_id>\n<registration_id>\n<alg>\n<public_key>" (P-256: raw r||s or DER) At most 128 characters. |
| signed_pre_keyrequired | object | |
| signed_pre_key.signaturerequired | string | At most 100 characters. |
| signed_pre_key.idrequired | number | Minimum 0, maximum 16777215. |
| signed_pre_key.public_keyrequired | string | At most 64 characters. |
| kyber_pre_keyrequired | object | |
| kyber_pre_key.idrequired | number | Minimum 0, maximum 16777215. |
| kyber_pre_key.public_keyrequired | string | At most 2200 characters. |
| kyber_pre_key.signaturerequired | string | At most 100 characters. |
| pre_keysrequired | object[] | |
| pre_keys[].idrequired | number | Minimum 0, maximum 16777215. |
| pre_keys[].public_keyrequired | string | At most 64 characters. |
| kyber_pre_keysrequired | object[] | |
| kyber_pre_keys[].idrequired | number | Minimum 0, maximum 16777215. |
| kyber_pre_keys[].public_keyrequired | string | At most 2200 characters. |
| kyber_pre_keys[].signaturerequired | string | At most 100 characters. |
| capabilities | object | |
| link_token | string | At most 64 characters. |
Response
201. The payload in data is of type object.
Remove a device with its queue and keys
DELETE/e2ee/devices/{device_id}
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| device_idrequired | string, path |
Response
200. The payload in data is not described in the spec yet.
Add a device key to a device from before device keys (linked session of that device, or a sign-in within 10 minutes), or replace it (device token of the current key)
PUT/e2ee/devices/{device_id}/key
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| device_idrequired | string, path |
Request body application/json
| Field | Type | Description |
|---|---|---|
| device_keyrequired | object | |
| device_key.algrequired | string | One of: "ed25519", "p256". |
| device_key.public_keyrequired | string | base64url public key: Ed25519 32 bytes; P-256 65 bytes uncompressed (or 33 compressed) At most 96 characters. |
| device_key.signaturerequired | string | base64url signature by this key over "kodkila-e2ee-device-key-v1\n<channel_id>\n<account_id>\n<registration_id>\n<alg>\n<public_key>" (P-256: raw r||s or DER) At most 128 characters. |
Response
200. The payload in data is not described in the spec yet.
Set this device's push token (apns / apns_voip / fcm)
PUT/e2ee/devices/{device_id}/push
Needs a signed-in user (Bearer token or access_token cookie).
Optional route_tag (16 to 32 base64url characters, random, made by the client per account and device): every push to this device then carries it as rt (APNs alert, background and VoIP payloads, FCM data), so an app with several accounts on one phone routes the push to the right one. Left out, the stored tag stays. It is cleared with the device's push tokens and never logged.
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| device_idrequired | string, path |
Request body application/json
| Field | Type | Description |
|---|---|---|
| route_tag | string | Route tag for this account on this device: 16 to 32 random base64url characters made by the client. Every push to the device carries it as rt. Left out: the stored tag stays. Example: "q3Vx9JkLm2Tz0pRw8Ya4bC" |
| platformrequired | string | One of: "apns", "apns_voip", "fcm". |
| tokenrequired | string | At least 8 characters, at most 4096 characters. |
| environment | string | One of: "production", "sandbox". |
| topic | string |
Response
200. The payload in data is not described in the spec yet.
Remove this device's push token (apns / apns_voip / fcm), e.g. on sign-out or when calls are turned off
DELETE/e2ee/devices/{device_id}/push
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| device_idrequired | string, path | |
| platformrequired | string, query | Which token to remove One of: "apns", "apns_voip", "fcm". |
Response
200. The payload in data is not described in the spec yet.
Prove this device with its device key (signed ts + single-use nonce) → a device token for this session
POST/e2ee/devices/{device_id}/token
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| device_idrequired | string, path |
Request body application/json
| Field | Type | Description |
|---|---|---|
| tsrequired | number | the device's clock, epoch ms (within 5 minutes of the server) |
| noncerequired | string | 16 to 64 random base64url characters, never reused |
| signaturerequired | string | base64url signature by the device key over "kodkila-e2ee-device-proof-v1\n<channel_id>\n<account_id>\n<device_id>\n<ts>\n<nonce>" At most 128 characters. |
Response
200. The payload in data is not described in the spec yet.
A single-use 10-minute token to link a new device (device 1 only); optionally bound to the new device's provisioning address
POST/e2ee/devices/link-token
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| provisioning_address | string | Bind the token to this provisioning address (the new device's QR): it then works only with that address, after the new device received the message, and lets the new device sign in without a password. |
Response
200. The payload in data is not described in the spec yet.
Username → account id (30/hour; 404 when not discoverable)
POST/e2ee/directory/lookup
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| usernamerequired | string | At least 3 characters, at most 64 characters. |
Response
200. The payload in data is not described in the spec yet.
Deliveries
GET/e2ee/gateway/deliveries
Needs a signed-in user (Bearer token or access_token cookie).
Gateway: Server-Sent Events of this channel's deliveries (data: = the
same JSON as the Redis e2ee:deliver channel).
Response
200. The payload in data is not described in the spec yet.
Gateway: report devices whose client proved it is there ({ devices }, each lasts 40 s); devices that disconnected go in { gone }
PUT/e2ee/gateway/live
Needs a signed-in user (Bearer token or access_token cookie).
Report a device only when its client itself sent something since the last report (an app frame or a WebSocket pong it answered), never because its socket is merely open: a suspended app keeps its socket open for minutes. Report every 25 s. A call skips its push only on a report at most 35 s old.
Request body application/json
| Field | Type | Description |
|---|---|---|
| devicesrequired | object[] | |
| devices[].account_idrequired | string | |
| devices[].device_idrequired | number | Minimum 1, maximum 2147483647. |
| gone | object[] | Devices that just disconnected (no longer live, wake pushes resume at once). |
| gone[].account_idrequired | string | |
| gone[].device_idrequired | number | Minimum 1, maximum 2147483647. |
Response
200. The payload in data is not described in the spec yet.
Upload pre-keys (one-time keys replace the unused ones)
PUT/e2ee/keys
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| signed_pre_key | object | |
| signed_pre_key.signaturerequired | string | At most 100 characters. |
| signed_pre_key.idrequired | number | Minimum 0, maximum 16777215. |
| signed_pre_key.public_keyrequired | string | At most 64 characters. |
| kyber_last_resort | object | |
| kyber_last_resort.idrequired | number | Minimum 0, maximum 16777215. |
| kyber_last_resort.public_keyrequired | string | At most 2200 characters. |
| kyber_last_resort.signaturerequired | string | At most 100 characters. |
| pre_keys | object[] | |
| pre_keys[].idrequired | number | Minimum 0, maximum 16777215. |
| pre_keys[].public_keyrequired | string | At most 64 characters. |
| kyber_pre_keys | object[] | |
| kyber_pre_keys[].idrequired | number | Minimum 0, maximum 16777215. |
| kyber_pre_keys[].public_keyrequired | string | At most 2200 characters. |
| kyber_pre_keys[].signaturerequired | string | At most 100 characters. |
Response
200. The payload in data is not described in the spec yet.
Pre-key bundle(s); consumes one-time keys (bearer or uak)
GET/e2ee/keys/{account_id}/{device_id}
Public: no sign-in needed.
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| account_idrequired | string, path | |
| device_idrequired | string, path | |
| unidentified-access-key | string, header |
Response
200. The payload in data is not described in the spec yet.
Unused one-time keys of this device (replenish under 20)
GET/e2ee/keys/count
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header |
Response
200. The payload in data is not described in the spec yet.
Queued envelopes of this device, oldest first
GET/e2ee/messages
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| limitrequired | string, query |
Response
200. The payload in data is not described in the spec yet.
Send envelopes to every device of an account (bearer or sealed sender)
PUT/e2ee/messages/{account_id}
Public: no sign-in needed.
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| account_idrequired | string, path | |
| unidentified-access-key | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| call | boolean | Wake with the call push (apns_voip / FCM {c:1}) instead of the message push |
| timestamprequired | number | Minimum 0. |
| online | boolean | |
| urgent | boolean | |
| messagesrequired | object[] | |
| messages[].device_idrequired | number | Minimum 1, maximum 2147483647. |
| messages[].registration_idrequired | number | Minimum 1, maximum 16380. |
| messages[].typerequired | number | One of: 1, 3, 6, 8. |
| messages[].contentrequired | string | At least 1 characters, at most 350000 characters. |
Response
200. The payload in data is of type object.
Acknowledge (delete) an envelope; 404 when already gone
DELETE/e2ee/messages/{guid}
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| guidrequired | string, path |
Response
200. The payload in data is not described in the spec yet.
Store an encrypted profile version and the access key
PUT/e2ee/profile
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| uakrequired | string | base64, 16 bytes At most 32 characters. |
| versionrequired | string | |
| commitmentrequired | string | At most 512 characters. |
| name_ct | string | At most 2048 characters. |
| about_ct | string | At most 4096 characters. |
| avatar_blob | string | At most 64 characters. |
| unrestricted_unidentified_accessrequired | boolean |
Response
200. The payload in data is not described in the spec yet.
An encrypted profile version (bearer or uak)
GET/e2ee/profile/{account_id}/{version}
Public: no sign-in needed.
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header | |
| account_idrequired | string, path | |
| versionrequired | string, path | |
| unidentified-access-key | string, header |
Response
200. The payload in data is not described in the spec yet.
New device: a one-use provisioning address (10 minutes) to show as a QR
POST/e2ee/provisioning
Public: no sign-in needed.
Parameters
| Name | Type | Description |
|---|---|---|
| x-ref | string, header | channel id |
Response
200. The payload in data is not described in the spec yet.
New device, long-poll fallback: waits up to ?timeout= s (default 25, max 55) → { body } or { body: null, expires }
GET/e2ee/provisioning/{address}
Public: no sign-in needed.
Parameters
| Name | Type | Description |
|---|---|---|
| addressrequired | string, path | |
| timeoutrequired | string, query |
Response
200. The payload in data is not described in the spec yet.
Primary device: deliver the sealed provisioning message (once; the address is then burned)
PUT/e2ee/provisioning/{address}
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| addressrequired | string, path |
Request body application/json
| Field | Type | Description |
|---|---|---|
| bodyrequired | string | The sealed provisioning message, base64url (at most 16384 bytes decoded) |
Response
200. The payload in data is not described in the spec yet.
New device: SSE; one `provisioning.message` event { body }, then the stream ends
GET/e2ee/provisioning/{address}/stream
Public: no sign-in needed.
Parameters
| Name | Type | Description |
|---|---|---|
| addressrequired | string, path |
Response
200. The payload in data is not described in the spec yet.
Can others find me by username?
PUT/e2ee/username/discoverable
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| x-device-token | string, header | device token (POST /e2ee/devices/:id/token); required for a device that has a device key |
| x-device-id | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| discoverablerequired | boolean |
Response
200. The payload in data is not described in the spec yet.