Platforms

Google Business Profile

Publish updates, events and offers with call-to-action buttons to Google Business Profile locations on Search and Maps.

Overview

The google_business platform creates local posts on Google Business Profile locations (shown on Google Search and Maps). You can post:

  • Updates (STANDARD): text with an optional photo
  • Events (EVENT): title, start and end time
  • Offers (OFFER): title, dates, coupon code, redeem link and terms
  • An optional call-to-action button (Book, Order online, Buy, Learn more, Sign up, Call now)

Connect the account

In Integrations, choose Google Business Profile and sign in with a Google account that manages the business. Every location that account can manage becomes its own account in Relaycast (shown as the location name and city).

App setup (self-hosted)

Google Business Profile uses the same Google Cloud project and OAuth client as YouTube (GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET).

  1. Enable My Business Account Management API, My Business Business Information API and Google My Business API in the project.
  2. Request Business Profile API access from Google. Until Google approves it, every one of these APIs has a quota of 0 requests per minute and connecting or posting fails.
  3. Add the redirect URI https://social-publish-kappa.vercel.app/api/integrations/google_business/callback to the OAuth client (override with GOOGLE_BUSINESS_REDIRECT_URI).

Scope requested: https://www.googleapis.com/auth/business.manage. Access tokens are refreshed automatically.

Post types & media rules

RuleLimit
Text (content)1,500 characters
MediaAt most 1 photo; videos are not supported through the API
Event / offer title58 characters; required for EVENT and OFFER
Event / offer dateseventStart and eventEnd required for EVENT and OFFER, format YYYY-MM-DDTHH:mm; end must be after start
Coupon code58 characters (offers)
Terms5,000 characters (offers)
Button linkctaUrl required for every button except CALL

eventStart and eventEnd are wall-clock times in the business's own time zone, not UTC. The CALL button uses the phone number on the Business Profile.

Options

OptionTypeRequiredDefaultDescription
topicTypeSTANDARD \EVENT \OFFERNo
ctaTypenone \BOOK \ORDER \SHOP \
ctaUrlstring (URL)NoButton link. Required for every button except Call now (which uses the business phone number). Only when ctaType is BOOK or ORDER or SHOP or LEARN_MORE or SIGN_UP.
eventTitlestringNoEvent / offer title Only when topicType is EVENT or OFFER.
eventStartstringNoStarts. YYYY-MM-DDTHH:mm in the business's local time. Only when topicType is EVENT or OFFER.
eventEndstringNoEnds. YYYY-MM-DDTHH:mm in the business's local time. Only when topicType is EVENT or OFFER.
couponCodestringNoCoupon code Only when topicType is OFFER.
redeemUrlstring (URL)NoRedeem online URL Only when topicType is OFFER.
termsstringNoTerms and conditions Only when topicType is OFFER.

Examples

Offer with a button

curl -X POST https://social-publish-api.onrender.com/v1/posts \
  -H "x-access-key: $RELAYCAST_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "content": "20% off all coffee beans this weekend. Show the code in store or use it online.",
    "media": [{ "url": "https://cdn.example.com/beans.jpg", "type": "image" }],
    "targets": [{
      "accountId": "0e1d2c3b-4a59-4687-b7c6-d5e4f3a2b1c0",
      "options": {
        "topicType": "OFFER",
        "eventTitle": "Weekend bean sale",
        "eventStart": "2026-11-14T08:00",
        "eventEnd": "2026-11-15T18:00",
        "couponCode": "BEANS20",
        "redeemUrl": "https://example.com/shop",
        "terms": "One use per customer.",
        "ctaType": "SHOP",
        "ctaUrl": "https://example.com/shop"
      }
    }],
    "scheduledFor": "2026-11-13T09:00:00Z"
  }'
const res = await fetch("https://social-publish-api.onrender.com/v1/posts", {
  method: "POST",
  headers: {
    "x-access-key": process.env.RELAYCAST_API_KEY!,
    "content-type": "application/json",
  },
  body: JSON.stringify({
    content: "20% off all coffee beans this weekend. Show the code in store or use it online.",
    media: [{ url: "https://cdn.example.com/beans.jpg", type: "image" }],
    targets: [
      {
        accountId: "0e1d2c3b-4a59-4687-b7c6-d5e4f3a2b1c0",
        options: {
          topicType: "OFFER",
          eventTitle: "Weekend bean sale",
          eventStart: "2026-11-14T08:00",
          eventEnd: "2026-11-15T18:00",
          couponCode: "BEANS20",
          redeemUrl: "https://example.com/shop",
          terms: "One use per customer.",
          ctaType: "SHOP",
          ctaUrl: "https://example.com/shop",
        },
      },
    ],
    scheduledFor: "2026-11-13T09:00:00Z",
  }),
});
const { data } = await res.json();
import os, requests

res = requests.post(
    "https://social-publish-api.onrender.com/v1/posts",
    headers={"x-access-key": os.environ["RELAYCAST_API_KEY"]},
    json={
        "content": "20% off all coffee beans this weekend. Show the code in store or use it online.",
        "media": [{"url": "https://cdn.example.com/beans.jpg", "type": "image"}],
        "targets": [{
            "accountId": "0e1d2c3b-4a59-4687-b7c6-d5e4f3a2b1c0",
            "options": {
                "topicType": "OFFER",
                "eventTitle": "Weekend bean sale",
                "eventStart": "2026-11-14T08:00",
                "eventEnd": "2026-11-15T18:00",
                "couponCode": "BEANS20",
                "redeemUrl": "https://example.com/shop",
                "terms": "One use per customer.",
                "ctaType": "SHOP",
                "ctaUrl": "https://example.com/shop",
            },
        }],
        "scheduledFor": "2026-11-13T09:00:00Z",
    },
)
data = res.json()["data"]

Update with a Call now button

Request body
{
  "content": "We're open late this Friday until 11pm.",
  "targets": [{
    "accountId": "0e1d2c3b-4a59-4687-b7c6-d5e4f3a2b1c0",
    "options": { "topicType": "STANDARD", "ctaType": "CALL" }
  }],
  "publishNow": true
}

Analytics & comments

Post analytics are not available: Google retired the only per-post insights API in 2023, and the remaining Performance API only reports location-level metrics. Reviews, Q&A and messaging are not supported.

Limitations & common errors

ErrorCause
Google Business posts allow 1500 characterscontent is too long.
Google Business posts created through the API support photos onlyA video was attached.
Google Business posts allow at most one photoMore than one image.
A URL is required for this call-to-action buttonctaType other than none/CALL without ctaUrl.
EVENT posts need a title / a start date/time / an end date/timeMissing event or offer fields.
Use YYYY-MM-DDTHH:mm (business local time)Wrong date format (no seconds, no time zone).
End must be after starteventEnd is before eventStart.
Connect or post fails: API access not approvedBusiness Profile API access hasn't been granted, or the APIs aren't enabled (quota 0).
Connect fails: no locations foundThe Google account doesn't manage any Business Profile locations.

Posts are created with language en.

This page is also available as Markdown.