Google — exchange OAuth code for access token

Overview

Exchanges a Google OAuth code for an access token, stores it (google_access_tokens), and then branches: with connect_google=1 + company_id_hash it links the token to that company and syncs its GBP locations (dispatching DuplicateGMBDebugger). With source=app it returns the token plus fetched account/location data; otherwise it returns only the stored token id + token. Requires the business.manage scope to have been granted at consent. Records gbp_connection_events.

Prerequisites

  • Either a bearer token in the Authorization header, or the invite hash this endpoint accepts in place of one.
  • Values for the required query parameter code — see the table below.

Base URL

EnvironmentURL
Productionhttps://production-api.shoutaboutus.com
Developmenthttps://development-api.shoutaboutus.com

Endpoint

GET /api/v1/google/access-token

Authentication

  • A bearer token is optional here. Send one to act as a signed-in user, or supply the documented hash instead.

  • Use a bearer token (api guard).

  • OR use the public connect-page pair (connect_google=1 + company_id_hash).

  • OR use an invite hash.

  • No token is needed for the latter two.

Rate limit

  • 30 requests/min per IP (public).

Query parameters

FieldTypeRequiredDescription
codestringRequiredGoogle OAuth authorization code.
connect_googleinteger (0,1)Optional1 → link token to company + sync GBP locations.
company_id_hashstringOptionalRequired when connect_google=1. Hashid of the target company.
sourcestring (app,web)Optionalapp returns account+location data; picks the redirect URI.
hashstringOptionalInvite hash encoding [store_id, 15]; grants access without a token.

How it works

  • 200 with the token payload (web/app) or the synced location list (connect_google=1). 400 for an invalid company hash. Note: missing business.manage scope, absent access token, and Google token-endpoint errors are surfaced via errorResponse (HTTP 500) with an explanatory message.

Response

200 OK (web flow) · 200

{
  "data": {
    "google_access_token_id": 42,
    "google_access_token": "<google-access-token>",
    "account_data": []
  }
}

200 OK (connect_google=1, locations synced) · 200

{
  "data": [
    {
      "name": "Demo Store",
      "url": "https://maps.google.com/?cid=1234567890"
    }
  ]
}

400 Invalid company · 400

{
  "message": "Bad Request",
  "status": "error",
  "errors": "Invalid request!"
}

500 Scope not granted · 500

{
  "message": "You still need to grant us access to your Google Business Profile. Please be sure the check boxes are all selected.",
  "status": "error",
  "errors": []
}

Errors

StatusMeaning
400Invalid company
401The bearer token is missing, expired or invalid
422The request failed validation — the response names the fields
500Scope not granted

Example request

curl --request GET \
  --url "https://production-api.shoutaboutus.com/api/v1/google/access-token?code=<google_oauth_code>&source=web" \
  --header 'Authorization: Bearer <bearer-token>' \
  --header 'Accept: application/json'

Did this page help you?