Workflows
Photos
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.jpgownerType 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,focalYfrom 0 to 1) instead of cropping: the apps crop per surface and keep that point in frame. - Write
altfor what the photo shows; the caption is what buyers read under it. - Say what it shows (
shows) and, when known, where it was taken (takenAtwith 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.