Developers
Put large-file delivery in the workflow.
Use REST when you want the protocol or MCP when an agent or production tool should drive it. The same workflow is implemented in the pre-release CLI. In every case, file bytes go directly to object storage and never through the API or MCP endpoint.
Authentication
- Create keys under Dashboard → API keys. Keys look like
ysk_+ 40 characters and act as your account — transfers get your plan’s tier and limits. - Send the key on every request as
Authorization: Bearer ysk_…. Bearer keys are the only auth on/api/v1and/api/mcp— no cookies, no sessions. - The full key is shown once at creation; we store only a keyed hash. Lost it? Revoke and mint a new one — revocation applies immediately.
Every request
curl -s https://yasync.com/api/v1/transfers \
-H "Authorization: Bearer ysk_a1b2c3d4…"Remote MCP: the transfer workflow as tools
Connect a Streamable HTTP MCP client to https://yasync.com/api/mcp and send the same Bearer key. The endpoint is stateless and returns JSON. It never accepts file bodies: upload planning tools return presigned URLs, and the client PUTs each part directly to object storage.
Available tools
yasync_create_transfer,yasync_list_transfers,yasync_get_transferyasync_register_file,yasync_plan_upload,yasync_get_upload_statusyasync_sign_upload_parts,yasync_complete_upload,yasync_abort_uploadyasync_finalize_transfer,yasync_delete_transfer
The tools call the same transfer and upload core as REST, so plan limits, ownership checks, resume state, and API-key rate limits stay consistent.
List the MCP tools
curl -s -X POST https://yasync.com/api/mcp \
-H "Authorization: Bearer $YASYNC_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'Quickstart: send a file in six curls
The whole send pipeline, by hand. Export YASYNC_KEY first, then carry transferId, fileId, and uploadId forward from each response.
1 — Create a transfer
Persist one UUID and reuse it on retries. Everything after this hangs off the returned transferId.
curl -s -X POST https://yasync.com/api/v1/transfers \ -H "Authorization: Bearer $YASYNC_KEY" \ -H "Content-Type: application/json" \ -d "{"creationRequestId":"$TRANSFER_REQUEST_UUID"}" # → {"transferId":"cme3k…","slug":"k4q0z7f2m9d1ab","url":"https://yasync.com/t/k4q0z7f2m9d1ab"}2 — Register the file
Name + exact byte size. Persist a key-safe fileId and reuse it on retries. Folder structure travels in the name ("renders/shot_010.mov").
curl -s -X POST https://yasync.com/api/v1/transfers/$TRANSFER_ID/files \ -H "Authorization: Bearer $YASYNC_KEY" \ -H "Content-Type: application/json" \ -d "{"fileId":"$CLIENT_FILE_ID","name":"big.mov","size":83886080}" # → {"fileId":"x7f3…","name":"big.mov","size":"83886080","contentType":"video/quicktime"}3 — Plan the upload
Compute the whole-file CRC32 locally first. Under 100 MiB it is required in the plan because the returned single-PUT URL is checksum-pinned; bigger files switch to per-part CRC32 — see below.
curl -s -X POST https://yasync.com/api/v1/transfers/$TRANSFER_ID/uploads \ -H "Authorization: Bearer $YASYNC_KEY" \ -H "Content-Type: application/json" \ -d "{"fileId":"x7f3…","fileSize":83886080,"crc32":"$CRC32_HEX"}" # → {"uploadId":"u01b…","mode":"s3_single_put","uploadUrl":"https://…","checksumCrc32":"…","requiredHeaders":{"x-amz-checksum-crc32":"…"}, …}4 — PUT the bytes
Straight to object storage — yasync never proxies your file bytes. Send the plan’s Content-Type and every returned requiredHeaders entry.
curl -s -X PUT "$UPLOAD_URL" \ -H "Content-Type: video/quicktime" \ -H "x-amz-checksum-crc32: $CHECKSUM_CRC32_BASE64" \ --data-binary @big.mov5 — Complete the upload
CRC32 is required again at completion. The server verifies stored size; for multipart it also folds the ordered, R2-validated part checksums and matches the whole-file CRC32.
curl -s -X POST https://yasync.com/api/v1/transfers/$TRANSFER_ID/uploads/$UPLOAD_ID/complete \ -H "Authorization: Bearer $YASYNC_KEY" \ -H "Content-Type: application/json" \ -d "{"crc32":"$CRC32_HEX"}"6 — Finalize → link
Optional title, message, and bcrypt-hashed password. Transactional email is disabled in development, so distribute the returned link through your own workflow.
curl -s -X POST https://yasync.com/api/v1/transfers/$TRANSFER_ID/finalize \ -H "Authorization: Bearer $YASYNC_KEY" \ -H "Content-Type: application/json" \ -d '{"title":"Rough cut v4","password":"review-secret"}' # → {"url":"https://yasync.com/t/k4q0z7f2m9d1ab"}
Big files: multipart
Files of 100 MiB and up plan as mode: "s3_multipart" with a fixed partSize and partCount. Request presigned part URLs in batches, PUT the parts in parallel with each URL’s requiredHeaders (keep each response’s ETag header), then send them all to /complete. Interrupted? Ask /status which parts already landed and resume from there.
# CRC32 each part locally; base64-encode its four big-endian bytes.
# Sign URLs for parts 1-2 (batch up to 100 per call).
curl -s -X POST https://yasync.com/api/v1/transfers/$TRANSFER_ID/uploads/$UPLOAD_ID/parts \
-H "Authorization: Bearer $YASYNC_KEY" \
-H "Content-Type: application/json" \
-d '{"parts":[{"partNumber":1,"checksumCrc32":"y/Q5Jg=="},{"partNumber":2,"checksumCrc32":"QixqFQ=="}]}'
# PUT each part with its returned x-amz-checksum-crc32 header. Then complete
# with every ETag, the same part checksums, and the required whole-file CRC32.
curl -s -X POST https://yasync.com/api/v1/transfers/$TRANSFER_ID/uploads/$UPLOAD_ID/complete \
-H "Authorization: Bearer $YASYNC_KEY" \
-H "Content-Type: application/json" \
-d '{"parts":[{"partNumber":1,"etag":"\"9b2cf5…\"","checksumCrc32":"y/Q5Jg=="},{"partNumber":2,"etag":"\"41ac00…\"","checksumCrc32":"QixqFQ=="}],"crc32":"3f8d2a1c"}'Endpoint reference
All byte counts are JSON strings (they can exceed 2⁵³). Timestamps are ISO 8601. Base URL: https://yasync.com.
Errors
Every non-2xx response has one stable shape. code is machine-matchable and never changes meaning within v1; message is for humans; some errors add a details object (e.g. the exact byte caps).
{
"error": {
"code": "FILE_TOO_LARGE",
"message": "Files on this tier are limited to 50 GB",
"details": { "maxFileBytes": "53687091200" }
}
}Rate limits
- 120 requests / minute per key across all v1 endpoints.
- 60 transfer creations / 10 minutes per key — batch files into one transfer instead of one transfer per file.
- 120 part-signing calls / minute per upload, each signing up to 100 part URLs — that comfortably feeds thousands of parallel parts.
- Hitting a limit returns
429withcode: "RATE_LIMITED"— back off and retry. Presigned PUTs to storage are not rate-limited by us.
CLI protocol preview
The tested yasync engine supports parallel multipart, persisted resume state, local CRC32, and machine-readable --json output. The command surface below is implemented, but no public binary or install script is published yet.
yasync login # link this machine to your account (browser approval)
yasync send big.mov --json # create → upload → finalize; prints the link
yasync send renders/ --title "Night renders" --password s3cret
yasync receive https://yasync.com/t/k4q0z7f2m9d1ab -o ~/Downloads
yasync ls # your transfers
yasync rm cme3k… # delete oneSigned Apple Silicon macOS preview verified locally; public packages are pending.
Versioning & stability
/api/v1is stable: fields are only ever added. Anything breaking ships as/api/v2— v1 keeps working./api/mcpis a thin adapter over the same v1 transfer core. Tool schemas may gain optional fields, but existing tool names and required inputs remain compatible.- Write clients that tolerate unknown JSON fields and match errors by
error.code, not message text. - An OpenAPI spec is on the roadmap for a later release; this page is the v1 reference for now.