Start an upload
Opens a resumable upload session and returns the part size to use.
Permission
The key must be granted files.write
A key without it gets 403 insufficient_scope, with the missing permission named in details.
The way to upload anything large. A single-request upload is capped at the edge and cut at 100 seconds, so beyond a certain size one request cannot succeed however patient the caller is.
Request body
| Field | Type | Description |
|---|---|---|
filename required |
string | The name the file will have. |
size required |
integer | Total bytes. Required because it decides the part size that comes back. |
mime_type |
string | Recorded, not trusted: the stored content type is sniffed from the bytes, which is what stops an executable arriving labelled as an image. |
folder_id |
string | Where the finished file lands. The root when omitted. |
Request
curl https://api.veruapis.com/v1/files/uploads \
-X POST \
-H "Authorization: Bearer vak_live_..." \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"filename": "q3-report.pdf",
"size": 104857600,
"mime_type": "application/pdf",
"folder_id": "0192f001-0000-7a41-b8d2-5e9f0c3a7b41"
}'
Idempotency-Key is required on every write. Retrying with the same key returns the original response rather than repeating the operation, so a timeout is something you retry rather than something you investigate.
Response
Answers 201.
| Field | Type | Description |
|---|---|---|
session_id |
string | Pass it in the path of every later call in this upload. |
document_id |
string | The file this will become, reserved now so you can record it before the bytes are all up. |
part_size |
integer | Slice the file by exactly this, except the last part. Answered rather than chosen, so it can change without breaking a client. |
total_size |
integer | Echoes what you sent. |
{
"data": {
"session_id": "0192b001-0000-7a41-b8d2-5e9f0c3a7b41",
"document_id": "0192a1c2-6f3e-7a41-b8d2-5e9f0c3a7b41",
"part_size": 8388608,
"total_size": 104857600
},
"meta": { "request_id": "req_01j8z9...", "timestamp": "2026-09-02T10:00:00Z" }
}
size is required because it decides the part size that comes back. Slice the file by part_size, PUT each part, then complete. mime_type is recorded but not trusted: the stored type is sniffed from the bytes.
Every failure uses the same shape, with a stable string code you can branch on. See the error reference.
Related
- DELETE Abort an upload
- POST Complete an upload
- POST Create a folder
- DELETE Delete a file
- DELETE Delete a folder
- GET Download a file
- GET Get file metadata
- GET Get upload status
- GET List files
- GET List folders
- GET List file permissions
- POST Share a file
- DELETE Revoke file access
- PATCH Rename or move a file
- PATCH Rename or move a folder
- PUT Upload a part