Reelspan publishes updates, events and offers (Google's "local posts") to a Google Business Profile location. You send the text and, if you like, a photo; Reelspan creates the post with an optional button and returns its link on Google.
What you can post
| Post | How | Notes |
|---|---|---|
| Text update | POST /v1/posts/text |
Up to 1,500 characters |
| Update with a photo | POST /v1/posts/photos |
One photo |
A post is a standard "What's new" update unless you make it an event or an offer with gbp_topic_type. Videos and photos for the profile's gallery aren't supported. Reelspan handles for you:
- The photo. Google fetches it from a short-lived signed link while the update is made.
- The button. Add a call-to-action button with a link, such as "Book" or "Order online".
Connect the account
Google Business connects with a Google sign-in: in the dashboard go to Accounts → Google Business, or send a white-label connect link. Sign in with a Google account that manages the Business Profile.
Google Business posting needs a Google Cloud project on Reelspan's side with Google's Business Profile APIs approved. Until it is set up, connecting fails with a message saying Google Business isn't set up yet, so it may not be available to you yet.
Choose the location
When you connect, the account's first location becomes the one posts go to. List the locations, with the chosen one marked, with GET /v1/google-business/locations:
curl "https://api.reelspan.com/v1/google-business/locations?profile=my-brand" \
-H "Authorization: Bearer $REELSPAN_API_KEY"const { locations } = await reelspan.request('GET', '/v1/google-business/locations', { query: { profile: 'my-brand' } });locations = reelspan.request("GET", "/v1/google-business/locations", query={"profile": "my-brand"})["locations"]{
"success": true,
"locations": [
{ "id": "accounts/1122334455/locations/998877", "name": "locations/998877", "title": "My Brand Soho", "account_id": "accounts/1122334455", "selected": true },
{ "id": "accounts/1122334455/locations/998878", "name": "locations/998878", "title": "My Brand Camden", "account_id": "accounts/1122334455", "selected": false }
],
"selected_location_id": "accounts/1122334455/locations/998877",
"selected_location_name": "My Brand Soho"
}The list is the one saved when the account was connected. Add refresh=true to read it again from Google (and save it), for example after adding a location; if the chosen location is gone, the choice is cleared.
To send posts to another location, choose it with POST /v1/google-business/location (needs the profiles scope). location_id can be the full id, locations/…, or the bare number:
curl -X POST https://api.reelspan.com/v1/google-business/location \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"profile": "my-brand", "location_id": "998878"}'{ "success": true, "location_id": "accounts/1122334455/locations/998878", "location_name": "My Brand Camden" }A location that isn't on the account gets 404 location_not_found, with the available ones in the message. DELETE /v1/google-business/location with {"profile": "my-brand"} clears the choice: then each post needs google_business_location_id, unless the account has one location.
To post to another location just once, send it in google_business_location_id on the post, in any of the same three forms.
Example
An update with a photo and a "Book" button:
curl -X POST https://api.reelspan.com/v1/posts/photos \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-F "user=my-brand" \
-F "platform[]=google_business" \
-F "google_business_title=Spring menu is here: wild garlic risotto and rhubarb tart, from this Friday." \
-F "google_business_cta=BOOK" \
-F "google_business_cta_url=https://example.com/book" \
-F "photos[][email protected]"import { Reelspan } from 'reelspan';
import { readFile } from 'node:fs/promises';
const reelspan = new Reelspan();
const post = await reelspan.posts.photos({
user: 'my-brand',
platforms: ['google_business'],
photos: [{ data: await readFile('photo1.jpg'), name: 'photo1.jpg', type: 'image/jpeg' }],
extra: {
google_business_title: 'Spring menu is here: wild garlic risotto and rhubarb tart, from this Friday.',
google_business_cta: 'BOOK',
google_business_cta_url: 'https://example.com/book',
},
});from reelspan import Reelspan
reelspan = Reelspan()
post = reelspan.posts.photos(
"my-brand", ["google_business"], ["photo1.jpg"],
extra={
"google_business_title": "Spring menu is here: wild garlic risotto and rhubarb tart, from this Friday.",
"google_business_cta": "BOOK",
"google_business_cta_url": "https://example.com/book",
},
)The network's id in platform[] is google_business.
Fields
| Field | Type | Values | What it does |
|---|---|---|---|
google_business_title |
string | up to 1,500 characters | The update's text. Falls back to title. Longer text is cut, with a warning. |
google_business_cta_url |
string | URL | Adds a button that opens this link. Without it there is no button. |
google_business_cta |
string | LEARN_MORE (default), BOOK, ORDER, SHOP, SIGN_UP |
The button's label: Learn more, Book, Order online, Buy, Sign up. Used only with google_business_cta_url. |
google_business_language |
string | language code, default en |
The language of the update. |
google_business_location_id |
string | accounts/…/locations/…, locations/… or the bare id |
The location to post to, instead of the chosen one. |
gbp_topic_type |
string | STANDARD (default), EVENT, OFFER |
An update, an event or an offer. |
gbp_event_title |
string | up to 58 characters | Events and offers: the title. Falls back to the first line of title. |
gbp_event_start, gbp_event_end |
string | ISO 8601 date (2026-12-05) or date and time (2026-12-05T18:00:00Z) |
Events and offers: when it runs. Both are required. A date and time is read in UTC. |
gbp_coupon_code |
string | Offers: a code to show. | |
gbp_redeem_url |
string | URL | Offers: where to redeem it online. |
gbp_terms |
string | Offers: the terms and conditions. |
The gbp_* names from Upload-Post work for the other fields too: gbp_location_id, gbp_cta_type, gbp_cta_url and gbp_language_code do the same as google_business_location_id, google_business_cta, google_business_cta_url and google_business_language. The google_business_* name wins when both are sent.
Events and offers
An event has a title and a start and end; an offer has the same plus an optional coupon code, redeem link and terms. Offers bring their own redeem link, so a call-to-action button is left off an offer.
curl -X POST https://api.reelspan.com/v1/posts/photos \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-F "user=my-brand" \
-F "platform[]=google_business" \
-F "google_business_title=20% off every tart this weekend. Show the code at the counter." \
-F "gbp_topic_type=OFFER" \
-F "gbp_event_title=Weekend tart sale" \
-F "gbp_event_start=2026-12-05" \
-F "gbp_event_end=2026-12-07" \
-F "gbp_coupon_code=TART20" \
-F "gbp_terms=One per customer." \
-F "photos[][email protected]"A missing title, start or end fails the post with event_required, and so does a date that can't be read.
Limits
- Text: 1,500 characters.
- Photos: one per update; with more, the first is used and the result says so.
- Shapes: 4:3 and 1:1 work best.
Good to know
- The link in the result is the update on Google Search, when Google returns one;
post_idis the update's full resource name. - First comment: Google Business updates have no comments, so
first_commentisn't posted; the result saysfirst_comment: "unsupported". - Analytics: none for Google Business yet.
After posting
- Delete an update, event or offer with Unpublish.
- Edit its text, or its button with
fields.google_business_cta_url(andfields.google_business_cta), with Edit a post.
For a post made outside Reelspan, post_id is the post's full name: accounts/…/locations/…/localPosts/….
Errors
error_code |
What happened | What to do |
|---|---|---|
location_required |
Several locations are connected and none is chosen | Choose one, or send google_business_location_id. The error lists the locations. |
invalid_topic_type |
gbp_topic_type isn't STANDARD, EVENT or OFFER |
Use one of those. |
event_required |
An event or offer without a title, start or end, or with a date that can't be read | Send gbp_event_title (or a title), gbp_event_start and gbp_event_end. |
google_business_error |
Google refused the update | Read error for Google's message. Reelspan retries server errors and rate limits. |
reauth_required |
The Google sign-in expired or was revoked | Reconnect Google Business. |