Publique posts no Google e no Facebook
Publique anúncios, eventos e ofertas; agende um post em vários locais, confirme a publicação por site, gerencie posts de um local e reaja a webhooks.
Um post é um cartão com data no Google Business Profile ou na Página do Facebook de um local: um anúncio, um evento ou uma oferta. Uma chamada cria o post, a publicação ocorre em segundo plano e uma segunda chamada informa se cada site o aceitou.
Os três tipos de post usam POST /posts com o corpo encapsulado em input. Um corpo sem esse encapsulamento é rejeitado com 400. Os SDKs criam o encapsulamento e validam o payload antes do envio.
1. Publique um anúncio
Um anúncio recebe uma mensagem, um botão opcional e uma imagem opcional.
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://acmekitchen.example.com/opening" } ], "postMediaUrl": [ { "site": "GOOGLE", "url": "https://cdn.example.com/opening.jpg", "type": "IMAGE" } ] }}'{ "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] } } }}Guarde socialPost.id. status começa em INPROGRESS e postLinks fica vazio até que um site aceite o post; a etapa 5 consulta ambos.
2. Publique um evento
Um evento adiciona postContextInfo com title, startDay, endDay e horários de exibição opcionais. O Google rejeita um evento sem título, e os SDKs lançam ValidationError antes do envio se ele estiver ausente.
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, giveaways, and up to 40% off in store." } ] }}'A resposta tem a mesma estrutura da etapa 1, com type: "EVENT" e as datas retornadas em socialPost.contextInfo. postContextInfo contém as datas do próprio evento; postScheduledDates (etapa 4) controla quando o post em si é publicado e retirado de publicação.
3. Publique uma oferta
O postContextInfo de uma oferta contém title, couponCode, discount, redeemUrl, termsConditions e o período de validade definido por startDay e endDay. Combine-o com um botão GET_OFFER no Facebook ou ORDER no Google; não existe um tipo REDEEM.
curl -X POST https://listingsapi.com/api/v4/posts \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "input": { "postName": "Summer 25% Off", "locationIds": ["TG9jYXRpb246MTgwMDI4OQ=="], "postType": "OFFER", "postSites": ["GOOGLE"], "postContextInfo": { "title": "25% off storewide", "couponCode": "SUMMER25", "discount": "25%", "redeemUrl": "https://acmekitchen.example.com/summer", "termsConditions": "Valid in store only through July 6. Cannot be combined with other offers.", "startDay": "2026-06-22", "endDay": "2026-07-06" }, "postMessage": [ { "site": "GOOGLE", "message": "Celebrate with us: 25% off everything in store this week." } ] }}'A resposta retorna os campos da oferta em socialPost.contextInfo e define scheduledStartDate e scheduledEndDate com base no período de validade.
4. Envie um post para vários locais com agendamento
POST /bulk-posts recebe o mesmo input e envia uma campanha para cada id em locationIds. Adicione postScheduledDates com startDatetime e endDatetime no formato ISO-8601 para publicar mais tarde e retirar de publicação automaticamente; o post é então criado como SCHEDULED. Defina uma mensagem própria para cada site quando o tom for diferente.
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" } }}'O endpoint de operações em lote retorna a mesma estrutura de POST /posts, portanto a resposta também usa a chave createSocialPost, com status: "SCHEDULED" e ambos os ids em locationIds. Um problema de validação resulta em 200 com success: false e um array errors preenchido; os SDKs lançam ValidationError nesse caso. Consulte uma campanha em lote com GET /bulk-posts/{postId}, que adiciona o status por local.
5. Verifique o status de publicação e obtenha os links dos posts
GET /posts/{postId} retorna a campanha em socialPostView. Consulte-o periodicamente após a criação até que socialPostInfo.status deixe de ser INPROGRESS, depois leia publishDetails[] para obter o resultado de cada site e postLinks[] para obter as URLs publicadas. Faça as consultas em intervalos de dezenas de segundos; um 429 vem acompanhado de Retry-After.
curl https://listingsapi.com/api/v4/posts/U29jaWFsUG9zdDo0NDEyMg== \-H "Authorization: API $LISTINGSAPI_KEY"{ "data": { "socialPostView": { "socialPostInfo": { "id": "U29jaWFsUG9zdDo0NDEyMg==", "status": "SUCCESS", "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" } ] }, "socialPostAnalyticsBySite": [ { "site": "GOOGLE", "views": 128, "clicks": 14, "reactions": 3, "shares": 0, "comments": 1 } ] } }}views, clicks, reactions, shares e comments se acumulam no mesmo registro, discriminados por site em socialPostAnalyticsBySite. Os SDKs retornam socialPostInfo diretamente, por isso os exemplos leem post.status.
6. Liste as publicações de um local e exclua uma
GET /locations/{locationId}/posts é uma página com paginação por deslocamento (page, perPage até 50) de todas as campanhas que incluem o local, em postsByLocation com records[] e pageInfo.totalRecords. Passe o id em base64 sem alterações; não aplique codificação de URL a ele. Não há filtro por tipo, então selecione ofertas ou eventos de type no seu próprio código. As campanhas para vários locais da etapa 4 são listadas separadamente por GET /locations/{locationId}/bulk-posts.
DELETE /posts/{postId} remove a campanha daqui e de todos os sites em que ela foi publicada. Não é possível desfazer essa ação, então confirme primeiro o id na lista.
curl "https://listingsapi.com/api/v4/locations/TG9jYXRpb246MTgwMDI4OQ==/posts?page=1&perPage=20" \-H "Authorization: API $LISTINGSAPI_KEY" curl -X DELETE https://listingsapi.com/api/v4/posts/U29jaWFsUG9zdDo0NDEyMg== \-H "Authorization: API $LISTINGSAPI_KEY"Uma exclusão retorna data.deleteSocialPost com success: true e o socialPostId que foi removido. Excluir um id que já foi removido retorna, em vez disso, uma resposta errors com data: null, então é fácil detectar uma segunda exclusão.
7. Reaja aos webhooks de publicações
Com uma URL de webhook configurada em /dashboard/webhooks, quatro eventos cobrem o ciclo de vida da publicação, todos no payload padrão. Eles são disparados por local, não por campanha: uma publicação em massa para 20 locais produz 20 valores de post_item_id com um único post_id compartilhado.
function handle(payload: { event: string; location_id: string; data: Record<string, unknown> }) {if (!payload.event.startsWith('local_post.')) return; const key = String(payload.data.post_item_id); // one row per locationswitch (payload.event) { case 'local_post.published': markLive(key, payload.location_id, payload.data.post_external_id); break; case 'local_post.rejected': markRejected(key, payload.location_id, payload.data.rejection_reason); break; case 'local_post.deleted': markDeleted(key); break;}}published_url geralmente está ausente, então continue consultando periodicamente conforme a etapa 5 para obter postLinks se precisar de um link clicável. Responda com 200 em até 5 segundos; não há novas tentativas. O receptor e a verificação de assinatura estão em Reaja a eventos com webhooks.
Próximas etapas
- Conecte o Google e importe locais e Conecte Páginas do Facebook: o pré-requisito para cada site.
- Busque dados analíticos do perfil: visualizações e ações no nível do perfil, junto com os contadores por publicação apresentados aqui.
- Reaja a eventos com webhooks: o receptor ao qual esses eventos são enviados.
- Referência: Crie uma publicação de anúncio, Crie uma publicação de evento, Crie uma publicação de oferta, Crie uma publicação em massa, Obtenha uma publicação, Busque publicações de um local, Exclua uma publicação.