← Yungle

Uploading files

File bytes do not travel through the JSON API. Endpoints that accept files return a tusEndpoint and one uploadToken per file, and you stream to that — over tus, a resumable upload protocol with client libraries in most languages.

Why not a plain POST

The point of the whole pipeline is that a 100 GB upload survives a dropped connection. Each part is encrypted and committed as it arrives, and the server remembers the offset — so a reconnect continues from the last committed part instead of starting again. A single POST gives you none of that, and a laptop lid closing costs you the whole file.

The flow

Register the files, upload each one, then use them. The registration response looks like this:

{
  "tusEndpoint": "https://yungle.co/files",
  "files": [
    { "id": "01JABC…", "name": "final-cut.mov", "size": 8123456789,
      "uploadToken": "eyJzY29wZ…" }
  ]
}

Point a tus client at tusEndpoint with these settings:

import * as tus from 'tus-js-client';

const upload = new tus.Upload(stream, {
  endpoint: tusEndpoint,
  uploadSize: file.size,
  // The token authorizes EVERY request, not only the creation POST —
  // HEAD, PATCH and DELETE are verified too. Metadata below reaches the
  // server only on the first POST, so it cannot carry the token alone.
  headers: { 'x-yungle-upload-token': file.uploadToken },
  metadata: {
    fileId: file.id,
    token: file.uploadToken,
    filename: file.name,
  },
  retryDelays: [0, 1000, 3000, 5000, 10000],
});
upload.start();

Rules that will bite you

  • Send x-yungle-upload-token on every request, not just the creation POST. HEAD, PATCH and DELETE are all authorized. A client that only sets it once gets a 401 partway through an otherwise working upload.
  • size must be exact. It is what the quota reservation and the truncation guard compare against. A size that does not match the bytes you send fails the upload rather than silently storing a partial file.
  • Upload tokens last two hours. That is the window to *start* in; a long upload in progress is not interrupted when it passes. If you register files and come back tomorrow, register them again.
  • To resume, HEAD the upload URL your tus client stored and continue from the offset it returns. Do not re-POST an upload that is already in progress — that starts a new one with a fresh encryption key and abandons what you sent.

After the bytes land

Each file is scanned for malware before it can be shared. GET /transfers/{id} reports scanResult per file: null while it is pending, then clean or infected. An infected file has its encryption key destroyed immediately, so it cannot be downloaded by anyone including you.

You do not have to wait for the scan before calling finalize — recipients are only emailed once every file has finished uploading, and the download path checks the verdict independently.

Folder structure is preserved by the path field on each file, e.g. "Ceremony/Raw". In a collection that builds real folders you can navigate and rename. In a transfer it is kept for the recipient's ZIP, which is the only place it needs to exist.