Skip to content
Docs / Platform / Files

Files

Large-file sharing on the owner's NAS (up to 5 GB, capability links), and the media APIs for captions, video, channel, playlist and web pages.

NAS file sharing

Upload a file once, get a shareable download link. Files are stored on the owner's NAS; metadata in the server database. Auth: key, approved session or trusted local network (require_user_or_local). No credit cost.

Public uploads are capped at about 100 MB by the edge, so large uploads must come from the owner's own network. Downloads through the public link work at any size.

Upload

POST /api/nas/upload (multipart/form-data)

curl -F "file=@lesson.mp4" -F "uploader=Anna" \
  -H "x-api-key: $MAXIMIND_API_KEY" https://maximind.dev/api/nas/upload
{"ok": true, "token": "Nv7KF3AXi", "filename": "lesson.mp4", "size_bytes": 3221225472,
 "url": "https://maximind.dev/nas/Nv7KF3AXi/lesson.mp4"}
Name Type Required Description
file file Yes Hard cap 5 GB; over returns HTTP 413 File too large and the partial upload is deleted.
uploader string No Display name attributed to the upload. Default: the caller's email.

token is a random capability id; url is the shareable link. NAS not configured: HTTP 503. NAS write failure: HTTP 502.

Download

GET /nas/{token}/{filename}

No auth: anyone with the link can download. Streams with HTTP Range support (Accept-Ranges: bytes, 206 with Content-Range for partial requests), so video seeking and resumable downloads work. Content-Disposition: inline with the original filename; Content-Type is the stored MIME (default application/octet-stream). Unknown token: 404.

curl -r 0-1048575 https://maximind.dev/nas/Nv7KF3AXi/lesson.mp4 -o part.mp4

List

GET /api/nas/items

curl -s https://maximind.dev/api/nas/items -H "x-api-key: $MAXIMIND_API_KEY"
{"ok": true, "enabled": true, "items": [
  {"token": "Nv7KF3AXi", "filename": "lesson.mp4", "size_bytes": 3221225472, "mime_type": "video/mp4",
   "uploader_email": "Anna", "created_at": 1781268000.0, "url": "https://maximind.dev/nas/Nv7KF3AXi/lesson.mp4"}]}

enabled reflects whether NAS storage is configured; newest first.

Capacity

GET /api/nas/space

{"ok": true, "total": 8000000000000, "used": 5000000000000, "free": 3000000000000}

All values in bytes. NAS unavailable: {"ok": false} with an optional error.

Delete

DELETE /api/nas/{token}

An admin can delete anything; a non-admin can only delete files whose uploader_email equals their own email (else 403). Removes the record and the file, invalidating the link. Unknown token: 404.

curl -X DELETE https://maximind.dev/api/nas/Nv7KF3AXi -H "x-api-key: $MAXIMIND_API_KEY"
{"ok": true}

Media APIs

A Supadata-compatible drop-in for paid transcript APIs, backed by yt-dlp, local Whisper fallback and trafilatura. Auth: key or session (require_api_key); the key needs the media capability. No local-network bypass. Missing key: 401 {"detail":"Invalid or missing API key"}.

Transcript

GET /v1/transcript (also POST /v1/transcript with a JSON body, and alias GET /v1/youtube/transcript)

Platform captions first (1 credit); local Whisper only when needed (about 1 credit per 30 s).

curl "https://maximind.dev/v1/transcript?url=arj7oStGLkU&lang=en&mode=native" \
  -H "x-api-key: $MAXIMIND_API_KEY"
{"lang": "en", "availableLangs": ["aa", "ab", "af", "..."],
 "content": [{"text": "So in college,", "offset": 12645, "duration": 1370, "lang": "en"}],
 "source": "native"}
Name Type Required Description
url string Yes Full video link (YouTube, TikTok, Instagram, X, anything yt-dlp supports) or a bare 11-character YouTube id. Other input: 422.
lang string No Preferred caption language (en, vi). auto or empty auto-detects; falls back to the video language, then en, then the first available.
text boolean No false (default): content is an array of {text, offset, duration, lang} in milliseconds. true: one joined string.
mode string No auto (default), native (captions only; 404 if none), generate (force Whisper). Other: 422.

source is native or generated. For YouTube, availableLangs includes the auto-translate targets and can exceed 100 codes. YouTube's anti-bot gate is handled best-effort with a signed-in browser profile on the server; when it wins, the error says so and GET /health reports youtube_login.

Async media transcode

Submit POST /v1/media/transcode to convert a presigned source into presigned S3 destinations, then poll GET /v1/media/transcode/{job_id}. Use the same base URL and x-api-key: $MAXIMIND_API_KEY as /v1/transcript (including https://maximind.macsvff.uk where configured). The require_api_key dependency enforces the key's media capability; primary keys/admins and legacy unrestricted keys retain access. Restricted keys without media receive 403 "this API key is not allowed to use the media APIs".

{
  "kind": "video",
  "preset": "intro-720p",
  "source_url": "https://legobit-media.s3.ap-southeast-1.amazonaws.com/raw.mov?PRESIGNED_GET",
  "outputs": {
    "main": {"put_url": "https://legobit-media.s3.ap-southeast-1.amazonaws.com/intro.mp4?PRESIGNED_PUT", "content_type": "video/mp4"},
    "poster": {"put_url": "https://legobit-media.s3.ap-southeast-1.amazonaws.com/poster.jpg?PRESIGNED_PUT", "content_type": "image/jpeg"}
  },
  "client": "vietlingo",
  "ref": "vl-mtj-123"
}

All fields shown are required for video. Audio uses kind: "audio", preset: "speech-64k", main.content_type: "audio/mp4", and omits poster. Unsupported kinds, mismatched presets/content types or invalid URLs return 422. Keep source and destination signatures valid for at least 3 hours, including queue time. MaxiMind needs no AWS credentials.

202 response: {"job_id":"…","status":"queued"}. Repeating the same (client, ref) while queued, running or done returns 202 with the existing job_id and its current status. A failed job may be resubmitted; use refreshed URLs and preferably a new ref suffix.

Poll with the same auth:

{
  "job_id": "…", "ref": "vl-mtj-123", "status": "done", "error": null,
  "outputs": {
    "main": {"bytes": 1234567, "duration_s": 60.1, "width": 720, "height": 1280},
    "poster": {"bytes": 45678}
  },
  "queued_at": "2026-10-03T10:00:00+00:00",
  "started_at": "2026-10-03T10:00:01+00:00",
  "finished_at": "2026-10-03T10:00:20+00:00"
}

status is queued|running|done|failed; error is null or a short failure message. Pending/failed jobs have outputs: {}. Unset timestamps are null; timestamps are UTC ISO 8601. Audio main.width and main.height are 0; audio has no poster. Unknown/pruned jobs return 404.

  • intro-720p: MP4, fits 1280×720 landscape or 720×1280 portrait, honours rotation, never upscales, even dimensions and at most 30 fps. H.264 High, CRF 23, maxrate 4M/bufsize 8M, yuv420p; AAC 96 kbps/48 kHz when audio exists; faststart. JPEG poster at min(1 s, 10% of duration), width at most 1280, quality 3.
  • speech-64k: M4A (audio/mp4), AAC-LC mono, 64 kbps, 48 kHz, faststart.
  • Transfers: HTTPS/443 only, host ending .amazonaws.com or explicitly in ALLOWED_MEDIA_HOSTS (initially media.vietlingo.com and the configured Legobit CDN dv4fftrcq5i64.cloudfront.net); all DNS results must be public, including a fresh check when opening a socket. Private, loopback, link-local and Tailscale addresses are refused. Redirects are refused for both GET and PUT. PUT streams the file with the exact supplied Content-Type. Transfer failures, including PUT failures, mark the job failed; signed URLs are never logged.
  • Limits: 250 MiB (250 × 1024² bytes), checked against Content-Length and during streaming; maximum duration 300 s, checked by ffprobe. Oversize/overlong input becomes failed with a clear error. Execution timeout: 20 minutes, including transfers; subprocess groups are killed on timeout/cancellation.
  • Scheduling/storage: its own single low-priority FIFO worker, separate from Whisper's queue. ffmpeg/ffprobe run behind taskpolicy -b and nice -n 19. SQLite ~/.maximind/media_jobs.db uses WAL and retains completed jobs at least 7 days; older completed records are pruned. Queued jobs resume after restart; interrupted running jobs fail with "interrupted, please resubmit". Each job's temp directory under ~/.maximind/tmp/transcode/ is deleted in finally.

Video info

GET /v1/video (alias GET /v1/youtube/video), 1 credit. Parameter url as above.

Returns id, title, description, url, platform, channel{name,id,url}, durationSeconds, viewCount, likeCount, commentCount, uploadDate (YYYYMMDD), thumbnail, tags, availableTranscriptLangs. Missing fields are null.

curl "https://maximind.dev/v1/video?url=arj7oStGLkU" -H "x-api-key: $MAXIMIND_API_KEY"

Channel and playlist

GET /v1/channel and GET /v1/playlist (aliases /v1/youtube/channel/videos, /v1/youtube/playlist/videos), 1 credit each.

Name Type Required Description
url string Yes Channel: full URL, /channel/ID, /c/name, /user/name or bare @handle. Playlist: a playlist?list=… URL.
limit integer No Default 50, clamped to 1 to 200.
curl "https://maximind.dev/v1/channel?url=@TED&limit=3" -H "x-api-key: $MAXIMIND_API_KEY"

Returns id, title, url, videoCount and videos[] of {id, title, url, durationSeconds, viewCount}; viewCount is often null in flat mode. Errors: 422 empty url; 400 not a channel or playlist; 504 if listing exceeds the 120 s yt-dlp timeout.

Web scrape

GET /v1/web/scrape, 1 credit.

Name Type Required Description
url string Yes Full http(s) URL. Other: 422.
markdown boolean No Default true: Markdown with links and tables. false: plain text.
timeout number No Seconds, default 20, clamped 1 to 60.
curl "https://maximind.dev/v1/web/scrape?url=https://example.com" -H "x-api-key: $MAXIMIND_API_KEY"
{"url": "https://example.com", "title": "Example Domain", "content": "Example Domain\nThis domain is for use in documentation examples…", "wordCount": 19}

Errors: upstream HTTP error returns that status; 502 fetch failure; 415 when the content type is not html, xml or text.

Errors

Status Meaning
400 URL unreadable; not a channel or playlist.
401 Missing or invalid key.
403 Deleting another user's NAS file as a non-admin.
404 No transcript in native mode; unknown NAS token.
413 NAS upload over 5 GB.
415 Scrape target is not html, xml or text.
422 Invalid url, mode or non-http(s) scrape URL.
502 / 503 NAS write failure / NAS not configured; scrape fetch failure.
504 Channel or playlist listing exceeded 120 s.

Limits and costs

  • NAS: 5 GB per file; about 100 MB per upload through the public edge; no credits.
  • Media: 1 credit per call; Whisper-generated transcripts about 1 credit per 30 s of audio. See Limits.