Relay
Relay
Files Projects Share code Join a class API keys Docs
PricingTermsAcceptable useDMCAReport abuse

Docs

Introduction

Upload

Files

Account

More

Developer API

Upload, manage and share files on Relay from your own code.

Quickstart

  1. Create a key in the API dashboard.
  2. Upload a file:
    curl -X POST https://relay.xstlo.com/api/files/upload \
      -H "Authorization: Bearer YOUR_API_KEY" \
      -F "file=@report.pdf"
  3. Use data.id for later calls and data.url to download it. Done.

End-to-end example

Upload a file, list your files, rename the upload, then delete it. It checks success and prints the code and requestId when a call fails.

KEY=YOUR_API_KEY

# 1. Upload (keep data.id)
curl -X POST https://relay.xstlo.com/api/files/upload \
  -H "Authorization: Bearer $KEY" -H "Idempotency-Key: $(uuidgen)" -F "file=@report.pdf"

# 2. List
curl "https://relay.xstlo.com/api/files/list?limit=5" -H "Authorization: Bearer $KEY"

# 3. Rename
curl -X PATCH https://relay.xstlo.com/api/files/FILE_ID \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -d '{"name": "renamed.pdf"}'

# 4. Delete
curl -X DELETE "https://relay.xstlo.com/api/files/delete?fileId=FILE_ID" -H "Authorization: Bearer $KEY"

Basics

Base URLhttps://relay.xstlo.com/api
AuthAuthorization: Bearer YOUR_API_KEY. The old ?api_key= query parameter still works but is deprecated: keys in URLs leak into logs and history.
BodiesJSON, or multipart/form-data for file uploads
ResponsesJSON with success: true and data, or success: false and error
CORSAccess-Control-Allow-Origin: * on every endpoint here, so browser code can call it directly
Request IDX-Request-Id on every response. Include it when you contact support.
OpenAPI/openapi.json: the whole API as an OpenAPI 3.1 spec, for client generators and tools like Postman.

Limits

AnonymousFree keyPlus key
Per file1GB1GB8GB
Storage2GB per IP2GB per account50GB per account
Requests20/hr uploads, 10/hr URL uploads (per IP)500/hr per key5,000/hr per key
API keys—230
File expiry15 days (7 for URL uploads)NeverWhile subscribed, then 15 days
  • Storage is shared by every key on an account. On Plus it is the same 50GB pool as your web uploads. Check usage with .
  • Anonymous means no key. Upload, URL upload, download and file-info work without one. A request with an invalid or rate-limited key fails; it never falls back to anonymous.
  • Over a limit: 413 (file too large), 507 (storage full) or 429 (rate limit). Size checks happen before any data is written.
  • On top of per-key limits, each network gets 1,200 API requests a minute across all endpoints. Past that, requests get 429 with Retry-After.

Rate-limit headers

X-RateLimit-Limit: 500          # requests allowed in this window
X-RateLimit-Remaining: 499      # requests left
X-RateLimit-Reset: 1791234567   # Unix seconds when the window resets
Retry-After: 1834               # only on 429: seconds to wait

Errors

Branch on code, not on the message. Messages can change; codes don't. Some errors add fields (for example resetAt on an anonymous 429).

{
  "success": false,
  "error": "File not found",
  "code": "file_not_found",
  "requestId": "req_5f2c9a1e7b3d4c8a9e0f1a2b"
}
StatuscodeWhen
400invalid_requestA parameter is missing or invalid
400invalid_urlA URL is malformed, not http(s), or points to a private address
401unauthorizedNot authenticated
401missing_api_keyAn API key is required but none was sent
401invalid_api_keyThe API key is unknown, disabled, or expired; the message says which
403permission_deniedThe API key lacks the permission this call needs
403subscription_endedThe key's Relay Plus subscription has ended, so it can't upload
403forbiddenNot allowed (for example, another account's file or folder)
404not_foundNot found
404file_not_foundNo file with that id that you can access
404folder_not_foundNo folder with that id that you own
409conflictConflicts with the current state
409idempotency_key_in_useA request with this Idempotency-Key is still running
413file_too_largeThe file is over your per-upload size limit
422unprocessableWell-formed but can't be processed
422idempotency_key_reusedThis Idempotency-Key was already used for a different request
422unsupported_sourceThe remote source can't be used with the multipart flow
429rate_limitedToo many requests; see Retry-After
500internal_errorSomething went wrong on our side
502upstream_errorStorage or the remote source failed
507storage_quota_exceededThe upload would exceed your storage quota

Safe retries (Idempotency-Key)

Upload endpoints accept an Idempotency-Key header: any unique 1–255 character printable ASCII string, such as a UUID. If a request times out, resend it with the same key. When the first attempt already succeeded you get its original response, with Idempotent-Replayed: true, instead of a second copy of the file.

  • Works on /api/files/upload, /api/files/remote-upload, /api/files/multipart/complete and /api/files/remote-upload/multipart/complete.
  • Successful responses are kept 24 hours. Failed requests aren't kept, so you can retry them with the same key.
  • Same key, different request: 422 idempotency_key_reused. Same key while the first is still running: 409 idempotency_key_in_use.
  • Keys are scoped to your API key (or IP without one). Without the header, every request is a new upload.

Legacy v1 API

The older /api/v1/files endpoints still work but new integrations should use the endpoints in this reference. A v1 key reaches only its own files (d/api/{keyId}/ or d/api/{accountId}/): other files return 404, and a list prefix outside them returns 403. The image CDN (/api/v1/images) is current, not legacy.