Skip to content

The Google door — any other Business Profile API for a business

MauKirim has typed endpoints for the common things (businesses, reviews, posts, photos, insights, attributes, verification). Google has more APIs that are scoped to a business: place action links (the “Order” and “Book” buttons), lodging (hotel amenities) and whatever Google adds next. The google door reaches them all without waiting for a MauKirim release.

It is not an open proxy. A request names one of a fixed set of Google API families and a path relative to one of your businesses; MauKirim adds the business’s own resource name, so a call cannot name another business, another account or another host.

Scope gmb — for every method including GET
Path id — the business id (gml_…)
Header Idempotency-Key — optional, recommended for every method except GET: 8–128 characters of letters, digits and _ . : -
Cost One metered Google call per request
{
"api": "placeactions",
"method": "GET",
"path": "/placeActionLinks",
"query": { "pageSize": 20 }
}
Field Required Rule
api yes One of the families below
method no GET (default), POST, PATCH, PUT or DELETE (case-insensitive)
path no Relative to the business; empty means the business itself. See the path rules
query no An object of at most 20 parameters. A name is 1–80 characters of letters, digits, _ and .. A value is a string, number or boolean of at most 500 characters, or an array of at most 30 of them (sent as a repeated parameter)
body no Any JSON, at most 64 KB once serialised. Sent with POST, PATCH and PUT
api Google API The path is relative to
info Business Information API (v1) locations/{location}
reviews My Business API (v4): reviews, posts, media accounts/{account}/locations/{location}
performance Business Profile Performance API (v1) locations/{location}
verifications Verifications API (v1) locations/{location}
placeactions My Business Place Actions API (v1) locations/{location}
lodging My Business Lodging API (v1) locations/{location}
accounts Account Management API (v1) locations/{location}

The {account} and {location} are the business’s own, filled in by MauKirim. Account-level Google calls (listing, creating or deleting accounts, managing account admins) are not reachable through this door.

The path is a sequence of segments, each starting with /, and may end in a Google custom method that starts with ::

  • Each /segment is 1 or more of letters, digits and _ . @ = -.
  • A :customMethod is : and letters only, for example :fetchVerificationOptions.
  • Empty is allowed and means the business itself.
  • At most 300 characters.
path Result
/placeActionLinks A child collection of the business
/placeActionLinks/abc123 One item
:fetchVerificationOptions A custom method on the business
/lodging The lodging data of the business
`` (empty) with GET, PATCH The business itself

Everything below is 400 invalid_input, answered before any Google call (so it spends no budget):

Refused Example
An api outside the list "api": "oauth2"
Another business, an account or a URL in path /../accounts/1, https://evil.example/x, //host
.. anywhere in the path /a/../b
A path that does not start with / or :, or has a character outside the set attributes, /a b, /a?x=1, /a#frag
A query string inside path /attributes?x=1 — put it in query
A method other than GET, POST, PATCH, PUT, DELETE TRACE
Deleting the business itself DELETE with an empty path
Changing managers: POST, PATCH, PUT or DELETE on any admins segment (any api) {"api":"accounts","method":"POST","path":"/admins"} — use the manager tools; GET /admins stays open
A :transfer, :associate, :clearLocationAssociation, :delete or :move method, in any api :transfer
A role of OWNER or PRIMARY_OWNER anywhere in a write body {"role":"OWNER"} — an API key never hands over ownership
More than 20 query parameters, a bad parameter name, or a value that is not text, a number or a boolean
A body over 64 KB

What Google itself refuses is reported by its mapped status: 403 is gmb_forbidden, a disabled or unapproved API is 503 gmb_api_unavailable, a rejected request is 400 invalid_input, an unknown resource is 404 gmb_location_not_found.

{ "ok": true, "status": "ok", "data": { "placeActionLinks": [ { "name": "locations/123/placeActionLinks/abc123", "uri": "https://order.example", "placeActionType": "FOOD_ORDERING" } ] } }

data is Google’s own answer, unmodified, so its field names and shapes are Google’s and can change when Google changes. For anything with a typed endpoint, prefer the typed endpoint: it is validated, mapped to MauKirim’s vocabulary and documented.

For every method except GET the answer also has "replayed": true | false.

Terminal window
curl -X POST https://app.maukirim.com/api/v1/gmb/locations/gml_8f3kq2x1ab/google \
-H "Authorization: Bearer mk_live_…" -H "Content-Type: application/json" \
-H "Idempotency-Key: links-gml_8f3kq2x1ab-order-1" \
-d '{
"api": "placeactions",
"method": "POST",
"path": "/placeActionLinks",
"body": { "uri": "https://order.example/kopi", "placeActionType": "FOOD_ORDERING" }
}'
const response = await fetch(`https://app.maukirim.com/api/v1/gmb/locations/${id}/google`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MAUKIRIM_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": `links-${id}-order-1`,
},
body: JSON.stringify({
api: "placeactions",
method: "POST",
path: "/placeActionLinks",
body: { uri: "https://order.example/kopi", placeActionType: "FOOD_ORDERING" },
}),
})
const { data, replayed } = await response.json()
$curl = curl_init("https://app.maukirim.com/api/v1/gmb/locations/$id/google");
curl_setopt_array($curl, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('MAUKIRIM_KEY'),
'Content-Type: application/json',
"Idempotency-Key: links-$id-order-1",
],
CURLOPT_POSTFIELDS => json_encode([
'api' => 'placeactions',
'method' => 'POST',
'path' => '/placeActionLinks',
'body' => ['uri' => 'https://order.example/kopi', 'placeActionType' => 'FOOD_ORDERING'],
]),
CURLOPT_RETURNTRANSFER => true,
]);
$result = json_decode(curl_exec($curl), true);

The bodies in these examples are illustrative: Google’s own reference for each API is authoritative for field names and values.

Every method except GET is treated as a write to the public listing and takes an Idempotency-Key: the same key with the same request (the same api, method, path, query and body) returns the stored answer with "replayed": true and makes no second call to Google; the same key with a different request is 409 gmb_idempotency_conflict. A GET is not stored and is never replayed. Stored answers are kept for 24 hours. Without a key, a retry repeats the write.

One metered call per request, drawn from your account’s share like any other (see rate limits). A refusal by the allow-list costs nothing. Whether a given Google API works depends on it being enabled, and for some approved, for the Google project MauKirim runs under. The place action links, lodging and Performance APIs are separate Google APIs, so one can be unavailable while another works; the answer for an unavailable one is 503 gmb_api_unavailable. We cannot tell you from here which your deployment has.

HTTP Code Condition
400 invalid_input Anything in What is refused, a malformed key, or Google rejected the request
401 api_key_invalid / api_key_revoked / api_key_expired
402 gmb_plan_required The package does not include the connector
403 api_key_scope_denied The key lacks gmb (a read key cannot use the door, even for GET)
403 gmb_forbidden Google says the connected account may not do this to this business
404 gmb_location_not_found Not your business, no such business, it left Google, or Google has no such resource
409 gmb_reconnect_required / gmb_location_disabled / gmb_idempotency_conflict See Errors
429 gmb_rate_limited No budget now (Retry-After)
502 gmb_upstream_error Google failed
503 gmb_api_unavailable That Google API is not enabled or approved for the deployment’s Google project