Uploads

Overview

Upload a file in three steps:

  1. Start the upload and receive a temporary storage URL.
  2. Send the file directly to storage at that URL.
  3. 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
}
FieldTypeRule
namestringFilename.
typestringOne of reference, reads, or subtraction.
sizeintegerExact 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
}
FieldMeaning
uploadIdUse this ID in the finish and cancel requests.
urlSend the file to this URL. The URL expires after 6 hours.
blockSizeSplit the file into blocks of this size in bytes.
concurrencySend 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.

  1. Divide the file into pieces no larger than blockSize bytes.

  2. 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 MDAwMDAw and MDAwMDAx.

  3. Upload each piece with PUT to:

    {url}&comp=block&blockid={blockId}

    Pieces can upload in parallel, but don’t run more than concurrency requests at once.

  4. After every piece has uploaded, commit the file with PUT to:

    {url}&comp=blocklist

    Set Content-Type to application/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

StatusMeaning
200The upload was finalized.
201The upload was initialized.
204The unfinished upload was cancelled.
400The JSON body or upload ID is malformed.
401The API credentials are missing or invalid.
403The API key or its owner lacks upload_file.
404The upload doesn’t exist, isn’t owned by the caller, or isn’t in the required unfinished state.
409Finalization found no committed blob or its byte size differs from size.
413The declared size exceeds the configured maximum but is within the hard upload limit.
422The initialization fields are invalid.
503Direct upload support is unavailable on this deployment.