# Location details

Read and update a Google Business Profile listing: hours, holiday hours, description, contact details, categories, attributes and action links.

Location details are the facts on a Google listing: opening hours, the holiday closures, the description, phone and website, the categories, the amenities and the buttons that let people book or order. Pozy reads and writes them for the account's selected location, or for any other location the same Google login manages when you pass `locationId`.

Google only accepts most edits on a verified location. Check [verification](https://pozy.ai/docs/google-business/verifications) first if updates do not stick.

## Read the listing

[`GET /v1/accounts/{accountId}/gmb-location-details`](https://pozy.ai/docs/api/getGoogleBusinessLocationDetails) returns the fields you name in `readMask`. Ask for only what you need.

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

console.log(data.location?.reviewUrl, data.regularHours);
```
```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-location-details",
    headers=H,
    params={"readMask": "title,regularHours,specialHours,profile,websiteUri,phoneNumbers"},
    timeout=30,
)
print(resp.json())
```

```json
{
  "success": true,
  "accountId": "6713b0e5d1f4c69a2b8e3f75",
  "locationId": "4821930576104832190",
  "location": {
    "name": "Padaria Rosa Chiado",
    "placeId": "ChIJ-example-place-id",
    "reviewUrl": "https://search.google.com/local/writereview?placeid=ChIJ-example-place-id",
    "mapsUri": "https://maps.google.com/maps?cid=7349201837465019283",
    "isVerified": true
  },
  "title": "Padaria Rosa Chiado",
  "regularHours": {
    "periods": [
      { "openDay": "MONDAY", "openTime": "07:30", "closeDay": "MONDAY", "closeTime": "19:00" }
    ]
  },
  "profile": { "description": "Sourdough, pastéis de nata and coffee since 1998." },
  "websiteUri": "https://example.com"
}
```

The `location` block is always included and is read-only. `reviewUrl` is the public "write a review" link, which is handy to print on receipts or behind a QR code. For a new or unverified location Google leaves out `placeId`, `reviewUrl` and `mapsUri`, so they come back `null` and `isVerified` is `false`.

Fields you can name in `readMask`:

| Field | Holds |
| --- | --- |
| `title` | The business name shown on Google |
| `regularHours` | Weekly opening hours |
| `specialHours` | Holiday and one-off hours |
| `moreHours` | Extra hour sets, such as delivery or kitchen hours |
| `profile` | `description` |
| `websiteUri` | Website |
| `phoneNumbers` | `primaryPhone` and `additionalPhones` |
| `categories` | `primaryCategory` and `additionalCategories` |
| `storefrontAddress` | The street address |
| `serviceArea` | Areas served, for businesses that travel to customers |
| `serviceItems` | Services (also editable on [Services and menus](https://pozy.ai/docs/google-business/services-menus)) |
| `openInfo` | `OPEN`, `CLOSED_TEMPORARILY` or `CLOSED_PERMANENTLY`, plus the opening date |
| `name`, `metadata` | Google's identifiers and metadata |

Do not put `location` in `readMask`. It is a response-only block and Google rejects the request with `400`.

## Update the listing

[`PUT /v1/accounts/{accountId}/gmb-location-details`](https://pozy.ai/docs/api/updateGoogleBusinessLocationDetails) changes only the fields named in `updateMask`. Fields you send but leave out of the mask are ignored, and the call returns `400` without a mask.

### Weekly hours

Send every opening period for the week. Days with no period show as closed.

```bash cURL
curl -X PUT https://api.pozy.ai/v1/accounts/6713b0e5d1f4c69a2b8e3f75/gmb-location-details \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "updateMask": "regularHours",
    "regularHours": {
      "periods": [
        { "openDay": "MONDAY", "openTime": "07:30", "closeDay": "MONDAY", "closeTime": "19:00" },
        { "openDay": "TUESDAY", "openTime": "07:30", "closeDay": "TUESDAY", "closeTime": "19:00" },
        { "openDay": "SATURDAY", "openTime": "08:00", "closeDay": "SATURDAY", "closeTime": "14:00" }
      ]
    }
  }'
```

### Holiday hours

`specialHours` overrides the weekly hours on specific dates. Mark a day `closed`, or give it its own `openTime` and `closeTime`.

```bash cURL
curl -X PUT https://api.pozy.ai/v1/accounts/6713b0e5d1f4c69a2b8e3f75/gmb-location-details \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "updateMask": "specialHours",
    "specialHours": {
      "specialHourPeriods": [
        { "startDate": { "year": 2026, "month": 12, "day": 25 }, "closed": true },
        { "startDate": { "year": 2026, "month": 12, "day": 24 }, "openTime": "07:30", "closeTime": "13:00" }
      ]
    }
  }'
```
```ts Node
const res = await fetch("https://api.pozy.ai/v1/accounts/6713b0e5d1f4c69a2b8e3f75/gmb-location-details", {
  method: "PUT",
  headers: {
    Authorization: `Bearer ${process.env.POZY_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    updateMask: "specialHours",
    specialHours: {
      specialHourPeriods: [
        { startDate: { year: 2026, month: 12, day: 25 }, closed: true },
        { startDate: { year: 2026, month: 12, day: 24 }, openTime: "07:30", closeTime: "13:00" },
      ],
    },
  }),
});
if (!res.ok) throw new Error((await res.json()).error);
```
```python Python
requests.put(
    "https://api.pozy.ai/v1/accounts/6713b0e5d1f4c69a2b8e3f75/gmb-location-details",
    headers=H,
    json={
        "updateMask": "specialHours",
        "specialHours": {
            "specialHourPeriods": [
                {"startDate": {"year": 2026, "month": 12, "day": 25}, "closed": True},
                {"startDate": {"year": 2026, "month": 12, "day": 24}, "openTime": "07:30", "closeTime": "13:00"},
            ]
        },
    },
    timeout=30,
).raise_for_status()
```

Sending `specialHours` replaces the whole list of special periods, so include the ones you want to keep.

### Several fields at once

Name each field in the mask, comma-separated:

```json
{
  "updateMask": "profile,websiteUri,phoneNumbers",
  "profile": { "description": "Sourdough, pastéis de nata and coffee since 1998. Gluten-free loaves on Fridays." },
  "websiteUri": "https://example.com/chiado",
  "phoneNumbers": { "primaryPhone": "+351 21 000 0123" }
}
```

To mark a temporary closure, update `openInfo` with `status: "CLOSED_TEMPORARILY"`. Set it back to `OPEN` when the location reopens.

## Attributes

Attributes are the yes-or-no and pick-list facts Google shows on a listing: dine-in, takeout, delivery, Wi-Fi, outdoor seating, accepted cards and many more. Which ones exist depends on the location's category.

1. Find the valid attributes with [`GET /v1/accounts/{accountId}/gmb-attribute-metadata`](https://pozy.ai/docs/api/getGmbAttributeMetadata). It returns each attribute's name, display name, `valueType` and allowed values. Ask for one location (pass `locationId`, or nothing for the selected location), or for a whole category (`categoryName` starting with `categories/` plus `regionCode`, optionally `languageCode`). Both page with `pageToken`.
2. Read what is set now with [`GET /v1/accounts/{accountId}/gmb-attributes`](https://pozy.ai/docs/api/getGoogleBusinessAttributes).
3. Update with [`PUT /v1/accounts/{accountId}/gmb-attributes`](https://pozy.ai/docs/api/updateGoogleBusinessAttributes), listing every attribute you change in `attributeMask`.

```bash cURL
curl -X PUT https://api.pozy.ai/v1/accounts/6713b0e5d1f4c69a2b8e3f75/gmb-attributes \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "attributeMask": "has_takeout,has_wifi,pay_credit_card_types_accepted",
    "attributes": [
      { "name": "has_takeout", "values": [true] },
      { "name": "has_wifi", "values": [true] },
      { "name": "pay_credit_card_types_accepted", "repeatedEnumValue": { "setValues": ["visa", "mastercard"] } }
    ]
  }'
```

| `valueType` | How to send it |
| --- | --- |
| `BOOL` | `values: [true]` or `[false]` |
| `ENUM` | `values: ["one_value"]` |
| `REPEATED_ENUM` | `repeatedEnumValue` with `setValues` and `unsetValues` |
| `URL` | `uriValues: [{ "uri": "https://..." }]` |

An attribute the category does not offer returns `400`.

## Action links

Action links are the buttons on the listing that take people to book an appointment, reserve a table, order food or shop online.

| Call | Does |
| --- | --- |
| [`GET .../gmb-place-actions`](https://pozy.ai/docs/api/listGoogleBusinessPlaceActions) | Lists the links, up to 100 per page |
| [`POST .../gmb-place-actions`](https://pozy.ai/docs/api/createGoogleBusinessPlaceAction) | Creates one with a `uri` and a `placeActionType` |
| [`PATCH .../gmb-place-actions`](https://pozy.ai/docs/api/updateGoogleBusinessPlaceAction) | Changes the `uri` or type of the link named in `name` |
| [`DELETE .../gmb-place-actions?name=...`](https://pozy.ai/docs/api/deleteGoogleBusinessPlaceAction) | Removes it |

`placeActionType` is one of `APPOINTMENT`, `ONLINE_APPOINTMENT`, `DINING_RESERVATION`, `FOOD_ORDERING`, `FOOD_DELIVERY`, `FOOD_TAKEOUT` or `SHOP_ONLINE`.

```bash cURL
curl -X POST https://api.pozy.ai/v1/accounts/6713b0e5d1f4c69a2b8e3f75/gmb-place-actions \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "uri": "https://example.com/order", "placeActionType": "FOOD_ORDERING" }'
```

The response returns the link's `name` (`locations/.../placeActionLinks/...`), which the update and delete calls take. A `PATCH` with neither `uri` nor `placeActionType` returns `400`.

## Endpoints

| Endpoint | What it does |
| --- | --- |
| [`GET /v1/accounts/{accountId}/gmb-attribute-metadata`](https://pozy.ai/docs/api/getGmbAttributeMetadata) | Get attribute metadata |
| [`GET /v1/accounts/{accountId}/gmb-attributes`](https://pozy.ai/docs/api/getGoogleBusinessAttributes) | Get attributes |
| [`PUT /v1/accounts/{accountId}/gmb-attributes`](https://pozy.ai/docs/api/updateGoogleBusinessAttributes) | Update attributes |
| [`GET /v1/accounts/{accountId}/gmb-location-details`](https://pozy.ai/docs/api/getGoogleBusinessLocationDetails) | Get location details |
| [`PUT /v1/accounts/{accountId}/gmb-location-details`](https://pozy.ai/docs/api/updateGoogleBusinessLocationDetails) | Update location details |
| [`GET /v1/accounts/{accountId}/gmb-place-actions`](https://pozy.ai/docs/api/listGoogleBusinessPlaceActions) | List action links |
| [`POST /v1/accounts/{accountId}/gmb-place-actions`](https://pozy.ai/docs/api/createGoogleBusinessPlaceAction) | Create action link |
| [`PATCH /v1/accounts/{accountId}/gmb-place-actions`](https://pozy.ai/docs/api/updateGoogleBusinessPlaceAction) | Update action link |
| [`DELETE /v1/accounts/{accountId}/gmb-place-actions`](https://pozy.ai/docs/api/deleteGoogleBusinessPlaceAction) | Delete action link |
