Skip to main content
File bytes never travel through the JSON API. You register each file, then stream it to the upload endpoint over tus, a resumable protocol, so a dropped connection costs you at most one part instead of the whole file. Read this page when you write your own upload client; the SDKs and the CLI already do all of it.

Prerequisites

  • An API key with transfers:write (for a transfer) or collections:write (for a collection, on a paid plan).
  • A file whose exact size in bytes you know before you start.
  • Optional: npm install yungle-client or pip 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 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.
You get back the upload endpoint and one target per file. Keep the id and uploadToken:
One call registers up to 500 files.
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.
The answer is 201 Created with the upload URL in Location, for example https://yungle.co/files/01JB9Q3T6A1C3E5G7J9L1N3P5R. Store it. It is what you resume against.
Create an upload once. A second POST for the same file starts over with a new encryption key and abandons everything already sent. To continue, use HEAD (step 4).
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 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.
Three rules follow from committing in parts:
  • 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-token on every request: POST, HEAD, PATCH and DELETE. tus metadata reaches the server only on the first POST. A request without a valid token is refused with 403.
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.
This works from a different process or machine, as long as you have the upload URL and a valid token. Retry 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 (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.
Use the new token on every request from then on. This endpoint sits outside /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 a path, 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 folderId to put the files inside an existing folder.
The CLI keeps folder structure when you pass it a directory.

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}: importing with receivedBytes, then ready or failed.
  • 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.