Publikasikan postingan ke Google dan Facebook
Publikasikan pengumuman, acara, penawaran; jadwalkan satu pos di banyak lokasi, cek tayang di tiap situs, kelola pos lokasi, dan tanggapi webhook pos.
Postingan adalah kartu bertanggal di Google Business Profile atau Halaman Facebook suatu lokasi: pengumuman, acara, atau penawaran. Satu panggilan membuatnya, publikasi berjalan di latar belakang, dan panggilan kedua memberi tahu Anda apakah setiap situs menerimanya.
Ketiga jenis postingan menggunakan POST /posts dengan body yang dibungkus dalam input. Body tanpa pembungkus ditolak dengan 400. SDK membuat pembungkus dan memvalidasi payload sebelum mengirimkannya.
1. Publikasikan pengumuman
Pengumuman menerima pesan, tombol opsional, dan gambar opsional.
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] } } }}Simpan socialPost.id. status awalnya bernilai INPROGRESS dan postLinks kosong hingga suatu situs menerima postingan; langkah 5 membaca kembali keduanya.
2. Publikasikan acara
Acara menambahkan postContextInfo dengan title, startDay, endDay, dan waktu tampilan opsional. Google menolak acara tanpa judul, dan SDK memunculkan ValidationError sebelum mengirim jika judul tidak ada.
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." } ] }}'Respons memiliki struktur yang sama dengan langkah 1, dengan type: "EVENT" dan tanggal yang dikembalikan di dalam socialPost.contextInfo. postContextInfo menyimpan tanggal acara itu sendiri; postScheduledDates (langkah 4) mengontrol kapan postingan itu sendiri dipublikasikan dan ditarik dari publikasi.
3. Publikasikan penawaran
postContextInfo pada penawaran memuat title, couponCode, discount, redeemUrl, termsConditions, serta rentang masa berlaku startDay dan endDay. Pasangkan dengan tombol GET_OFFER di Facebook atau ORDER di Google; tidak ada jenis 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." } ] }}'Respons mengembalikan field penawaran di dalam socialPost.contextInfo dan menetapkan scheduledStartDate serta scheduledEndDate berdasarkan rentang masa berlaku.
4. Kirim satu postingan ke banyak lokasi sesuai jadwal
POST /bulk-posts menerima input yang sama dan mengirim satu kampanye ke setiap id dalam locationIds. Tambahkan postScheduledDates dengan startDatetime dan endDatetime dalam format ISO-8601 untuk memublikasikan nanti dan menariknya dari publikasi secara otomatis; postingan kemudian dibuat sebagai SCHEDULED. Berikan pesan tersendiri untuk setiap situs jika gaya bahasanya berbeda.
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" } }}'Endpoint massal mengembalikan struktur yang sama dengan POST /posts, sehingga respons juga menggunakan kunci createSocialPost, dengan status: "SCHEDULED" dan kedua id di dalam locationIds. Masalah validasi mengembalikan 200 dengan success: false dan array errors yang terisi; SDK memunculkan ValidationError untuk masalah tersebut. Baca kembali kampanye massal dengan GET /bulk-posts/{postId}, yang menambahkan status per lokasi.
5. Periksa status publikasi dan kumpulkan tautan postingan
GET /posts/{postId} mengembalikan kampanye di dalam socialPostView. Lakukan polling setelah pembuatan hingga socialPostInfo.status tidak lagi bernilai INPROGRESS, lalu baca publishDetails[] untuk hasil setiap situs dan postLinks[] untuk URL postingan yang sudah tayang. Beri jeda puluhan detik di antara polling; 429 disertai 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, dan comments terakumulasi pada rekaman yang sama, dengan perincian per situs di dalam socialPostAnalyticsBySite. SDK mengembalikan socialPostInfo secara langsung, sehingga contoh membaca post.status.
6. Tampilkan daftar postingan suatu lokasi dan hapus salah satunya
GET /locations/{locationId}/posts adalah halaman berbasis offset (page, perPage hingga 50) yang memuat setiap kampanye yang menyertakan lokasi tersebut, di bawah postsByLocation dengan records[] dan pageInfo.totalRecords. Teruskan id base64 tanpa perubahan; jangan lakukan pengodean URL pada id tersebut. Tidak ada filter jenis, jadi pilih penawaran atau acara dari type dalam kode Anda sendiri. Kampanye multilokasi dari langkah 4 dicantumkan secara terpisah oleh GET /locations/{locationId}/bulk-posts.
DELETE /posts/{postId} menghapus kampanye di sini dan menariknya dari setiap situs tempat kampanye tersebut telah dipublikasikan. Penghapusan tidak dapat dibatalkan, jadi pastikan id dari daftar terlebih dahulu.
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"Operasi penghapusan mengembalikan data.deleteSocialPost dengan success: true dan socialPostId yang dihapusnya. Menghapus id yang sudah tidak ada akan mengembalikan respons errors dengan data: null sebagai gantinya, sehingga penghapusan kedua mudah dideteksi.
7. Tanggapi webhook postingan
Dengan URL webhook yang ditetapkan di /dashboard/webhooks, empat peristiwa mencakup siklus hidup postingan, semuanya menggunakan payload standar. Peristiwa ini dipicu per lokasi, bukan per kampanye: postingan massal ke 20 lokasi menghasilkan 20 nilai post_item_id dengan satu post_id yang sama.
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 biasanya tidak ada, jadi terus lakukan polling pada langkah 5 untuk mendapatkan postLinks jika Anda memerlukan tautan yang dapat diklik. Berikan respons 200 dalam waktu 5 detik; tidak ada percobaan ulang. Penerima dan pemeriksaan tanda tangan dijelaskan di Tanggapi peristiwa dengan webhook.
Langkah selanjutnya
- Hubungkan Google dan impor lokasi dan Hubungkan Halaman Facebook: prasyarat untuk setiap situs.
- Ambil analitik profil: jumlah penayangan dan tindakan pada tingkat profil, melengkapi penghitung per postingan di sini.
- Tanggapi peristiwa dengan webhook: penerima yang menerima peristiwa ini.
- Referensi: Buat postingan pengumuman, Buat postingan acara, Buat postingan penawaran, Buat postingan massal, Dapatkan postingan, Ambil postingan untuk suatu lokasi, Hapus postingan.