Theme

Media API

The media library: upload images, PDFs and zips, keep alt text current, and delete what nothing should reference any more.

All endpoints need a bearer token (see Overview & auth).

Endpoints

Method & pathWhat it does
GET /api/v1/mediaThe library, newest first. Filters: q (file name and alt text), kind (image, pdf or zip), limit (up to 200; default 200), offset (skip that many, for paging through a library bigger than one response).
POST /api/v1/mediaUpload a file as multipart form data: the file under file, optional alt_text alongside. Refused with 422 when no storage backend is configured, the type isn't an image, PDF or zip, or the file is over its ceiling (10 MB for images, 25 MB for files).
GET /api/v1/media/:idOne item: hosted URL, content type, kind, size, alt text.
PATCH /api/v1/media/:idUpdate alt_text — what an image carries when inserted into email content.
DELETE /api/v1/media/:idDeletes the stored file and the row. Already-sent emails referencing the URL keep the reference and lose the file behind it — delete only what nothing should point at any more.
GET /api/v1/media/storageWhere media serves from: backend, uploads_enabled, public_base_url and configured. Credentials never appear here — storage keys are entered in Settings and stay in the instance.
POST /api/v1/media/storage/checkRound-trips a probe file to prove media actually loads: uploads it, fetches it back over the public host, deletes it. 200 with ok: true on success, 422 with a message naming the step that broke otherwise.

Checking media hosting

A media URL that 404s is frozen into every email referencing it, and already-sent mail can't be repointed — so it's worth proving the host serves before a send rather than after one.

curl -X POST https://your-instance.example.com/api/v1/media/storage/check \
  -H "Authorization: Bearer $MIMEO_API_TOKEN"
{
  "ok": true,
  "message": "files.yourdomain.com served a test file — media hosting is working.",
  "url": "https://files.yourdomain.com/mimeo-host-check/… .txt",
  "storage": {
    "backend": "r2",
    "uploads_enabled": true,
    "public_base_url": "https://files.yourdomain.com",
    "configured": true
  }
}

On failure the message distinguishes the causes that look alike from the outside: a host that doesn't resolve yet, a certificate still issuing, public access switched off, or a domain connected to the wrong bucket.

Uploading

curl -X POST https://your-instance.example.com/api/v1/media \
  -H "Authorization: Bearer $MIMEO_TOKEN" \
  -F "[email protected]" \
  -F "alt_text=The dashboard, mid-campaign"

The response is the stored item:

{
  "media": {
    "id": 12,
    "filename": "hero.png",
    "url": "https://media.example.com/3f9a.../hero.png",
    "content_type": "image/png",
    "kind": "image",
    "byte_size": 48213,
    "alt_text": "The dashboard, mid-campaign",
    "created_at": "2026-08-02T12:00:00Z"
  }
}

Referencing media in email content

Email bodies are markdown; media inserts by URL. An image goes in as an inline image carrying its alt text, and a PDF or zip as a link:

![The dashboard, mid-campaign](https://media.example.com/3f9a.../hero.png)

[press-kit.zip](https://media.example.com/81c2.../press-kit.zip)

Errors

StatusWhen
422No storage configured, no file part, an unsupported type, an over-ceiling file, or a failed alt-text save. The error names the fix.
404No media item with that id.