Skip to content

Google Business connect sessions — create, read and list

A connect session is one end user’s trip through the hosted connect flow: you create it, send the client to its url, and read the outcome. The whole workflow, with samples, is in Connect your clients’ Google Business Profiles. The addresses a session may return to are managed with return addresses.

These endpoints need a package that includes the connector (402 gmb_plan_required otherwise).

{
"id": "gms_7d2q9m4k1x",
"state": "completed",
"externalId": "client-4821",
"connectionId": "gmc_5p1x8c3m7z",
"error": null,
"expiresAt": "2026-10-14T02:30:00.000Z",
"createdAt": "2026-10-14T02:00:00.000Z",
"completedAt": "2026-10-14T02:03:41.000Z"
}
Field Meaning
id The session id (gms_…). Store it against your own client record
state pending, completed, cancelled, failed or expired. expired is a pending session whose expiresAt has passed: its link no longer works, and the customer creates a new session
externalId Your own id for the end user, as you passed it
connectionId The connection (gmc_…) created, once completed; otherwise null
error A symbolic gmb_* code when failed; otherwise null. Never Google’s wording
expiresAt When the link stops working: 30 minutes after creation
createdAt, completedAt completedAt is set when the session leaves pending (completed, cancelled or failed)
url Only in the response that creates the session. The link to send the end user to. A secret: it is never returned again, and only its hash is stored

Creates a session.

Scope gmb
Body application/json
Rate limit 120 sessions per hour per account
Field Required Rule
externalId yes 1–128 characters of letters, digits and _ . : @ + -
redirectUrl yes https (or http on localhost), no credentials, no fragment, up to 2,000 characters, inside a registered return address. A query string is allowed and is kept; the connect flow adds maukirim_session, status, external_id, connection_id and error to it
label no Up to 80 characters; the connection’s label. Blank is ignored

The checks run in this order: the package, externalId, redirectUrl against the allow-list, then the rate limit. A refusal creates nothing.

Terminal window
curl -X POST https://app.maukirim.com/api/v1/gmb/connect-sessions \
-H "Authorization: Bearer mk_live_…" \
-H "Content-Type: application/json" \
-d '{ "externalId": "client-4821", "redirectUrl": "https://app.example.com/google/return?ref=4821", "label": "Kopi Satu" }'
const response = await fetch("https://app.maukirim.com/api/v1/gmb/connect-sessions", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.MAUKIRIM_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
externalId: "client-4821",
redirectUrl: "https://app.example.com/google/return?ref=4821",
label: "Kopi Satu",
}),
})
const { session } = await response.json() // session.url is the link; keep it out of your logs
$curl = curl_init('https://app.maukirim.com/api/v1/gmb/connect-sessions');
curl_setopt_array($curl, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('MAUKIRIM_KEY'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'externalId' => 'client-4821',
'redirectUrl' => 'https://app.example.com/google/return?ref=4821',
'label' => 'Kopi Satu',
]),
CURLOPT_RETURNTRANSFER => true,
]);
$session = json_decode(curl_exec($curl), true)['session'];

201 Created:

{
"ok": true,
"session": {
"id": "gms_7d2q9m4k1x",
"state": "pending",
"externalId": "client-4821",
"connectionId": null,
"error": null,
"expiresAt": "2026-10-14T02:30:00.000Z",
"createdAt": "2026-10-14T02:00:00.000Z",
"completedAt": null,
"url": "https://app.maukirim.com/connect/gmb/gcs_Tq8…"
}
}

Creating a session is not idempotent: there is no Idempotency-Key and every call makes a new link.

When the trip ends the browser is sent to redirectUrl with these parameters added:

Parameter Value
maukirim_session The session id
status success, cancelled or error
external_id Your externalId
connection_id On success only
error access_denied for cancelled; a gmb_* code for error

It never carries a token, the link or any Google identifier. Read the session to confirm the result instead of trusting the query string.

HTTP Code Condition
400 invalid_input The body is not a JSON object, or externalId is missing or outside its pattern
400 gmb_redirect_not_allowed redirectUrl is missing, not absolute, not https (or localhost http), has credentials or a fragment, or is not inside a registered return address
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
429 rate_limited More than 120 sessions in an hour. Carries Retry-After and retryAfterSeconds

One session. It never contains url.

Scope read or gmb
Path id — the session id (gms_…)
Terminal window
curl https://app.maukirim.com/api/v1/gmb/connect-sessions/gms_7d2q9m4k1x -H "Authorization: Bearer mk_live_…"
const response = await fetch(`https://app.maukirim.com/api/v1/gmb/connect-sessions/${sessionId}`, {
headers: { Authorization: `Bearer ${process.env.MAUKIRIM_KEY}` },
})
const { session } = await response.json()
if (session.state === "completed") console.log(session.connectionId)
$curl = curl_init("https://app.maukirim.com/api/v1/gmb/connect-sessions/$sessionId");
curl_setopt_array($curl, [
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('MAUKIRIM_KEY')],
CURLOPT_RETURNTRANSFER => true,
]);
$session = json_decode(curl_exec($curl), true)['session'];
{
"ok": true,
"session": {
"id": "gms_7d2q9m4k1x",
"state": "failed",
"externalId": "client-4821",
"connectionId": null,
"error": "gmb_authorization_failed",
"expiresAt": "2026-10-14T02:30:00.000Z",
"createdAt": "2026-10-14T02:00:00.000Z",
"completedAt": "2026-10-14T02:03:41.000Z"
}
}

No Google call and no budget.

HTTP Code Condition
402 gmb_plan_required The package does not include the connector
403 api_key_scope_denied Neither read nor gmb
404 gmb_session_not_found No such session, or it is not this account’s. Identical for both

Your recent sessions, newest first.

Scope read or gmb
Query param Type Default Validation
limit integer 50 1–200; anything else is 400 invalid_input
externalId string — Keep only the sessions made for this end user. The filter is part of the query, so limit counts this end user’s sessions
Terminal window
curl "https://app.maukirim.com/api/v1/gmb/connect-sessions?externalId=client-4821&limit=20" \
-H "Authorization: Bearer mk_live_…"
{
"ok": true,
"sessions": [
{ "id": "gms_7d2q9m4k1x", "state": "completed", "externalId": "client-4821", "connectionId": "gmc_5p1x8c3m7z", "error": null,
"expiresAt": "2026-10-14T02:30:00.000Z", "createdAt": "2026-10-14T02:00:00.000Z", "completedAt": "2026-10-14T02:03:41.000Z" }
]
}

There is no paging cursor and no total. The list never contains a url.

HTTP Code Condition
400 invalid_input A bad limit
402 gmb_plan_required The package does not include the connector
403 api_key_scope_denied Neither read nor gmb