Update a location's details and hours

Change contact details, publish a full weekly schedule with one-off overrides, mark a temporary closure, set Google categories, and read the changes back.

POST /locations/update is a partial update. Everything goes under input, input.id is the only required field, and only the fields you send change. The same call handles a one-line phone fix and a full schedule rewrite, so the steps below differ only in what they put in the body.

1. Update phone and website

Send id plus the fields to change. bizUrl is what publishers show as the website. The Python SDK's locations.update() takes a dict with camelCase keys, and the Node SDK's updateLocation() takes the same object.

Phone and website
curl -X POST https://listingsapi.com/api/v4/locations/update \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{  "input": {    "id": "TG9jYXRpb246MTgwMDI4OQ==",    "phone": "5125550199",    "bizUrl": "https://acmekitchen.example.com"  }}'
JSON
{  "data": {    "updateLocation": {      "success": true,      "errors": null,      "location": {        "id": "TG9jYXRpb246MTgwMDI4OQ==",        "databaseId": 1800289,        "name": "Jenny Home",        "phone": "5125550199",        "status": "APPROVED"      }    }  }}

A validation failure still returns HTTP 200, with success: false and the reason in data.updateLocation.errors, so check success rather than the status code. Both SDKs raise ValidationError for that case.

2. Set weekly hours

businessHours is an array with one entry per weekday. Always send all seven, and mark a closed day with type: "CLOSED" and an empty slots array rather than leaving it out. Intervals inside a day must not overlap.

FieldValuesNotes
dayMONDAY to SUNDAY, or SPECIALSPECIAL is a one-off override for the date in specialDate.
typeOPEN or CLOSEDUse CLOSED with slots: [] for a non-operating day.
slots[].start, slots[].end09:00am, 05:00pmTwelve-hour times with am or pm. Several slots per day allowed for split shifts.
specialDateYYYY-MM-DDOnly on a SPECIAL entry, sent alongside the seven weekday entries, never instead of them.
moreHours[]hoursTypeId, moreHour[]Secondary schedules such as delivery or drive-through. moreHour uses the same day, type, slots shape and has no specialDate.
Weekly hours
curl -X POST https://listingsapi.com/api/v4/locations/update \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{  "input": {    "id": "TG9jYXRpb246MTgwMDI4OQ==",    "businessHours": [      { "day": "MONDAY",    "type": "OPEN",   "slots": [{ "start": "09:00am", "end": "05:00pm" }] },      { "day": "TUESDAY",   "type": "OPEN",   "slots": [{ "start": "09:00am", "end": "05:00pm" }] },      { "day": "WEDNESDAY", "type": "OPEN",   "slots": [{ "start": "09:00am", "end": "05:00pm" }] },      { "day": "THURSDAY",  "type": "OPEN",   "slots": [{ "start": "09:00am", "end": "05:00pm" }] },      { "day": "FRIDAY",    "type": "OPEN",   "slots": [{ "start": "09:00am", "end": "05:00pm" }] },      { "day": "SATURDAY",  "type": "OPEN",   "slots": [{ "start": "10:00am", "end": "02:00pm" }] },      { "day": "SUNDAY",    "type": "CLOSED", "slots": [] }    ]  }}'

For a holiday, append a SPECIAL entry to the same array. It overrides that one date and leaves the weekly pattern alone:

JSON
{ "day": "SPECIAL", "type": "CLOSED", "specialDate": "2026-12-25", "slots": [] }

3. Mark a temporary closure or hide the address

temporarilyClosed: true tells publishers the business is closed for now and stops publishing its hours; set it back to false when you reopen. For a service-area business, hideAddress: true keeps the street address off listings and makes city optional.

Temporary closure
curl -X POST https://listingsapi.com/api/v4/locations/update \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "input": { "id": "TG9jYXRpb246MTgwMDI4OQ==", "temporarilyClosed": true } }'

4. Set Google categories

Google Business Profile has its own category taxonomy, separate from the numeric subCategoryId. primaryGbpSiteCategoryId takes a GCID such as gcid:restaurant, and additionalGbpSiteCategoryIds takes more of them. Both are resolved against countryIso, so send the country in the same call.

Google categories
curl -X POST https://listingsapi.com/api/v4/locations/update \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{  "input": {    "id": "TG9jYXRpb246MTgwMDI4OQ==",    "countryIso": "US",    "primaryGbpSiteCategoryId": "gcid:restaurant",    "additionalGbpSiteCategoryIds": ["gcid:pizza_restaurant", "gcid:italian_restaurant"]  }}'

Do not confuse these with additionalCategoryIds, which takes integer databaseId values from the subcategories endpoint. See Look up countries, states and categories.

5. Read the location back

GET /locations-by-ids returns the full record for one or more base64 ids, passed as a JSON array in the ids query parameter. Compare phone, businessHours, and temporarilyClosed with what you sent.

Verify
curl -G https://listingsapi.com/api/v4/locations-by-ids \--data-urlencode 'ids=["TG9jYXRpb246MTgwMDI4OQ=="]' \-H "Authorization: API $LISTINGSAPI_KEY"
JSON
{  "data": {    "getLocationsByIds": [      {        "id": "TG9jYXRpb246MTgwMDI4OQ==",        "databaseId": 1800289,        "name": "Jenny Home",        "phone": "5125550199",        "hideAddress": false,        "temporarilyClosed": true      }    ]  }}

Ids that do not exist in your account are dropped from the array without an error, so compare the returned count with what you asked for.

If webhooks are configured, a profile.updated event fires. It is debounced to one delivery per location per 60 seconds, on the leading edge: later edits in that window are collapsed, and changed_fields describes only the edit that opened it. Read the location back when the event arrives, and again after the window has closed.

Next steps