Media Downloader API

Complete reference for integrating with the Media Downloader API — version 3.1

Overview

The Media Downloader API provides programmatic access to download media from Instagram, TikTok, YouTube, Facebook, Twitter, Pinterest, and other platforms. All download operations are asynchronous.

Quick Start

Download a video in three steps:

Step 1 — Submit download  →  Step 2 — Poll task  →  Step 3 — Fetch file
# Step 1: Submit
curl -X POST https://medialoader.69media.pro/api/v1/download \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{"url":"https://www.instagram.com/p/ABC123/"}'

# Step 2: Poll (replace TASK_ID with the id from step 1)
curl https://medialoader.69media.pro/api/v1/tasks/TASK_ID \
  -H "X-API-Key: YOUR_API_KEY"

# Step 3: Download file (replace PATH with files[0] value from step 2)
curl -OJ -L https://medialoader.69media.pro/api/v1/files/PATH \
  -H "X-API-Key: YOUR_API_KEY"
import requests, time

BASE  = "https://medialoader.69media.pro/api/v1"
HDRS  = {"X-API-Key": "YOUR_API_KEY"}

# Step 1: Submit
r = requests.post(f"{BASE}/download", json={"url": "https://www.instagram.com/p/ABC123/"}, headers=HDRS)
task_id = r.json()["id"]

# Step 2: Poll until done
while True:
    task = requests.get(f"{BASE}/tasks/{task_id}", headers=HDRS).json()
    if task["status"] in ("completed", "error"):
        break
    time.sleep(2)

# Step 3: Download files (task["files"] is a list of relative path strings)
for f in task.get("files", []):
    data = requests.get(f"{BASE}/files/{f}", headers=HDRS)
    filename = f.split("/")[-1]
    with open(filename, "wb") as fp:
        fp.write(data.content)
const BASE  = "https://medialoader.69media.pro/api/v1";
const HDRS  = { "X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json" };

// Step 1: Submit
const { id } = await fetch(`${BASE}/download`, {
    method: "POST", headers: HDRS,
    body: JSON.stringify({ url: "https://www.instagram.com/p/ABC123/" })
}).then(r => r.json());

// Step 2: Poll
let task;
do {
    await new Promise(r => setTimeout(r, 2000));
    task = await fetch(`${BASE}/tasks/${id}`, { headers: HDRS }).then(r => r.json());
} while (!["completed", "error"].includes(task.status));

// Step 3: files is an array of relative path strings
console.log(task.files?.map(f => `${BASE}/files/${encodeURIComponent(f)}`));

Authentication

When API key authentication is enabled, every request to /api/* must include the key. Admin routes always require a separate admin token.

🔑
API key authentication can be toggled on or off by a superadmin. If your instance is public (no key required), you can skip the X-API-Key header entirely.

API Key Header (recommended)

GET /api/v1/tasks HTTP/1.1
X-API-Key: YOUR_API_KEY
Content-Type: application/json

Query Parameter (legacy)

Supported for backward compatibility. Avoid — keys are visible in logs and browser history.

GET /api/v1/tasks?api_key=YOUR_API_KEY

Admin Token

Admin endpoints (/api/v1/admin/*) require X-Admin-Token obtained from POST /api/v1/admin/login.

GET /api/v1/admin/me HTTP/1.1
X-Admin-Token: <token from POST /api/v1/admin/login>

Base URL

EnvironmentBase URL
Productionhttps://medialoader.69media.pro
Local devhttp://localhost:8000

Error Codes

HTTPMeaningCommon cause
200OKSuccess
202AcceptedDownload task queued
400Bad RequestInvalid parameters or URL
401UnauthorizedMissing or wrong API key / admin token
403ForbiddenInsufficient admin role
404Not FoundTask, file, or session doesn't exist
409ConflictResource already exists
422Validation ErrorRequest body schema error
429Too Many RequestsRate limit exceeded (see X-RateLimit-Reset)
500Server ErrorUnexpected server failure

All error responses: {"detail": "Human-readable message"}

Rate Limits

Default: 240 requests per minute per IP. When exceeded the server returns 429 with headers X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, and Retry-After.


Download Endpoints

POST /api/v1/download Queue a single media download

Submits a download task and returns immediately with a task object (HTTP 202). The actual download runs in the background — poll GET /tasks/{id} for progress.

Request body

FieldTypeDescription
urlrequiredstringFull media URL (Instagram, TikTok, YouTube, Facebook, Twitter, Pinterest, etc.)
qualityoptionalstringmax (default), high, medium, low
download_alloptionalbooleanFetch all items from a carousel/playlist (default: false)
max_itemsoptionalintegerLimit items for profiles/playlists (1–10 000)
proxyoptionalstringOutbound proxy URL for this download

Response — 202 Accepted (TaskStatusInfo)

FieldTypeDescription
idstringTask UUID — use to poll status
statusstringpending | downloading | uploading | completed | error
progressfloat0.0 – 100.0
platformstringDetected platform (instagram, tiktok, youtube, …)
filesarray<string>Relative file paths (populated after completion)
errorstring|nullError message when status is error
wasabi_urlsobjectMap of path → presigned URL for cloud-stored files
source_urlstringOriginal media URL on the source platform
profile_urlstringAuthor profile/channel URL
curl -X POST https://medialoader.69media.pro/api/v1/download \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://www.tiktok.com/@user/video/7123456789",
    "quality": "max"
  }'
requests.post(
    "https://medialoader.69media.pro/api/v1/download",
    json={"url": "https://www.tiktok.com/@user/video/7123456789", "quality": "max"},
    headers={"X-API-Key": "YOUR_API_KEY"}
)
{
  "id": "3f1a2b4c-8d9e-4f0a-b1c2-d3e4f5a6b7c8",
  "url": "https://www.tiktok.com/@user/video/7123456789",
  "status": "pending",
  "progress": 0.0,
  "platform": "tiktok",
  "files": [],
  "error": null,
  "created_at": 1714000000.0,
  "elapsed_seconds": 0.0,
  "total_items": 0,
  "downloaded_items": 0,
  "wasabi_urls": {},
  "source_url": "",
  "profile_url": ""
}
POST /api/v1/batch-download Queue multiple downloads at once

Submit up to 50 URLs in a single call. Duplicates are deduplicated. Each URL becomes an independent task. Returns {"tasks": [...]}.

FieldTypeDescription
urlsrequiredarray<string>1–50 URLs
qualityoptionalstringSame as single download
download_alloptionalbooleanApply to all URLs
max_itemsoptionalintegerApplied per URL
proxyoptionalstringShared proxy for all URLs
curl -X POST https://medialoader.69media.pro/api/v1/batch-download \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": [
      "https://www.instagram.com/p/ABC123/",
      "https://www.tiktok.com/@user/video/7123456789"
    ],
    "quality": "max"
  }'
GET /api/v1/tasks/{task_id} Poll task progress

Returns the current state of a task. Poll every 2–5 seconds until status is completed or error.

💡
When status == "completed", the files field is an array of relative path strings (e.g. "tiktok/user/video.mp4"). Use these paths with GET /api/v1/files/{path}.
curl https://medialoader.69media.pro/api/v1/tasks/3f1a2b4c-8d9e-4f0a-b1c2-d3e4f5a6b7c8 \
  -H "X-API-Key: YOUR_API_KEY"
{
  "id": "3f1a2b4c-8d9e-4f0a-b1c2-d3e4f5a6b7c8",
  "status": "completed",
  "progress": 100.0,
  "elapsed_seconds": 4.2,
  "files": ["tiktok/user/video.mp4"],
  "total_items": 1,
  "downloaded_items": 1,
  "source_url": "https://www.tiktok.com/@user/video/7123456789",
  "profile_url": "https://www.tiktok.com/@user",
  "wasabi_urls": {}
}
GET /api/v1/tasks List all tasks
Query paramTypeDescription
statusoptionalstringFilter: pending, downloading, uploading, completed, error
limitoptionalintegerMax results (1–500, default 100)
offsetoptionalintegerPagination offset (default 0)
curl "https://medialoader.69media.pro/api/v1/tasks?status=completed&limit=20" \
  -H "X-API-Key: YOUR_API_KEY"
DELETE /api/v1/tasks/{task_id} Cancel an in-flight task

Attempts to cancel a pending or downloading task. Returns {"id": "...", "cancelled": true} if successful, or {"cancelled": false} if the task was already finished.

curl -X DELETE https://medialoader.69media.pro/api/v1/tasks/TASK_ID \
  -H "X-API-Key: YOUR_API_KEY"

File Endpoints

GET /api/v1/files List downloaded files

Returns all files in the download directory with optional filtering and sorting. Response: {"total": N, "files": [...]}.

Query paramTypeDescription
sortoptionalstringdate (default), name, size
media_typeoptionalstringFilter: video | image | audio | other
platformoptionalstringFilter by platform folder (e.g. tiktok)
profileoptionalstringFilter by source profile/channel name

Each file object includes: name, size_bytes, size_human, modified, media_type, source_platform, source_profile, wasabi (bool), download_url, thumbnail_url, source_url, profile_url.

curl "https://medialoader.69media.pro/api/v1/files" \
  -H "X-API-Key: YOUR_API_KEY"
{
  "total": 142,
  "files": [
    {
      "name": "Instagram/user123/video_abc.mp4",
      "size_bytes": 14532096,
      "size_human": "13.9 MB",
      "modified": 1747123456.0,
      "media_type": "video",
      "source_platform": "Instagram",
      "source_profile": "user123",
      "wasabi": false,
      "download_url": "/api/v1/files/Instagram/user123/video_abc.mp4",
      "thumbnail_url": "/api/v1/thumbs/Instagram/user123/video_abc.mp4",
      "source_url": "https://www.instagram.com/reel/Cxyz/",
      "profile_url": "https://www.instagram.com/user123/"
    }
  ]
}
# Only videos from Instagram, sorted by size
curl "https://medialoader.69media.pro/api/v1/files?media_type=video&platform=Instagram&sort=size" \
  -H "X-API-Key: YOUR_API_KEY"

# Images from a specific profile
curl "https://medialoader.69media.pro/api/v1/files?media_type=image&profile=user123" \
  -H "X-API-Key: YOUR_API_KEY"
GET /api/v1/profiles List source profiles

Returns unique profile/channel names extracted from download paths, with file counts and total bytes.

Query paramTypeDescription
platformoptionalstringFilter by platform
curl "https://medialoader.69media.pro/api/v1/profiles?platform=instagram" \
  -H "X-API-Key: YOUR_API_KEY"
GET /api/v1/files/{path} Download a file

Returns the file as a binary response, or a 307 Temporary Redirect to Wasabi/S3 cloud storage if the file is stored remotely. Media files are served inline; other types as attachments.

# Download and save with original filename (-L follows 307 redirect)
curl -OJ -L https://medialoader.69media.pro/api/v1/files/tiktok%2Fuser%2Fvideo.mp4 \
  -H "X-API-Key: YOUR_API_KEY"
DELETE /api/v1/files/{path} Delete a single file

Deletes the specified file locally and removes it from the Wasabi manifest. Returns {"deleted": "path/to/file.mp4"}.

curl -X DELETE https://medialoader.69media.pro/api/v1/files/tiktok%2Fuser%2Fvideo.mp4 \
  -H "X-API-Key: YOUR_API_KEY"
DELETE /api/v1/files Delete all downloaded files
⚠️
Permanently deletes ALL files and clears the Wasabi manifest. Irreversible. Must pass ?confirm=true.
curl -X DELETE "https://medialoader.69media.pro/api/v1/files?confirm=true" \
  -H "X-API-Key: YOUR_API_KEY"
POST /api/v1/files/archive Download files as ZIP archive

Builds a ZIP from the supplied relative file paths and streams it back. Returns application/zip.

FieldTypeDescription
filesrequiredarray<string>Relative paths of files to include in the archive
curl -X POST https://medialoader.69media.pro/api/v1/files/archive \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"files":["tiktok/user/video1.mp4","instagram/user/photo.jpg"]}' \
  -o archive.zip
GET /api/v1/thumbs/{path} Get video thumbnail

Returns a cached JPEG thumbnail for a video file. Generated on first request via ffmpeg. Supports Wasabi-stored files. Response: image/jpeg, cached for 24 hours.

curl https://medialoader.69media.pro/api/v1/thumbs/tiktok%2Fuser%2Fvideo.mp4 \
  -H "X-API-Key: YOUR_API_KEY" -o thumb.jpg

Gallery Endpoints

History Endpoints

GET /api/v1/history Download history

Returns past download attempts (success and error) in reverse-chronological order.

Query paramTypeDescription
limitoptionalintegerMax results (1–500, default 50)
offsetoptionalintegerPagination offset (default 0)
platformoptionalstringFilter by platform
statusoptionalstringFilter: success | error
curl "https://medialoader.69media.pro/api/v1/history?limit=20&status=success" \
  -H "X-API-Key: YOUR_API_KEY"
DELETE /api/v1/history Clear download history

Deletes all history entries. Returns {"status": "ok", "cleared": N}.

curl -X DELETE https://medialoader.69media.pro/api/v1/history \
  -H "X-API-Key: YOUR_API_KEY"

System Endpoints

GET /api/v1/health Service health check

Returns server status, version, uptime, storage stats, and availability of optional components.

curl https://medialoader.69media.pro/api/v1/health \
  -H "X-API-Key: YOUR_API_KEY"
{
  "status": "ok",
  "version": "3.1.0",
  "uptime_seconds": 86400.0,
  "download_dir": "/app/downloads",
  "total_files": 42,
  "total_size_human": "1.2 GB",
  "active_tasks": 2,
  "proxy_pool": {
    "total_parsed": 334492,
    "verified_pool_size": 98,
    "https_capable": 14,
    "socks5_count": 10,
    "socks4_count": 84,
    "blacklisted": 0,
    "avg_speed_ms": 1329,
    "fastest_ms": 93,
    "refresh_cycles": 232,
    "sources_count": 118,
    "top_proxies": ["..."]
  },
  "ffmpeg_available": true,
  "cookies_configured": true,
  "instagram_sessions": 3,
  "instagrapi_available": false,
  "download_methods": ["instaloader", "instagrapi", "yt-dlp", "cobalt", "facebook-direct"],
  "redis_connected": false,
  "wasabi_configured": false,
  "wasabi_bucket": null,
  "platform_info": {
    "system": "Linux",
    "release": "6.8.0-106-generic",
    "python_version": "3.12.0",
    "machine": "x86_64"
  }
}
GET /api/v1/methods Available download methods

Returns the currently available downloader cascade and the readiness of each method (instaloader, instagrapi, yt-dlp).

curl https://medialoader.69media.pro/api/v1/methods \
  -H "X-API-Key: YOUR_API_KEY"
GET /api/v1/proxy-stats Proxy pool statistics

Returns current proxy pool metrics: pool size, verified count, speed, blacklisted count, and refresh state.

curl https://medialoader.69media.pro/api/v1/proxy-stats \
  -H "X-API-Key: YOUR_API_KEY"
GET /api/v1/cobalt-status Cobalt runtime status

Checks the configured Cobalt instance and returns its availability, version, and supported services list.

curl https://medialoader.69media.pro/api/v1/cobalt-status \
  -H "X-API-Key: YOUR_API_KEY"
GET /api/v1/ollama-status Ollama server inventory

Discovers all configured Ollama endpoints and reports model availability for extraction and AML workloads.

curl https://medialoader.69media.pro/api/v1/ollama-status \
  -H "X-API-Key: YOUR_API_KEY"
GET /api/v1/debug Protected dependency diagnostics

Runs extended checks for yt-dlp, ffmpeg, and a sample extractor probe. Requires a valid API key. Returns 403 if no API key is configured.

curl https://medialoader.69media.pro/api/v1/debug \
  -H "X-API-Key: YOUR_API_KEY"

Cookie Endpoints

Cookies enable authenticated access to platforms like Instagram, TikTok, Twitter, YouTube, Facebook, and Pinterest.

GET /api/v1/cookies/status Instagram cookie status

Shows whether the primary Instagram cookie file exists and contains a usable sessionid.

curl https://medialoader.69media.pro/api/v1/cookies/status \
  -H "X-API-Key: YOUR_API_KEY"
GET /api/v1/cookies/all Cookie inventory for all platforms

Returns file presence, auth-readiness, and cookie-name previews for every supported platform.

curl https://medialoader.69media.pro/api/v1/cookies/all \
  -H "X-API-Key: YOUR_API_KEY"
POST /api/v1/cookies/manual Store Instagram cookies manually

Creates or replaces the primary Instagram Netscape cookie file from manually supplied values.

FieldTypeDescription
sessionidrequiredstringInstagram sessionid cookie value (min 10 chars)
csrftokenoptionalstringInstagram csrftoken cookie
ds_user_idoptionalstringInstagram ds_user_id cookie
curl -X POST https://medialoader.69media.pro/api/v1/cookies/manual \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sessionid": "12345678%3AAbCdEfGhIjKlMn%3A12",
    "csrftoken": "abcdef1234567890abcdef1234567890",
    "ds_user_id": "12345678"
  }'
POST /api/v1/cookies/platform Store cookies for any platform

Persists cookies for any supported platform in Netscape format. Supported platforms: instagram, twitter, tiktok, facebook, youtube, pinterest.

FieldTypeDescription
platformrequiredstringPlatform identifier
cookiesrequiredobjectMap of cookie name → value
curl -X POST https://medialoader.69media.pro/api/v1/cookies/platform \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "tiktok",
    "cookies": {
      "sessionid": "abc123def456",
      "tt_webid_v2": "7123456789012345678"
    }
  }'
POST /api/v1/cookies/import-from-browser Import Instagram cookies from browser

Attempts to locate an installed browser (Chrome, Firefox, Edge) with an active Instagram session and exports its cookies into the server cookie store. No request body needed.

curl -X POST https://medialoader.69media.pro/api/v1/cookies/import-from-browser \
  -H "X-API-Key: YOUR_API_KEY"

Session Endpoints

Multi-account Instagram session management backed by Netscape cookie files.

GET /api/v1/sessions List Instagram sessions

Returns all configured Instagram cookie sessions and their status (availability, fail count, blocked time).

curl https://medialoader.69media.pro/api/v1/sessions \
  -H "X-API-Key: YOUR_API_KEY"
POST /api/v1/sessions/reload Reload sessions from disk

Reloads all Instagram sessions from cookie files on disk. Useful after manually adding new session files.

curl -X POST https://medialoader.69media.pro/api/v1/sessions/reload \
  -H "X-API-Key: YOUR_API_KEY"
POST /api/v1/sessions/add Register a session file

Adds a named session from cookies/sessions/{name}.txt into the in-memory Instagram session pool.

Query paramTypeDescription
namerequiredstringSession name (a-z, A-Z, 0-9, _, -; max 64 chars). Must match filename in cookies/sessions/
curl -X POST "https://medialoader.69media.pro/api/v1/sessions/add?name=account2" \
  -H "X-API-Key: YOUR_API_KEY"

Auth (Browser Automation) Endpoints

Interactive Playwright-backed browser sessions for establishing authenticated platform sessions. Flow: start → interact via action → check statusfinish (saves cookies).

POST /api/v1/auth/start Open browser login session

Launches a Playwright browser on the login page for the selected platform. Returns a session_id and a base64-encoded screenshot.

FieldTypeDescription
platformrequiredstringinstagram, facebook, twitter, tiktok, youtube, pinterest
curl -X POST https://medialoader.69media.pro/api/v1/auth/start \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"platform": "instagram"}'
GET /api/v1/auth/screenshot/{session_id} Capture browser screenshot

Returns the latest base64-encoded PNG screenshot and detected authentication cookie presence for the active session.

curl https://medialoader.69media.pro/api/v1/auth/screenshot/SESSION_ID \
  -H "X-API-Key: YOUR_API_KEY"
POST /api/v1/auth/action Perform a browser action

Executes a browser action inside the active Playwright session and returns the updated state with a new screenshot.

FieldTypeDescription
session_idrequiredstringAuth-session identifier
actionrequiredstringclick, type, press, goto, scroll, wait, clear_and_type, fill
selectoroptionalstringCSS selector for click, type, fill
textoptionalstringText for type / fill
keyoptionalstringKey for press (default: Enter)
urloptionalstringURL for goto (http/https only)
directionoptionalstringup | down for scroll
msoptionalintegerMilliseconds for wait (100–5000)
curl -X POST https://medialoader.69media.pro/api/v1/auth/action \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "session_id": "SESSION_ID",
    "action": "fill",
    "selector": "input[name=username]",
    "text": "myaccount"
  }'
GET /api/v1/auth/status/{session_id} Check authentication state

Inspects the current browser session and reports whether the required cookies for the selected platform are present. Returns authenticated: true/false and per-cookie presence flags.

curl https://medialoader.69media.pro/api/v1/auth/status/SESSION_ID \
  -H "X-API-Key: YOUR_API_KEY"
POST /api/v1/auth/finish/{session_id} Save cookies and close session

Extracts cookies from the browser, saves them to the platform cookie store, and closes the Playwright session. Returns saved: true/false and the file path.

curl -X POST https://medialoader.69media.pro/api/v1/auth/finish/SESSION_ID \
  -H "X-API-Key: YOUR_API_KEY"
POST /api/v1/auth/close/{session_id} Close session without saving

Stops the Playwright session and discards any unsaved browser state.

curl -X POST https://medialoader.69media.pro/api/v1/auth/close/SESSION_ID \
  -H "X-API-Key: YOUR_API_KEY"
GET /api/v1/auth/sessions List active auth sessions

Returns all currently active interactive authorization sessions with their platform, age, and current URL.

curl https://medialoader.69media.pro/api/v1/auth/sessions \
  -H "X-API-Key: YOUR_API_KEY"

Admin Endpoints

Admin endpoints require authentication via a session token. Obtain it from POST /api/v1/admin/login and pass it in X-Admin-Token header on all subsequent admin calls.

API key management requires the superadmin role. User management requires admin or superadmin.

POST /api/v1/admin/login Get admin session token
FieldTypeDescription
emailrequiredstringAdmin account email
passwordrequiredstringAdmin password

Returns: {"token": "...", "user": {"id": 1, "email": "...", "role": "superadmin"}}

curl -X POST https://medialoader.69media.pro/api/v1/admin/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@example.com","password":"secret"}'
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": 1,
    "email": "admin@example.com",
    "role": "superadmin"
  }
}
POST /api/v1/admin/logout Invalidate admin session

Deletes the current admin session token. Pass X-Admin-Token header. Returns {"status": "ok"}.

curl -X POST https://medialoader.69media.pro/api/v1/admin/logout \
  -H "X-Admin-Token: ADMIN_TOKEN"
GET /api/v1/admin/me Get current admin identity

Returns the user bound to the supplied X-Admin-Token session. Response: {"user": {"id": 1, "email": "...", "role": "..."}}.

curl https://medialoader.69media.pro/api/v1/admin/me \
  -H "X-Admin-Token: ADMIN_TOKEN"
GET /api/v1/admin/users List managed users

Returns all users. Requires admin or superadmin role. Response: {"users": [...]}.

curl https://medialoader.69media.pro/api/v1/admin/users \
  -H "X-Admin-Token: ADMIN_TOKEN"
POST /api/v1/admin/users Create a managed user

Creates a new user in the admin database. Requires superadmin role.

FieldTypeDescription
emailrequiredstringNew user email
passwordrequiredstringPassword (min 6 characters)
roleoptionalstringuser (default), admin, superadmin
curl -X POST https://medialoader.69media.pro/api/v1/admin/users \
  -H "X-Admin-Token: ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email":"dev@example.com","password":"securepass","role":"admin"}'
{
  "user": {
    "id": 42,
    "email": "dev@example.com",
    "role": "admin"
  }
}
GET /api/v1/admin/settings/api-key Get current API key settings

Returns whether API key authentication is required and the current active key. Superadmins see the full key; admins see a masked version.

curl https://medialoader.69media.pro/api/v1/admin/settings/api-key \
  -H "X-Admin-Token: ADMIN_TOKEN"
{
  "api_key_required": true,
  "api_key": "YOUR_API_KEY",
  "api_key_source": "database"
}
PUT /api/v1/admin/settings/api-key Enable / disable API key requirement

Toggle whether clients must supply an API key. When enabling, a key is auto-generated if none exists. Requires superadmin role.

FieldTypeDescription
requiredrequiredbooleantrue to require API key, false to allow public access
curl -X PUT https://medialoader.69media.pro/api/v1/admin/settings/api-key \
  -H "X-Admin-Token: ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"required": true}'
curl -X PUT https://medialoader.69media.pro/api/v1/admin/settings/api-key \
  -H "X-Admin-Token: ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"required": false}'
POST /api/v1/admin/settings/api-key/regenerate Generate a new API key

Generates a new random API key and replaces the current one. All existing clients must update their key. Requires superadmin role.

⚠️
The new key is shown only once. Copy it before closing the response.
curl -X POST https://medialoader.69media.pro/api/v1/admin/settings/api-key/regenerate \
  -H "X-Admin-Token: ADMIN_TOKEN"
{
  "api_key": "YOUR_NEW_API_KEY",
  "message": "API key regenerated. Update key in all clients."
}

Personal API Keys

Each admin user can generate their own API keys (prefix mdl_). These keys are accepted in the X-API-Key header for all /api/* endpoints. Superadmins can additionally manage keys for any user.

GET /api/v1/admin/user/api-keys List my personal API keys

Returns all active API keys for the currently authenticated user. Requires X-Admin-Token.

curl https://medialoader.69media.pro/api/v1/admin/user/api-keys \
  -H "X-Admin-Token: ADMIN_TOKEN"
{
  "keys": [
    {
      "id": 1,
      "key_prefix": "mdl_tMWmNiaF",
      "label": "production",
      "created_at": "2026-05-13T10:00:00+00:00",
      "last_used_at": "2026-05-13T11:30:00+00:00"
    }
  ]
}
POST /api/v1/admin/user/api-keys Create a personal API key

Generates a new API key for the current user. The full key is returned once only — save it immediately. Max 10 active keys per user.

curl -X POST https://medialoader.69media.pro/api/v1/admin/user/api-keys \
  -H "X-Admin-Token: ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"label": "my-integration"}'
{
  "key": "mdl_tMWmNiaFKyJbo5kmXr...",
  "record": {
    "id": 1,
    "key_prefix": "mdl_tMWmNiaF",
    "label": "my-integration",
    "created_at": "2026-05-13T10:00:00+00:00",
    "last_used_at": null
  }
}

Use the returned key in API calls:

curl https://medialoader.69media.pro/api/v1/files \
  -H "X-API-Key: mdl_tMWmNiaFKyJbo5kmXr..."
DELETE /api/v1/admin/user/api-keys/{key_id} Revoke a personal API key

Permanently deactivates the specified key. Only the owning user can revoke their own keys.

curl -X DELETE https://medialoader.69media.pro/api/v1/admin/user/api-keys/1 \
  -H "X-Admin-Token: ADMIN_TOKEN"

Superadmin: Manage all keys

Superadmins can view all keys system-wide, create keys for any user, and revoke any key.

GET /api/v1/admin/all-api-keys List ALL API keys (superadmin)

Returns every active personal API key across all users. Requires superadmin role.

curl https://medialoader.69media.pro/api/v1/admin/all-api-keys \
  -H "X-Admin-Token: SUPERADMIN_TOKEN"
POST /api/v1/admin/all-api-keys Create key for any user (superadmin)

Generates a new API key for the specified user. Requires superadmin role. Full key shown once only.

curl -X POST https://medialoader.69media.pro/api/v1/admin/all-api-keys \
  -H "X-Admin-Token: SUPERADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"user_id": 2, "label": "client-integration"}'
DELETE /api/v1/admin/all-api-keys/{key_id} Revoke any key (superadmin)

Permanently deactivates any API key regardless of owner. Requires superadmin role.

curl -X DELETE https://medialoader.69media.pro/api/v1/admin/all-api-keys/5 \
  -H "X-Admin-Token: SUPERADMIN_TOKEN"

Integration Guides

Python — Full Integration Example

import time, requests

class MediaDownloaderClient:
    def __init__(self, base_url: str, api_key: str = ""):
        self.base = base_url.rstrip("/") + "/api/v1"
        self.headers = {"Content-Type": "application/json"}
        if api_key:
            self.headers["X-API-Key"] = api_key

    def download(self, url: str, quality: str = "max", poll_interval: float = 3) -> dict:
        r = requests.post(f"{self.base}/download",
                          json={"url": url, "quality": quality},
                          headers=self.headers)
        r.raise_for_status()
        task_id = r.json()["id"]
        return self._poll(task_id, poll_interval)

    def batch_download(self, urls: list, quality: str = "max", poll_interval: float = 3) -> list:
        r = requests.post(f"{self.base}/batch-download",
                          json={"urls": urls, "quality": quality},
                          headers=self.headers)
        r.raise_for_status()
        ids = [t["id"] for t in r.json()["tasks"]]
        return [self._poll(tid, poll_interval) for tid in ids]

    def get_file(self, path: str) -> bytes:
        # path is a relative string like "tiktok/user/video.mp4"
        r = requests.get(f"{self.base}/files/{path}", headers=self.headers, allow_redirects=True)
        r.raise_for_status()
        return r.content

    def _poll(self, task_id: str, interval: float) -> dict:
        while True:
            task = requests.get(f"{self.base}/tasks/{task_id}",
                                headers=self.headers).json()
            if task["status"] in ("completed", "error"):
                return task
            time.sleep(interval)


# Usage
client = MediaDownloaderClient(
    base_url="https://medialoader.69media.pro",
    api_key="YOUR_API_KEY"
)
task = client.download("https://www.tiktok.com/@user/video/7123456789")
if task["status"] == "completed":
    # task["files"] is a list of relative path strings
    for f in task["files"]:
        data = client.get_file(f)
        filename = f.split("/")[-1]
        open(filename, "wb").write(data)
        print(f"Saved: {filename}")

JavaScript / Node.js — Full Integration Example

class MediaDownloaderClient {
    constructor(baseUrl, apiKey = "") {
        this.base = baseUrl.replace(/\/$/, "") + "/api/v1";
        this.headers = { "Content-Type": "application/json",
                         ...(apiKey && { "X-API-Key": apiKey }) };
    }

    async download(url, quality = "max") {
        const { id } = await this._post("/download", { url, quality });
        return await this._poll(id);
    }

    async batchDownload(urls, quality = "max") {
        const { tasks } = await this._post("/batch-download", { urls, quality });
        return Promise.all(tasks.map(t => this._poll(t.id)));
    }

    // files in task are relative path strings, encode them for URL use
    getFileUrl(filePath) {
        return `${this.base}/files/${encodeURIComponent(filePath)}`;
    }

    async _poll(taskId, interval = 3000) {
        let task;
        do {
            await new Promise(r => setTimeout(r, interval));
            task = await fetch(`${this.base}/tasks/${taskId}`, { headers: this.headers }).then(r => r.json());
        } while (!["completed", "error"].includes(task.status));
        return task;
    }

    async _post(path, body) {
        const res = await fetch(this.base + path, { method: "POST", headers: this.headers, body: JSON.stringify(body) });
        if (!res.ok) throw new Error(await res.text());
        return res.json();
    }
}

// Usage
const client = new MediaDownloaderClient("https://medialoader.69media.pro", "YOUR_API_KEY");
const task = await client.download("https://www.instagram.com/p/ABC123/");
// task.files is an array of relative path strings
console.log(task.files?.map(f => client.getFileUrl(f)));

API Key Setup Workflow

# 1. Login as superadmin
TOKEN=$(curl -s -X POST https://medialoader.69media.pro/api/v1/admin/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@example.com","password":"secret"}' | jq -r '.token')

# 2. Enable API key requirement (auto-generates a key)
curl -X PUT https://medialoader.69media.pro/api/v1/admin/settings/api-key \
  -H "X-Admin-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"required": true}'

# 3. View the current key
curl https://medialoader.69media.pro/api/v1/admin/settings/api-key \
  -H "X-Admin-Token: $TOKEN"

# 4. Rotate the key (all clients must update)
curl -X POST https://medialoader.69media.pro/api/v1/admin/settings/api-key/regenerate \
  -H "X-Admin-Token: $TOKEN"

# 5. Disable key requirement (public access)
curl -X PUT https://medialoader.69media.pro/api/v1/admin/settings/api-key \
  -H "X-Admin-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"required": false}'
API key management is also available in the web UI at /admin under API-ключ while logged in as superadmin.

Interactive docs: Swagger UI →  |  OpenAPI spec: openapi.json →