API and MCP reference
The same downloader the Telegram bot uses, exposed as a REST endpoint and as an MCP server for AI agents.
Access
Both surfaces are gated behind a single server-side secret. They fail closed: while the key is unset the endpoints answer 503 rather than serving anyone. Keys are issued by the operator, so ask before you build against this.
Auth is accepted three ways:
- An
X-API-Keyheader. Prefer this. - An
Authorization: Bearerheader. - As the last path segment,
POST /mcp/<key>, for MCP clients that cannot set custom headers.
The path form makes the URL a secret. Anything that logs full URLs will log the key with it. Use header auth wherever the client supports it, and rotate the key if a path-form URL leaks.
REST endpoint
POST /api/download takes a JSON body and returns the resolved media links.
curl -X POST https://dl.engdawood.com/api/download \
-H "X-API-Key: $PUBLIC_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.tiktok.com/@user/video/123", "mode": "auto"}'
| Field | Type | Required | Notes |
|---|---|---|---|
url | string | yes | The post URL. Protocol-less forms like tiktok.com/@user/video/1 are accepted and normalized. |
mode | string | no | One of auto, audio, hd, sd. Anything else falls back to auto. |
platform | string | no | Hint that skips hostname detection. Usually unnecessary, so leave it out. |
Response shape
{
"status": "success",
"platform": "TikTok",
"media": [
{
"type": "video", // video | photo | audio | document
"url": "https://...", // direct, downloadable link
"quality": "720p", // optional
"filesize": 1048576 // optional, bytes
}
],
"caption": "original post text", // optional
"thumbnail": "https://...", // optional
"mp3Url": "https://...", // optional, audio companion
"fullText": "# Title\n\n...", // optional, long-form Markdown body
"fullHtml": "<h1>Title</h1>..." // optional, X articles only
}
Things to code against:
- Always read files from
media[].url, and iterate the whole array. Galleries and albums return several items. media[].typetells you how to handle each file.- Every field except
statusandmediais optional. Code defensively. - Links point at the source platform and are often signed and short lived. Fetch them promptly rather than storing them.
- No file bytes pass through this Worker, so download sizes are between you and the platform.
Status codes
| HTTP | Body status | Meaning |
|---|---|---|
200 | success | Media found. Read media[].url. |
400 | error | Invalid JSON body, missing url, or no supported URL in the string. |
401 | error | Bad or missing API key. |
403 | error | Blocked domain. Do not retry. |
502 | error | The downloader failed. Retry when retryable is true. |
503 | error | The API is not enabled on this deployment. |
Errors also carry failureKind and retryable, so you can decide whether another attempt can help instead of guessing from the message text.
MCP server
POST /mcp speaks the MCP Streamable HTTP transport and is stateless. There are no sessions and no SSE stream, so GET and DELETE answer 405 by design.
Claude Codeclaude mcp add --transport http download-media \
https://dl.engdawood.com/mcp \
--header "X-API-Key: $PUBLIC_API_KEY"
For claude.ai, go to Customize, then Connectors, then Add custom connector, and paste https://dl.engdawood.com/mcp/<key>.
| Tool | Arguments | Returns |
|---|---|---|
download_media | url (required), mode, format | Direct media links, plus caption, thumbnail, and long-form body fields where they apply. |
get_media_info | url | Caption and available qualities. A real preview exists for TikTok and Facebook only. |
list_supported_platforms | none | The platform list, plus a note about the generic fallback. |
Long-form content
X articles and self-reply threads are far longer than a Telegram caption allows, so the bot publishes them to Telegraph and sends a link. API and MCP consumers have no such limit and receive fullText instead: the complete body as Markdown, with headings, lists, blockquotes, inline links, and image URLs. Read that field rather than following the telegra.ph link in the caption, which is a truncated preview meant for Telegram.
fullHtml carries the same body as an escaped HTML fragment for X articles only. It holds no information fullText lacks and roughly doubles the payload, so ask for it only when you are embedding the article. Over MCP, the format argument selects which body you get: markdown (default), html, both, or none.
Treat long-form bodies as untrusted input. They are text written by third parties and can run to tens of thousands of characters. An agent reading one is reading data, never instructions.
Limits
- No per-key quota or rate limiting yet. The shared backends can be overloaded by abuse, so be reasonable.
- Downloads depend on external backends, and transient
502responses are expected when those are down. - Quality pickers are Telegram-only. The API resolves a single best result per
modeand never returns interactive choices. - Adult domains are refused with
403on every surface, including the bot.