File Upload and Public Sharing
Use this guide to upload files, manage access, and share them publicly or with an email allowlist.
When to use
- You want to host a downloadable file (PDF, CSV, image, etc.) behind your handle.
- You need to restrict file access to specific email addresses.
- You want to set an expiry date on a shared file.
Access modes
| Mode | Who can download |
|---|---|
| PUBLIC | Anyone with the link |
| EMAIL_ALLOWLIST | Only visitors whose email is on the allowlist, via magic link |
UI path
- Open
https://app.{PUBLIC_DOMAIN}. - Navigate to your handle and open the Files section.
- Click Upload File and select a file (max 250 MB).
- Choose an access mode (Public or Email Allowlist).
- Optionally set an expiry date.
- Copy the public URL to share.
Required auth
- CREATOR-level
JWTor above to upload, list, and delete files. PATwithfiles.readorfiles.writescope for automation.- No auth required for public file downloads.
API fallback
Create a file record and get an upload URL
POST /v2/handles/{handle}/files
{
"fileName": "report.pdf",
"accessMode": "PUBLIC",
"sizeBytes": 102400,
"expiresAt": "2026-06-01T00:00:00Z"
}
The response includes a presigned uploadUrl (valid for 15 minutes) and a publicUrl for sharing. Upload the file to the presigned URL using a PUT request.
For email-restricted files, set accessMode to EMAIL_ALLOWLIST and include an allowedEmails array (max 200 addresses).
List files
GET /v2/handles/{handle}/files
Returns up to 500 files sorted by creation date (newest first). Expired files are removed automatically.
Delete a file
DELETE /v2/handles/{handle}/files/{fileId}
Removes the file from storage and deletes its metadata.
PAT endpoints
The same operations are available via PAT at the /v2/public/handles/{handle}/files path family. Requires files.read or files.write scope.
Public download
GET /v2/public/files/{fileId}
Returns a 302 redirect to a time-limited download URL. For EMAIL_ALLOWLIST files, the visitor must first request a magic link:
POST /v2/public/files/{fileId}/magic-link
{
"email": "buyer@example.com"
}
The visitor receives an email with a link that grants a session cookie for downloading.
Common errors
| Code | Error | Cause |
|---|---|---|
| 400 | invalid_file_name | File name empty or exceeds 180 bytes |
| 400 | invalid_size_bytes | File larger than 250 MB |
| 400 | allowed_emails_required | EMAIL_ALLOWLIST mode without email list |
| 403 | email_not_allowlisted | Visitor email not on the allowlist |
| 410 | file_expired | File has passed its expiry date |
File lifecycle
- Create — metadata stored, presigned upload URL returned.
- Upload — client sends file to the presigned URL.
- Access — visitors download via the public URL.
- Expire (optional) — after the expiry date, downloads return 410 and storage is cleaned up automatically.
- Delete (manual) — removes the file and metadata immediately.
Related: