Direct uploads
Send large files without routing bytes through your application server.
Upload files into temporary sessions, create tracked transfers, organize them in collections, collect verified submissions, and read recipient activity through one versioned HTTP API.
curl -X POST https://file.fast/api/v1/transfers \
-H "Authorization: Bearer $FILEFAST_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"client_request_id": "8ab9cfe4-076e-4fae-9e74-5f2d55b559c7",
"file_ids": ["FILE_SECRET_1", "FILE_SECRET_2"],
"recipients": ["[email protected]"],
"subject": "Final files",
"notify_on_download": true
}'
Send large files without routing bytes through your application server.
Share a link or send to verified email recipients.
Read opens, downloads, events, comments, and decisions.
Create verified request links and read contributor-separated submissions.
Quickstart
Use the standard multipart endpoint for a simple server-side upload, then pass its file ID to the transfer endpoint. Store the resulting transfer ID and share URL rather than a standalone file link.
curl -X POST https://file.fast/api/v1/upload \
-H "Accept: application/json" \
-H "Authorization: Bearer $FILEFAST_TOKEN" \
-F "[email protected]" > upload.json
FILE_ID="$(jq -r '.data.file.metadata.id' upload.json)"
curl -X POST https://file.fast/api/v1/transfers/link \
-H "Accept: application/json" \
-H "Authorization: Bearer $FILEFAST_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"file_ids\":[\"$FILE_ID\"]}"
const body = new FormData();
body.append('file', file);
const response = await fetch('https://file.fast/api/v1/upload', {
method: 'POST',
headers: { Authorization: `Bearer ${FILEFAST_TOKEN}` },
body,
});
const upload = await response.json();
const transferResponse = await fetch('https://file.fast/api/v1/transfers/link', {
method: 'POST',
headers: {
Authorization: `Bearer ${FILEFAST_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ file_ids: [upload.data.file.metadata.id] }),
});
const transfer = await transferResponse.json();
console.log(transfer.data.transfer.share_url);
import requests
with open("project-final.zip", "rb") as file:
upload = requests.post(
"https://file.fast/api/v1/upload",
headers={"Authorization": "Bearer " + FILEFAST_TOKEN},
files={"file": file},
).json()
transfer = requests.post(
"https://file.fast/api/v1/transfers/link",
headers={"Authorization": "Bearer " + FILEFAST_TOKEN},
json={"file_ids": [upload["data"]["file"]["metadata"]["id"]]},
).json()
print(transfer["data"]["transfer"]["share_url"])
{
"status": true,
"data": {
"transfer": {
"id": 841,
"title": "project-final.zip",
"share_url": "https://file.fast/x/8fq2xk",
"files": [{
"id": "BpQ", "name": "project-final.zip",
"size": { "bytes": 52428800, "readable": "50 MB" }
}]
}
}
}
Authentication
Plus, Creator, and Teams accounts can create named, scoped personal access tokens in the FileFast profile. Send the token in the Authorization header on every authenticated request. Free remains available through the first-party web and mobile send experience. Unclassified legacy wildcard tokens fail with token_rotation_required and must be replaced from the profile.
Direct upload
For files up to 5 GiB, request one temporary URL, PUT the bytes directly to FileFast storage, then finalize. Finalization returns safety_status and ready; while ready is false, poll GET /upload/status/{secret} and do not create the transfer yet. For larger plan-sized files or unreliable connections, use resumable multipart upload below.
Send the file name, byte size, and MIME type.
PUT the file bytes to the returned temporary URL.
Register the upload and receive its file ID for transfer creation.
# 1. Request an upload URL
curl -X POST https://file.fast/api/v1/upload/presign \
-H "Authorization: Bearer $FILEFAST_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"film.mov","size":2147483648,"mimetype":"video/quicktime"}'
# 2. PUT to the returned data.upload_url
curl -X PUT -H "Content-Type: video/quicktime" --upload-file film.mov "$UPLOAD_URL"
# 3. Finalize with the returned data.filename
curl -X POST https://file.fast/api/v1/upload/finalize \
-H "Authorization: Bearer $FILEFAST_TOKEN" \
-H "Content-Type: application/json" \
-d '{"filename":"RETURNED_FILENAME"}'
# 4. If data.ready is false, poll with the returned metadata.id
curl https://file.fast/api/v1/upload/status/RETURNED_FILE_ID \
-H "Authorization: Bearer $FILEFAST_TOKEN"
# 5. Create one transfer after every upload is ready
curl -X POST https://file.fast/api/v1/transfers/link \
-H "Authorization: Bearer $FILEFAST_TOKEN" \
-H "Content-Type: application/json" \
-d '{"client_request_id":"8ab9cfe4-076e-4fae-9e74-5f2d55b559c7","file_ids":["RETURNED_FILE_ID"]}'Resumable multipart
Create a 24-hour session, upload numbered parts directly to storage, and persist the returned upload ID, key, filename, part number, and ETag. Use the returned recommended part size; every part except the last must be at least 5 MiB. After a timeout or restart, call status and skip every part FileFast already has. Complete assembles the object; finalize returns the upload handle consumed by transfer creation. Abort removes an unfinished provider session.
Start the owner-scoped session.
Reconcile saved part numbers and ETags.
Upload each numbered part to its temporary URL.
Submit the ordered part number and ETag list.
Register the assembled object once.
Clean up only when the user intentionally cancels.
POST /upload/multipart/create { name, size, mimetype }
POST /upload/multipart/status { uploadId, key, filename }
POST /upload/multipart/sign { uploadId, key, partNumber }
PUT returned_url <binary part bytes>
POST /upload/multipart/complete { uploadId, key, filename, parts: [{ ETag, PartNumber }] }
POST /upload/finalize { filename }
GET /upload/status/{secret} until data.ready is true
POST /transfers/link { file_ids: [secret] }
# Intentional cancellation only
POST /upload/multipart/abort { uploadId, key, filename }It persists a restart checkpoint, reconciles stored parts, retries failed PUTs, respects the 10,000-part limit, and supports intentional abort. Use it in Node or a trusted client; never expose a long-lived personal token in a public page.
Delivery API
Create a tracked link or deliver one or more files to email recipients. Transfer detail brings files, recipient status, timeline events, and enabled review activity back into your application.
Advanced access, preview, watermark, and review fields work only when the authenticated plan includes those live capabilities. The API never bypasses plan entitlements.
Transfer #1842
Campaign-final.zip
Receive API
Create a request link for a form, project, or client portal. Contributors verify their email without creating an account, upload through the same resumable safety pipeline as FileFast web, and remain separated by contributor and submission time.
Creating requests requires a plan with the live file_requests capability. Closing a request stops future uploads but preserves every received submission.
curl -X POST https://file.fast/api/v1/requests \
-H "Authorization: Bearer $FILEFAST_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Final campaign assets",
"instructions": "PDF and source files, please",
"access_mode": "verified",
"max_files": 20,
"accepted_extensions": ["pdf", "zip", "psd"],
"client_request_id": "8ab9cfe4-076e-4fae-9e74-5f2d55b559c7"
}'
Outbound webhooks
Register a public HTTPS endpoint in your profile and choose the events your integration needs. FileFast signs the exact JSON body with an endpoint secret that is shown once and encrypted at rest.
transfer.opened
transfer.downloaded
transfer.reviewed
transfer.expired
delivery.failed
// Headers: Webhook-Id, Webhook-Timestamp, Webhook-Signature
$body = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_WEBHOOK_TIMESTAMP'];
$signature = $_SERVER['HTTP_WEBHOOK_SIGNATURE'];
if (abs(time() - (int) $timestamp) > 300) {
http_response_code(400); exit;
}
$expected = 'v1=' . hash_hmac(
'sha256', $timestamp . '.' . $body, getenv('FILEFAST_WEBHOOK_SECRET')
);
if (!hash_equals($expected, $signature)) {
http_response_code(401); exit;
}
Reject stale Webhook-Timestamp values and deduplicate the stable Webhook-Id in your receiver.
Non-2xx responses and network failures retry with increasing backoff for up to five attempts.
Payloads use transfer and file identifiers without exposing recipient email addresses or raw actor identities.
Delivery attempts and their latest status are visible beside each endpoint. A successful receiver should return any 2xx response quickly and process longer work asynchronously.
Request and response models
The API uses a consistent status envelope. Successful payloads live under data; validation errors include field-level messages.
client_request_iduuid?Stable retry key for one send intent; exact replays return the original transfer.file_idsarrayOne or more ordered file secrets in a single transfer.relative_pathsarray?Optional logical paths aligned one-for-one with file_ids.recipientsarrayOne or more valid email addresses, limited by plan.subjectstring?Optional subject, up to 120 characters.messagestring?Optional recipient message, up to 1,000 characters.access_modeenum?public, tracked, or restricted.view_modeenum?preview_download, download_only, preview_only, or preview_watermark.review_enabledboolean?Requires the client-review capability.Sent and received histories return 20 results per page with current, last, per-page, and total values.
"pagination": {
"current_page": 1,
"last_page": 4,
"per_page": 20,
"total": 67
}
Reference
Paths use https://file.fast/api/v1 unless the full /api/… path is shown.
30 endpoints
/upload
Upload one file through FileFast
/upload/presign
Create a temporary direct-to-storage upload
/upload/finalize
Finalize a completed direct upload
/upload/status/{secret}
Read post-upload safety status
/upload/multipart/create
Start a resumable multipart upload
/upload/multipart/status
Reconcile already stored upload parts
/upload/multipart/sign
Create a temporary URL for one upload part
/upload/multipart/complete
Assemble uploaded parts into one object
/upload/multipart/abort
Cancel an unfinished multipart upload
/transfers
Send an ordered file set to email recipients
/transfers/link
Create or record a link transfer
/collections
List private transfer collections
/collections
Create a private transfer collection
/collections/{collection}
Rename a private transfer collection
/collections/{collection}
Delete a collection while preserving its transfers
/transfers/sent
List sent file transfers and recipient status
/transfers/received
List file transfers received by this account
/transfers
Remove selected sent transfers into their recovery window
/transfers/collections
Move selected visible transfers into a private collection or no collection
/transfers/{id}
Read transfer files, recipients, activity, and review
/transfers/{id}/notifications
Replace saved transfer alert controls
/transfers/{id}/collection
Move a transfer into a private collection or no collection
/transfers/{id}/review/close
Close an enabled client review
/requests
List visible incoming file requests
/requests
Create a verified incoming file request
/requests/{publicId}
Read request limits and received submissions
/requests/{publicId}/status
Open, pause, or close a request
/me
Read the account attached to the token
/notification-preferences
Read notification preferences
/notification-preferences
Replace notification preferences
No endpoint matches that search. Try a resource name, HTTP method, or path.
Errors and limits
Validation failures return field errors plus a stable machine-readable code. Every API response includes X-Request-ID, X-RateLimit-Limit, and X-RateLimit-Remaining; a 429 also includes Retry-After. Personal-token limits are 120 requests/minute on Plus, 300 on Creator, and 600 on Teams.
{
"status": false,
"request_id": "b62b7e9d-…",
"error": { "code": "validation_failed" },
"errors": {
"size": [
"Storage limit exceeded. Delete files or choose a larger plan."
]
}
}File size, storage, download activity, retention, recipient, and review limits follow the account.
Repeating a successful direct-upload finalize returns the existing upload record.
Upload-session and transfer mutations verify that the resource belongs to the authenticated user.
Not part of the stable public API
Mobile sign-in/device routes and Enterprise SCIM provisioning are separate client or contracted surfaces. OAuth applications and generated SDKs remain roadmap items. The route-checked OpenAPI 3.1 document and scoped personal bearer tokens are live. Signed outbound webhook delivery has passed local QA.
Start building
Create a named token, test with a small file, then move large workloads to direct upload. Keep secrets server-side and store returned upload and transfer IDs.