Quickstart
Create a key in Settings → API keys, then check it works:
curl https://yungle.co/api/v1/me \
-H "Authorization: Bearer $YUNGLE_API_KEY"Sending a file is three calls plus the upload itself:
# 1. Create the draft. Nothing is live and nobody is emailed yet.
curl -X POST https://yungle.co/api/v1/transfers \
-H "Authorization: Bearer $YUNGLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"files":[{"name":"final-cut.mov","size":8123456789}]}'
# → { "transfer": { "id": "01J…", "slug": "…" },
# "tusEndpoint": "https://yungle.co/files",
# "files": [ { "id": "01J…", "uploadToken": "…" } ] }
# 2. Stream the bytes to tusEndpoint (resumable — see Uploading files).
# 3. Send it.
curl -X POST https://yungle.co/api/v1/transfers/01J…/finalize \
-H "Authorization: Bearer $YUNGLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"recipients":["client@example.com"],"message":"Final cut attached."}'How it is shaped
- Base URL is
https://yungle.co/api/v1. Everything is JSON in and JSON out. - File bytes never go through this API. Endpoints that accept files hand you a tus endpoint and a per-file token; you stream to that. It is resumable at part granularity, which is the point — a 100 GB upload should survive a dropped connection.
- Creating and sending are separate calls. A transfer is created as a draft, so bytes land before anyone is emailed a link.
- Resources are addressed by id, never by slug. A share slug is a capability — anyone holding it can download — so it is returned but never used as an address.
Versioning
/api/v1 is additive-only. New fields and new endpoints may appear; existing fields will not change meaning or disappear, and no new required request field will be added. A change that would break a client gets /api/v2 instead, and v1 keeps working.
The machine-readable contract lives at /api/v1/openapi.json — OpenAPI 3.1, generated from the same definitions the server validates with, so it cannot drift from the running code. It needs no key to read.