Workflows

Photos

Markdown

Photos never travel through MCP tools. They go to two plain HTTP endpoints with the same API key: upload_media for one photo and upload_media_batch for up to ten.

Whose photos

Photos are the creator's own files. Never download images from the web, stock sites or social media, and never generate them. Ask who took each photo: a photo that is not the creator's own carries the photographer's name in credit, and credits render everywhere the photo does.

The one exception is a guide the creator asks you to build from licensed photos: then only licences that allow commercial use (the Unsplash License, CC0, CC BY with its attribution), and every photo carries credit, licence, sourcePageUrl and creditUrl.

Upload one photo

Resize to 2,048 px on the long side and compress first (around 80 percent quality, well under 1 MB). Then send the bytes with the owner on the query string:

curl -X POST "https://sceniq.earth/api/v1/media/upload?ownerType=spot&ownerId=SPOT_ID&credit=Mara%20Lindgren&alt=Rainbow%20rings%20of%20Grand%20Prismatic%20Spring" \
  -H "Authorization: Bearer $SCENIQ_API_KEY" \
  -H "Content-Type: image/jpeg" \
  --data-binary @grand-prismatic.jpg

ownerType is spot, product (store thumbnail and sales page material), collection (a chapter) or listing (sales page slides). Multipart with a file field and the same fields works too.

What the server does

It checks the real file type (JPEG, PNG or WebP; at most 6 MB and 6,000 px per side), applies the EXIF rotation, scales the long side to 2,048 px, stores WebP without EXIF, GPS, XMP or IPTC metadata, and keeps the capture date as capturedOn. Photos get a 640 px thumbnail the apps use for maps, lists and offline downloads. The response is the new photo with its mediaId.

Several photos at once

curl -X POST "https://sceniq.earth/api/v1/media/upload-batch" \
  -H "Authorization: Bearer $SCENIQ_API_KEY" \
  -F 'manifest=[{"file":"a","ownerType":"spot","ownerId":"SPOT_ID","credit":"Mara Lindgren","alt":"The spring from the overlook"}]' \
  -F "a=@overlook.jpg"

Each file succeeds or fails on its own; the response lists every result. Each file counts against the upload limit.

Chapter covers and intro photos

target=blob stores the file without a media row and returns a storageId: pass it as coverStorageId to update_chapter or as photoStorageId in set_chapter_intro sections.

After the upload

  • Upload each photo once. Keep the mediaId; change captions, credits and the rest with update_media. To replace a photo, upload the new one and delete_media the old one.
  • Upload the full framing and set a focal point (focalX, focalY from 0 to 1) instead of cropping: the apps crop per surface and keep that point in frame.
  • Write alt for what the photo shows; the caption is what buyers read under it.
  • Say what it shows (shows) and, when known, where it was taken (takenAt with its precision) and how that was confirmed (locationVerifiedBy). Readiness flags a precise location more than 2 km from the pin, and photos taken before a change at the spot.
  • reorder_media moves a photo in its gallery; list_media shows every photo with its fields.

A guide publishes only when every live spot with photos turned on has at least one photo.