Google Business
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 first if updates do not stick.
#Read the listing
GET /v1/accounts/{accountId}/gmb-location-details returns the fields you name in readMask. Ask for only what you need.
curl "https://api.pozy.ai/v1/accounts/6713b0e5d1f4c69a2b8e3f75/gmb-location-details?readMask=title,regularHours,specialHours,profile,websiteUri,phoneNumbers" \
-H "Authorization: Bearer $POZY_API_KEY"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);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()){
"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) |
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 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.
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.
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" }
]
}
}'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);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:
{
"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.
- Find the valid attributes with
GET /v1/accounts/{accountId}/gmb-attribute-metadata. It returns each attribute's name, display name,valueTypeand allowed values. Ask for one location (passlocationId, or nothing for the selected location), or for a whole category (categoryNamestarting withcategories/plusregionCode, optionallylanguageCode). Both page withpageToken. - Read what is set now with
GET /v1/accounts/{accountId}/gmb-attributes. - Update with
PUT /v1/accounts/{accountId}/gmb-attributes, listing every attribute you change inattributeMask.
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 |
Lists the links, up to 100 per page |
POST .../gmb-place-actions |
Creates one with a uri and a placeActionType |
PATCH .../gmb-place-actions |
Changes the uri or type of the link named in name |
DELETE .../gmb-place-actions?name=... |
Removes it |
placeActionType is one of APPOINTMENT, ONLINE_APPOINTMENT, DINING_RESERVATION, FOOD_ORDERING, FOOD_DELIVERY, FOOD_TAKEOUT or SHOP_ONLINE.
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 |
Get attribute metadata |
GET /v1/accounts/{accountId}/gmb-attributes |
Get attributes |
PUT /v1/accounts/{accountId}/gmb-attributes |
Update attributes |
GET /v1/accounts/{accountId}/gmb-location-details |
Get location details |
PUT /v1/accounts/{accountId}/gmb-location-details |
Update location details |
GET /v1/accounts/{accountId}/gmb-place-actions |
List action links |
POST /v1/accounts/{accountId}/gmb-place-actions |
Create action link |
PATCH /v1/accounts/{accountId}/gmb-place-actions |
Update action link |
DELETE /v1/accounts/{accountId}/gmb-place-actions |
Delete action link |