Uploads
Overview
Upload a file in three steps:
- Start the upload and receive a temporary storage URL.
- Send the file directly to storage at that URL.
- Tell Virtool to finish the upload.
The file bytes never pass through the Virtool server, allowing large uploads.
Authenticate
Authenticate requests to Virtool with HTTP Basic authentication. Use your user
handle as the username and an API key as the password. The API key and its owner
must both have the upload_file permission.
The signed storage requests in the transfer step don’t use the API key. The temporary storage URL contains all authorization needed to write that one file.
Start an upload
Send a POST request to /api/v1/uploads.
VT_URL="https://virtool.example.com"
VT_HANDLE="alice"
VT_API_KEY="your-api-key"
curl --user "$VT_HANDLE:$VT_API_KEY" \
--header "Content-Type: application/json" \
--data '{"name":"reads_1.fq.gz","type":"reads","size":10737418240}' \
"$VT_URL/api/v1/uploads"
{
"name": "reads_1.fq.gz",
"type": "reads",
"size": 10737418240
}
| Field | Type | Rule |
|---|---|---|
name | string | Filename. |
type | string | One of reference, reads, or subtraction. |
size | integer | Exact file size in bytes, from 0 to the configured maximum upload size. |
An administrator sets the maximum upload size. It defaults to 5,000,000,000
bytes and can be raised to the hard upload limit of 120,000,000,000 bytes (120
GB). A size that exceeds the configured maximum returns 413; one that
exceeds the hard upload limit fails validation with 422. Check the
initialization response before starting the block uploads.
The server sends back a 201 response.
{
"uploadId": 123,
"url": "https://...",
"blockSize": 16777216,
"concurrency": 4
}
| Field | Meaning |
|---|---|
uploadId | Use this ID in the finish and cancel requests. |
url | Send the file to this URL. The URL expires after 6 hours. |
blockSize | Split the file into blocks of this size in bytes. |
concurrency | Send up to this many blocks at the same time. |
The upload API requires a Virtool instance configured for direct uploads to
Azure Blob Storage. A 503 response means this instance doesn’t support the
upload API; contact its administrator.
Upload the file
Use the url, blockSize, and concurrency values from the start response.
-
Divide the file into pieces no larger than
blockSizebytes. -
Number the pieces from zero. Turn each number into a block ID by padding it to six digits and base64-encoding it. The first two IDs are
MDAwMDAwandMDAwMDAx. -
Upload each piece with
PUTto:{url}&comp=block&blockid={blockId}Pieces can upload in parallel, but don’t run more than
concurrencyrequests at once. -
After every piece has uploaded, commit the file with
PUTto:{url}&comp=blocklistSet
Content-Typetoapplication/xml. The body lists the block IDs in file order:
<?xml version="1.0" encoding="utf-8"?>
<BlockList>
<Latest>MDAwMDAw</Latest>
<Latest>MDAwMDAx</Latest>
</BlockList>
Set x-ms-blob-content-type to the file’s media type, or
application/octet-stream when it’s unknown.
These are standard HTTP requests and don’t require an Azure SDK. If a request fails because of a network or server error, retry it. Cancel the upload if it can’t be completed.
Finish an upload
Send a POST request to /api/v1/uploads/{uploadId}/finalize.
curl --user "$VT_HANDLE:$VT_API_KEY" \
--request POST \
"$VT_URL/api/v1/uploads/123/finalize"
The server verifies the stored file size, marks the upload ready, and returns
the upload record. Finalization is idempotent, so it’s safe to retry if the
response is lost. A missing block list or mismatched size returns 409.
Cancel an upload
Send a DELETE request to /api/v1/uploads/{uploadId}.
curl --user "$VT_HANDLE:$VT_API_KEY" \
--request DELETE \
"$VT_URL/api/v1/uploads/123"
Cancellation removes an unfinished upload owned by the caller and returns
204. Use it after a permanent transfer, commit, or finalization failure so the
pending upload doesn’t remain until automatic cleanup.
Responses
| Status | Meaning |
|---|---|
200 | The upload was finalized. |
201 | The upload was initialized. |
204 | The unfinished upload was cancelled. |
400 | The JSON body or upload ID is malformed. |
401 | The API credentials are missing or invalid. |
403 | The API key or its owner lacks upload_file. |
404 | The upload doesn’t exist, isn’t owned by the caller, or isn’t in the required unfinished state. |
409 | Finalization found no committed blob or its byte size differs from size. |
413 | The declared size exceeds the configured maximum but is within the hard upload limit. |
422 | The initialization fields are invalid. |
503 | Direct upload support is unavailable on this deployment. |