帖子

每个帖子端点均附有 cURL、Python 和 Node 示例:涵盖公告、活动和优惠、定时发布、针对单个地点的营销活动和批量营销活动、状态轮询以及删除。

帖子是发布到某个地点的 Google Business Profile 或 Facebook 公共主页上的简短动态:可以是公告、有明确日期的活动,或带有优惠券的优惠信息。一个营销活动可以同时面向多个地点和这两个网站。发布以异步方式进行,因此每次创建调用都会立即返回,您需要通过轮询获取结果。3 个 GET 端点可使用 Read(读取)密钥;创建和删除则需要 Write(写入)密钥。

端点概览

方法路径功能参考
POST/posts发布公告,即一条普通消息,可选附带按钮和图片。创建公告帖子
POST/posts发布活动,包含标题以及开始和结束时间。创建活动帖子
POST/posts发布优惠,包含优惠码、折扣和条款。创建优惠帖子
GET/posts/{postId}获取单个营销活动,包含各网站的发布状态和互动次数。获取帖子
GET/locations/{locationId}/posts获取面向某个地点的营销活动的一页结果。获取某个地点的帖子
DELETE/posts/{postId}永久删除营销活动,并在所有网站上撤下该营销活动。删除帖子
POST/bulk-posts将单个营销活动分发到多个地点。创建批量帖子
GET/bulk-posts/{postId}获取单个批量营销活动,包含按地点细分的分析数据。按 ID 获取批量帖子
GET/locations/{locationId}/bulk-posts获取包含某个地点的批量营销活动,支持筛选和排序。获取某个地点的批量帖子

各处都会用到的值

下面的 4 个枚举由所有创建端点共用。

字段接受的值
postTypeANNOUNCEMENT, EVENT, OFFER, COVID19, PRODUCT
postSites 和每个 siteGOOGLE, FACEBOOK
postCta[].typeBOOK, ORDER, SHOP, LEARN_MORE, SIGN_UP, GET_OFFER
postMediaUrl[].typeIMAGE, VIDEO

发布公告

POST /posts

公告接受一条消息,并且每个网站可选附带 1 个按钮和 1 张图片。请为 postSites 中列出的每个网站提供 1 个 postMessage 条目。响应会返回新建的营销活动,其中 status 设为 INPROGRESS,因为发布在后台进行。

参数

名称位置是否必填说明
input.postNamebody是内部营销活动名称,绝不会向客户显示。
input.locationIdsbody是base64 地点 ID 数组。
input.postTypebody是此处为 ANNOUNCEMENT。
input.postSitesbody是由 GOOGLE 和 FACEBOOK 组成的数组。
input.postMessagebody否对象数组,每个对象包含 site 和 message。
input.postCtabody否对象数组,每个对象包含 site、type、url。
input.postMediaUrlbody否对象数组,每个对象包含 site、url、type。
input.clientMutationIdbody否原样返回,用于关联。
Announcement
curl -X POST https://listingsapi.com/api/v4/posts \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{  "input": {    "postName": "Grand Opening Announcement",    "locationIds": ["TG9jYXRpb246MTgwMDI4OQ=="],    "postType": "ANNOUNCEMENT",    "postSites": ["GOOGLE"],    "postMessage": [      { "site": "GOOGLE", "message": "We are now open! Visit us this week for our grand opening." }    ],    "postCta": [      { "site": "GOOGLE", "type": "LEARN_MORE", "url": "https://jennyhome.example/opening" }    ],    "postMediaUrl": [      { "site": "GOOGLE", "url": "https://cdn.example.com/opening.jpg", "type": "IMAGE" }    ]  }}'
JSON
{  "data": {    "createSocialPost": {      "success": true,      "errors": [],      "socialPost": {        "id": "U29jaWFsUG9zdDo0NDEyMg==",        "name": "Grand Opening Announcement",        "status": "INPROGRESS",        "type": "ANNOUNCEMENT",        "sites": ["GOOGLE"],        "publishDetails": [          { "site": "GOOGLE", "status": "PUBLISHING", "createdDate": "2026-06-28", "submissionError": null }        ],        "postLinks": [],        "locationIds": [1800289]      }    }  }}

请保存 socialPost.id。它是此处所有其他端点都需要的 base64 帖子 ID。两个 SDK 的辅助函数都接受单个 message 字符串,并将其展开为每个网站各 1 个条目,因此您只需在 cURL 中手动构建 postMessage 数组。

发布活动

POST /posts

活动会显示为带日期的卡片。活动本身的时间安排位于 postContextInfo 中。独立的 postScheduledDates 对象控制帖子本身何时显示和到期,这一时段通常是活动开始前的预热期。Google 会拒绝没有标题的活动,而且如果缺少 title,两个 SDK 都会在发送前抛出验证错误。

参数

名称位置是否必填说明
input.postTypebody是此处为 EVENT。
input.postContextInfo.titlebody实际使用时必填活动标题。Google 会拒绝没有标题的活动。
input.postContextInfo.startDay, endDaybody否日期,YYYY-MM-DD。
input.postContextInfo.startTime, endTimebody否用于显示的字符串,例如 10:00am。
input.postScheduledDatesbody否包含 startDatetime、endDatetime、removalSites 的对象。

公告参数表中的所有内容也都适用。

Event
curl -X POST https://listingsapi.com/api/v4/posts \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{  "input": {    "postName": "Summer Sale Kickoff Event",    "locationIds": ["TG9jYXRpb246MTgwMDI4OQ=="],    "postType": "EVENT",    "postSites": ["GOOGLE"],    "postContextInfo": {      "title": "Summer Sale Kickoff",      "startDay": "2026-07-15",      "startTime": "10:00am",      "endDay": "2026-07-15",      "endTime": "06:00pm"    },    "postMessage": [      { "site": "GOOGLE", "message": "Join us for the Summer Sale kickoff, refreshments and up to 40 percent off in store." }    ]  }}'
JSON
{  "data": {    "createSocialPost": {      "success": true,      "socialPost": {        "id": "U29jaWFsUG9zdDo0NDEyMw==",        "status": "INPROGRESS",        "type": "EVENT",        "scheduledStartDate": "2026-07-15",        "scheduledEndDate": "2026-07-15",        "contextInfo": {          "title": "Summer Sale Kickoff",          "startDay": "2026-07-15",          "startTime": "10:00am",          "endDay": "2026-07-15",          "endTime": "06:00pm"        }      }    }  }}

返回的 contextInfo 是活动时段。scheduledStartDate 和 scheduledEndDate 描述帖子本身的时间安排,此处与活动日期一致,因为未发送 postScheduledDates。

发布优惠

POST /posts

优惠是一张促销卡片,包含优惠码、折扣、兑换链接和条款。所有这些内容都放在 postContextInfo 中,startDay 和 endDay 限定的是优惠的有效期,而不是帖子的有效期。

参数

名称位置是否必填说明
input.postTypebody是此处为 OFFER。
input.postContextInfo.titlebody实际使用时必填用于标识优惠。两个 SDK 都要求提供此项。
input.postContextInfo.couponCodebody否客户用于兑换的代码。
input.postContextInfo.discountbody否自由文本,例如 25%。
input.postContextInfo.redeemUrlbody否兑换优惠的地址。
input.postContextInfo.termsConditionsbody否细则。
input.postContextInfo.startDay, endDaybody否有效时间段,YYYY-MM-DD。
Offer
curl -X POST https://listingsapi.com/api/v4/posts \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{  "input": {    "postName": "Festive 25 Percent Off",    "locationIds": ["TG9jYXRpb246MTgwMDI4OQ=="],    "postType": "OFFER",    "postSites": ["GOOGLE"],    "postContextInfo": {      "title": "25% off storewide",      "couponCode": "FESTIVE25",      "discount": "25%",      "redeemUrl": "https://jennyhome.example/festive",      "termsConditions": "Valid in-store only through July 6.",      "startDay": "2026-06-22",      "endDay": "2026-07-06"    },    "postMessage": [      { "site": "GOOGLE", "message": "Celebrate with us, 25 percent off everything in store this week." }    ],    "postCta": [      { "site": "GOOGLE", "type": "GET_OFFER", "url": "https://jennyhome.example/festive" }    ]  }}'
JSON
{  "data": {    "createSocialPost": {      "success": true,      "socialPost": {        "id": "U29jaWFsUG9zdDo0NDEyNA==",        "status": "INPROGRESS",        "type": "OFFER",        "contextInfo": {          "title": "25% off storewide",          "couponCode": "FESTIVE25",          "discount": "25%",          "startDay": "2026-06-22",          "endDay": "2026-07-06"        }      }    }  }}

对于优惠按钮,Google 接受 ORDER,Facebook 接受 GET_OFFER。如果促销提前结束,请删除营销活动,而不是编辑它。

读取单个帖子及其状态

GET /posts/{postId}

返回已受理营销活动的发布结果。响应在 data.socialPostView 下包含营销活动内容、每个站点对应的一个 publishDetails 条目、互动计数,以及发布成功后的上线链接。

参数

名称位置是否必填说明
postIdpath是来自创建响应或列表的 Base64 帖子 ID。
Get a post
curl https://listingsapi.com/api/v4/posts/U29jaWFsUG9zdDo0NDEyMg== \-H "Authorization: API $LISTINGSAPI_KEY"
JSON
{  "data": {    "socialPostView": {      "socialPostId": "U29jaWFsUG9zdDo0NDEyMg==",      "socialPostInfo": {        "status": "SUCCESS",        "type": "ANNOUNCEMENT",        "views": 128,        "clicks": 14,        "publishDetails": [          { "site": "GOOGLE", "status": "PUBLISHED", "publishedDate": "2026-06-28", "submissionError": null }        ],        "postLinks": [          { "site": "GOOGLE", "link": "https://www.google.com/maps/place/?post=44122" }        ]      },      "publishedLocationsCount": 1,      "socialPostAnalyticsBySite": [        { "site": "GOOGLE", "views": 128, "clicks": 14, "reactions": 3, "shares": 0, "comments": 1 }      ]    }  }}

有 2 个重要的状态字段,它们分别回答不同的问题。

字段值含义
socialPostInfo.statusINPROGRESS已受理,发布仍在进行中。
SUCCESS发布已完成。请读取 publishDetails,查看各站点的结果。
SCHEDULED正在等待 postScheduledDates 时间段开始。
EXPIRED预定时间段已结束,帖子已下线。
publishDetails[].statusPUBLISHING该站点尚未响应。
PUBLISHED已在该站点上线。请在 postLinks 中查找 URL。
ERROR该站点拒绝了此帖子。submissionError 说明了原因。

营销活动的状态可能显示为 SUCCESS,而其中某个站点的状态为 ERROR,因此请务必检查 publishDetails,不要只查看顶层状态。

列出某个地点的帖子

GET /locations/{locationId}/posts

在 data.postsByLocation 下返回包含指定地点的所有营销活动历史记录,采用偏移量分页。在安排新内容发布之前,请使用它核查已经上线的内容。

参数

名称位置是否必填说明
locationIdpath是Base64 ID,原样传入。
pagequery否从 1 开始的页码,默认为 1。
perPagequery否默认为 10,不得超过 50。
Posts on a location
curl "https://listingsapi.com/api/v4/locations/TG9jYXRpb246MTgwMDI4OQ==/posts?page=1&perPage=10" \-H "Authorization: API $LISTINGSAPI_KEY"
JSON
{  "data": {    "postsByLocation": {      "records": [        {          "id": "U29jaWFsUG9zdDo0NDEyMg==",          "name": "Summer Hours Update",          "status": "SUCCESS",          "type": "ANNOUNCEMENT",          "createdAt": "2026-06-28",          "views": 128,          "clicks": 14,          "sites": ["GOOGLE"]        }      ],      "pageInfo": { "totalPages": 1, "hasNextPage": false, "totalRecords": 1 }    }  }}

此路由不支持服务端筛选。它仅接受 page 和 perPage,其他参数都会被忽略,因此请读取每条记录中的 type 和 status,并在您自己的代码中进行筛选。如需在服务端排序和筛选,请改用下方的批量列表端点。

删除帖子

DELETE /posts/{postId}

此操作是永久性的,会将帖子从所有已发布到的站点下线。此操作无法撤销,也没有编辑端点,因此要更正已上线的帖子,您需要先将其删除,再发布替代帖子。

参数

名称位置是否必填说明
postIdpath是Base64 帖子 ID。
clientMutationIdbody否可选,原样返回以便关联。
Delete
curl -X DELETE https://listingsapi.com/api/v4/posts/U29jaWFsUG9zdDo0NDEyMg== \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "clientMutationId": "delete-44122-req-1" }'
JSON
{  "data": {    "deleteSocialPost": {      "success": true,      "socialPostId": "U29jaWFsUG9zdDo0NDEyMg=="    }  }}

删除未知或已删除的帖子会返回错误响应,其中 data 被设置为 null,而不是 success: false。

在多个地点发布同一个营销活动

POST /bulk-posts

接口约定与 POST /posts 相同,专为大批量地点设计:在 locationIds 中列出所有地点,一个营销活动即可覆盖全部地点。响应位于 createSocialPost 键下,与 POST /posts 相同。

参数

名称位置是否必填说明
input.postNamebody是内部营销活动名称。
input.locationIdsbody是所有发布目标地点的 base64 ID。
input.postTypebody是EVENT、OFFER 和 PRODUCT 还需要 postContextInfo 或 products。
input.postSitesbody是GOOGLE、FACEBOOK,或两者。
input.postScheduledDatesbody否采用 ISO 8601 格式的 startDatetime 和 endDatetime。创建的帖子状态为 SCHEDULED。
input.componentIdentifierbody否您自己的参考标识,便于以后用作筛选条件。
Bulk publish
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 are back. Visit us this week for our summer menu." },      { "site": "FACEBOOK", "message": "We are back. Swing by for the new summer menu." }    ],    "postScheduledDates": {      "startDatetime": "2026-07-10T09:00:00Z",      "endDatetime": "2026-07-24T23:59:00Z"    }  }}'
JSON
{  "data": {    "createSocialPost": {      "success": true,      "errors": null,      "socialPost": {        "id": "U29jaWFsUG9zdDo5OTIwMQ==",        "name": "July Reopening Announcement",        "status": "SCHEDULED",        "type": "ANNOUNCEMENT",        "scheduledStartDate": "2026-07-10",        "scheduledEndDate": "2026-07-24",        "sites": ["GOOGLE", "FACEBOOK"],        "locationIds": [1800289, 1800290]      }    }  }}

两个 SDK 的辅助函数都会默认将 sites 设为 Google 和 Facebook,为您展开按站点划分的消息映射,并自动编码数字形式的地点 ID,因此在任一 SDK 中,批量发布通常都是代码最简短的调用。

读取单个批量营销活动

GET /bulk-posts/{postId}

这是 GET /posts/{postId} 的批量版本。它返回相同的数据结构,其中 publishedLocationsCount 大于 1,socialPostAnalyticsByLocationId 中包含按门店细分的分析数据。

参数

名称位置是否必填说明
postIdpath是Base64 编码的批量帖子 ID,而非原始整数。
Get a bulk post
curl https://listingsapi.com/api/v4/bulk-posts/U29jaWFsUG9zdDo1MTA4OA== \-H "Authorization: API $LISTINGSAPI_KEY"
JSON
{  "data": {    "socialPostView": {      "socialPostId": "U29jaWFsUG9zdDo1MTA4OA==",      "socialPostInfo": {        "name": "Festive Offer - All Stores",        "status": "SUCCESS",        "type": "OFFER",        "views": 4210,        "clicks": 318,        "sites": ["GOOGLE", "FACEBOOK"]      },      "socialPostAnalyticsByLocationId": [        {          "locationId": 1800289,          "siteStats": [            { "site": "GOOGLE", "status": "PUBLISHED", "views": 1040, "clicks": 80 },            { "site": "FACEBOOK", "status": "PUBLISHED", "views": 360, "clicks": 26 }          ]        }      ]    }  }}

socialPostAnalyticsBySite 汇总营销活动在所有门店的数据,而 socialPostAnalyticsByLocationId 则按门店细分这些相同的指标。查看各门店的 status 值,找出存在站点操作失败的地点。

列出某个地点的批量营销活动

GET /locations/{locationId}/bulk-posts

在 data.rollupSocialPosts 下使用偏移量分页。与按地点列出的列表不同,此路由支持筛选和排序,因此适合用于营销活动控制台。

参数

名称位置是否必填说明
locationIdpath是Base64 编码的 ID,按原样传入。
page, perPagequery否偏移量分页。
filtersquery否使用 JSON 编码,按 type、status、creationDateRange 或 siteUrls 筛选。
sortFieldsquery否使用 JSON 编码,例如字段为 created_at,排序顺序为 Descending。
locationIdsquery否使用 JSON 编码的数组,包含需要额外纳入的地点 ID。
componentIdentifierquery否将结果限制为由您的集成创建的营销活动。

可排序字段包括 name、type、status、created_at、schedule_start_date、schedule_end_date、client_name、clicks、views 和 shares。

Bulk posts on a location
curl -G https://listingsapi.com/api/v4/locations/TG9jYXRpb246MTgwMDI4OQ==/bulk-posts \-H "Authorization: API $LISTINGSAPI_KEY" \--data-urlencode 'page=1' \--data-urlencode 'perPage=10' \--data-urlencode 'sortFields={"field":"created_at","order":"Descending"}'
JSON
{  "data": {    "rollupSocialPosts": {      "records": [        {          "id": "U29jaWFsUG9zdDo1MTA4OA==",          "name": "Festive Offer - All Stores",          "status": "SUCCESS",          "type": "OFFER",          "createdAt": "2026-06-20",          "views": 4210,          "clicks": 318        }      ],      "pageInfo": { "totalPages": 1, "hasNextPage": false, "totalRecords": 1 }    }  }}

两个 SDK 都会自动对 filters 和 sortFields 对象做 JSON 编码,因此请将它们作为原生字典或对象传入。

您会遇到的错误

代码或状态含义解决方法
400 缺少 $input 变量请求体未封装在 input 中。将所有字段嵌套在同一个 input 键下。
SY90016,HTTP 状态为 400创建或删除操作使用了 Read 密钥。请使用 Write 密钥。
401密钥缺失或无效。请发送 Authorization: API <YOUR_API_KEY>。
429,附带 Retry-After调用次数过多,通常是由于轮询帖子状态。请等待所指示的秒数。请参阅速率限制。
200,附带 success: false验证失败。请查看 data.createSocialPost 中的 errors。
per_page must not exceed 50perPage 超过地点列表的上限。请将请求数量设为 50 或更少。
tag is not a supported parameter for this query向按地点访问帖子的路由发送了 tag。请仅发送 page 和 perPage。

完整列表请参阅错误代码。

后续步骤