Fileroy for developers

Your uploads. Your workflow.

Upload videos and files from your own scripts, desktop tools, or server. File data goes straight to Cloudflare R2 using temporary upload URLs. Fileroy verifies the uploaded file and returns its real download link.

Start with one command

Download the Python uploader above. It requires Python 3.9+ and has no extra dependencies. It splits large files into parts, uploads up to three parts in parallel, retries temporary failures, and prints real completion progress and your download link.

Visitor upload

python fileroy-upload.py video.mp4

No account or API key is required for visitor uploads. Visitor plan rules and expiry apply. Guest files do not appear in a user account and do not earn account download rewards.

Upload to your account

Sign in, open Settings → API keys, and create a key using your account password. Existing email verification and two-factor authentication checks apply. Set FILEROY_API_KEY in your environment before running the uploader.

# macOS / Linux
export FILEROY_API_KEY='YOUR_PRIVATE_KEY'
python fileroy-upload.py video.mp4

# PowerShell
$env:FILEROY_API_KEY = 'YOUR_PRIVATE_KEY'
python fileroy-upload.py video.mp4

Press Ctrl+C to cancel an unfinished upload. Account uploads appear in My Files and keep the existing download and eligible earnings rules.

Authentication

Base URL: https://fileroy.com/api/v1

For account uploads, send your key in the Authorization header on every API request. Keys expire and can be revoked in Settings → API keys. Only a hash is stored; the full key is shown once.

Authorization: Bearer YOUR_PRIVATE_KEY
Accept: application/json
Content-Type: application/json

For guest uploads, omit Authorization when starting. The response contains a private upload_token. Send it as X-Upload-Token on subsequent controls for that upload. A guest token is restricted to its upload and the same public IP address; changing IP can prevent completion.

Never put API keys or upload tokens in URLs, shared frontend code, public repositories, or logs. Send the account key only to Fileroy API requests, never to an R2 upload URL. Treat presigned URLs as private temporary credentials.

The upload workflow

  1. Read /limits to check the current plan and file rules.
  2. Start an upload with the filename and exact byte size.
  3. Request part URLs. Use the part_size returned by Fileroy; the last part may be smaller.
  4. PUT each exact file slice to its signed URL. Keep all signed query parameters intact. Do not send your Fileroy key to R2.
  5. Complete the upload. Fileroy checks the actual parts, stored byte size, ownership, and quotas before saving file metadata.

1. Start

curl -X POST 'https://fileroy.com/api/v1/uploads' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer YOUR_PRIVATE_KEY' \
  -d '{"original_name":"video.mp4","name":"My video","size":12345678}'

{"id":"UPLOAD_ID","part_size":16777216,"parts":1,"expires_at":"..."}

This is an example response. Always use the actual returned part_size, parts, and expiry. Guest responses also include upload_token.

2. Request URLs and upload bytes

POST /api/v1/uploads/UPLOAD_ID/parts
{"parts":[1]}

{"urls":[{"part":1,"url":"SIGNED_R2_URL","size":12345678}],"expires_in":600}

curl --request PUT --upload-file part-1.bin 'SIGNED_R2_URL'

Request up to 12 distinct part numbers at a time. Each R2 PUT must have Content-Length equal to that part’s returned size. The included Python uploader handles slicing and headers. URLs expire; request a new URL before retrying an expired one.

3. Finish

POST /api/v1/uploads/UPLOAD_ID/complete
{}

{"type":"success","shared_id":"...","download_link":"https://fileroy.com/SHARED_ID/file"}

Use the actual download_link from the response. Repeating completion returns the same result. Downloads keep the existing visibility, password, permissions, and page flow.

Endpoints

MethodPathPurpose
GET/limitsCurrent visitor or authenticated plan limits; use Authorization for your account.
POST/uploadsReserve quota and start a multipart upload.
POST/uploads/{id}/partsGet temporary URLs for the requested parts.
POST/uploads/{id}/completeVerify the stored file and save metadata. Send {}.
GET/uploads/{id}Read upload state and the download link after completion.
DELETE/uploads/{id}Cancel an unfinished upload. Send {}. Completed files are never deleted by this endpoint.

Start request fields

  • original_name: required filename including extension, maximum 255 characters; no path separators.
  • name: required display name, maximum 255 characters.
  • size: required positive integer, exact file size in bytes.
  • visibility: optional boolean; true by default. Guest uploads are always public.
  • password: optional file password, maximum 255 characters.
  • description: optional text, maximum 1000 characters.
  • folder: optional existing folder ID belonging to your account. Guests cannot use folders.

Limits & error handling

There is no separate API upload allowance. Website and API uploads share your current plan’s maximum file size, storage space, accepted extensions, expiry, and active-upload limit. Pending uploads reserve storage too. API uploads currently require the existing direct R2 storage provider to be enabled.

Control requests accept JSON only, up to 16 KiB. File bytes must go to the signed R2 URL. The API allows up to 60 control requests per minute per source IP, and up to 10 starts per minute. A 429 response includes Retry-After. Keep requests below these limits and retry with backoff.

StatusMeaning
401 / 403Invalid, expired, or revoked key; missing guest token; blocked, unverified, or incomplete account; uploads disabled for the plan.
404Unknown upload or ownership check failed. No other user’s upload details are revealed.
409Expired, cancelled, or already finished upload, or direct storage unavailable.
413 / 415Control body too large or not JSON.
422Invalid metadata, incomplete upload, rejected file type, size mismatch, plan limit, or insufficient storage. Read message and errors.
429 / 503Rate limit or temporary provider failure. Retry later with backoff.

Check expires_at when resuming a saved upload. Unfinished uploads expire and are cleaned up automatically. Cancel when abandoning a file to release its reserved storage. The API never accepts arbitrary remote URLs to fetch files.