Google ve Facebook'ta gönderi yayımlayın

Duyuru, etkinlik ve teklif yayımlayın; çok konumlu gönderi planlayın, her sitede yayını doğrulayın, konum gönderilerini yönetin ve webhook'ları yanıtlayın.

Gönderi, bir konumun Google Business Profile veya Facebook Sayfasında yer alan tarihli bir karttır: duyuru, etkinlik veya teklif olabilir. Bir çağrı gönderiyi oluşturur, yayımlama arka planda yürütülür ve ikinci bir çağrı her sitenin gönderiyi kabul edip etmediğini bildirir.

Üç gönderi türü de gövde input içine sarılmış olarak POST /posts kullanır. Sarmalanmamış bir gövde 400 ile reddedilir. SDK'lar sarmalayıcıyı oluşturur ve göndermeden önce veri yükünü doğrular.

input alanıAmaç
postNameDahili kampanya adı. Müşterilere gösterilmez.
locationIdsBase64 konum id değerleri.
postTypeANNOUNCEMENT, EVENT veya OFFER.
postSitesGOOGLE, FACEBOOK veya her ikisi.
postMessage[]postSites içindeki her site için bir { site, message }.
postCta[]İsteğe bağlı { site, type, url }. type değeri BOOK, ORDER, SHOP, LEARN_MORE, SIGN_UP veya GET_OFFER olur.
postMediaUrl[]type değeri IMAGE veya VIDEO olan isteğe bağlı { site, url, type }.
postContextInfoEtkinlik tarihleri veya teklif ayrıntıları. EVENT ve OFFER için zorunludur.

1. Bir duyuru yayımlayın

Bir duyuru bir mesaj, isteğe bağlı bir düğme ve isteğe bağlı bir görsel alır.

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://acmekitchen.example.com/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 değerini saklayın. status başlangıçta INPROGRESS değerindedir ve bir site gönderiyi kabul edene kadar postLinks boş kalır; 5. adımda her ikisi de geri okunur.

2. Bir etkinlik yayımlayın

Bir etkinlik, title, startDay, endDay ve isteğe bağlı görüntüleme saatlerini içeren postContextInfo ekler. Google, başlığı olmayan bir etkinliği reddeder ve başlık eksikse SDK'lar göndermeden önce ValidationError hatası üretir.

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, giveaways, and up to 40% off in store." }    ]  }}'

Yanıt, 1. adımdakiyle aynı yapıdadır; type: "EVENT" içerir ve tarihler socialPost.contextInfo altında döndürülür. postContextInfo etkinliğin kendi tarihlerini tutar; postScheduledDates (4. adım), gönderinin ne zaman yayımlanacağını ve yayından kaldırılacağını belirler.

3. Bir teklif yayımlayın

Bir teklifin postContextInfo alanı title, couponCode, discount, redeemUrl, termsConditions ve geçerlilik aralığını belirleyen startDay ile endDay alanlarını taşır. Bunu Facebook'ta bir GET_OFFER düğmesiyle veya Google'da ORDER düğmesiyle eşleştirin; REDEEM türü yoktur.

Offer
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." }    ]  }}'

Yanıt, teklif alanlarını socialPost.contextInfo altında döndürür ve scheduledStartDate ile scheduledEndDate değerlerini geçerlilik aralığına göre ayarlar.

4. Tek bir gönderiyi zamanlayarak birden çok konuma gönderin

POST /bulk-posts aynı input değerini alır ve tek bir kampanyayı locationIds içindeki her id değerine gönderir. Daha sonra yayımlamak ve otomatik olarak yayından kaldırmak için ISO-8601 biçimindeki startDatetime ve endDatetime değerlerini içeren postScheduledDates ekleyin; gönderi bu durumda SCHEDULED olarak oluşturulur. Üslup farklı olduğunda her site için ayrı bir mesaj yazın.

Bulk post
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"    }  }}'

Toplu işlem uç noktası POST /posts ile aynı yapıyı döndürür; bu nedenle yanıtın anahtarı da createSocialPost olur ve yanıt status: "SCHEDULED" ile locationIds içinde her iki id değerini içerir. Bir doğrulama sorunu oluştuğunda success: false ve içi doldurulmuş bir errors dizisiyle birlikte 200 döndürülür; SDK'lar bunun için ValidationError hatası üretir. Toplu kampanyayı, konum başına durum bilgisi ekleyen GET /bulk-posts/{postId} ile geri okuyun.

5. Yayımlama durumunu kontrol edin ve gönderi bağlantılarını toplayın

GET /posts/{postId}, kampanyayı socialPostView altında döndürür. Oluşturma işleminden sonra socialPostInfo.status, INPROGRESS durumundan çıkana kadar düzenli aralıklarla sorgulayın; ardından her sitenin sonucu için publishDetails[] ve yayındaki URL'ler için postLinks[] alanını okuyun. Sorgulamalar arasında onlarca saniye bırakın; 429 ile birlikte Retry-After gelir.

Post status
curl https://listingsapi.com/api/v4/posts/U29jaWFsUG9zdDo0NDEyMg== \-H "Authorization: API $LISTINGSAPI_KEY"
JSON
{  "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 }      ]    }  }}
AlanDeğerlerAnlam
socialPostInfo.statusINPROGRESS, SCHEDULED, SUCCESS, EXPIREDKampanyanın bütünü. SUCCESS, yayımlamanın tamamlandığı anlamına gelir; her sitenin gönderiyi kabul ettiği anlamına gelmez.
publishDetails[].statusPUBLISHING, PUBLISHED, ERRORHer site için bir kayıt. ERROR durumunda submissionError nedenini belirtir.
postLinks[]{ site, link }Yayımlandıktan sonra her site için yayındaki URL.

views, clicks, reactions, shares ve comments aynı kayıtta birikir ve socialPostAnalyticsBySite içinde site bazında ayrılır. SDK'lar doğrudan socialPostInfo döndürür; bu nedenle örnekler post.status alanını okur.

6. Bir konumun gönderilerini listeleyin ve birini silin

GET /locations/{locationId}/posts, konumu içeren tüm kampanyaların postsByLocation altında records[] ve pageInfo.totalRecords ile sunulduğu, ofset tabanlı bir sayfadır (page, en fazla 50 olacak şekilde perPage). base64 id değerini değiştirmeden iletin; URL kodlaması uygulamayın. Tür filtresi yoktur; bu nedenle teklifleri veya etkinlikleri kendi kodunuzda type içinden seçin. 4. adımdaki çok konumlu kampanyalar GET /locations/{locationId}/bulk-posts tarafından ayrı olarak listelenir.

DELETE /posts/{postId}, kampanyayı buradan kaldırır ve ulaştığı tüm sitelerden yayından kaldırır. Geri alma olanağı yoktur; bu nedenle önce listedeki id değerini doğrulayın.

List and delete
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"

Silme işlemi, success: true ve kaldırdığı socialPostId ile birlikte data.deleteSocialPost yanıtını döndürür. Zaten silinmiş bir id değerini silmek ise data: null içeren bir errors yanıtı döndürür; böylece ikinci bir silme işlemi kolayca tespit edilebilir.

7. Gönderi webhook'larına tepki verin

/dashboard/webhooks üzerinde bir webhook URL'si ayarlandığında, tamamı standart veri yükünde yer alan dört olay gönderinin yaşam döngüsünü kapsar. Bu olaylar kampanya başına değil, konum başına tetiklenir: 20 konuma yapılan toplu gönderi, ortak bir post_id ile 20 post_item_id değeri üretir.

OlayTetiklenme koşuluEk data alanı
local_post.createdÖğe Google için sıraya alındı. Henüz yayında değil.
local_post.publishedGoogle öğeyi kabul etti ve öğe yayında.post_external_id, Google'ın kaynak adı.
local_post.rejectedGoogle öğeyi reddetti veya gönderim başarısız oldu.rejection_reason.
local_post.deletedÖğe silindi.post_external_id.
Route local_post events
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 genellikle bulunmaz; bu nedenle tıklanabilir bir bağlantıya ihtiyacınız varsa postLinks için 5. adımdaki sorgulamayı tekrarlamaya devam edin. 5 saniye içinde 200 yanıtını döndürün; yeniden deneme yapılmaz. Alıcı ve imza denetimi Webhook'larla olaylara tepki verin bölümündedir.

Sonraki adımlar