REST API v1 Base: api.transfilio.com

Build with the Transfilio API

Programmatic file transfers with enterprise-grade encryption. Upload, share, and track — all through a simple REST interface.

Rate limited
Hashed API keys
Monthly quotas
terminal
# 1. Create an upload
curl -X POST https://api.transfilio.com/api/v1/uploads \
-H "Authorization: Bearer zs_live_..." \
-H "Content-Type: application/json" \
-d '{"file_name":"document.pdf","file_size":2048576,"file_type":"application/pdf"}'

# Response
{
"upload_id": "b7c9...",
"status": "pending",
"upload_url": "/api/v1/uploads/b7c9.../content",
"completion_url": "/api/v1/uploads/b7c9.../complete"
}

# 2. PUT the exact file bytes to upload_url
curl -X PUT https://api.transfilio.com/api/v1/uploads/b7c9.../content \
-H "Authorization: Bearer zs_live_..." \
-H "Content-Type: application/octet-stream" \
--data-binary @document.pdf
01

Quick Start

Get up and running in under 5 minutes

1

Get Your API Key

Sign up, go to Settings → API Keys, and generate a new key.

2

Make a Request

Add your key to the Authorization header as a Bearer token.

3

Upload & Share

Upload files, create share links, and track downloads — all via the API.

Your first request

# Check API status
curl https://api.transfilio.com/api/health

# 1. Create an upload
curl -X POST https://api.transfilio.com/api/v1/uploads \
-H "Authorization: Bearer zs_live_..." \
-H "Content-Type: application/json" \
-d '{"file_name":"report.pdf","file_size":2048576,"file_type":"application/pdf"}'

# 2. Send the exact bytes to the returned upload_url
curl -X PUT https://api.transfilio.com/api/v1/uploads/b7c9.../content \
-H "Authorization: Bearer zs_live_..." \
-H "Content-Type: application/octet-stream" \
--data-binary @report.pdf

# 3. Verify completion (required for signed S3 upload URLs)
curl -X POST https://api.transfilio.com/api/v1/uploads/b7c9.../complete \
-H "Authorization: Bearer zs_live_..."

# 4. Create a share link
curl -X POST https://api.transfilio.com/api/v1/links \
-H "Authorization: Bearer zs_live_..." \
-H "Content-Type: application/json" \
-d '{"transfer_id": "b7c9..."}'
02

Authentication

All API requests require authentication via an API key

Bearer Token

Recommended
# In your request headers
Authorization: Bearer zs_live_a1b2c3d4e5f6

Standard OAuth-style Bearer token. Works with all HTTP clients.

X-API-Key Header

Alternative
# Custom header alternative
X-API-Key: zs_live_a1b2c3d4e5f6

Useful when Authorization header is already in use.

Security: Never expose keys in client-side code. Use environment variables and rotate regularly via POST /api/v1/api-keys/:id/rotate (24h grace period).

03

Base Configuration

Common settings for all API requests

https://api.transfilio.com
Header Value Required
Authorization Bearer {api_key} Yes
Content-Type application/json Yes
Accept application/json Optional

List endpoints return cursor-paginated results. Use limit and after query parameters. Pass the previous response's next_cursor as the next after value.

# Response includes pagination metadata
{
"data": [...],
"pagination": {
"limit": 20,
"has_more": true,
"next_cursor": "b7c9..."
}
}
04

API Reference

Complete endpoint reference with request and response details

GET /api/health Public

Returns API health status. No authentication required.

Response

{"status": "ok", "version": "1.0.0"}

Uploads

POST /api/v1/uploads Auth required

Create an upload and receive a server-controlled PUT destination. The destination is an authenticated API path for local storage or a short-lived signed URL for S3.

Parameters

file_name string required — Original file name
file_size integer required — File size in bytes
file_type string — MIME type
metadata object — Application-defined metadata
workspace_id string — Accepted workspace destination. Owners, admins, and members may upload; viewers are read-only.

Response

{"upload_id": "b7c9...", "status": "pending", "upload_url": "/api/v1/uploads/b7c9.../content", "upload_method": "PUT", "completion_url": "/api/v1/uploads/b7c9.../complete", "storage_provider": "local"}
PUT /api/v1/uploads/:id/content Auth required

Send the raw file bytes with Content-Type application/octet-stream. This authenticated endpoint streams the request to storage, requires the exact declared file size, records a SHA-256 hash, and completes the upload. A mismatch returns PAYLOAD_SIZE_MISMATCH. Use the returned signed upload_url directly instead when storage_provider is s3.

Response

{"id": "b7c9...", "status": "completed", "bytes_uploaded": 2048576, "sha256_hash": "8f4343..."}
POST /api/v1/uploads/:id/complete Auth required

Verify the stored object's size and complete a direct-to-storage upload. It is safe to repeat this request; usage and completion events are recorded only once.

Response

{"id": "b7c9...", "status": "completed", "bytes_uploaded": 2048576}
GET /api/v1/uploads/:id Auth required

Retrieve upload status, progress, hashes, and storage metadata.

Response

{"id": "b7c9...", "file_name": "report.pdf", "file_size": 2048576, "status": "pending", "bytes_uploaded": 0}
PATCH /api/v1/uploads/:id Auth required

Update mutable upload metadata or mark an upload as uploading, failed, or cancelled. File locations are server controlled, and completed status is accepted only by the verified completion endpoint.

Parameters

status string — uploading, failed, or cancelled
metadata object — Application-defined metadata
error_message string — Failure detail when status is failed

Response

{"id": "b7c9...", "status": "uploading"}
DELETE /api/v1/uploads/:id Auth required

Permanently delete an upload and all associated share links.

Response

204 No Content

Share Links

POST /api/v1/links Auth required

Create a secure share link with optional password, expiry, and download limit.

Parameters

transfer_id string required — ID of the upload session to share
password string — Optional password protection
expires_in integer — Seconds until expiry
max_downloads integer — Maximum download count

Response

{"id": "c2d4...", "token": "abc123", "transfer_id": "b7c9...", "download_count": 0, "is_active": true}
GET /api/v1/links/:id Auth required

Retrieve share link details including download statistics.

Response

{"id": "c2d4...", "token": "abc123", "download_count": 5, "is_active": true}
DELETE /api/v1/links/:id Auth required

Revoke a share link immediately.

Response

204 No Content

Transfers

GET /api/v1/transfers Auth required

List your personal transfers, or pass workspace_id to list transfers visible to an accepted workspace member.

Parameters

limit integer — Results per page (1–100, default: 20)
after string — Transfer ID cursor returned by the previous page
workspace_id string — Workspace whose shared transfers should be listed

Response

{"data": [...], "pagination": {"limit": 20, "has_more": true, "next_cursor": "b7c9..."}}

Usage & Billing

GET /api/v1/usage Auth required

Get current billing period usage including storage, transfers, and API calls.

Response

{"bytes_transferred": 5368709120, "transfer_count": 45, "api_calls_this_month": 892, "api_calls_limit": 1000, "api_calls_remaining": 108, "api_calls_reset_at": 1785542400}

API Key Management

POST /api/v1/api-keys/:id/rotate Auth required

Rotate an API key with a 24-hour grace period for the old key.

Parameters

grace_period_hours integer — Grace period (default: 24, max: 72)

Response

{"new_key": "zs_live_newkey123", "old_key_expires_at": "2026-03-14T10:00:00Z"}
05

Rate Limits

Per-key hourly protection and plan-based monthly allowances

Response Headers

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 994
X-RateLimit-Reset: 1710345600
X-Api-Monthly-Limit: 1000
X-Api-Monthly-Remaining: 108
X-Api-Monthly-Reset: 1711929600

# When rate limited (HTTP 429):
Retry-After: 42 (seconds)

Limits by Plan

Plan Calls/Month Max File
Free Not included 2 GB
Pro 1,000 5 GB
Team 10,000 20 GB
Business 100,000 50 GB
Enterprise 1,000,000 100 GB

Each accepted request consumes the monthly plan allowance. Per-key hourly protection also applies. When either limit is exhausted, the API returns 429 Too Many Requests with a Retry-After header indicating seconds to wait.

06

Webhooks

Business and Enterprise accounts can receive signed transfer and share lifecycle events

transfer.created
transfer.completed
transfer.failed
transfer.deleted
share.created
share.accessed
share.expired

Example Payload

POST https://your-app.com/webhooks/transfilio
X-Transfilio-Signature: sha256=a1b2c3...
X-Transfilio-Event: transfer.completed

{
"id": "83d30a54-...",
"file_name": "report.pdf",
"file_size": 1048576,
"file_type": "application/pdf",
"status": "completed",
"sha256_hash": "8f4343...",
"occurred_at": "2026-07-13T14:30:00Z"
}

Signature Verification

All payloads are signed with HMAC-SHA256. Verify the X-Transfilio-Signature header to ensure authenticity.

import hmac, hashlib

def verify_signature(payload, signature, secret):
expected = hmac.new(
    secret.encode(),
    payload.encode(),
    hashlib.sha256
).hexdigest()
return hmac.compare_digest(
    f"sha256={expected}", signature
)
07

Error Handling

Consistent JSON error responses with actionable codes

Error Format

{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key",
"details": []
}
}

Status Codes

200 OK Request succeeded
201 Created Resource created successfully
400 Bad Request Invalid parameters or malformed request
401 Unauthorized Missing or invalid API key
403 Forbidden Insufficient permissions
404 Not Found Resource does not exist
422 Unprocessable Validation error with details
429 Rate Limited Too many requests — see Retry-After
500 Server Error Internal error — contact support
08

HTTP Client Examples

Use any standard HTTP client — no proprietary SDK is required

Py

Python

pip install requests
JS

JavaScript

Built-in fetch
Rb

Ruby

Net::HTTP
Ex

Elixir

Req

Request Example

import os, requests

base_url = "https://api.transfilio.com"
headers = {"Authorization": "Bearer zs_live_..."}
file_path = "report.pdf"
upload = requests.post(
base_url + "/api/v1/uploads",
headers=headers,
json={"file_name": os.path.basename(file_path), "file_size": os.path.getsize(file_path)}
).json()

upload_url = upload["upload_url"]
put_headers = {"Content-Type": "application/octet-stream"}
if upload_url.startswith("/"):
upload_url = base_url + upload_url
put_headers.update(headers)
with open(file_path, "rb") as file:
requests.put(upload_url, headers=put_headers, data=file).raise_for_status()

requests.post(base_url + upload["completion_url"], headers=headers).raise_for_status()
link = requests.post(
base_url + "/api/v1/links",
headers=headers,
json={"transfer_id": upload["upload_id"], "max_downloads": 10}
).json()
print(link["token"])

Ready to integrate?

Get your API key and start building in minutes. API access starts on Pro with 1,000 calls per month.