Media upload service for Pollinations
Upload files and get back a URL to use with Pollinations models.
- Upload media files via
POST /upload - Retrieve media by id via
GET /:id - Publish an upload by tagging it — anyone can browse a tag's public gallery via
GET /media?tag= - Delete your published items via
DELETE /media/:id - CORS enabled for browser uploads
Uploads require a pollinations.ai API key. Get one at enter.pollinations.ai.
# Multipart form-data
curl -X POST https://media.pollinations.ai/upload \
-H "Authorization: Bearer <your-api-key>" \
-F "file=@image.jpg"
# Base64 JSON
curl -X POST https://media.pollinations.ai/upload \
-H "Authorization: Bearer <your-api-key>" \
-H "Content-Type: application/json" \
-d '{
"data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
"contentType": "image/png",
"name": "image.png"
}'
# Returns:
# {
# "id": "3f9c1e2a-7b4d-4e2f-9a1c-8d6b5e4f3a2b",
# "url": "https://media.pollinations.ai/3f9c1e2a-7b4d-4e2f-9a1c-8d6b5e4f3a2b",
# "contentType": "image/jpeg",
# "size": 123456
# }Tags are the publish action: add a tags field and the upload becomes publicly
listed in each tag's gallery. Untagged uploads stay unlisted — reachable only
by their unguessable id URL.
# Upload + publish
curl -X POST https://media.pollinations.ai/upload \
-H "Authorization: Bearer <your-api-key>" \
-F "file=@image.jpg" \
-F "tags=sunset,landscape"
# Browse a tag's gallery — public, no API key
curl "https://media.pollinations.ai/media?tag=sunset"
# Unpublish + remove (owner's secret sk_ key)
curl -X DELETE https://media.pollinations.ai/media/<id> \
-H "Authorization: Bearer <your-sk-key>"curl https://media.pollinations.ai/3f9c1e2a-7b4d-4e2f-9a1c-8d6b5e4f3a2b
# Returns: original file with correct content-typecurl -I https://media.pollinations.ai/3f9c1e2a-7b4d-4e2f-9a1c-8d6b5e4f3a2b
# Returns: 200 with headers, or 404 if not foundUpload a media file. Requires API key via Authorization: Bearer <key> header or ?key=<key> query parameter.
Request:
Content-Type: multipart/form-datawithfilefield (optionaltagsfield: comma-separated)- Or JSON with
Content-Type: application/json:{ "data": "base64-encoded-file-data", "contentType": "image/jpeg", "name": "image.jpg", "tags": ["sunset", "landscape"] }
Tagging publishes the upload to each tag's public gallery. tags accepts a
comma-separated string (or a JSON array in the JSON format), max 8 tags,
each lowercase letters, digits, and _.:- (not leading), max 128 chars.
Publishing requires a key attached to a user account.
Response:
{
"id": "unique-media-id",
"url": "https://media.pollinations.ai/{id}",
"contentType": "image/jpeg",
"size": 123456,
"tags": ["sunset", "landscape"]
}tags is present only when the upload was tagged.
Errors:
400- No file provided, empty file, invalid JSON/base64, or invalid tags413- File too large (max 100MB of decoded/file bytes)
Retrieve a media file by its id.
Response:
- Binary file with correct
Content-Type - Untagged uploads:
Cache-Control: public, max-age=31536000, immutable - Published (tagged) uploads:
Cache-Control: no-storeso deletion takes effect immediately
Headers:
Content-Type- MIME typeCache-Control- immutable for untagged uploads;no-storefor published uploadsX-Content-Id- Media idX-Content-Size- File size in bytes
Errors:
404- File not found
Check if a file exists without downloading.
Response:
200with metadata headers if exists404if not found
List the public gallery for a tag: every published item carrying that tag, any owner, newest first. Fully public — no API key.
Query params: tag (required), limit (1–100, default 20), cursor (opaque, from a prior response's nextCursor).
Response: { items, nextCursor, hasMore }. Pass nextCursor back as ?cursor= while hasMore is true. Items never expose who uploaded them.
Errors:
400- Missing/emptytag, or invalidlimit/cursor
Delete a published item you own: removes the file, its catalog entry, and all
its tags — it disappears from galleries and its URL 404s. Requires your
secret (sk_) API key; publishable (pk_) keys are rejected since anyone
can read them out of a public client.
Untagged uploads were never published and can't be deleted — they expire on their own (see Retention Policy).
Response: { "deleted": true, "id": "<id>" }
Errors:
401- Missing or invalid API key403- Not a secret key, key has no user account, or you don't own the item404- Unknown id, or an untagged (never published) upload
Service info and health check.
# Upload reference image
MEDIA_URL=$(curl -s -X POST https://media.pollinations.ai/upload \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@reference.jpg" | jq -r '.url')
# Use with Pollinations image API
curl "https://image.pollinations.ai/prompt/transform%20to%20cyberpunk?image=$MEDIA_URL"# Upload audio sample
curl -X POST https://media.pollinations.ai/upload \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@voice-sample.mp3"# Install dependencies
npm install
# Run locally
npm run dev
# Deploy to production
npm run deploy:production- Max file size: 100MB of decoded/file bytes
- Storage: Cloudflare R2
- Default retention: 30-day lifecycle; a GET refreshes objects once they are at least 15 days old
Each upload gets a unique id. That single id is the storage key, the retrieval id (GET /:id), and — for published uploads — the catalog id you list and delete by. Re-uploading the same bytes yields a new id (no content deduplication).
- Immutable bytes: an id is never reused for other content. Untagged uploads use long-lived immutable caching; published uploads use
no-storebecause owners can delete them.
- 30-day lifecycle: A GET refreshes an object once it is at least 15 days old, avoiding a storage rewrite on every access. This applies to published (tagged) items too — an expired published item keeps its catalog entry in the gallery, but the URL 404s.
- Delete (alpha): Owners can delete their published items via
DELETE /media/:id(secret key). Untagged uploads can't be deleted — they expire on their own. - Publishing (alpha): Tag uploads (via the
tagsfield) to publish them, then list withGET /media?tag=. See the API Reference. - Abuse/copyright: For takedown requests, contact the Pollinations team.
Uploads require a pollinations.ai API key (pk_ or sk_). Get one at enter.pollinations.ai.
Pass the key via:
Authorization: Bearer <key>header (recommended)?key=<key>query parameter
Retrieval (GET /:id, HEAD /:id) is public — no authentication required.
Built with 🌸 by Pollinations.AI