Posts

Publish announcements, events, and offers to Google and Facebook with the listingsapi-js SDK.

Post methods publish content to Google Business Profile and Facebook, then let you monitor per-site publish status and analytics. All post methods live directly on the ListingsAPI client instance.

Publishing is asynchronous: create calls return status: 'INPROGRESS', and the post publishes in the background. Poll fetchPost until the status is SUCCESS, and check publishDetails[].submissionError for per-site failures.

bulkPublish

Publish one post to Google and Facebook across many locations in a single call. sites defaults to both. The message (or per-site map) expands to one entry per site, location IDs are encoded automatically, and the payload is validated client-side before any network call (an invalid payload throws ValidationError immediately).

TypeScript
const result = await client.bulkPublish({name: 'Holiday hours',locationIds: [16808, 16809, 16810],message: 'Open until 10pm through the holidays!',mediaUrl: 'https://cdn.example.com/holiday.jpg',ctaType: 'LEARN_MORE',ctaUrl: 'https://example.com/holiday-hours',});console.log(result.socialPost.id, result.socialPost.status); // INPROGRESS, publishes async

Pass an object as message for per-site copy:

TypeScript
await client.bulkPublish({name: 'Holiday hours',locationIds: [16808, 16809],message: {  GOOGLE: 'Open until 10pm through the holidays. Book online!',  FACEBOOK: 'We are staying open late for the holidays. See you soon!',},});

Options

ParameterTypeDescription
namestringInternal campaign name (not shown to customers). Required.
locationIdsArray<string | number>Locations to publish to (numeric or base64 IDs). Required.
messagestring or per-site mapPost body for every site, or { GOOGLE, FACEBOOK } map. Required.
sitesPostSite[]Target sites; defaults to ['GOOGLE', 'FACEBOOK'].
postTypePostTypeANNOUNCEMENT (default), EVENT, OFFER, COVID19, or PRODUCT.
ctaTypePostCtaTypeBOOK, ORDER, SHOP, LEARN_MORE, SIGN_UP, or GET_OFFER. Requires ctaUrl.
ctaUrlstringDestination for the CTA button. Requires ctaType.
mediaUrlstringPublic image URL attached on every site.
scheduledDatesobject{ startDatetime, endDatetime, removalSites } for scheduled publish/expiry.
contextInfoobjectEvent or offer details when postType needs them.
additionalFieldsobjectExtra flat camelCase fields merged into the request body as-is.

createAnnouncement

Create an ANNOUNCEMENT post: a plain message with optional CTA and media. Takes the same options as bulkPublish minus postType and contextInfo; here sites defaults to ['GOOGLE'].

TypeScript
await client.createAnnouncement({name: 'Grand Opening',locationIds: [16808],message: 'Acme Dental is now open in the Mission!',sites: ['GOOGLE'],ctaType: 'LEARN_MORE',ctaUrl: 'https://example.com/opening',});

createEvent

Create an EVENT post with a title and a start/end window. title is required (Google requires it); startDay and endDay are YYYY-MM-DD dates, and startTime/endTime are optional display times. sites defaults to ['GOOGLE'].

TypeScript
await client.createEvent({name: 'Live music',locationIds: [16808],message: 'Join us Friday for live jazz!',title: 'Jazz Night',startDay: '2026-08-01',endDay: '2026-08-01',startTime: '7:00pm',endTime: '10:00pm',});

createOffer

Create an OFFER post with a coupon, discount, and terms. title is required; all other offer fields are optional. sites defaults to ['GOOGLE'].

TypeScript
await client.createOffer({name: 'Summer sale',locationIds: [16808],message: '20% off whitening all week!',title: 'Summer Sale',couponCode: 'SUMMER20',discount: '20%',redeemUrl: 'https://example.com/sale',termsConditions: 'One per customer.',startDay: '2026-08-01',endDay: '2026-08-07',});

Offer options

ParameterTypeDescription
titlestringOffer title. Required.
couponCodestringCode customers redeem.
discountstringDiscount description, for example '20%'.
redeemUrlstringOnline redemption link.
termsConditionsstringTerms and conditions text.
startDaystringOffer validity start, YYYY-MM-DD.
endDaystringOffer validity end, YYYY-MM-DD.

createPost

Create a post from a raw body (flat fields, not input-wrapped), sent to the API as-is with no client-side validation. Prefer createAnnouncement, createEvent, or createOffer, which build and validate this body for you.

TypeScript
await client.createPost({postName: 'Grand Opening',locationIds: ['TG9jYXRpb246MTY4MDg='],postType: 'ANNOUNCEMENT',postSites: ['GOOGLE'],postMessage: [{ site: 'GOOGLE', message: 'We are now open!' }],});

fetchPost

Get a post with its content, per-site publish status, and analytics. Use it to poll an INPROGRESS post until it publishes.

TypeScript
let post = await client.fetchPost('U29jaWFsUG9zdDo0NDEyMg=='); while (post.status === 'INPROGRESS') {await new Promise((resolve) => setTimeout(resolve, 5000));post = await client.fetchPost('U29jaWFsUG9zdDo0NDEyMg==');} for (const detail of post.publishDetails ?? []) {if (detail.submissionError) {  console.log('failed:', detail.submissionError);}}

deletePost

Delete a post and remove it from every site it was published to.

TypeScript
await client.deletePost('U29jaWFsUG9zdDo0NDEyMg==');

fetchLocationPosts

List post campaigns targeting a location. Uses offset pagination (page and perPage); tag defaults to 'all' because the API errors when it is omitted.

TypeScript
const posts = await client.fetchLocationPosts(16808, { page: 1, perPage: 10 });

Options

ParameterTypeDescription
tagstringSegment to pull posts from; defaults to 'all'.
pagenumberPage number (1-based).
perPagenumberResults per page.
filtersobjectPost filter fields (JSON-encoded automatically).
sortFieldsobjectSort object like { field: 'created_at', order: 'Descending' }.

fetchBulkPost

Get a bulk campaign with per-location publish status and analytics.

TypeScript
const bulk = await client.fetchBulkPost('QnVsa1Bvc3Q6OTk=');

fetchLocationBulkPosts

List bulk (multi-location) campaigns that include a location. Takes the same options as fetchLocationPosts.

TypeScript
const campaigns = await client.fetchLocationBulkPosts(16808, { page: 1, perPage: 10 });