Developers

Media

Upload images or videos that posts will reference. Small files can go directly with multipart; for large files, request a presigned URL and upload straight to storage. You can also hand us a public HTTPS URL and we'll fetch it, which is useful for agents that have already generated or stored media elsewhere.

Upload via multipart

POST/api/v1/media
bash
curl -X POST https://postme.live/api/v1/media \
  -H "Authorization: Bearer pml_live_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "[email protected]"

Upload via URL

POST/api/v1/media
bash
curl -X POST https://postme.live/api/v1/media \
  -H "Authorization: Bearer pml_live_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com/hero.jpg" }'

URLs must be https://, resolve to a public IP (no private, loopback, link-local, or ULA addresses), and download in under 5 minutes for files no larger than 1 GB.

Upload large files with a presigned URL

Multipart streams the bytes through the API and is best for small files. For large media, ask for a presigned PUT URL, send the bytes straight to storage, then register the object. Three steps:

POST/api/v1/media/upload-url
bash
# 1. Request a presigned PUT URL
curl -X POST https://postme.live/api/v1/media/upload-url \
  -H "Authorization: Bearer pml_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "filename": "clip.mp4", "content_type": "video/mp4", "size": 73400320 }'
# → { "upload_url": "https://…", "key": "…", "expires_in": 600 }

# 2. PUT the bytes straight to storage (same Content-Type)
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: video/mp4" \
  --data-binary @clip.mp4

# 3. Register the uploaded object
curl -X POST https://postme.live/api/v1/media \
  -H "Authorization: Bearer pml_live_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "key": "<key from step 1>" }'

The presigned URL is valid for 10 minutes and accepts exactly the content_type you declared. Step 3 returns the same 201 Created body as the other methods and is where plan caps are enforced against the real object size. Requesting the URL is not a billable write, so it needs no Idempotency-Key; step 3 does.

Agents on the MCP server run this exact flow with the postmelive_create_media_upload and postmelive_upload_media tools — the way to attach a local file that isn't already at a public URL.

Response: 201 Created

json
{
  "id": "9f3a…",
  "kind": "image",
  "bytes": 184320,
  "mime": "image/jpeg",
  "filename": "hero.jpg",
  "url": "https://media.postme.live/…",
  "thumbnail_status": "pending"
}

Use the returned id in media[].id on a subsequent POST /posts. Thumbnail generation, ffprobe metadata extraction, and YouTube poster- frame candidates run asynchronously on the worker; the post endpoint doesn't wait for them.

List media

GET/api/v1/media

Lists the workspace's media library, newest first, cursor-paginated. Filter by ?kind=image or ?kind=video (any other value is a 400). Scope media:read.

bash
curl "https://postme.live/api/v1/media?kind=image&limit=50" \
  -H "Authorization: Bearer pml_live_..."

Response: 200 OK

json
{
  "data": [
    {
      "id": "9f3a4b2c-6d7e-4a1b-8c9d-0e1f2a3b4c5d",
      "kind": "image",
      "mime": "image/jpeg",
      "bytes": 184320,
      "width": 1080,
      "height": 1350,
      "duration_ms": null,
      "filename": "hero.jpg",
      "url": "https://media.postme.live/…",
      "thumbnail_status": "ready",
      "thumbnails": {
        "thumb": { "url": "https://media.postme.live/…", "width": 320, "height": 400 },
        "preview": { "url": "https://media.postme.live/…", "width": 640, "height": 800 },
        "display": { "url": "https://media.postme.live/…", "width": 1080, "height": 1350 }
      },
      "created_at": "2026-06-27T14:02:11Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

The list returns the full media record, including width/ height, duration_ms (videos), the generated thumbnails set, and created_at. Any of those is null until the worker has processed the asset (watch thumbnail_status).

Get a media item

GET/api/v1/media/{id}

A single media item, shaped exactly like one element of the list above (not wrapped in data). Media in another workspace reads as 404. Scope media:read.

bash
curl https://postme.live/api/v1/media/9f3a4b2c-6d7e-4a1b-8c9d-0e1f2a3b4c5d \
  -H "Authorization: Bearer pml_live_..."

Limits

LimitValue
Maximum file size1 GB (bounded by your plan's per-file cap)
Multipart request sizeUp to 16 MB; use a presigned URL or url fetch for larger files
Presigned URL lifetime10 minutes
URL fetch timeout5 minutes
Allowed URL schemeshttps://
Allowed remote networksPublic IPs only (no private/loopback/link-local/ULA)
Media: Public API