Prerequisites
- An API key with
transfers:write(for a transfer) orcollections:write(for a collection, on a paid plan). - A file whose exact size in bytes you know before you start.
- Optional:
npm install yungle-clientorpip install yungle, whose upload helpers implement every rule below.
How an upload works
When the last byte lands, the file is ready and queued for a virus scan. There is no separate “complete” call.
Steps
1
Register the file
Send its name and exact You get back the upload endpoint and one target per file. Keep the One call registers up to 500 files.
size. The size must match the bytes you upload: it is what the quota reservation and the truncation check compare against, and a mismatch fails the upload.id and uploadToken:2
Create the upload
POST to tusEndpoint with the file’s size and three metadata values, each base64-encoded: fileId, token and filename. Send the token in the x-yungle-upload-token header as well.201 Created with the upload URL in Location, for example https://yungle.co/files/01JB9Q3T6A1C3E5G7J9L1N3P5R. Store it. It is what you resume against.3
Send the bytes, one part per request
The server encrypts and stores each file in parts of 32 MiB (33,554,432 bytes). Files larger than about 281 GiB use larger parts, because a file has at most 9,000: the part size is then Three rules follow from committing in parts:
ceil(size / 9000) rounded up to a whole MiB.Send one part per PATCH, starting at offset 0. Each response is 204 with Upload-Offset: the end of the last part the server committed. Always continue from that value, never from what you sent.- A request smaller than one part never advances the offset. The server answers with the previous boundary, and a client that resends forever never finishes. Send at least one full part per request, except for the last, shorter piece of the file.
- Keep each request short. Since 2026-10-11 the web app sends exactly one part per
PATCH, and so should you. A single request carrying a whole large file can be cut off by a proxy deadline (30 minutes per request), and each resume would hit the same wall. The SDKs send 64 MiB per request, two parts. - Send
x-yungle-upload-tokenon every request:POST,HEAD,PATCHandDELETE. tus metadata reaches the server only on the firstPOST. A request without a valid token is refused with403.
4
Resume after a dropped connection
HEAD the stored upload URL. Upload-Offset is where the server stands, always on a part boundary. Continue PATCHing from there.5xx, 409, 423, 429 and network errors after a short wait; treat other 4xx answers as final.5
Renew the token on long uploads
An upload token lasts two hours (Use the new token on every request from then on. This endpoint sits outside
uploadTokenExpiresAt). An upload that runs longer needs a fresh one before it expires, or its next request is refused. Trade the current token for a new one at any point; halfway through its life is a good moment, and renewing more often does no harm./api/v1 and takes the upload token, not your API key. 401 means the token is invalid or already expired, and 404 that the upload has finished or was cancelled; neither is worth retrying. An expired token cannot be renewed: register the file again.Renewing also tells Yungle the upload is alive, so its quota stays reserved and recipients see that files are still arriving.Use an SDK instead
Both SDKs implement the steps above: they create the upload once, send part-sized chunks, resume from the server’s offset, retry transient failures, and renew the token for as long as the upload runs.Folders
Give each file apath, the folder it sits in, such as "Ceremony/Raw". Leave it out for a loose file.
- In a transfer, the path is kept for the recipient: the zip they download has the same folders.
- In a collection, the path creates real folders you can browse and rename, up to 10 levels deep. You can also pass
folderIdto put the files inside an existing folder.
Import from a URL instead
When the file is already online, such as a presigned S3 link, a CDN or a release asset, let Yungle fetch it. Put{ "url": "…", "name": "…" } in imports, alongside or instead of files, on any of the three register calls. The bytes go from the source to Yungle without passing through your machine.
- The source must be reachable from the public internet and state the file’s size.
- An import counts like an upload: same quota, size limits, virus scan and API metering.
- Follow it with
GET /imports/{fileId}:importingwithreceivedBytes, thenreadyorfailed. - Up to 20 imports per call.
Limits
Uploads through the API are metered separately from your plan, the same on every plan: the first 10 GB each month are free, then €0.02 per GB from prepaid credit. When the credit runs out, a register call returns
402 out_of_credit. Request rates are on Limits.
After the bytes land
Each file is scanned for malware once its last byte arrives.GET /transfers/{id} reports scanResult per file: null while the scan is pending, then clean, infected, or unscanned when the scanner could not inspect it. An infected file’s encryption key is destroyed at once, so nobody can download it, you included. You do not need to wait for the scan before you send a transfer.
Next steps
Send a transfer
Register, upload and send, end to end.
Client collections
Upload folders into a lasting place for each client.
Send from CI
Ship build artefacts with the CLI.
Errors
Every error code and what to do about it.
