form.pdf.
Choose the destination
personal://Documents: your personal Documents folder.team://Documents: your team’s Documents folder.@mc/Documents: the Documents folder in an authorized scope. Also sendscope: "mc:<UUID or slug>".
scope only for @mc destinations. For artifact:// destinations, use a storage root ID plus a
relative path, not a folder ID. To upload to a chat session’s folder, send sessionId instead of
targetUri.
Where a file is stored and which record owns it are set separately. To attach a file to a record,
set ownerType and ownerId on each file. For filings, use the
filing upload example, then continue at
Upload the file.
Prepare the request
Start an upload to your team’s Documents folder. Replace12345 with the file’s size in bytes.
targetUri and files[], each with path, signedUrl, optional headers,
expiresAt, and uploadToken. With onConflict: "rename", an existing file with the same name is
kept and the new file gets a different name. With "fail", conflicting files are listed in
conflicts[] and get no upload URL.
Upload the file
PUT the raw file bytes (not JSON or multipart) tofiles[0].signedUrl with exactly the headers in
files[0].headers:
files[0].uploadToken:
results[].success, even when the status is 200. A successful result contains uri
and artifact. Save artifact.id to refer to the file, and artifact.name, which can differ from
the name you asked for.
A failed result contains error.code and error.message. For example, NOT_FOUND means the
uploaded file wasn’t found, and EXPIRED means the token expired. Don’t send scope or the owner
fields again; the token already carries them.
Limits and retries
- Each call accepts up to 100 files and a JSON body up to 1 MiB.
- Use the signed URL before its
expiresAt, and confirm within one hour. - Neither call is idempotent. After a lost response, check the destination before retrying; confirming twice can create a second version.
- Search indexing runs after confirmation and isn’t finished when the call returns.