update_media
Set a photo's caption, alt, credit, focal point or provenance.
/v1/media/{mediaId}Credits render as Photo: Name and are a hard platform rule: never drop or invent one; ask the creator whose photo it is. Only sent fields change; null clears a metadata field (alt, focal point, licence, shows, takenAt and the rest), while caption and credit take text and store it as sent. The response carries warnings that did not stop the write.
curl -X PATCH "https://sceniq.earth/api/v1/media/kg71s3d5f7g9h1j3k5k7z9x1c3v5b7n9" \
-H "Authorization: Bearer $SCENIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"alt": "A deep blue pool ringed with orange and yellow, steam drifting over the boardwalk below",
"focalX": 0.52,
"focalY": 0.46,
"shows": {
"kind": "spot"
},
"takenAt": {
"lat": 44.5199,
"lon": -110.8406,
"precision": "gps"
},
"locationVerifiedBy": "geotag"
}'Path parameters
- mediaIdstring · photo idrequired
Id of the media row.
Body parameters
- altstring or nulloptional
Alt text: what the photo shows, for screen readers. The caption is the fallback.
- captionstringoptional
Caption text, shown under the photo. Stored as sent.
- capturedOnstring or nulloptional
Capture date (YYYY-MM-DD). Upload reads it from the file's metadata before stripping it when present.
- creditstringoptional
Photographer credit, rendered as Photo: Name. Stored as sent.
- creditUrlstring or nulloptional
The photographer's profile page.
- focalXnumber or nulloptional
Focal point 0 (left) to 1 (right); with
focalYthe apps keep it in frame when they crop to a card. - focalYnumber or nulloptional
Focal point 0 (top) to 1 (bottom).
- licencestring or nulloptional
Licence name (Unsplash License, CC BY 4.0).
- locationVerifiedBystring or nulloptional
How the location was confirmed: geotag, landmark,
photographer_caption, creator or other.geotaglandmarkphotographer_captioncreatorother - reviewNotesstring or nulloptional
Notes for the creator's review (why a value was chosen, what could not be verified). Never shown to buyers;
get_guide_readinesslists them. Empty string clears. What the photo shows, null clears: { kind: spot|
view_from_spot|nearby|approach|detail|other, label? }.Show 2 fieldsHide fieldsof PhotoShows
- kindstringrequired
spot (the place itself),
view_from_spot(the view from it), nearby (a sight near the spot; readiness then skips its distance check), approach (the way there), detail or other.spotview_from_spotnearbyapproachdetailother - labelstringoptional
What exactly it shows, at most 80 characters (the north face from the lake).
- sourcePageUrlstring or nulloptional
The page the photo was licensed from (an Unsplash photo page). Not the image file.
Where it was taken, null clears: { lat, lon, precision: gps|geocode|none }. A gps fix more than 2 km from the pin is flagged by readiness.
Show 3 fieldsHide fieldsof PhotoTakenAt
- latnumberrequired
Latitude in decimal degrees (-90 to 90).
- lonnumberrequired
Longitude in decimal degrees (-180 to 180).
- precisionstringrequired
gps (a camera or phone fix), geocode (looked up from a place name, often coarse on stock sites) or none (an estimate; readiness lists it as resting on judgement).
gpsgeocodenone
Returns
200 OK with this object.
- okbooleanrequired
Always true: the write went through.
Always
true - mediaIdstring · photo idrequired
The photo's id.
- warningsarray of stringsoptional
Notes about things the write accepted but you should look at (a plain http link). Present only when there are any.
{
"ok": true,
"mediaId": "kg71s3d5f7g9h1j3k5k7z9x1c3v5b7n9"
}Errors
Every error is { error: { code, message } }. Act on the code.
- 400invalid_argumentA required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message).
- 400invalid_requestA writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence.
- 401unauthenticatedThe request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key).
- 401invalid_api_keyThe key is unknown, revoked or expired.
- 403api_scope_requiredA read-only key called a write operation, or a key without the publish option called publish_changes.
- 403forbiddenThe key belongs to a creator account that is no longer active.
- 404not_foundThe id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists.
- 413payload_too_largeA JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB.
- 429rate_limitedOver a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour.
- 500internal_errorAn unexpected failure. The message is hidden on purpose.