Upload
Chunked file upload and download for drive files via presigned storage URLs.
File upload and download for drive files. File records are created via the Files service. Binary content is then uploaded directly to cloud storage through presigned URLs.
Unlike tasks/notes where attachments are children of the main entity, in drive the File record IS the entity — it owns chunks directly. Access is checked against file_user_role on the file itself.
Service: drive.upload
Upload flow
- Create a file record via drive.files.create with
kind: "file"andsize_bytes. The server returns the assignedidwithstatus: "pending" - Call requestUploadUrl to get a presigned upload URL for each chunk
- PUT the encrypted chunk body to the presigned URL (standard HTTP PUT, not WebSocket)
- Call confirmChunk for each uploaded chunk — the server verifies the upload and registers the chunk
- Repeat steps 2–4 for all chunks
- Call finalizeUpload to mark the file as
ready
For thumbnails repeat steps 2–4 with chunk_type: "thumbnail_128" (single chunk). Thumbnails do not require a separate finalize call — the server sets thumbnail_128_id automatically on confirm.
requestUploadUrl
Request a presigned upload URL for a single chunk.
WebSocket
Request
{
"jsonrpc": "2.0",
"method": "drive.upload.requestUploadUrl",
"params": {
"file_id": "1920438291510",
"object_key": "a1/a1b2c3d4-e5f6-7890-abcd-ef1234567890"
},
"id": 30
}
| Param | Type | Required | Description |
|---|---|---|---|
file_id |
string |
✅ | File 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-drive-files/a1/a1b2c3d4-e5f6-7890-abcd-ef1234567890?X-Amz-..."
},
"id": 30
}
confirmChunk
Confirm that a chunk was successfully uploaded. The server HEAD-verifies the object in S3, creates a Chunk row, and links it to the file via FileChunk.
WebSocket
Request
{
"jsonrpc": "2.0",
"method": "drive.upload.confirmChunk",
"params": {
"file_id": "1920438291510",
"object_key": "a1/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"chunk_index": 0
},
"id": 31
}
| Param | Type | Required | Description |
|---|---|---|---|
file_id |
string |
✅ | File record id |
object_key |
string |
✅ | Object key used during upload |
chunk_index |
integer |
0-based chunk order. Default 0 |
|
chunk_type |
string |
"file" (default) or "thumbnail_128" |
Response
{
"jsonrpc": "2.0",
"result": {
"chunk_id": "1920438291580",
"chunk_index": 0,
"size_bytes": 262188
},
"id": 31
}
finalizeUpload
Mark the file as ready after all content chunks have been uploaded and confirmed. The server verifies that at least one file chunk exists.
WebSocket
Request
{
"jsonrpc": "2.0",
"method": "drive.upload.finalizeUpload",
"params": {
"file_id": "1920438291510"
},
"id": 32
}
| Param | Type | Required | Description |
|---|---|---|---|
file_id |
string |
✅ | File record id |
Response
{
"jsonrpc": "2.0",
"result": {
"file_id": "1920438291510",
"status": "ready"
},
"id": 32
}
requestDownloadUrls
Request presigned download URLs for specific chunks of a file.
WebSocket
Request
{
"jsonrpc": "2.0",
"method": "drive.upload.requestDownloadUrls",
"params": {
"file_id": "1920438291510",
"chunk_indexes": [0, 1]
},
"id": 33
}
| Param | Type | Required | Description |
|---|---|---|---|
file_id |
string |
✅ | File 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-drive-files/a1/a1b2c3d4-...?X-Amz-...",
"size_bytes": 262188
},
{
"chunk_index": 1,
"download_url": "https://storage.example.com/enbox-drive-files/b2/b2c3d4e5-...?X-Amz-...",
"size_bytes": 131116
}
],
"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.
Danger:
chunk_indexesis required. The server does not support returning all chunks in one call — the client must specify exactly which chunks it needs. This keeps presign cost explicit and enables partial/range-request streaming.