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).
- Enable My Business Account Management API, My Business Business Information API and Google My Business API in the project.
- 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.
- Add the redirect URI
https://social-publish-kappa.vercel.app/api/integrations/google_business/callbackto the OAuth client (override withGOOGLE_BUSINESS_REDIRECT_URI).
Scope requested: https://www.googleapis.com/auth/business.manage. Access tokens are refreshed automatically.
Post types & media rules
| Rule | Limit |
|---|---|
Text (content) | 1,500 characters |
| Media | At most 1 photo; videos are not supported through the API |
| Event / offer title | 58 characters; required for EVENT and OFFER |
| Event / offer dates | eventStart and eventEnd required for EVENT and OFFER, format YYYY-MM-DDTHH:mm; end must be after start |
| Coupon code | 58 characters (offers) |
| Terms | 5,000 characters (offers) |
| Button link | ctaUrl 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
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
topicType | STANDARD \ | EVENT \ | OFFER | No |
ctaType | none \ | BOOK \ | ORDER \ | SHOP \ |
ctaUrl | string (URL) | No | Button 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. | |
eventTitle | string | No | Event / offer title Only when topicType is EVENT or OFFER. | |
eventStart | string | No | Starts. YYYY-MM-DDTHH:mm in the business's local time. Only when topicType is EVENT or OFFER. | |
eventEnd | string | No | Ends. YYYY-MM-DDTHH:mm in the business's local time. Only when topicType is EVENT or OFFER. | |
couponCode | string | No | Coupon code Only when topicType is OFFER. | |
redeemUrl | string (URL) | No | Redeem online URL Only when topicType is OFFER. | |
terms | string | No | Terms 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
{
"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
| Error | Cause |
|---|---|
Google Business posts allow 1500 characters | content is too long. |
Google Business posts created through the API support photos only | A video was attached. |
Google Business posts allow at most one photo | More than one image. |
A URL is required for this call-to-action button | ctaType other than none/CALL without ctaUrl. |
EVENT posts need a title / a start date/time / an end date/time | Missing event or offer fields. |
Use YYYY-MM-DDTHH:mm (business local time) | Wrong date format (no seconds, no time zone). |
End must be after start | eventEnd is before eventStart. |
| Connect or post fails: API access not approved | Business Profile API access hasn't been granted, or the APIs aren't enabled (quota 0). |
| Connect fails: no locations found | The Google account doesn't manage any Business Profile locations. |
Posts are created with language en.
This page is also available as Markdown.