/api/v4/locations/photosUpload photos to a location
Attaches media to a location, either by public image URL or by referencing files already in your media library.
Parameters
Body
A nested field marked required applies only when you send its parent. If the parent is optional and you omit it, its required children do not apply.
| Name | Type | Required | Description |
|---|---|---|---|
| input.locationId | string | required | The location's Base64-encoded Relay ID to attach media to. |
| input.photos | array of objects | required | Images to attach. `photo` is the only required key on each item. |
| input.photos[].photo | string | required | A publicly accessible JPEG or PNG URL that Listings API fetches and stores. The field is named `photo`, not `url`. |
| input.photos[].type | string | optional | Which slot the image fills: `LOGO`, `COVER`, or `ADDITIONAL`. Defaults to an additional photo. |
| input.photos[].starred | boolean | optional | Star the photo as it is attached, instead of a follow-up call to the star endpoint. Only additional photos can be starred, at most 4 per location. |
| input.photos[].source | string | optional | Free-text label recording where the image came from. |
Sample request
Ready-to-paste body. Replace placeholder IDs and values with yours.
{ "input": { "locationId": "TG9jYXRpb246MTgwMDI4OQ==", "photos": [ { "photo": "https://cdn.example.com/jenny-home/logo.png", "type": "LOGO" }, { "photo": "https://cdn.example.com/jenny-home/storefront.jpg", "type": "ADDITIONAL" } ] }}Responses
200Photos attached inline. Returns the created photo records; `errors` is null on success and `request` is empty because nothing was queued.
{ "data": { "addLocationPhotos": { "clientMutationId": null, "success": true, "request": {}, "photos": [ { "id": "TWVkaWFGaWxlOjU4Nzg5MzE=", "databaseId": 5878931, "url": "https://sy-media-store.s3-us-west-2.amazonaws.com/f868bb3f/59c670a3/f47d62a6.png", "thumbnailUrl": "https://sy-media-store.s3-us-west-2.amazonaws.com/f868bb3f/59c670a3/thumbnail_f47d62a6.png", "type": "LOGO", "starred": false }, { "id": "TWVkaWFGaWxlOjU4Nzg5MzI=", "databaseId": 5878932, "url": "https://sy-media-store.s3-us-west-2.amazonaws.com/f868bb3f/59c670a3/ef4ffb12.jpg", "thumbnailUrl": "https://sy-media-store.s3-us-west-2.amazonaws.com/f868bb3f/59c670a3/thumbnail_ef4ffb12.jpg", "type": "ADDITIONAL", "starred": false } ], "errors": null } }}401Unauthenticated, missing or invalid API key.
Attaches one or more images to a location. Supply a photos array where each item carries at least photo, a public image URL that Listings API fetches and stores. locationId and a non-empty photos array are always required.
Two shapes of success
A small batch uploads inline: photos carries the finished media and request is an empty object, as in the sample above. A large batch is queued instead, and the same 200 looks like this:
{ "data": { "addLocationPhotos": { "clientMutationId": null, "success": true, "request": { "requestId": "e6c2d9d9-9a18-4015-88cf-9a4e19a6f49a", "status": "PROCCESSING" }, "photos": [], "errors": null } }}Both are successes, so handle them by testing whether request.requestId is present rather than by assuming photos is populated.
The URL field is photo. Not url, and not image. Alongside it each item accepts an optional type (LOGO, COVER, or ADDITIONAL), starred, and source; publisherOverride and partnerMediaId are also accepted for partner integrations. A returned photo has no caption field.
Use case: seed a new location's imagery. Right after creating a location such as "Jenny Home", POST its logo and storefront photos by URL in a single call. The response returns each new photo's id, which you pass to the star and remove endpoints later.
Use case: reuse an approved asset across locations. Point multiple locations at the same hosted image URL in their photos arrays so every location shares the same source asset.
Gotchas.
- Images must be JPEG or PNG. Publisher size rules apply per category (a typical floor is ~10 KB and ceiling of a few MB).
- Large batches are processed asynchronously. Above a server-side batch size, the call queues the work instead of uploading inline:
photoscomes back empty andrequest.requestIdis set. PollGET /locations/photos/requests/{requestId}with that id to track completion. The threshold is server-side configuration, so treat it as "large batches may be queued" rather than a fixed number, and branch on whetherrequest.requestIdis present. - Do not switch on
request.status. On the queued response it is the literal stringPROCCESSING, which is spelled differently from thePROCESSINGthe poll endpoint reports for the same job.request.requestIdbeing present is the reliable signal. - Passing
starred: trueon more than the 4 allowed starred photos fails the whole call withSY15012. The check counts the location's existing starred photos plus the starred items in this request. - A location keeps a single logo and single cover; re-uploading either category replaces the existing image.
- Set
typeexplicitly when you mean an image to be the logo or cover. Without it the image is stored as an additional photo.
curl -X POST 'https://listingsapi.com/api/v4/locations/photos' \ -H "Authorization: API $LISTINGSAPI_KEY" \ -H 'Content-Type: application/json' \ -d '{ "input": { "locationId": "TG9jYXRpb246MTgwMDI4OQ==", "photos": [ { "photo": "https://cdn.example.com/jenny-home/logo.png", "type": "LOGO" }, { "photo": "https://cdn.example.com/jenny-home/storefront.jpg", "type": "ADDITIONAL" } ] } }'