REST API

Programmatic access to packages, files, magic-links, and tokens. Token-authenticated. Self-documenting OpenAPI 3 spec available on every running instance.

Live, on your instance: Each SpeedyFiles deployment ships its own interactive API docs at:
  • /api/v1/docs — Swagger UI (try requests in the browser)
  • /api/v1/redoc — ReDoc (clean reference style)
  • /api/v1/openapi.json — machine-readable spec

Authentication

Every request needs a Bearer token in the Authorization header:

Authorization: Bearer sf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Creating a token

  1. Log in to your SpeedyFiles instance
  2. Top-right user menu → AccountAPI tokens
  3. Click "Create token", give it a name and optional expiry, submit
  4. Copy the token immediately — it's shown once and never again

Token scope

Tokens inherit the role of the user that creates them:

Token format

Raw tokens start with sf_ followed by ~43 base64url-safe chars (~32 bytes of entropy). Only the SHA-256 hash is stored in the DB. The first 11 characters (e.g. sf_4F2eTjA) are stored as a prefix for the UI so you can identify tokens after creation — the rest is unrecoverable.

Endpoints

MethodPathDescription
GET/api/v1/healthHealth check (no auth)
GET/api/v1/meCurrent authenticated user
GET/api/v1/me/tokensList your API tokens
POST/api/v1/me/tokensCreate new token (returns raw once)
DELETE/api/v1/me/tokens/{id}Revoke token
GET/api/v1/packagesList packages (paginated)
POST/api/v1/packagesCreate new package (draft state)
GET/api/v1/packages/{id}Package details + files
POST/api/v1/packages/{id}/filesUpload a file (multipart)
POST/api/v1/packages/{id}/finalizeMint magic link + send email
POST/api/v1/packages/{id}/revokeRevoke active links
DELETE/api/v1/packages/{id}Permanently delete

Errors

Standard HTTP status codes. Body is {"detail": "..."}:

200 / 201 / 204Success
401Missing, invalid, or expired token
403Token valid but lacks permission (admin endpoint, or accessing another user's package)
404Package / file / token not found
409Conflict (e.g., email already in use)
422Validation error — body shape or field constraint violated

Code examples

curl — full send flow

TOKEN="sf_your_token_here"
HOST="https://files.example.com"

# 1. Create package
PKG=$(curl -s -X POST $HOST/api/v1/packages \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Q4 financials",
    "recipient_email": "cfo@acme.com",
    "recipient_name": "Acme CFO",
    "direction": "outbound",
    "ttl_days": 14
  }' | jq -r .id)

# 2. Upload one or more files
curl -X POST $HOST/api/v1/packages/$PKG/files \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@./Q4-report.pdf"

curl -X POST $HOST/api/v1/packages/$PKG/files \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@./Q4-spreadsheet.xlsx"

# 3. Finalize — recipient gets email, magic_link returned in response
curl -X POST $HOST/api/v1/packages/$PKG/finalize \
  -H "Authorization: Bearer $TOKEN" | jq

Python

import requests

API = "https://files.example.com/api/v1"
auth = {"Authorization": "Bearer sf_your_token_here"}

# Create package
pkg = requests.post(f"{API}/packages", headers=auth, json={
    "title": "Q4 financials",
    "recipient_email": "cfo@acme.com",
    "recipient_name": "Acme CFO",
    "direction": "outbound",
    "ttl_days": 14,
}).json()
pkg_id = pkg["id"]

# Upload files
for path in ["Q4-report.pdf", "Q4-spreadsheet.xlsx"]:
    with open(path, "rb") as f:
        requests.post(
            f"{API}/packages/{pkg_id}/files",
            headers=auth,
            files={"file": f},
        ).raise_for_status()

# Finalize
result = requests.post(f"{API}/packages/{pkg_id}/finalize", headers=auth).json()
print("Magic link:", result["magic_link"])

Node.js (fetch)

const API = "https://files.example.com/api/v1";
const auth = { "Authorization": "Bearer sf_your_token_here" };

// 1. Create package
const pkg = await (await fetch(`${API}/packages`, {
  method: "POST",
  headers: { ...auth, "Content-Type": "application/json" },
  body: JSON.stringify({
    title: "Q4 financials",
    recipient_email: "cfo@acme.com",
    recipient_name: "Acme CFO",
    direction: "outbound",
    ttl_days: 14,
  }),
})).json();

// 2. Upload a file
const form = new FormData();
form.append("file", new Blob([fs.readFileSync("Q4-report.pdf")]), "Q4-report.pdf");
await fetch(`${API}/packages/${pkg.id}/files`, {
  method: "POST", headers: auth, body: form,
});

// 3. Finalize
const result = await (await fetch(`${API}/packages/${pkg.id}/finalize`, {
  method: "POST", headers: auth,
})).json();
console.log("Magic link:", result.magic_link);

Webhooks (alternative)

For event-driven integrations, see Webhooks. SpeedyFiles can POST to your URL when packages are created, downloaded, uploaded, expired, or deleted — no polling required.

Schemas

The full Pydantic models — including request/response shapes for every endpoint, error codes, and example payloads — are auto-generated and live at /api/v1/docs on your running instance. Open the Swagger UI in a browser to explore.