---
title: "Add files to an unsent transfer"
method: POST
path: "/transfers/{id}/files"
tags: ["Transfers"]
---

# Add files to an unsent transfer

`POST /transfers/{id}/files`

## Request

- Base URL: `https://yungle.co/api/v1`
- URL: `https://yungle.co/api/v1/transfers/{id}/files`
- Auth: HTTP bearer

## Request body

- object
  - `files` object[]: Files you will upload yourself.
    - `name` string, required: Filename as it should appear to the recipient.
    - `size` integer, required: Exact size in bytes. Must match what you upload.
    - `type` string: MIME type. Best effort; never trusted.
    - `path` string: Directory within an uploaded folder, e.g. "Ceremony/Raw". Omit for a loose file.
  - `imports` object[]: Files Yungle fetches from URLs itself, so the bytes never pass through you. Up to 20 per call. Each is created like an upload (quota, size ceilings, API metering) and imported in the background; follow it with `GET /imports/{fileId}`.
    - `url` string, uri, required: A public http(s) URL Yungle fetches the file from — a presigned S3 link, a CDN, a release asset. It must state the file size (Content-Length, or a Range answer). Private network addresses are refused.
    - `name` string: The file name. Defaults to the one the source gives.
    - `path` string: Folder to place it in, e.g. "Exports/Final".

## Response `201`

Upload targets for the new files.

- object
  - `tusEndpoint` string, uri, required: Stream each file here with tus.
  - `files` UploadTarget[], required: One per entry in `files`, in the same order.
    - `id` string, required: File id, for removing it later.
    - `name` string, required
    - `size` integer, required: Bytes, as registered. The upload must be exactly this long.
    - `uploadToken` string, required: Send as `x-yungle-upload-token` on every tus request for this file.
    - `uploadTokenExpiresAt` string, date-time, required: When `uploadToken` stops working (two hours). An upload that may run longer renews it before then: `POST /api/uploads/token` with the current token in `x-yungle-upload-token` returns `{ uploadToken, expiresAt }`. An expired token cannot be renewed.
  - `imports` ImportStarted[], required: One per entry in `imports`, in the same order. Empty when none were sent.
    - `fileId` string, required
    - `name` string, required
    - `size` integer, required: Bytes, as the source stated them.
    - `source` string, required: The host it is fetched from. Never the full URL, which may carry a signature.
    - `status` string, required: Currently one of: `queued`. Treat unknown values as unknown, not as an error.

## Other responses

- `400`: The request was malformed or failed validation. Codes: `invalid_request`, `folder_error`.
- `401`: Missing or invalid credential. Codes: `unauthorized`.
- `402`: Needs a paid plan, or prepaid credit for metered usage. Codes: `upgrade_required`, `out_of_credit`.
- `403`: The credential lacks a required scope, or a shared link refused access. Codes: `insufficient_scope`, `password_required`, `wrong_password`, `guests_only`.
- `404`: No such resource in this workspace. Codes: `not_found`.
- `409`: Already exists, an Idempotency-Key conflict, or end-to-end encrypted content the server cannot serve. Codes: `conflict`, `e2ee_unsupported`.
- `410`: The transfer has been sent, revoked or expired; or a shared link is no longer available. Codes: `not_editable`, `link_unavailable`.
- `413`: Over the storage quota or the transfer size ceiling. Codes: `quota_exceeded`, `transfer_too_large`.
- `429`: Rate limit or email budget exhausted. Wait for `Retry-After`. Codes: `rate_limited`, `email_budget_exhausted`.
- `500`: Our fault. `details.requestId` ties it to our logs. Codes: `internal_error`.

---

[API](https://skmtc.dev/yungle/apis/yungle-api.md) · [All operations](https://skmtc.dev/yungle/apis/yungle-api/llms.txt) · [OpenAPI document](https://skmtc.dev/yungle/apis/yungle-api/revisions/fee7cb2d7419?raw)
