YTDL.my

YTDL.my public HTTP API

Base URL: your deployment’s public origin (same as NEXT_PUBLIC_APP_URL; e.g. https://ytdl.my).

Version: see the running app’s OpenAPI at /docs if enabled, or public/openapi.yaml in the repo.

This document describes this gateway (account, billing, quotas, download proxy). It does not document private worker hostnames or keys.


Authentication (user API)

MethodHeader
API keyX-API-Key: <key>
BearerAuthorization: Bearer <key>

Issue keys from the authenticated dashboard. Endpoints that require a key return 401 when missing or invalid.

GET /api/healthz, GET /healthz, and GET /api/v1/d (signed downloads) do not use API keys.


Adding cookie sets to the pool (operators)

Downloads may use a shared server-side pool of Netscape-format cookie exports. Operators append rows via HTTP; this is not the same auth as dashboard API keys (X-API-Key). Ingest is gated by a separate secret configured on the server.

POST /api/internal/youtube-cookies

ItemValue
URL{BASE_URL}/api/internal/youtube-cookies
HeaderAuthorization: Bearer <YT_COOKIE_INGEST_SECRET>
HeaderContent-Type: application/json
Body{ "cookies": "<full Netscape cookie file as one string>" }

The secret YT_COOKIE_INGEST_SECRET must be set in the gateway environment (not exposed to clients). If it is unset, this endpoint returns 503.

201{ "ok": true, "id": "<row id>" }
400 — body invalid or empty / too large
401 — Bearer missing or wrong
503 — ingest disabled (secret not configured)

Example: send a Netscape file with curl and jq

Use jq to read the file and build valid JSON (handles escaping and newlines). Replace the base URL and secret with your values:

export BASE_URL="http://localhost:3000"
export YT_COOKIE_INGEST_SECRET="your-ingest-secret-from-server-env"

jq -Rs '{cookies: .}' path/to/www.youtube.com_cookies.txt | \
  curl -sS -X POST "${BASE_URL}/api/internal/youtube-cookies" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer ${YT_COOKIE_INGEST_SECRET}" \
    -d @-
  • -Rs on jq reads raw input as a single string and wraps it in { "cookies": "..." }.
  • -d @- sends that JSON on stdin to curl.

One line (same idea):

jq -Rs '{cookies: .}' www.youtube.com_cookies.txt | curl -sS -X POST 'http://localhost:3000/api/internal/youtube-cookies' -H 'Content-Type: application/json' -H "Authorization: Bearer $YT_COOKIE_INGEST_SECRET" -d @-

You can also paste the file contents into a JSON body manually, but you must escape quotes and newlines; using jq avoids that.


Endpoints (summary)

MethodPathAuthRole
GET/api/healthznoHealth
POST/api/internal/youtube-cookiesBearer ingest secretAppend one Netscape cookie export to the pool
POST/api/v1/jobsyesCreate a download job
GET/api/v1/jobs/{job_id}yesPoll job status (mirrors upstream)
GET/api/v1/d?...no (signed)Stream finished file

POST /api/v1/jobs may block for a long time while the upstream worker runs (Route Handler timeout is capped; see deployment limits). Responses mirror the private worker (job_id, status, signed download_url rewritten to /api/v1/d on this host).


Signed downloads

Signed URLs use query parameters job_id, e (expiry unix time), s (hex HMAC). The gateway’s /api/v1/d handler proxies bytes from the worker without exposing the worker’s URL.