Google Business

Services and food menus

Keep the services a Google Business Profile location offers, and the menus of a restaurant or cafe, in sync with your own system.

Google shows a list of services on many listings (a plumber's pipe repair, a salon's colour treatment) and full menus on restaurants and cafes. If your product already knows what a business sells, push it to Google with these endpoints instead of asking the owner to type it twice. Both work on verified locations only.

#Services

GET /v1/accounts/{accountId}/gmb-services reads the service list. PUT /v1/accounts/{accountId}/gmb-services replaces it.

PUT replaces the whole list

Google has no way to update one service. Every PUT must contain all the services you want to keep. Read the list, change it, send it back.

Each service is one of two kinds, with an optional price:

Kind Fields When to use it
structuredServiceItem serviceTypeId from Google's catalog for the category, optional description When Google already knows the service
freeFormServiceItem category (the location's category, such as categories/gcid:hair_salon) and a label with displayName, optional description and languageCode Anything Google's catalog does not list

price uses Google's money format: currencyCode, whole units as a string, and optional nanos for the fraction (500000000 is 0.50).

curl -X PUT https://api.pozy.ai/v1/accounts/6719c8e1a7f2b05d3e9c4f60/gmb-services \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "serviceItems": [
      {
        "freeFormServiceItem": {
          "category": "categories/gcid:hair_salon",
          "label": { "displayName": "Cut and blow-dry", "description": "45 minutes, includes wash" }
        },
        "price": { "currencyCode": "EUR", "units": "35" }
      },
      {
        "freeFormServiceItem": {
          "category": "categories/gcid:hair_salon",
          "label": { "displayName": "Full colour", "description": "Up to 2 hours" }
        },
        "price": { "currencyCode": "EUR", "units": "79", "nanos": 500000000 }
      }
    ]
  }'

The response returns the list as Google stored it. Keep that copy; it is the one to send back next time. The location's categories, which a free-form service must use, come from categories in location details.

#Food menus

Restaurants, cafes and other places Google gives menu support to can publish their menus. GET /v1/accounts/{accountId}/gmb-food-menus reads them and PUT updates them. Send the full menus array with updateMask: "menus".

A menu is a tree: menus contain sections, sections contain items, and items can have options.

Level Fields
Menu labels (name per language), sections, optional cuisines and sourceUrl
Section labels, items
Item labels (name and description), attributes, optional options
Option Its own labels and attributes, for variants such as sizes

Item attributes:

Attribute Values
price currencyCode, units, optional nanos
dietaryRestriction For example VEGETARIAN, VEGAN, GLUTEN_FREE
allergen For example DAIRY, GLUTEN, SHELLFISH
spiciness MILD, MEDIUM or HOT
servesNumPeople A whole number
preparationMethods Google's preparation method values
mediaKeys Photos of the item already on the listing
cURL
curl -X PUT https://api.pozy.ai/v1/accounts/6713b0e5d1f4c69a2b8e3f75/gmb-food-menus \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "updateMask": "menus",
    "menus": [{
      "labels": [{ "displayName": "Breakfast", "languageCode": "en" }],
      "sections": [{
        "labels": [{ "displayName": "Pastries" }],
        "items": [{
          "labels": [{ "displayName": "Pastel de nata", "description": "Custard tart, baked hourly" }],
          "attributes": { "price": { "currencyCode": "EUR", "units": "1", "nanos": 400000000 }, "dietaryRestriction": ["VEGETARIAN"] }
        }, {
          "labels": [{ "displayName": "Croissant" }],
          "attributes": { "price": { "currencyCode": "EUR", "units": "2" } },
          "options": [
            { "labels": [{ "displayName": "Plain" }], "attributes": { "price": { "currencyCode": "EUR", "units": "2" } } },
            { "labels": [{ "displayName": "Ham and cheese" }], "attributes": { "price": { "currencyCode": "EUR", "units": "3", "nanos": 500000000 } } }
          ]
        }]
      }]
    }]
  }'

Menus only exist on locations Google gives menu support to. On other locations the call returns 400.

#Common errors

Error Cause Fix
400 gbp_bad_request on services Google rejected an item, often a category the location does not have or an unknown serviceTypeId Use the location's own categories, or a free-form item
400 on menus The location has no menu support, or the account has no location selected Check the location's category and the selected location
403 The Google login cannot manage this location Reconnect with an owner or manager
401 token_invalid Google revoked the sign-in Reconnect the account

#Endpoints