Skip to main content
POST
Start an upload

Authorizations

Authorization
string
header
required

Workspace credential issued from the automation console at /automation. Send it as Authorization: Bearer vq_ws_.... This is NOT a Data API key: a vq_key_ credential is refused here and names the other product in the error.

Body

application/json

Ask for somewhere to put a file.

sizeBytes is required and is not advisory: it decides the part size and the part count, both of which are fixed for the life of the session. R2 cannot be asked to assemble parts it was not told to expect, so a size that turns out to be wrong fails at complete time rather than corrupting a document.

matterId
string
required

mat_ identifier of the matter to upload into. Must belong to your organization.

Example:

"mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6"

filename
string
required

Filename to store, including its extension. Trimmed; whitespace alone is refused. This exact string is used to build the stored object, so it cannot be changed afterwards.

Required string length: 1 - 255
Example:

"msa-acme-v3.docx"

contentType
string
required

IANA media type of the file, for example application/pdf. Must be on the supported list or the request is refused before any URL is signed.

Required string length: 1 - 255
Example:

"application/pdf"

sizeBytes
integer
required

Exact size of the file in bytes. Not advisory: it fixes the part size and part count for the life of the session, and a wrong value fails at complete time. Must be greater than zero.

Required range: x <= 2147483648
Example:

248193

folderId
string | null

fld_ identifier to file the document under on the way in. Saves a second call. Must belong to your organization.

Example:

"fld_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6"

handwritten
boolean
default:false

Set true for scanned or handwritten pages to route the file through vision OCR instead of the text-layer reader. Leaving it false on a scanned exhibit ingests it badly.

Example:

false

Response

Successful Response

An open upload, and every URL needed to fill it.

Two things are deliberately not here.

The R2 object KEY. It is inside each presigned URL and cannot not be, since an S3 presigned URL is a signed PATH. What is refused is publishing it as a FIELD: a field is a stable, structured handle a client would build on and we could never withdraw, whereas the URL is a fifteen-minute capability for one object the caller was already granted. Nothing cross-tenant is disclosed either way; the uuids in that path are the caller's own.

The DOCUMENT ID. There is no document until the bytes land, only an intention to create one, and publishing an id for a row that may never be filled invites a customer to store it and then poll something that never starts. It arrives on the operation's resource at complete time, which is the first moment it means anything.

uploadId
string
required

Public identifier for this upload session, upl_ followed by 32 hex characters. Use it to presign a part and to complete the upload.

Example:

"upl_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6"

partSize
integer
required

Size in bytes of every part except the last. Split the file on exactly this boundary or the assembled object will not match.

Example:

5242880

totalParts
integer
required

How many parts to upload. Always at least 1: a small file is a one-part upload rather than a separate code path.

Example:

3

parts
UploadPartLink · object[]
required

One presigned URL per part, in order.

expiresAt
string<date-time>
required

When the whole SESSION expires (RFC 3339), which is much later than any individual part URL. Past this, storage discards the parts and the upload has to start again.

Example:

"2026-08-19T14:32:10Z"

Last modified on August 23, 2026