madebydanny.uk / cdn
-Developer API
-A REST API for programmatic access to MBD CDN — upload files, manage your library, and check usage from your own apps and scripts.
-base url
-https://cdn.madebydanny.uk-
make your first request in 60 seconds
-Get an API key
-Reach out via Bluesky DMs to request a key, with your APP_NAME and the KEY_OWNER. Keys look like mbd_ followed by 64 hex characters.
Upload a file
-Send the raw file body as a POST with the correct Content-Type. Pass your key in the Authorization header.
curl -X POST https://cdn.madebydanny.uk/v1/upload \ - -H "Authorization: Bearer mbd_your_key_here" \ - -H "Content-Type: image/png" \ - --data-binary @photo.png-
Get your public URL
-A successful upload returns a JSON object. The url field is your permanent public link — ready to embed anywhere.
{
- "success": true,
- "url": "https://cdn.madebydanny.uk/user-content/2026-04-29/abc123.png",
- "id": "abc12345-1234-1234-1234-abc123456789",
- "contentType": "image/png",
- "fileType": "image",
- "size": 204800
-}
- Use the URL anywhere
-Files are served over Cloudflare's global edge with Cache-Control: immutable. Embed in HTML, markdown, social posts, or wherever you like.
<img src="https://cdn.madebydanny.uk/user-content/2026-04-29/abc123.png" - alt="My photo">-
- -
javascript example
-// Upload a File object (e.g. from an <input type="file">) -async function uploadToCDN(file, apiKey) { - const res = await fetch('https://cdn.madebydanny.uk/v1/upload', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${apiKey}`, - 'Content-Type': file.type, - }, - body: file, - }); - - const data = await res.json(); - if (!data.success) throw new Error(data.error); - return data.url; // permanent public URL -} - -// Usage -const url = await uploadToCDN(fileInputEl.files[0], 'mbd_your_key_here'); -console.log(url); // https://cdn.madebydanny.uk/user-content/...-
All /v1/ routes require an API key sent as a Bearer token in the Authorization header. Anonymous uploads via POST / continue to work without any key.
sending your key
-Authorization: Bearer mbd_your_key_here-
key format
-mbd_ followed by 64 hex characters (32 random bytes). Example: mbd_a3f1b2c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2
- file operations
- -| Name | Type | Required | Description |
|---|---|---|---|
| Authorization | -string | -required | -Bearer token — Bearer mbd_… |
-
| Content-Type | -string | -required | -MIME type of the file, e.g. image/png |
-
| Content-Length | -integer | -optional | -File size in bytes. Recommended — allows accurate quota pre-checks. | -
{
- "success": true,
- "url": "https://cdn.madebydanny.uk/user-content/2026-04-29/<uuid>.png",
- "id": "<uuid>",
- "path": "user-content/2026-04-29/<uuid>.png",
- "contentType": "image/png",
- "fileType": "image",
- "size": 204800
-}
- | Header | Description |
|---|---|
| X-RateLimit-Limit-Files | Max files per day for this key |
| X-RateLimit-Remaining-Files | Files remaining today |
| X-RateLimit-Limit-Bytes | Max bytes per day for this key |
| X-RateLimit-Remaining-Bytes | Bytes remaining today |
| X-RateLimit-Reset | Unix timestamp when quota resets (midnight UTC) |
| Name | Type | Required | Description |
|---|---|---|---|
| limit | -integer | -optional | -Number of files to return (default 50, max 100). | -
| cursor | -string | -optional | -Pagination cursor from previous response. | -
tier comparison
-| Limit | -Anonymous (No Key) | -API Key | -
|---|---|---|
| Max file size | -5 MB | -25 MB | -
| Files per day | -20 | -1,000 | -
| Bandwidth per day | -100 MB | -5 GB | -
X-RateLimit-* response headers returned after a successful upload.
- http status codes
-Everything worked as expected. -
Missing file, unsupported content type, or the payload is too large. Check the response body for details. -
Missing, malformed, or invalid API key. Ensure you are passing the key exactly as
Bearer mbd_....
- You have hit your daily quota for either files or bytes. Check the
X-RateLimit headers to see when your limit resets.
- Something went wrong on our end (e.g., an issue connecting to the R2 bucket or D1 database). Try again later. -