# Photos and videos

List, add and remove the photos and videos on a Google Business Profile listing, and choose where each one appears.

Photos are often the first thing people look at on a listing: the shop front, the counter, the food. Pozy lets you add them from a public URL, label where they belong (cover, logo, interior, menu and so on) and remove old ones. This is separate from the single image you attach to a [post](https://pozy.ai/docs/google-business/posts); media added here lives on the listing itself.

## List what is on the listing

[`GET /v1/accounts/{accountId}/gmb-media`](https://pozy.ai/docs/api/listGoogleBusinessMedia) returns up to 100 items per page with `pageToken` for the next page, plus `totalMediaItemsCount`.

```bash cURL
curl "https://api.pozy.ai/v1/accounts/6713b0e5d1f4c69a2b8e3f75/gmb-media?pageSize=50" \
  -H "Authorization: Bearer $POZY_API_KEY"
```
```ts Node
const res = await fetch("https://api.pozy.ai/v1/accounts/6713b0e5d1f4c69a2b8e3f75/gmb-media?pageSize=50", {
  headers: { Authorization: `Bearer ${process.env.POZY_API_KEY}` },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);

for (const m of data.mediaItems) console.log(m.mediaFormat, m.locationAssociation?.category, m.googleUrl);
```
```python Python
import os
import requests

H = {"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"}
resp = requests.get(
    "https://api.pozy.ai/v1/accounts/6713b0e5d1f4c69a2b8e3f75/gmb-media",
    headers=H,
    params={"pageSize": 50},
    timeout=30,
)
for m in resp.json()["mediaItems"]:
    print(m["mediaFormat"], m.get("locationAssociation", {}).get("category"), m["googleUrl"])
```

```json
{
  "success": true,
  "accountId": "6713b0e5d1f4c69a2b8e3f75",
  "locationId": "4821930576104832190",
  "mediaItems": [
    {
      "name": "accounts/118273645509/locations/4821930576104832190/media/AF1QipExample01",
      "mediaFormat": "PHOTO",
      "googleUrl": "https://lh3.googleusercontent.com/p/example-01",
      "thumbnailUrl": "https://lh3.googleusercontent.com/p/example-01=s200",
      "description": "Counter at opening time",
      "createTime": "2026-09-02T08:10:00Z",
      "locationAssociation": { "category": "INTERIOR" }
    }
  ],
  "totalMediaItemsCount": 23
}
```

Add `locationId` to any of these calls to work on another location under the same Google login.

## Add a photo or video

[`POST /v1/accounts/{accountId}/gmb-media`](https://pozy.ai/docs/api/createGoogleBusinessMedia) takes a `sourceUrl` that Google can download, an optional `description` and a `category`. Set `mediaFormat` to `VIDEO` for a video; the default is `PHOTO`.

```bash cURL
curl -X POST https://api.pozy.ai/v1/accounts/6713b0e5d1f4c69a2b8e3f75/gmb-media \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sourceUrl": "https://pozy.ai/media/shopfront-autumn.jpg",
    "description": "Shop front in the morning",
    "category": "EXTERIOR"
  }'
```
```ts Node
const res = await fetch("https://api.pozy.ai/v1/accounts/6713b0e5d1f4c69a2b8e3f75/gmb-media", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.POZY_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    sourceUrl: "https://pozy.ai/media/shopfront-autumn.jpg",
    description: "Shop front in the morning",
    category: "EXTERIOR",
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);

console.log(data.name, data.googleUrl);
```
```python Python
resp = requests.post(
    "https://api.pozy.ai/v1/accounts/6713b0e5d1f4c69a2b8e3f75/gmb-media",
    headers=H,
    json={
        "sourceUrl": "https://pozy.ai/media/shopfront-autumn.jpg",
        "description": "Shop front in the morning",
        "category": "EXTERIOR",
    },
    timeout=30,
)
print(resp.json()["googleUrl"])
```

The URL must be public, need no login and return the file itself rather than a web page. If the file is on your computer, [upload it to Pozy](https://pozy.ai/docs/publishing/media) first and use the URL you get back.

## Pick the category

`category` decides where Google shows the item.

| Category | Where it shows |
| --- | --- |
| `COVER` | The main image at the top of the listing |
| `PROFILE` | The listing's profile image |
| `LOGO` | The business logo |
| `EXTERIOR` | Outside views, the entrance, the street |
| `INTERIOR` | Inside the premises |
| `PRODUCT` | Products you sell |
| `FOOD_AND_DRINK` | Dishes and drinks |
| `MENU` | Photos of the menu |
| `COMMON_AREA` | Shared spaces such as a lobby or terrace |
| `ROOMS` | Rooms, for hotels and similar |
| `TEAMS` | The people who work there |
| `AT_WORK` | The team at work |
| `ADDITIONAL` | Anything else |
| `CATEGORY_UNSPECIFIED` | No category |

## Remove an item

[`DELETE /v1/accounts/{accountId}/gmb-media?mediaId=...`](https://pozy.ai/docs/api/deleteGoogleBusinessMedia) removes one item. `mediaId` is the last segment of the item's `name` (`AF1QipExample01` in the example above).

```bash cURL
curl -X DELETE "https://api.pozy.ai/v1/accounts/6713b0e5d1f4c69a2b8e3f75/gmb-media?mediaId=AF1QipExample01" \
  -H "Authorization: Bearer $POZY_API_KEY"
```

Photos that customers uploaded to the listing cannot be removed through the API.

## Common errors

| Error | Cause | Fix |
| --- | --- | --- |
| `400` on upload | Google could not fetch the URL, or the format is not one it accepts | Use a public HTTPS link that returns a common photo or video file, and set `mediaFormat` to match |
| `403` | The Google login cannot manage this location | Reconnect with an owner or manager of the listing |
| `401` `token_invalid` | Google revoked the sign-in | Reconnect the account |

## Endpoints

| Endpoint | What it does |
| --- | --- |
| [`GET /v1/accounts/{accountId}/gmb-media`](https://pozy.ai/docs/api/listGoogleBusinessMedia) | List media |
| [`POST /v1/accounts/{accountId}/gmb-media`](https://pozy.ai/docs/api/createGoogleBusinessMedia) | Upload photo |
| [`DELETE /v1/accounts/{accountId}/gmb-media`](https://pozy.ai/docs/api/deleteGoogleBusinessMedia) | Delete photo |
