- -
-

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
AuthorizationstringrequiredBearer token — Bearer mbd_…
Content-TypestringrequiredMIME type of the file, e.g. image/png
Content-LengthintegeroptionalFile 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
limitintegeroptionalNumber of files to return (default 50, max 100).
cursorstringoptionalPagination cursor from previous response.
-
-
- -
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - -
LimitAnonymous (No Key)API Key
Max file size5 MB25 MB
Files per day201,000
Bandwidth per day100 MB5 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.
-
-
-
- -
-