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.

text
https://cdn.madebydanny.uk
1

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.

2

Upload a file

Send the raw file body as a POST with the correct Content-Type. Pass your key in the Authorization header.

bash — curl
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
3

Get your public URL

A successful upload returns a JSON object. The url field is your permanent public link — ready to embed anywhere.

json — response
{
  "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
}
4

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.

html
<img src="https://cdn.madebydanny.uk/user-content/2026-04-29/abc123.png"
     alt="My photo">

javascript — fetch
// 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.

http header
Authorization: Bearer mbd_your_key_here
Keep your key secret. Treat it like a password — don't commit it to public repos or include it in client-side code. Store it in environment variables or a secrets manager.
Keys are prefixed with mbd_ followed by 64 hex characters (32 random bytes). Example: mbd_a3f1b2c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2
POST /v1/upload API key
Upload a file and receive a permanent public URL.
Headers
NameTypeRequiredDescription
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.
Body
Raw file bytes. Send the binary file body directly — no multipart encoding, no JSON wrapper.
Response — 200 OK
json
{
  "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
}
Rate-limit response headers
HeaderDescription
X-RateLimit-Limit-FilesMax files per day for this key
X-RateLimit-Remaining-FilesFiles remaining today
X-RateLimit-Limit-BytesMax bytes per day for this key
X-RateLimit-Remaining-BytesBytes remaining today
X-RateLimit-ResetUnix timestamp when quota resets (midnight UTC)
GET /v1/files API key
List files uploaded with this API key, newest first.
Query Parameters
NameTypeRequiredDescription
limit integer optional Number of files to return (default 50, max 100).
cursor string optional Pagination cursor from previous response.
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
Rate limits reset at midnight UTC. If you need higher limits for a specific project, please reach out via Bluesky. You can check your remaining limits at any time by viewing the X-RateLimit-* response headers returned after a successful upload.
200 OK
Everything worked as expected.
400 Bad Request
Missing file, unsupported content type, or the payload is too large. Check the response body for details.
401 Unauthorized
Missing, malformed, or invalid API key. Ensure you are passing the key exactly as Bearer mbd_....
429 Too Many Requests
You have hit your daily quota for either files or bytes. Check the X-RateLimit headers to see when your limit resets.
500 Internal Server Error
Something went wrong on our end (e.g., an issue connecting to the R2 bucket or D1 database). Try again later.