upload.am API
Upload, store, and share files from your own scripts, servers, and apps — the same speed, storage, and link controls the website gives your users, over a plain REST API.
- REST + JSON
- Bearer tokens
- Presigned S3 uploads
- Resumable multipart
- Same limits as the website
Prefer plain text? Full reference as .md — handy for scripts and AI agents.
# 1. Get a presigned upload URL
curl -X POST https://upload.am/api/v1/upload/token \
-H "Authorization: Bearer ua_live_xxx" -H "Content-Type: application/json" \
-d '{"file_name": "report.pdf", "file_size": 204800}'
# 2. Put the bytes straight on storage
curl -X PUT "$upload_url" --data-binary @report.pdf
# 3. Confirm — the file now exists in your account
curl -X POST https://upload.am/api/v1/upload/confirm \
-H "Authorization: Bearer ua_live_xxx" -H "Content-Type: application/json" \
-d '{"object_key": "...", "public_uuid": "...", "node_id": 1,
"original_name": "report.pdf", "size_bytes": 204800}'
Authentication
Exchange an email and password for an API token:
curl -X POST https://upload.am/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"your-password"}'
That call needs no Bearer header. It returns a token plus the same
object as GET /me. POST /auth/logout revokes that token.
You can still create tokens by hand in
Account → API.
A leaked Bearer still cannot mint new tokens — only the account password can.
Every other request needs:
Authorization: Bearer ua_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
| Status | Error code | Meaning |
|---|---|---|
| 401 | missing_token | No Authorization header |
| 401 | invalid_token | Token not found or revoked |
| 401 | invalid_credentials | Wrong email or password on /auth/login |
| 403 | account_disabled | Account suspended |
Rate limits
Every endpoint has its own independent limit, counted per token —
hitting the ceiling on one endpoint never blocks another. Going over
returns 429 with a Retry-After header.
Storage quota and the max size of a single file follow your account's
plan (see GET /me below) — download speed itself is unmetered on every plan, same as on the website.
Uploading files
Files go straight into object storage over a presigned URL — the upload.am servers see the request headers, never the file bytes in full. It's the same protocol behind the website's own dropzone.
Small files (up to 8 MB)
A single PUT, three calls total — this is the flow shown in the quickstart above:
/upload/token→ presigned PUT URL{upload_url}→ the raw file bytes/upload/confirm→ registers the file in your accountLarge files — S3 multipart
The file is split into parts, each one gets its own presigned PUT:
/upload/multipart/create/upload/multipart/sign-part→ once per part/upload/multipart/complete/upload/confirmAny S3-compatible SDK (aws-sdk, boto3…) speaks this part/ETag format natively — nothing upload.am-specific at this step.
Options accepted by /upload/confirm
| Field | Type | Description |
|---|---|---|
| password | string | Password required to download — same as the website's dropzone |
| max_downloads | int, 1–1000 | File is deleted once the limit is hit |
| link_ttl | 10m·1h·24h·7d | Link expires sooner than the plan's retention, if that's sooner |
| folder_uuid | string | Place the file into an existing folder. Unknown or foreign uuid → 404 folder_not_found, the file is not silently dropped into the root |
| sha256 | 64 hex chars | Checksum computed on your side, verified on download |
Files
/filesList — folder_uuid or root. q without a folder searches the whole account/files/{uuid}File details/files/{uuid}Rename, set/clear password, set/clear download limit/files/{uuid}/moveMove to a folder (or the root)/files/{uuid}/downloadIssue a download link/files/{uuid}Move to trash — 204 empty body/files/{uuid}/restoreRestore from trash/files/{uuid}/forcePermanently delete a trashed file — 204Downloading — the Free-plan wait, without cookies
POST /files/{uuid}/download doesn't ask for the file's own password —
that password protects the public /d/ page from strangers; your API token already
proved this is your file. This call does not increment download_count
and does not consume max_downloads — those apply to public /d/ downloads only.
On paid plans the link comes back immediately. On Free, the same
10-second anti-bot wait the website shows applies — call the endpoint twice:
curl -X POST https://upload.am/api/v1/files/b6f1.../download -H "Authorization: Bearer ua_live_xxx"
→ 202 { "status": "waiting", "wait_seconds": 10 }
sleep 10
curl -X POST https://upload.am/api/v1/files/b6f1.../download -H "Authorization: Bearer ua_live_xxx"
→ 200 { "status": "ready", "download_url": "https://files.upload.am/...", "expires_in": 600 }
Folders
/foldersList — parent_uuid optional/folders{"name", "parent_uuid"}/folders/ensure{"path", "parent_uuid"} — create or reuse a folder path/folders/{uuid}Rename/folders/{uuid}Only if empty — files inside move up one levelBatches
One link for several just-uploaded files, no password/expiry setup needed — each file keeps its own download page inside. Files that already have a batch_uuid cannot join another group (422 files_not_found). There is no DELETE /batches in v1.
/batches{"uuids": [...]}/batches/{uuid}Plan, features and limits
GET /me returns what the account may do. Read it on every start and after a plan change; never hard-code plan codes.
plan.features— keys of included features:esign,ocr,online_editor,templates,work_tools,data_room,backups,block_sync,legal_hold,dlp,sso.entitlements.limits[]—key,used,max(null= unlimited). Keys:storage,file,rooms,portals,household,seats,spaces,api_tokens,active_links,shared_folders,history_days.entitlements.features[]— every feature withallowedand themin_planthat includes it.- A locked feature answers
403 {"error":"plan_feature_locked","feature":"…","min_plan":"…"}; an exhausted limit answers403 {"error":"plan_limit_reached","limit":"…","max":N}.
The complete reference of every endpoint, file fields and error codes: /docs/api.md.
Errors
Validation failures (422) use Laravel's standard shape. Everything else is {"error": "code", "message": "..."}.
| Status | Meaning |
|---|---|
| 404 | {"error":"not_found"} — not found, or not yours. Upload with a bad folder_uuid returns folder_not_found |
| 403 | plan_feature_locked, plan_limit_reached, child_account, device_wipe_pending, forbidden |
| 423 | retention_locked (file locked until a date), protected (legal hold), trash_locked |
| 422 | Validation, plus blocked_extension, blocked_content, weak_password, cannot_shorten |
| 409 | Conflict — e.g. confirming the same upload twice |
| 410 | Expired or revoked |
| 413 | Over the plan's size or storage quota |
| 429 | Rate limited — see Retry-After |
| 507 | Storage node temporarily full |
Changelog
Every change to the API lands here, dated, the day it ships.
Business API: rooms, work tools, e-signature, file operations, team administration
- Team administration in the API: `GET/PATCH /team`, `GET/PATCH /team/policies` (invite domains, link rules, stamp, retention), `GET /team/audit`, `GET /team/audit/export` (CSV), `GET /team/usage`, groups (`/team/groups`), folder grants (`/team/folders/{uuid}/grants`, `/group-grants`), `POST /team/members/{id}/transfer`, shared team Inbox (`/team/inbox`, `/toggle`, `/regenerate`), `GET/PUT /team/encryption`, read-only `GET /team/sso` (SSO is managed in the web app only), `POST /team/trial`.
- Devices and sign-in: `GET /devices`, `POST /devices/{id}/sign-out`, `POST/DELETE /devices/{id}/wipe`, `POST /me/two-factor/recovery-codes`, `POST /me/export`, `DELETE /me`.
- API tokens: `GET/POST /tokens`, `DELETE /tokens/{id}` (`403 plan_limit_reached`).
- Billing: `GET/POST /invoices`, `GET /invoices/{number}/pdf`, `/agreement`, `GET /me/plan` (plan, usage, features with `min_plan`).
- `GET /vpn/profile`; `GET/PATCH /brand` and logo upload (`/brand/logo/token`, `/confirm`, `DELETE /brand/logo`), personal or team.
- `GET /team/members` now includes `user_id` for each member.
- Rooms API: list, create, update and destroy Drop Rooms, client portals and data rooms (`/rooms`), with the public link, deadline and plan limits in every response.
- Room files and folders: attach your files or whole folders, move files between room folders, remove files, view the room activity feed.
- Client checklist API: add, list, delete and reopen document, form and approval requests, and set client reminders.
- Data room API: NDA and Q&A settings, per-document access (open, stamped, view only, hidden), questions and answers, document index and read report (JSON or CSV).
- Photo selection API: enable client selection with a limit, list the selected files and export them for Lightroom, Capture One or CSV.
- Templates API: list built-in and own templates, save case-folder templates, create a folder structure from a template, save a room as a template and create a room from a template.
- New `POST /transfers/lookup`, `POST /transfers`, `GET /transfers`, `POST /transfers/{uuid}/accept|decline|cancel`: send files to another upload.am user (move or copy, 24h/7d/30d request lifetime) and answer incoming requests.
- New `GET /inbox/items` (files from the public drop link plus incoming transfers waiting for a decision) and `GET /inbox/badge` (counter).
- New messages API: `GET/POST /messages`, `POST /messages/{id}/read`, `POST /messages/read-all`, `POST /messages/{id}/block`, `GET /messages/blocked`, `DELETE /messages/blocked/{userId}`; `POST /support` sends a support request.
- New shared folders API: `GET/POST /shared-folders`, `DELETE /shared-folders/{id}`, `GET /shared-folders/{folderUuid}/files`. `POST` answers `403 plan_limit_reached` when the `shared_folders` limit is used up.
- New household (family) API: `GET /household`, `POST /household/invite`, `POST /household/members/{id}/child`, `DELETE /household/members/{id}`, `POST /household/leave`, `POST /household/album`, `GET /household/members/{id}/files`, `POST /household/invites/{token}/accept|decline`.
- `GET/POST /projects`, `GET/PATCH/DELETE /projects/{uuid}` — projects with due dates and an optional client; `POST /projects/{uuid}/tasks`, `PATCH|DELETE /projects/{uuid}/tasks/{id}`, `POST /projects/{uuid}/tasks/{id}/attach` — tasks with assignee, due date, done flag and attached files; `GET /tasks` — my tasks filtered by `status`, `due`, `project`. Plan feature `work_tools`.
- `GET/POST /clients`, `GET/PATCH/DELETE /clients/{uuid}`, `POST /clients/{uuid}/docs`, `PATCH|DELETE /clients/{uuid}/docs/{id}` — clients with contracts and invoices linked to files; the list returns unpaid and overdue totals per currency in `meta`. Plan feature `work_tools`.
- `GET/POST /knowledge-base`, `GET/PATCH/DELETE /knowledge-base/{uuid}`, `POST /knowledge-base/{uuid}/share` — Markdown knowledge base with search (`q`), categories and an optional secret public link. Plan feature `work_tools`.
- `GET/POST /automations`, `POST /automations/{id}/toggle`, `DELETE /automations/{id}` — "if a file arrives, then move / label / lock / email / create a task" rules with conditions on folder, extension and name, and a run counter. Plan feature `work_tools`.
- `GET/POST /signatures`, `GET /signatures/{uuid}`, `POST /signatures/{uuid}/cancel`, `POST /signatures/{uuid}/signers/{id}/resend`, `GET /signature-templates`, `DELETE /signature-templates/{id}` — e-signature for PDFs: up to 10 signers, sequential or parallel, expiry, message, templates, audit log, and temporary links to the signed PDF and completion certificate. Plan feature `esign`.
- All of these accept the `X-Upload-Team:
` header to work in a team workspace (read: any non-guest member; write: owner/admin/editor/contributor). - Added `POST /bulk`: delete, move, lock, label, to_team and to_personal for files, and delete/move for folders, with a per-uuid result (done, skipped, error) and the same permission, retention-lock and legal-hold checks as the website.
- Added `POST/DELETE /files/{uuid}/edit-lock` (24-hour editing lock on team files) and the review API: `GET /files/{uuid}/review`, `POST /files/{uuid}/review/comments`, `POST /files/{uuid}/review/comments/{id}/resolve`, `POST /files/{uuid}/review/decision`.
- Added `GET /files/{uuid}/edit-url` (online editor session for Word, Excel and PowerPoint files; plan feature `online_editor`).
- Added `POST /files/{uuid}/extract`, `GET /duplicates`, `POST /duplicates/clean`, `GET /trash/expired` and `POST /trash/restore-expired`.
- Added `GET /rollback/preview` and `POST /rollback` (restore the account, a folder or a team to a date within 90 days).
- Added `PATCH /shares/{uuid}` (expiry, password, download limit, view-only, watermark, login, IP allow-list, recipient, reminders) and `GET /shares/{uuid}/visits` (visit history with country and device summaries).
- Added `GET /activity` (account events, share downloads and room events with pagination).
- `PATCH /folders/{uuid}` now accepts `parent_uuid` to move a folder; added `GET /folders/{uuid}/protection`.
- `POST /tokens` requires the account password; transfers with `mode: move` refuse files that are locked or under legal hold (`423 retention_locked`).
Plans, features and limits; documented error codes
- `GET /me` returns `plan.features` (keys of the features your plan includes) and `entitlements` (`source`, `limits[]` with `key`, `used`, `max` where `max: null` means unlimited, and `features[]` with `allowed` and `min_plan`). Read them on every start instead of hard-coding plan codes.
- New numeric limits `api_tokens`, `active_links`, `shared_folders`, `history_days`. `POST /shares` answers `403 plan_limit_reached` when one is exhausted.
- A feature outside the plan answers `403 plan_feature_locked` with `feature` and `min_plan`.
- `GET /billing/plans` items carry `family`, `price_year_cents`, `household_max` and `features`; plans not on sale are not returned.
- File objects carry `label`, `sensitive`, `tags`, `has_text`, `retain_until` and `legal_hold`.
- `GET /device` and `POST /device/wiped` (remote wipe of a lost device); `403 device_wipe_pending` until the wipe is confirmed.
- The affiliate payout wallet fields and `PATCH /me/payout-wallet` were removed on 2026-10-11.
Block-level sync and text search
- `GET /files/{uuid}/blocks`, `POST /files/{uuid}/delta` and `POST /files/{uuid}/delta/{id}/complete` — send only changed 8–64 MB blocks of a large file; unchanged blocks are copied inside the storage; the result is a new file version.
- `GET /files?q=` also searches the recognized text of images and PDFs. Files carry `tags` and `has_text`.
Teams
- `GET /teams` — your teams with role, guest flag and seat usage.
- `GET /team/members`, `POST /team/invites` (role or `guest: true`), `DELETE /team/invites/{id}`, `PATCH /team/members/{id}` (role: admin, editor, contributor, viewer, member; status) and `DELETE /team/members/{id}` (files pass to the team owner). Select the team with the `X-Upload-Team` header; changes need a team admin.
Data protection
- `GET /protection` and `PATCH /protection/retention` — retention periods for the trash and old versions (account or team via `X-Upload-Team`).
- `POST /files/{uuid}/lock` and `POST /folders/{uuid}/lock` — lock files until a date (cannot be deleted, renamed or overwritten; only extendable). New file fields: `retain_until`, `legal_hold`, `label`, `sensitive`.
- `GET/POST /holds` and `POST /holds/{uuid}/release` — legal holds for teams. Errors `423 retention_locked` and `423 protected`.
- `GET /backups`, `POST /backups/restore-requests`, `GET /alerts`, `POST /alerts/{id}/dismiss|restore` — server backups, restore requests and ransomware alerts.
- `GET /sensitive` and `POST /files/{uuid}/label` — confidential data detection and labels.
Profile avatar
- `GET /me` and `PATCH /me` now include `avatar_url`.
- `POST /me/avatar/token` + `POST /me/avatar/confirm` — upload or replace your profile picture (2MB limit, same presigned flow as regular files).
Account management
- `PATCH /me` to change your name/email, `PATCH /me/password` to change your password (requires current password) — by request from desktop client users who don't want to open the website just to update their profile.
Account-wide file listing
- `GET /files?all=1` lists every file in your account in one flat, paginated feed (up to 200 per page) — useful for client-side tools like duplicate detection by `sha256`.
Trash, file versions, Upload Inbox
- `GET /files?trashed=1` lists deleted files; `GET /files?inbox_pending=1` lists files awaiting review from your Upload Inbox.
- `GET /files/{uuid}/versions`, `.../versions/{v}/restore`, `.../versions/{v}/download` — file version history.
- `POST /files/{uuid}/accept` and `.../decline` for Upload Inbox submissions.
- `GET/PATCH /inbox`, `POST /inbox/regenerate-token` — manage your Upload Inbox link and rules.
Login, logout, folder paths
- `POST /auth/login` — email and password return a Bearer token. No token needed for this call.
- `POST /auth/logout` revokes the current token.
- `POST /folders/ensure` creates a folder path (`Contracts/2024`) or returns the existing one.
File search and response fields
- `GET /files?q=` without `folder_uuid` searches all files in the account, not only the root.
- `download_count` is always an integer (`0` if none).
- `POST /batches` includes `batch_uuid` on each file in the same response.
Confirm response, folders, download counter
- `POST /upload/confirm` returns the standard file object (`data`), same as `GET /files/{uuid}`.
- New field `batch_uuid` on file objects.
- Invalid `folder_uuid` on upload returns `404`.
- `POST /files/{uuid}/download` no longer counts against `max_downloads`.
- Consistent JSON for `404` responses.
Initial public release
- Bearer token authentication, managed from the dashboard (Account → API).
- File uploads via presigned S3 URLs — single PUT for small files, multipart for large ones. Same protocol the website itself uses.
- Files: list, get, rename, set password, set download limit, move, trash, restore, permanently delete, get a download link.
- Folders: list, create, rename, delete.
- Shares: create password-protected / time-limited / download-limited public links, list, revoke.
- Batches: group already-uploaded files under one shareable link.
- `GET /me` for account, plan, and quota information.