Upload

File upload and download for message attachments via presigned URLs to cloud storage.

Service: messages.upload

Attachments are created inline with the parent message (message_attachment in messages.create) with status: "pending". Binary content is then uploaded directly to cloud storage through presigned URLs, and the attachment is finalized to ready. Downloads go the reverse way — any chat participant may download (the chat content key is wrapped for every participant), while uploads are restricted to the message’s sender.

Upload flow

  1. Create the message including the attachment entry (without id) in message_attachment — the server returns the assigned attachment id with status: "pending"
  2. Call requestUploadUrl to get a presigned upload URL for each part
  3. PUT the encrypted chunk body to the presigned URL (standard HTTP PUT, not WebSocket)
  4. Call confirmChunk for each uploaded part — pass the etag from the S3 PUT response
  5. Call finalizeUpload to assemble parts and mark the attachment as ready

For thumbnails repeat steps 2–4 with chunk_type: "thumbnail_128" (single chunk). Thumbnails do not require a separate finalize call.

requestUploadUrl

Request a presigned upload URL for a single chunk/part. Upload access: the message’s sender only.

WebSocket

Request

{
  "jsonrpc": "2.0",
  "method": "messages.upload.requestUploadUrl",
  "params": {
    "file_id": "220240846547600000",
    "object_key": "a1/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "chunk_type": "file"
  },
  "id": 30
}
Param Type Required Description
file_id string Attachment record id
object_key string Client-generated object key for storage (format: <uuid[:2]>/<uuid>)
chunk_type string "file" (default) or "thumbnail_128"

Response

{
  "jsonrpc": "2.0",
  "result": {
    "object_key": "a1/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "upload_url": "https://storage.example.com/enbox-messages-attachments/a1/a1b2c3d4-...?X-Amz-..."
  },
  "id": 30
}

confirmChunk

Confirm that a chunk/part was successfully uploaded. For multipart uploads, pass the etag returned by S3 in the PUT response header.

WebSocket

Request

{
  "jsonrpc": "2.0",
  "method": "messages.upload.confirmChunk",
  "params": {
    "file_id": "220240846547600000",
    "object_key": "a1/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "chunk_index": 0,
    "chunk_type": "file",
    "etag": "\"d41d8cd98f00b204e9800998ecf8427e\""
  },
  "id": 31
}
Param Type Required Description
file_id string Attachment record id
object_key string Object key used during upload
chunk_index integer 0-based part order. Default 0
chunk_type string "file" (default) or "thumbnail_128"
etag string S3 ETag from the PUT response. Required for multipart file chunks

Response

{
  "jsonrpc": "2.0",
  "result": {
    "chunk_id": "220240846547600010",
    "chunk_index": 0,
    "size_bytes": 245760
  },
  "id": 31
}

finalizeUpload

Complete the multipart upload and mark the attachment as ready. The server assembles all confirmed parts into a single S3 object, then creates the final chunk record and links it — in one transaction.

WebSocket

Request

{
  "jsonrpc": "2.0",
  "method": "messages.upload.finalizeUpload",
  "params": {
    "file_id": "220240846547600000"
  },
  "id": 32
}
Param Type Required Description
file_id string Attachment record id

Response

{
  "jsonrpc": "2.0",
  "result": {
    "file_id": "220240846547600000",
    "status": "ready"
  },
  "id": 32
}

requestDownloadUrls

Request presigned download URLs for specific chunks of an attachment. Download access: any participant of the message’s chat.

WebSocket

Request

{
  "jsonrpc": "2.0",
  "method": "messages.upload.requestDownloadUrls",
  "params": {
    "file_id": "220240846547600000",
    "chunk_indexes": [0],
    "chunk_type": "file"
  },
  "id": 33
}
Param Type Required Description
file_id string Attachment record id
chunk_indexes integer[] 0-based indexes of chunks to download
chunk_type string "file" (default) or "thumbnail_128"

Response

{
  "jsonrpc": "2.0",
  "result": [
    {
      "chunk_index": 0,
      "download_url": "https://storage.example.com/enbox-messages-attachments/a1/a1b2c3d4-...?X-Amz-...",
      "size_bytes": 245760
    }
  ],
  "id": 33
}

For thumbnails (chunk_type: "thumbnail_128") use chunk_indexes: [0]. The result contains a single entry or an empty array if no thumbnail exists.