API Reference

Programmatic access to upload, manage, and analyze your media.

1. Introduction

All endpoints use the following base URL:

https://www.torrentcdn.store

Authentication: Bearer token or API key in the Authorization header.

Format: All requests and responses are JSON.

Two credential types work: a short-lived token from POST /auth/login (or POST /auth/register) — issued after you pass the two-factor step (see section 2) — or an API key created in your dashboard (tcdn_…). Keys are shown once at creation, stored only as a hash, and sent exactly like a token: Authorization: Bearer tcdn_…. Revoke or rotate them any time from the dashboard.

2. Authentication

POST/auth/register

Create a new account. With mandatory two-factor authentication, the response carries a short-lived mfa_token instead of a session token — complete the enrollment flow below before any session exists.

Request

{
  "email": "you@example.com",
  "password": "yourpassword1"
}

Response

{
  "mfa_required": true,
  "mfa_token": "<short-lived_token>",
  "needs_setup": true,
  "token_type": "bearer"
}
POST/auth/login

Log in with your credentials. The password is only the first factor: when 2FA is required (and for every MFA-enabled account) you get a second-factor step, not a session token.

Request

{
  "email": "you@example.com",
  "password": "yourpassword1"
}

Response

{
  "mfa_required": true,
  "mfa_token": "<short-lived_token>",
  "needs_setup": false,
  "token_type": "bearer"
}

needs_setup is false when the account already has 2FA (the code step only), and true when the account still must enroll. On deployments where 2FA is not enforced (e.g. local development), these endpoints return {"access_token", "token_type"} as before.

Start login — returns the second-factor step (complete it via /auth/mfa/confirm)

curl -X POST https://www.torrentcdn.store/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com","password":"yourpassword1"}'
# → {"mfa_required":true,"mfa_token":"<mfa>","needs_setup":false,"token_type":"bearer"}

Mandatory two-factor authentication

Two-factor authentication (2FA) is required for every account. You enroll an authenticator app (Google Authenticator, Authy, 1Password, …) once, and every sign-in asks for a 6-digit code after your password. There is no way to sign up or log in without it.

At signup, enrollment happens immediately: after your account is created, the signup flow walks you through scanning the QR code, saving your backup codes, and entering a code — before you receive a session. Your account is born with 2FA on.

At login, the password is only the first half. The API never mints a session for a password alone — it returns a short-lived mfa_token that must be exchanged for your real session at POST /auth/mfa/confirm with a code. The token expires in ~5 minutes.

The three-step API flow is:

  1. POST /auth/register (or /auth/login) → mfa_required + mfa_token, no session.
  2. POST /auth/mfa/setup with the mfa_token → secret, otpauth URI, and 10 single-use backup codes (shown exactly once).
  3. POST /auth/mfa/confirm with the mfa_token + a valid code → your session token. If the account had no 2FA yet, this also enrolls it.
POST/auth/mfa/setup

Begin enrollment. Mints a TOTP secret, its otpauth URI, and 10 single-use backup codes. Authenticated by the short-lived mfa_token (mid-signup / mid-login, when no session exists yet) or by your session token (dashboard). The backup codes are returned in plaintext exactly once — save them before leaving this step.

Request

Headers:
  Authorization: Bearer <mfa_token>

Response

{
  "secret": "JBSWY3DPEHPK3PXP",
  "otpauth_uri": "otpauth://totp/TorrentCDN:you@example.com?secret=JBSWY3DPEHPK3PXP&issuer=TorrentCDN",
  "backup_codes": ["ABC1234567", "DEF2345678", "GHI3456789"]
}
POST/auth/mfa/confirm

Complete the second factor: present the mfa_token plus a valid 6-digit TOTP code (or a single-use backup code) to receive your real session token. When the account had no 2FA yet, confirming also enrolls it — this is how signup and mandatory-login enrollment finish.

Request

{
  "mfa_token": "<short-lived_token>",
  "code": "123456"
}

Response

{
  "access_token": "<your_access_token>",
  "token_type": "bearer"
}

Full enrollment flow (3 calls)

# 1. Create the account — no session yet, just an mfa_token
curl -X POST https://www.torrentcdn.store/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com","password":"yourpassword1"}'
# → {"mfa_required":true,"mfa_token":"<mfa>","needs_setup":true,"token_type":"bearer"}

# 2. Enroll — returns the secret + backup codes (shown once)
curl -X POST https://www.torrentcdn.store/auth/mfa/setup \
  -H "Authorization: Bearer <mfa>"

# 3. Confirm with a code from your authenticator app → real session
curl -X POST https://www.torrentcdn.store/auth/mfa/confirm \
  -H "Content-Type: application/json" \
  -d '{"mfa_token":"<mfa>","code":"123456"}'

Already enrolled? Login returns needs_setup: false and you skip straight to the code step. Manage 2FA from the dashboard: POST /auth/mfa/enable after setup, or POST /auth/mfa/disable with a current code (you will be asked to re-enroll at your next sign-in). Losing your authenticator is what the backup codes are for — each is single-use and can never be shown again.

Lost your authenticator?

The single-use backup codes shown at enrollment are your recovery path — each can be entered at login exactly once. If you lose both the app and every backup code, the account cannot sign in: two-factor authentication is enforced for every account and cannot be removed with a password alone (by design, so a stolen password can never strip 2FA). Contact support with proof of account ownership to have two-factor authentication reset.

3. Upload File

Two ways to upload. POST /upload sends the file through the API proxy — simple, but the proxy caps request bodies at ~4.5MB, so it only suits small files. For anything real (video), use the presigned flow: presign → PUT the file bytes directly to storage (never through the proxy) → finalize.

POST/upload

Upload a small file through the API proxy. The file is stored and a magnet link + embed URL are generated. Prefer the presigned flow below for anything over ~4.5MB.

Request

Headers:
  Authorization: Bearer <YOUR_TOKEN>
Body:
  multipart/form-data, field name: "file"

Response

{
  "file_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "filename": "video.mp4",
  "minio_url": "https://<project>.supabase.co/storage/v1/object/public/...",
  "magnet_link": "magnet:?xt=urn:btih:...",
  "file_size_mb": 12.4,
  "embed_url": "https://www.torrentcdn.store/embed/3fa85f64-..."
}

curl example

curl -X POST https://www.torrentcdn.store/upload \
  -H "Authorization: Bearer <YOUR_TOKEN>" \
  -F "file=@video.mp4"
POST/upload/presign

Step 1 — issue a short-lived (15 min) presigned PUT URL for direct-to-storage upload. The file bytes never touch the API proxy, so any size up to your plan limit works. Idempotent: send the same idempotency_key on retries — if a previous attempt already completed, it returns as `result` and you can skip the upload entirely.

Request

Headers:
  Authorization: Bearer <YOUR_TOKEN>
Body (JSON):
{
  "filename": "video.mp4",
  "file_size": 134217728,
  "content_type": "video/mp4",
  "idempotency_key": "optional-stable-id"
}

Response

{
  "upload_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "presigned_url": "https://<project>.supabase.co/storage/v1/s3/...?X-Amz-Signature=...",
  "object_key": "<user-id>/3fa85f64-.../video.mp4",
  "content_type": "video/mp4",
  "expires_in": 900,
  "result": null
}

Step 2 — PUT the file bytes straight to storage

curl -X PUT "<presigned_url>" -H "Content-Type: video/mp4" --data-binary @video.mp4

No Authorization header here — the signature is in the URL. The Content-Type must exactly match the value returned by presign.

POST/upload/presign/finalize/{upload_id}

Step 3 — verify + finalize the stored object (size + file-header checks), generate the torrent magnet link and thumbnail, and record the file. Idempotent: retrying after a lost response returns the original result instead of duplicating the file.

Request

Headers:
  Authorization: Bearer <YOUR_TOKEN>

Response

{
  "file_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "filename": "video.mp4",
  "minio_url": "https://<project>.supabase.co/storage/v1/object/public/...",
  "magnet_link": "magnet:?xt=urn:btih:...",
  "file_size_mb": 128.0,
  "embed_url": "https://www.torrentcdn.store/embed/3fa85f64-..."
}

4. List Files

GET/files

List all files for the authenticated user, with per-file analytics.

Request

Headers:
  Authorization: Bearer <YOUR_TOKEN>

Response

[
  {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "filename": "video.mp4",
    "file_size_mb": 12.4,
    "views": 42,
    "p2p_offload_percent": 91.2,
    "bandwidth_saved_gb": 1.203,
    "active_peers": 0
  }
]

5. Get File

GET/files/{file_id}

Get a single file's details by its ID.

Request

Headers:
  Authorization: Bearer <YOUR_TOKEN>

Response

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "filename": "video.mp4",
  "file_size_mb": 12.4,
  "views": 42,
  "p2p_offload_percent": 91.2
}

6. Delete File

DELETE/files/{file_id}

Permanently delete a file and its stored data.

Request

Headers:
  Authorization: Bearer <YOUR_TOKEN>

Response

{
  "detail": "File deleted successfully"
}

7. Analytics

GET/analytics/{file_id}

Get delivery analytics for one of your files. Requires authentication — only the file's owner can read its stats.

Request

Headers:
  Authorization: Bearer <YOUR_TOKEN>

Response

{
  "total_views": 42,
  "p2p_offload_percent": 91.2,
  "bandwidth_saved_gb": 1.203,
  "active_peers": 3
}

8. Embed

Drop the SDK script on your page and add a single div. The player auto-mounts and streams via P2P.

<!-- Add to your HTML -->
<script src="https://www.torrentcdn.store/sdk.js"></script>
<div data-torrent-cdn="FILE_ID"></div>
TorrentCDN — P2P Video Delivery That Gets Cheaper As You Scale