> ## Documentation Index
> Fetch the complete documentation index at: https://docs.yungle.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Add files to an unsent transfer



## OpenAPI

````yaml /openapi.json post /transfers/{id}/files
openapi: 3.1.0
info:
  title: Yungle API
  version: 1.0.0
  description: >-
    Send transfers, build collections and sync contacts from your own systems.
    Every account can use it: transfers and contacts on the free plan,
    collections on a paid one.


    Lists that can grow without bound (transfers, collection files) take `limit`
    and `cursor` and return `nextCursor`; pass it back unchanged for the next
    page, and stop when it is null.


    Any POST accepts an `Idempotency-Key` header (1–255 printable characters; a
    UUID). A retry with the same key and body within 24 hours replays the
    original success with `Idempotent-Replayed: true` and creates nothing.


    File bytes never travel through this API: endpoints that accept files return
    a tus endpoint and a per-file upload token, and you stream to that. See
    https://docs.yungle.co/guides/upload-large-files.


    The vault and end-to-end encrypted transfers are not reachable here, and
    cannot be: their keys are derived in the client and never sent to us.


    **Errors** are JSON with a stable `error.code` (the `Error` schema);
    `error.docs` links to the explanation. See https://docs.yungle.co/errors.


    **Rate limits** are reported on every metered response in the IETF draft
    `RateLimit` and `RateLimit-Policy` headers, per key per minute and per
    workspace per day. A 429 carries `Retry-After` in seconds. See
    https://docs.yungle.co/limits.


    **Versioning.** The version is in the path. `/api/v1` changes additively
    only: new endpoints, optional fields and response fields may appear; nothing
    existing is removed, renamed or made required. A breaking change ships as
    `/api/v2`. An operation that is going away is marked `deprecated: true`
    here, answers with a `Deprecation` header (RFC 9745) and a `Sunset` header
    (RFC 8594) giving its last day, and is announced in the changelog at least
    six months before that day: https://docs.yungle.co/changelog. No v1
    operation is deprecated.
  contact:
    name: Yungle
    url: https://docs.yungle.co
  license:
    name: MIT
    identifier: MIT
  termsOfService: https://yungle.co/legal/terms
servers:
  - url: https://yungle.co/api/v1
security:
  - apiKey: []
tags:
  - name: Account
    description: Who the key is and what it may do.
  - name: Transfers
    description: One-off sends with an expiring link.
  - name: Collections
    description: Durable, folder-structured spaces clients are invited into.
  - name: Contacts
    description: The workspace address book.
  - name: Upload requests
    description: Public links that let other people send files into your collections.
  - name: Downloads
    description: >-
      Getting bytes out: signed, resumable URLs for your own transfers and
      collections, and for links shared with you.
  - name: Webhooks
    description: >-
      Events pushed to your URL, signed with `Yungle-Signature`, or kept for you
      to pull. See the Webhooks guide.
paths:
  /transfers/{id}/files:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Transfer id. Never the share slug, which is a capability.
    post:
      tags:
        - Transfers
      summary: Add files to an unsent transfer
      operationId: addTransferFiles
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                files:
                  type: array
                  items:
                    type: object
                    properties:
                      name:
                        type: string
                        minLength: 1
                        maxLength: 512
                        description: Filename as it should appear to the recipient.
                      size:
                        type: integer
                        minimum: 0
                        description: Exact size in bytes. Must match what you upload.
                      type:
                        type: string
                        maxLength: 255
                        default: ''
                        description: MIME type. Best effort; never trusted.
                      path:
                        type: string
                        maxLength: 1024
                        description: >-
                          Directory within an uploaded folder, e.g.
                          "Ceremony/Raw". Omit for a loose file.
                    required:
                      - name
                      - size
                    additionalProperties: false
                  maxItems: 500
                  default: []
                  description: Files you will upload yourself.
                imports:
                  type: array
                  items:
                    type: object
                    properties:
                      url:
                        type: string
                        format: uri
                        maxLength: 4096
                        description: >-
                          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:
                        type: string
                        minLength: 1
                        maxLength: 512
                        description: The file name. Defaults to the one the source gives.
                      path:
                        type: string
                        maxLength: 1024
                        description: Folder to place it in, e.g. "Exports/Final".
                    required:
                      - url
                    additionalProperties: false
                  maxItems: 20
                  description: >-
                    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}`.
              additionalProperties: false
              $schema: http://json-schema.org/draft-07/schema#
      responses:
        '201':
          description: Upload targets for the new files.
          headers:
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
          content:
            application/json:
              schema:
                type: object
                properties:
                  tusEndpoint:
                    type: string
                    format: uri
                    description: Stream each file here with tus.
                  files:
                    type: array
                    items:
                      $ref: '#/components/schemas/UploadTarget'
                    description: One per entry in `files`, in the same order.
                  imports:
                    type: array
                    items:
                      $ref: '#/components/schemas/ImportStarted'
                    description: >-
                      One per entry in `imports`, in the same order. Empty when
                      none were sent.
                required:
                  - tusEndpoint
                  - files
                  - imports
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/PaymentRequired'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '410':
          $ref: '#/components/responses/Gone'
        '413':
          $ref: '#/components/responses/PayloadTooLarge'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  headers:
    RateLimit:
      description: >-
        What is left in each bucket this request was charged against, e.g.
        `"key";r=87;t=34, "workspace";r=19880;t=40211` (`r` remaining, `t`
        seconds until reset). draft-ietf-httpapi-ratelimit-headers.
      schema:
        type: string
    RateLimit-Policy:
      description: >-
        The buckets themselves, e.g. `"key";q=120;w=60,
        "workspace";q=20000;w=86400` (`q` quota, `w` window in seconds).
      schema:
        type: string
  schemas:
    UploadTarget:
      type: object
      properties:
        id:
          type: string
          description: File id, for removing it later.
        name:
          type: string
        size:
          type: integer
          minimum: 0
          description: Bytes, as registered. The upload must be exactly this long.
        uploadToken:
          type: string
          description: Send as `x-yungle-upload-token` on every tus request for this file.
        uploadTokenExpiresAt:
          type: string
          format: date-time
          description: >-
            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.
      required:
        - id
        - name
        - size
        - uploadToken
        - uploadTokenExpiresAt
      description: Where to stream one file.
    ImportStarted:
      type: object
      properties:
        fileId:
          type: string
        name:
          type: string
        size:
          type: integer
          minimum: 0
          description: Bytes, as the source stated them.
        source:
          type: string
          description: >-
            The host it is fetched from. Never the full URL, which may carry a
            signature.
        status:
          type: string
          description: >-
            Currently one of: `queued`. Treat unknown values as unknown, not as
            an error.
      required:
        - fileId
        - name
        - size
        - source
        - status
      description: A file Yungle is fetching from a URL.
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              enum:
                - unauthorized
                - insufficient_scope
                - upgrade_required
                - out_of_credit
                - not_found
                - invalid_request
                - folder_error
                - conflict
                - not_editable
                - quota_exceeded
                - transfer_too_large
                - rate_limited
                - email_budget_exhausted
                - password_required
                - wrong_password
                - guests_only
                - link_unavailable
                - e2ee_unsupported
                - internal_error
              description: >-
                Stable and machine-readable: branch on this. New codes may be
                added within an existing status.
            message:
              type: string
              description: For a human reading a log. May change; do not parse it.
            details:
              type: object
              additionalProperties: true
              description: >-
                Present only when there is something actionable, and shaped per
                code.
            docs:
              type: string
              format: uri
              description: The page that explains this code and what to do about it.
  responses:
    BadRequest:
      description: >-
        The request was malformed or failed validation. Codes:
        `invalid_request`, `folder_error`.
      headers:
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimit-Policy'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: 'Missing or invalid credential. Codes: `unauthorized`.'
      headers:
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimit-Policy'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    PaymentRequired:
      description: >-
        Needs a paid plan, or prepaid credit for metered usage. Codes:
        `upgrade_required`, `out_of_credit`.
      headers:
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimit-Policy'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: >-
        The credential lacks a required scope, or a shared link refused access.
        Codes: `insufficient_scope`, `password_required`, `wrong_password`,
        `guests_only`.
      headers:
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimit-Policy'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: 'No such resource in this workspace. Codes: `not_found`.'
      headers:
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimit-Policy'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Conflict:
      description: >-
        Already exists, an Idempotency-Key conflict, or end-to-end encrypted
        content the server cannot serve. Codes: `conflict`, `e2ee_unsupported`.
      headers:
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimit-Policy'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Gone:
      description: >-
        The transfer has been sent, revoked or expired; or a shared link is no
        longer available. Codes: `not_editable`, `link_unavailable`.
      headers:
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimit-Policy'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    PayloadTooLarge:
      description: >-
        Over the storage quota or the transfer size ceiling. Codes:
        `quota_exceeded`, `transfer_too_large`.
      headers:
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimit-Policy'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    TooManyRequests:
      description: >-
        Rate limit or email budget exhausted. Wait for `Retry-After`. Codes:
        `rate_limited`, `email_budget_exhausted`.
      headers:
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimit-Policy'
        Retry-After:
          description: Seconds to wait before retrying.
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalError:
      description: >-
        Our fault. `details.requestId` ties it to our logs. Codes:
        `internal_error`.
      headers:
        RateLimit:
          $ref: '#/components/headers/RateLimit'
        RateLimit-Policy:
          $ref: '#/components/headers/RateLimit-Policy'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: >-
        An API key from Settings → API keys, sent as `Authorization: Bearer
        yk_live_…`. Scopes: transfers:read, transfers:write, collections:read,
        collections:write, contacts:read, contacts:write, webhooks:read,
        webhooks:write. A write scope implies read of the same resource.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.