This section as Markdown: View Download

Google Business Profile Integration

Connect your agent to Google Business Profile to read the Google reviews of the locations you choose, draft a reply to each new review, and post the replies you approve.

Overview

The Google Business Profile integration powers the int-google-business-reviews skill (Google Business Reviews). The agent works through Google's Business Profile APIs with an OAuth client from your own Google Cloud project. It reads the reviews of the Business Profile locations you selected, drafts one reply per new review in the reviewer's language, sends the drafts to you, and posts a reply only after you approve it.

Skills that use this integration:

  • int-google-business-reviews — Reads the Google reviews of the selected locations, drafts replies, posts approved replies, and follows Google's moderation of each posted reply.

Bundled task:

  • cs-cron-google-review-scanner — every 2 hours (0 */2 * * *): scans the selected locations for new reviews and sends you the drafted replies. It runs only when Google Business Profile is connected.

Availability

ModeStatusNotes
"own"Available — the only modeAn OAuth client from your own Google Cloud project. Google must approve that project for Business Profile API access before any call works.
"wiro"Not availableWiro-managed one-click connect is not available for Google Business Profile.

Google approves the project first. You request Business Profile API access for your Google Cloud project, and Google reviews requests within 14 days. Until the project is approved, every call to Google fails, and connecting typically ends with "No accounts available". See Google Cloud setup.

Prerequisites

  • A verified Business Profile. Google asks for a profile that has been verified and active for 60+ days, with the business website listed, before it grants API access.
  • A Google account that is an owner or manager of the Business Profile. Request API access with its email, and connect with the Google account that manages the business.
  • A Google Cloud project approved for Business Profile API access, with an OAuth client of type Web application — see Google Cloud setup.
  • An agent with int-google-business-reviews enabled — see Using the Skill.
  • For API integrations only: a Wiro API key (Authentication), a deployed agent (Agent Overview) and its useragentguid, and an HTTPS return URL that your backend controls. http://localhost and http://127.0.0.1 are accepted for local development only.

Google Cloud setup

Do these steps once, in this order, in the Google Cloud project whose OAuth client the agent will use.

Step 1: Create or pick a project

In the Google Cloud Console, create a project or pick an existing one. Copy its Project number from the project dashboard; you need it for the access request in Step 2.

Step 2: Request Business Profile API access

  1. Open Google's Business Profile API contact form and choose Application for Basic API Access.
  2. Apply for the project from Step 1, with an email that is an owner or manager of the Business Profile.
  3. Google asks for a profile that has been verified and active for 60+ days, with the business website listed, and reviews requests within 14 days. See Google's prerequisites and FAQ.

Step 3: Check the approval

Open IAM & Admin → Quotas for the project and look at the requests-per-minute quota of the Business Profile APIs:

  • 0 requests per minute — not approved yet. Every call to Google fails until this changes.
  • 300 requests per minute — approved. Continue with Step 4.

Step 4: Enable the APIs

After approval, enable these three APIs in the project:

Step 5: Set the audience

In Google Auth Platform → Audience:

  • Choose External.
  • Set the publishing status to In production. While the app is in Testing, Google expires the refresh token after 7 days (Google's OAuth 2.0 documentation), and the agent loses access every week.

When you connect, Google may warn that the app is unverified. It is your own app: continue as the app's owner.

Step 6: Add the scope

In Data Access, add this scope:

https://www.googleapis.com/auth/business.manage

Step 7: Create the OAuth client

In Clients, create an OAuth client of type Web application and add this Authorized redirect URI, exactly as written:

https://api.wiro.ai/v1/UserAgentOAuth/GBPCallback

Copy the Client ID and the Client Secret.

Connect in the Wiro dashboard

  1. Open your agent, go to Credentials, and find the Google Business Profile card.
  2. Paste the OAuth Client ID and OAuth Client Secret from Step 7.
  3. Click Connect Google Business Profile and sign in with the Google account that manages the business. If Google warns that the app is unverified, continue as the app's owner.
  4. Choose the Business Profile accounts the agent may use.
  5. Choose the locations. Up to 100 locations per account are listed.
  6. Wiro saves the selection and restarts the agent if it was running.

To change the locations later, use Manage on the Google Business Profile card. The agent reads and answers reviews only for the locations you selected.

What the agent does

  • Reads new reviews of the selected locations.
  • Drafts one reply per new review, in the reviewer's language. When Google shows a translated review, the agent answers the original text.
  • Follows your review preferences. Before drafting, it reads the cs-review-preferences custom skill: tone, length by rating, contact line, sign-off, and house rules.
  • Sends the drafts to you, numbered, in chat and on Telegram if it is connected. Answer in chat:
    • ok 1 — approve draft 1
    • ok all — approve every draft
    • skip 2 — skip draft 2
    • edit 1: <text> — replace draft 1 with your text
  • Posts approved replies through the Google Business Profile API.
  • Follows Google's moderation. Google reviews every reply before it is public: a reply is PENDING, then APPROVED, or REJECTED with a policy violation. The agent tells you about rejected replies.
  • Edits or deletes a posted reply only when you ask.
  • Starts with recent reviews. The first scan of a location drafts replies only for unanswered reviews from the last 30 days, and reports how many older reviews have no reply.
  • Escalates instead of answering. Legal, health, safety and discrimination complaints go to you instead of getting a reply.
  • Never offers incentives for reviews, and never shares reviewer details beyond their public first name.
  • Keeps review content for at most 30 days, as Google's API policy requires.

What the agent cannot do

These are outside this integration:

  • Changing business details — name, hours, address, or photos.
  • Creating posts.
  • Answering Q&A.
  • Reporting or removing a review. The business does that in Google Maps.
  • Replying for locations you did not select.

Approvals

  • Every reply waits for your approval by default, one approval per reply. The rule lives in the cs-approval-policy custom skill.
  • Why: Google's Business Profile API policies say automated replies need the business's prior, specific and express consent. This is why replies wait for your approval by default.
  • Auto-approve rules. You can add an override to cs-approval-policy, for example "auto-approve replies to 5-star reviews". Matching replies are then posted without asking, at most 5 per scan unless cs-review-preferences sets another number.

Limits

LimitValue
Reply lengthAt most 4096 bytes. Letters such as ç, ğ, ş and é count as 2 bytes.
Google API quota300 requests per minute for the Google Cloud project after approval (0 before).
Locations listed per accountUp to 100.
Automatic repliesAt most 5 per scan, unless cs-review-preferences sets another number.
Review content keptAt most 30 days.

Scheduled task

TaskSkill keyDefault scheduleWhat it does
Review scannercs-cron-google-review-scanner0 */2 * * * (every 2 hours)Reads new reviews of the selected locations, drafts replies, and sends them to you for approval; posts the replies an auto-approve rule allows. Runs only when Google Business Profile is connected.

To change what the scanner does, edit the custom skills it reads rather than the task:

  • cs-review-preferences — tone, length by rating, contact line, sign-off, house rules, and the number of automatic replies per scan.
  • cs-approval-policy — which replies wait for your approval.

Connect through the API

Use this flow when you build your own settings screen on top of Wiro agents. Complete the Google Cloud setup first. Every request is authenticated as described in Authentication.

Step 1: Save your OAuth client

curl -X POST "https://api.wiro.ai/v1/UserAgent/CredentialUpsert" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "useragentguid": "your-useragent-guid",
    "fields": [
      { "credentialkey": "google-business", "fieldname": "clientid", "fieldvalue": "YOUR_GOOGLE_OAUTH_CLIENT_ID" },
      { "credentialkey": "google-business", "fieldname": "clientsecret", "fieldvalue": "YOUR_GOOGLE_OAUTH_CLIENT_SECRET" },
      { "credentialkey": "google-business", "fieldname": "authmethod", "fieldvalue": "own" }
    ]
  }'

Response: { "result": true, "errors": [], "applied": 3 }. clientid and clientsecret are not returned by POST /UserAgent/Detail, so check result and errors[] here.

Step 2: Start the connection

curl -X POST "https://api.wiro.ai/v1/UserAgentOAuth/OAuthConnect" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "useragentguid": "your-useragent-guid",
    "credentialkey": "google-business",
    "redirecturl": "https://your-app.com/settings/integrations",
    "authmethod": "own"
  }'

Response:

{
  "result": true,
  "errors": [],
  "authorizeUrl": "https://accounts.google.com/o/oauth2/v2/auth?client_id=...&redirect_uri=https%3A%2F%2Fapi.wiro.ai%2Fv1%2FUserAgentOAuth%2FGBPCallback&response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fbusiness.manage&state=...&access_type=offline&prompt=consent"
}

Redirect the user's browser to authorizeUrl with a full-page redirect rather than a popup. Wiro requests the business.manage scope with offline access, so Google issues a refresh token.

Always send authmethod: "own". Without it, or with "wiro", OAuthConnect returns Wiro-managed OAuth is not enabled for Google Business Profile.

State TTL: Wiro keeps the OAuth state for 15 minutes. If the user takes longer on Google's consent screen, the connection fails with gbp_error=session_expired; call OAuthConnect again.

Step 3: Handle the return

After the user approves, Google sends them to Wiro's callback (https://api.wiro.ai/v1/UserAgentOAuth/GBPCallback). Wiro exchanges the code, lists the Business Profile accounts the Google user can access, stores the tokens server-side, and redirects the browser to your redirecturl.

Success URL looks like:

https://your-app.com/settings/integrations?gbp_connected=true&gbp_accounts=%5B%7B%22id%22%3A%22112233445566778899001%22%2C%22name%22%3A%22Acme%20Bakery%22%7D%5D
  • gbp_accounts is encodeURIComponent(JSON.stringify([...])).
  • Each element is { id, name }: id is the numeric Business Profile account ID as a string, name is the account name.
  • The list is never empty on success. When no Business Profile account can be listed, the callback returns gbp_error=no_accounts instead; right after setup this usually means Google has not approved the project yet or an API is disabled (see Troubleshooting).
  • On failure the URL carries gbp_error=<code>, and possibly gbp_error_detail.

Parse in the browser:

const params = new URLSearchParams(window.location.search);

if (params.get("gbp_connected") === "true") {
  const accounts = JSON.parse(params.get("gbp_accounts") || "[]");
  presentAccountPicker(accounts);
} else if (params.get("gbp_error")) {
  handleError(params.get("gbp_error"));
}

Step 4: Save the account selection

This call is required, even when only one account is returned:

curl -X POST "https://api.wiro.ai/v1/UserAgentOAuth/SetPickerAccounts" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "useragentguid": "your-useragent-guid",
    "credentialkey": "google-business",
    "accounts": [
      { "accountid": "112233445566778899001", "accountname": "Acme Bakery" }
    ]
  }'

Response:

{
  "result": true,
  "errors": [],
  "accounts": [
    { "id": "112233445566778899001", "name": "Acme Bakery" }
  ]
}

Behavior:

  • Send one or more { accountid, accountname } entries picked from gbp_accounts (id becomes accountid, name becomes accountname). Non-digits in accountid are stripped server-side.
  • Each call replaces the previous account selection. Locations already chosen for accounts that stay selected are kept; locations of removed accounts are dropped.
  • If the agent was running, Wiro restarts it.

Step 5: Choose the locations

Discover the locations of the selected accounts:

curl -X POST "https://api.wiro.ai/v1/UserAgentOAuth/DiscoverPickerItems" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "useragentguid": "your-useragent-guid",
    "credentialkey": "google-business",
    "pickerkey": "locations"
  }'

Response:

{
  "result": true,
  "errors": [],
  "pickerkey": "locations",
  "groups": [
    {
      "parent": {
        "accountid": "112233445566778899001",
        "accountname": "Acme Bakery"
      },
      "items": [
        { "locationid": "9876543210987654321", "locationtitle": "Acme Bakery Downtown" },
        { "locationid": "1234567890123456789", "locationtitle": "Acme Bakery Riverside" }
      ]
    }
  ]
}

Up to 100 locations per account are listed. A group carries errorcode and an empty items array when Google did not return the locations of that account.

Save the selection within five minutes. Copy locationid and locationtitle from the discovery response unchanged, and include every group returned without an errorcode exactly once; an empty items array selects no location for that account:

curl -X POST "https://api.wiro.ai/v1/UserAgentOAuth/SetPickerAccounts" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "useragentguid": "your-useragent-guid",
    "credentialkey": "google-business",
    "pickerkey": "locations",
    "selections": [
      {
        "parentvalue": "112233445566778899001",
        "items": [
          { "locationid": "9876543210987654321", "locationtitle": "Acme Bakery Downtown" }
        ]
      }
    ]
  }'

Response:

{
  "result": true,
  "errors": [],
  "pickerkey": "locations",
  "locationmappings": [
    {
      "accountid": "112233445566778899001",
      "accountname": "Acme Bakery",
      "locationid": "9876543210987654321",
      "locationtitle": "Acme Bakery Downtown"
    }
  ]
}

The dashboard runs this step automatically after the account selection. If the agent was running, Wiro restarts it.

Step 6: Verify the connection

curl -X POST "https://api.wiro.ai/v1/UserAgentOAuth/OAuthStatus" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "useragentguid": "your-useragent-guid",
    "credentialkey": "google-business"
  }'

Response:

{
  "result": true,
  "errors": [],
  "connected": true,
  "accounts": [
    { "id": "112233445566778899001", "name": "Acme Bakery" }
  ],
  "connectedat": "2026-10-17T09:00:00.000Z",
  "tokenexpiresat": "2026-10-17T10:00:00.000Z",
  "pickersteps": {
    "locations": {
      "pickerkey": "locations",
      "optional": false,
      "configured": true,
      "groups": [
        {
          "parent": {
            "accountid": "112233445566778899001",
            "accountname": "Acme Bakery"
          },
          "items": [
            { "locationid": "9876543210987654321", "locationtitle": "Acme Bakery Downtown" }
          ]
        }
      ]
    }
  },
  "locationmappings": [
    {
      "accountid": "112233445566778899001",
      "accountname": "Acme Bakery",
      "locationid": "9876543210987654321",
      "locationtitle": "Acme Bakery Downtown"
    }
  ]
}

Field notes:

  • connected is true when the connection has a current access token and at least one account is selected. It does not look at locations: pickersteps.locations.configured is true once at least one location is selected.
  • tokenexpiresat is the expiry of the current access token (about one hour ahead). Wiro renews the access token while the agent is running.
  • connectedat is the time of the last successful Connect.

Step 7: Start the agent if it's not running

curl -X POST "https://api.wiro.ai/v1/UserAgent/Start" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{ "guid": "your-useragent-guid" }'

Check POST /UserAgent/Detail first: if setuprequired is still true, a credential the agent requires is incomplete, and Start will refuse. See Agent Credentials — Setup Required.

Credential fields

FieldTypeDescription
clientidstringOAuth Client ID of your Google Cloud OAuth client (own mode). Not returned by POST /UserAgent/Detail.
clientsecretstring (secret)OAuth Client Secret (own mode). Encrypted at rest; not returned by POST /UserAgent/Detail.
accountidarray of stringsNumeric IDs of the selected Business Profile accounts. Required. Filled by the connection flow (SetPickerAccounts).
accountnamearray of stringsNames of the selected accounts, in the same order. Filled by the connection flow.
locationmappingsarray of objectsThe selected locations, one { accountid, accountname, locationid, locationtitle } entry per location. Server-managed; written by the location step.

POST /UserAgent/CredentialUpsert rejects writes to accountid, accountname and locationmappings with <Field label> is managed by the connection flow. Access and refresh tokens are stored server-side and are never returned by any endpoint.

API Reference

All endpoints require Wiro authentication — see Authentication for x-api-key + optional signature headers.

POST /UserAgentOAuth/OAuthConnect

ParameterTypeRequiredDescription
useragentguidstringYesAgent instance GUID.
credentialkeystringYes"google-business".
redirecturlstringYesHTTPS URL (or http://localhost / http://127.0.0.1 for development) where the browser returns after Google.
authmethodstringYes"own", the only available mode.

Response: { result, errors, authorizeUrl }. If result: false, inspect errors[0].message — common messages: Invalid redirect URL, User agent not found or unauthorized, Wiro-managed OAuth is not enabled for Google Business Profile (no authmethod, or "wiro"), and Google Business Profile credentials not configured (the Client ID or Client Secret is not saved).

GET /UserAgentOAuth/GBPCallback

Server-side endpoint invoked by Google. You don't call it: you register it as the Authorized redirect URI of your OAuth client and handle the final redirect back to your redirecturl.

Query paramMeaning
gbp_connected=trueAuthorization completed.
gbp_accountsURL-encoded JSON array of { id, name } for the Business Profile accounts the Google user can access. Always at least one entry.
gbp_error=<code>The connection failed. See Troubleshooting.
gbp_error_detailOptional detail that can accompany gbp_error.

POST /UserAgentOAuth/SetPickerAccounts

The same endpoint saves both picker steps.

Account selection:

ParameterTypeRequiredDescription
useragentguidstringYesAgent instance GUID.
credentialkeystringYes"google-business".
accountsarrayYesOne or more { accountid, accountname } entries. accountid is the numeric account ID (non-digits stripped); accountname is the display name shown in dashboards and OAuthStatus responses.

Response: { result, errors, accounts: [{id, name}, ...] }. Replaces the previous account selection and restarts the agent if it was running.

Location selection, after DiscoverPickerItems:

ParameterTypeRequiredDescription
useragentguidstringYesAgent instance GUID.
credentialkeystringYes"google-business".
pickerkeystringYes"locations".
selectionsarrayYesOne { parentvalue, items } entry for every group discovery returned without an errorcode. parentvalue is the account ID; each item carries locationid and locationtitle. Empty items selects no location for that account.

Response: { result, errors, pickerkey: "locations", locationmappings: [{accountid, accountname, locationid, locationtitle}] }.

POST /UserAgentOAuth/DiscoverPickerItems

Lists the locations of the selected Business Profile accounts, grouped by account. Call it after the account selection is saved.

ParameterTypeRequiredDescription
useragentguidstringYesAgent instance GUID.
credentialkeystringYes"google-business".
pickerkeystringYes"locations".

Response: { result, errors, pickerkey: "locations", groups: [{parent: {accountid, accountname}, items: [{locationid, locationtitle}], errorcode?}] }. Up to 100 locations per account. The access token stays server-side. Wiro keeps the discovered candidates for five minutes; save the location selection before they expire.

POST /UserAgentOAuth/OAuthStatus

ParameterTypeRequiredDescription
useragentguidstringYesAgent instance GUID.
credentialkeystringYes"google-business".

Response fields:

FieldTypeDescription
connectedbooleantrue when the connection has a current access token and at least one selected account. Use setuprequired from POST /UserAgent/Detail for whole-agent readiness.
accountsarrayOne { id, name } per selected account (id = accountid, name = accountname).
locationmappingsarrayThe selected locations, one { accountid, accountname, locationid, locationtitle } entry each.
pickersteps.locationsobjectLocation selection grouped by account for UI rendering: { pickerkey, optional, configured, groups[] }.
connectedatstringISO timestamp of the last successful Connect.
tokenexpiresatstringISO expiry of the current access token (about one hour ahead while the agent runs).

POST /UserAgentOAuth/OAuthDisconnect

Body: { useragentguid, credentialkey: "google-business" }. Clears the tokens and the account and location selections in Wiro. Your Client ID and Client Secret are kept, so you can connect again without re-entering them. Wiro does not ask Google to revoke the authorization.

curl -X POST "https://api.wiro.ai/v1/UserAgentOAuth/OAuthDisconnect" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "useragentguid": "your-useragent-guid",
    "credentialkey": "google-business"
  }'

Response: { "result": true, "errors": [] }. Running agents restart automatically.

Token lifecycle

Wiro renews the access token with the stored refresh token while the agent is running. While the consent screen is in Testing, Google expires the refresh token after 7 days; set it to In production to avoid weekly disconnects. If Google revokes the access, or OAuthStatus keeps reporting connected: false, call OAuthDisconnect and run Steps 2–5 again. There is no customer-facing token-refresh endpoint.

Using the Skill

Google Review Manager has int-google-business-reviews on by default. On any other agent, enable it with POST /UserAgent/SkillsApply (see Agent Skills → Toggling Integration Skills):

curl -X POST "https://api.wiro.ai/v1/UserAgent/SkillsApply" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "useragentguid": "your-useragent-guid",
    "idempotencyKey": "550e8400-e29b-41d4-a716-446655440002",
    "skills": {
      "int-google-business-reviews": true
    }
  }'

Pricing: like the App Store and Google Play review skills, int-google-business-reviews adds $1 and 100 credits per month to the agent's skill weights (monthly_price_weight_usd: 1, monthly_credits_weight: 100). Preview the result with POST /UserAgent/PricingPreview before you apply it. As with every agent turn, scans and replies are billed on the LLM tokens they use.

Adjust the scanner's schedule with enabled and interval only — the task body (value) is owned by the bundled integration skill and silently dropped on writes:

curl -X POST "https://api.wiro.ai/v1/UserAgent/CustomSkillUpsert" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "useragentguid": "your-useragent-guid",
    "skillkey": "cs-cron-google-review-scanner",
    "enabled": true,
    "interval": "0 */4 * * *"
  }'

To change how replies read, edit cs-review-preferences; to change which replies wait for approval, edit cs-approval-policy — see Agent Skills → Updating Preferences.

Troubleshooting

Error codeMeaningWhat to do
no_accountsSign-in worked, but no Business Profile account could be listed for this Google user. Right after setup this usually means the project is not approved yet (quota 0) or an API is disabled.Check Steps 3 and 4 of the Google Cloud setup, then connect again. Otherwise connect with the Google account that owns or manages the business.
authorization_deniedThe user cancelled on Google's consent screen, or Google returned an error instead of an authorization code.Start again and approve the consent screen.
session_expiredMore than 15 minutes passed between OAuthConnect and the return from Google, or the state was already used.Call OAuthConnect again.
missing_paramsThe callback was opened without an OAuth state.Don't open the callback URL directly. Start a new flow with OAuthConnect.
token_exchange_failedGoogle did not return an access token for the authorization code, usually because of a wrong Client Secret or a redirect URI mismatch.Re-copy the Client Secret, check the redirect URI, and connect again.
useragent_not_foundThe agent was deleted, or is no longer owned by the account that started the flow, before Google returned.Start again with OAuthConnect for an existing agent.
internal_errorUnexpected server error during callback processing.Retry once. If it persists, contact Wiro support with the timestamp and your useragentguid.
Wiro-managed OAuth is not enabled for Google Business ProfileReturned in OAuthConnect's errors[] when authmethod is missing or "wiro".Send authmethod: "own".
Google Business Profile credentials not configuredReturned in OAuthConnect's errors[] when the Client ID or Client Secret is not saved.Save both with POST /UserAgent/CredentialUpsert (Step 1), then retry.
Picker candidates expired. Discover them again.More than five minutes passed after location discovery, or the account selection changed.Call DiscoverPickerItems again, then resubmit the location selection.
selections must include every available parent exactly onceThe location selection left out or repeated an account group.Send one selections[] entry per group returned without errorcode; use items: [] to select no location for an account.

Because no valid state is left to read your redirecturl from, missing_params and session_expired send the browser to https://wiro.ai with the error parameter instead of to your app.

"No accounts available" right after connecting

The Google Cloud project is usually not approved yet (0 requests per minute in IAM & Admin → Quotas), or one of the three APIs from Step 4 is disabled. Connect again once Google has approved the project and the APIs are enabled.

redirect_uri_mismatch on Google's page

The Authorized redirect URI on your OAuth client does not exactly match https://api.wiro.ai/v1/UserAgentOAuth/GBPCallback. Fix it in Clients; Google can take from a few minutes to a few hours to apply the change (Google Cloud help).

The connection drops every week

The consent screen is still in Testing, where Google expires the refresh token after 7 days. Set the publishing status to In production in Audience, then connect again.

The agent reports a Google access problem

The agent tells you in chat when Google says the project is not approved, an API is disabled, the account cannot manage a location, or the connection expired. Fix the cause in Google Cloud or in the Business Profile. For an expired connection, click Disconnect on the Google Business Profile card, then connect again.

Google rejected a reply

Google reviews every reply before it is public. When it marks a reply REJECTED for a policy violation, the agent tells you; ask it to edit or delete that reply.

connected: true, but no reviews are answered

connected covers the account selection only. Check that at least one location is selected: use Manage on the Google Business Profile card, or run the location step (Step 5) through the API.

Multi-Tenant Architecture

For SaaS products connecting many businesses through a single Wiro-powered backend:

  1. One Wiro agent instance per business. Call POST /UserAgent/Deploy during onboarding, then run the connection flow for that business's useragentguid.
  2. Tokens are isolated per agent instance. One business's Google authorization is never visible to another — they live under different useragentguid values.
  3. The consent screen shows your app. The connection uses your own OAuth client, so Google shows the app name of your Google Cloud project.
  4. The quota belongs to the Google Cloud project. Every connection made with the same OAuth client shares its 300 requests per minute.