POST/api/v4/bulk-posts

Create a bulk post

Creates one social post and publishes it across many locations in a single request.

Requires an API key. See Authentication for header format and key rotation.

Parameters

Body

A nested field marked required applies only when you send its parent. If the parent is optional and you omit it, its required children do not apply.

NameTypeRequiredDescription
inputobjectrequiredWrapper object. Every field below is a property of `input`, the entire body must be nested under it.
input.postNamestringrequiredInternal name for the campaign (not shown publicly).
input.locationIdsarray of stringsrequiredBase64-encoded location Relay IDs to publish to.
input.postTypestringrequiredOne of `EVENT`, `OFFER`, `ANNOUNCEMENT`, `COVID19`, `PRODUCT`.
input.postSitesarray of stringsrequiredTarget publishers: `GOOGLE` and/or `FACEBOOK`.
input.postMessagearray of objectsoptionalPer-site post body. Each entry: `site` and `message`.
input.postMessage[].sitestringrequiredPublisher for this message: `GOOGLE` or `FACEBOOK`.
input.postMessage[].messagestringrequiredPost body text for that site.
input.postMediaUrlarray of objectsoptionalPer-site media. Each entry: `site`, `url`, and `type` (`IMAGE` or `VIDEO`).
input.postMediaUrl[].sitestringrequiredPublisher for this media asset.
input.postMediaUrl[].urlstringrequiredPublicly accessible media URL.
input.postMediaUrl[].typestringoptional`IMAGE` or `VIDEO`.
input.postCtaarray of objectsoptionalPer-site call-to-action button. Each entry: `site`, `type`, `url`.
input.postScheduledDatesobjectoptionalScheduling window: `startDatetime`, `endDatetime`, and optional `removalSites`. When provided, the post is created with status `SCHEDULED`.
input.postScheduledDates.startDatetimestringrequiredISO-8601 datetime the post goes live.
input.postScheduledDates.endDatetimestringrequiredISO-8601 datetime the post is removed.
input.postContextInfoobjectoptionalType-specific details (offer coupon/redeem/terms, or event title/times). Required by `OFFER`, `EVENT`, and `PRODUCT` posts.
input.productsarray of objectsoptionalProduct entries for `PRODUCT` posts (name, price, photo, cta).
input.componentIdentifierstringoptionalOptional client component reference for tracking.
input.componentTypestringoptionalOptional client component type for tracking.

Sample request

Ready-to-paste body. Replace placeholder IDs and values with yours.

Request body
{  "input": {    "postName": "July Reopening Announcement",    "locationIds": [      "TG9jYXRpb246MTgwMDI4OQ==",      "TG9jYXRpb246MTgwMDI5MA=="    ],    "postType": "ANNOUNCEMENT",    "postSites": ["GOOGLE", "FACEBOOK"],    "postMessage": [      { "site": "GOOGLE", "message": "We're back! Visit us this week for our summer menu." },      { "site": "FACEBOOK", "message": "We're back! Swing by for the new summer menu." }    ],    "postMediaUrl": [      { "site": "GOOGLE", "url": "https://cdn.example.com/summer.jpg", "type": "IMAGE" }    ],    "postScheduledDates": {      "startDatetime": "2026-07-10T09:00:00Z",      "endDatetime": "2026-07-24T23:59:00Z"    }  }}

Responses

200Bulk post accepted. `success` is true and the created campaign is returned. Note the response is keyed under `createSocialPost`, the bulk endpoint shares the same underlying mutation and response shape as `POST /posts`.
Response
{  "data": {    "createSocialPost": {      "clientMutationId": null,      "success": true,      "errors": null,      "socialPost": {        "id": "U29jaWFsUG9zdDo5OTIwMQ==",        "name": "July Reopening Announcement",        "status": "SCHEDULED",        "type": "ANNOUNCEMENT",        "createdAt": "2026-07-08",        "scheduledStartDate": "2026-07-10",        "scheduledEndDate": "2026-07-24",        "sites": ["GOOGLE", "FACEBOOK"],        "locationIds": [1800289, 1800290]      }    }  }}
400Bad request, the body was not wrapped in `input` (GraphQL: `Variable "$input" of required type ... was not provided`).
401Unauthenticated, missing or invalid API key.

Creates a single post campaign and fans it out to every location in locationIds, publishing to the selected postSites. Unlike the per-location create, one call targets your whole fleet, which is the efficient way to run a company-wide announcement, offer, or event.

Request shape. The entire body must be wrapped in an input object, every field (postName, locationIds, postType, …) is a property of input. A flat, unwrapped body is rejected with an HTTP 400 (Variable "$input" of required type ... was not provided). This is the same contract as POST /posts; the two endpoints share the underlying mutation, which is why a successful response is keyed under createSocialPost rather than a bulk-specific key.

Use case: company-wide announcement (shown above). Set postType: "ANNOUNCEMENT", list the location IDs, and provide one postMessage per site. Add postScheduledDates to run the post over a fixed window (the post is then created with status SCHEDULED); omit it to publish immediately.

Use case: a limited-time offer across all stores. Switch postType to OFFER and supply the coupon in postContextInfo (still wrapped in input):

JSON
{  "input": {    "postName": "Summer 20% Off",    "locationIds": ["TG9jYXRpb246MTgwMDI4OQ=="],    "postType": "OFFER",    "postSites": ["GOOGLE"],    "postMessage": [{ "site": "GOOGLE", "message": "20% off through July!" }],    "postContextInfo": {      "title": "Summer Sale",      "couponCode": "SUMMER20",      "redeemUrl": "https://example.com/offer",      "termsConditions": "Valid through July 31",      "startDay": "2026-07-10",      "startTime": "09:00",      "endDay": "2026-07-31",      "endTime": "23:59"    }  }}

Gotchas.

  • The body must be wrapped in input; sending the fields at the top level returns an HTTP 400.
  • postType, postSites, postName, and locationIds are required; EVENT, OFFER, and PRODUCT types additionally require the matching postContextInfo (or products) fields.
  • postSites accepts only GOOGLE and FACEBOOK; the target locations must have the corresponding channel connected or that site is skipped.
  • The response returns HTTP 200 with success: false and a populated errors array on partial or full validation failure, check success, then track live delivery per location with the fetch bulk post endpoint.
Request
curl -X POST 'https://listingsapi.com/api/v4/bulk-posts' \  -H "Authorization: API $LISTINGSAPI_KEY" \  -H 'Content-Type: application/json' \  -d '{    "input": {      "postName": "July Reopening Announcement",      "locationIds": [        "TG9jYXRpb246MTgwMDI4OQ==",        "TG9jYXRpb246MTgwMDI5MA=="      ],      "postType": "ANNOUNCEMENT",      "postSites": [        "GOOGLE",        "FACEBOOK"      ],      "postMessage": [        {          "site": "GOOGLE",          "message": "We're back! Visit us this week for our summer menu."        },        {          "site": "FACEBOOK",          "message": "We're back! Swing by for the new summer menu."        }      ],      "postMediaUrl": [        {          "site": "GOOGLE",          "url": "https://cdn.example.com/summer.jpg",          "type": "IMAGE"        }      ],      "postScheduledDates": {        "startDatetime": "2026-07-10T09:00:00Z",        "endDatetime": "2026-07-24T23:59:00Z"      }    }  }'