Publications
Publiez des annonces, des événements et des offres sur Google et Facebook via client.posts.
Toutes les méthodes de publication se trouvent sous client.posts. Les méthodes qui prennent un location_id acceptent des ID numériques ou encodés en base64 ; consultez ID des établissements.
Les publications sont diffusées sur deux sites : GOOGLE et FACEBOOK. Les types de publication sont ANNOUNCEMENT, EVENT, OFFER, COVID19 et PRODUCT. Les types d'appel à l'action sont BOOK, ORDER, SHOP, LEARN_MORE, SIGN_UP et GET_OFFER ; cta_type et cta_url doivent toujours être fournis ensemble.
Publication asynchrone
La publication est asynchrone. Les appels de création renvoient status: INPROGRESS ; interrogez régulièrement posts.retrieve() (ou posts.bulk_retrieve() pour les campagnes groupées) jusqu'à ce que le statut soit SUCCESS, et vérifiez publishDetails[].submissionError pour détecter les échecs par site.
Messages par site
Chaque méthode de création accepte message sous forme de chaîne simple, ce qui publie le même texte sur chaque site, ou de dictionnaire associant chaque site à un texte :
message = { "GOOGLE": "Book your summer checkup today!", "FACEBOOK": "Summer checkups are here. Tag a friend who needs one!",}Lorsque message est un dictionnaire, il doit contenir une entrée pour chaque site figurant dans sites ; le SDK lève ValidationError avant tout appel réseau s'il manque une entrée.
posts.bulk_publish
Publiez un même contenu pour plusieurs établissements sur Google et Facebook en un seul appel. Il s'agit de la méthode recommandée pour publier : sites cible les deux sites par défaut, le message unique (ou le dictionnaire par site) est converti en une entrée par site, les ID des établissements sont encodés automatiquement et la charge utile est validée côté client avant tout appel réseau.
client.posts.bulk_publish( *, name: str, location_ids: list[str | int], message: str | dict[str, str], sites: list[str] | None = None, post_type: str = "ANNOUNCEMENT", cta_type: str | None = None, cta_url: str | None = None, media_url: str | None = None, scheduled_dates: dict | None = None, context_info: dict | None = None, additional_fields: dict | None = None,) -> APIObjectresult = client.posts.bulk_publish( name="Holiday hours", location_ids=[16808, 16809, 16810], message="Open until 10pm through the holidays!", media_url="https://cdn.example.com/holiday.jpg", cta_type="LEARN_MORE", cta_url="https://example.com/holiday-hours",)print(result.socialPost.id, result.socialPost.status) # INPROGRESS, publishes asyncposts.create_announcement
Créez une publication ANNOUNCEMENT : un message simple avec un appel à l'action et des médias facultatifs. sites vaut ["GOOGLE"] par défaut.
client.posts.create_announcement( *, name: str, location_ids: list[str | int], message: str | dict[str, str], sites: list[str] | None = None, cta_type: str | None = None, cta_url: str | None = None, media_url: str | None = None, scheduled_dates: dict | None = None, additional_fields: dict | None = None,) -> APIObjectresult = client.posts.create_announcement( name="Grand Opening", location_ids=[16808], message="Acme Dental is now open!", sites=["GOOGLE"], cta_type="LEARN_MORE", cta_url="https://acmedental.example.com/opening",)print(result.socialPost.id)posts.create_event
Créez une publication EVENT avec un titre et une période définie par un début et une fin. Google exige le titre de l'événement ; le SDK lève ValidationError s'il est absent. start_day et end_day sont des dates (YYYY-MM-DD) ; start_time et end_time sont des chaînes destinées à l'affichage, comme "10:00am".
client.posts.create_event( *, name: str, location_ids: list[str | int], message: str | dict[str, str], title: str, start_day: str, end_day: str, start_time: str | None = None, end_time: str | None = None, sites: list[str] | None = None, cta_type: str | None = None, cta_url: str | None = None, media_url: str | None = None, scheduled_dates: dict | None = None, additional_fields: dict | None = None,) -> APIObjectresult = client.posts.create_event( name="Free checkup day", location_ids=[16808], message="Join us for free dental checkups!", title="Free Checkup Day", start_day="2026-08-01", end_day="2026-08-01", start_time="10:00am", end_time="4:00pm", cta_type="BOOK", cta_url="https://acmedental.example.com/book",)print(result.socialPost.id)posts.create_offer
Créez une publication OFFER avec un coupon, une remise et des conditions. title définit le libellé de l'offre et est obligatoire ; start_day et end_day (YYYY-MM-DD) délimitent sa période de validité.
client.posts.create_offer( *, name: str, location_ids: list[str | int], message: str | dict[str, str], title: str, coupon_code: str | None = None, discount: str | None = None, redeem_url: str | None = None, terms_conditions: str | None = None, start_day: str | None = None, end_day: str | None = None, sites: list[str] | None = None, cta_type: str | None = None, cta_url: str | None = None, media_url: str | None = None, scheduled_dates: dict | None = None, additional_fields: dict | None = None,) -> APIObjectresult = client.posts.create_offer( name="Summer whitening sale", location_ids=[16808], message="20% off teeth whitening all week!", title="Summer Whitening Sale", coupon_code="SUMMER20", discount="20%", redeem_url="https://acmedental.example.com/sale", terms_conditions="One per patient. Not valid with other offers.", start_day="2026-08-01", end_day="2026-08-07",)print(result.socialPost.id)posts.create
Créez une publication à partir d'un dictionnaire représentant le corps brut. Vous transmettez les champs à plat dans camelCase, et la fonction utilitaire les place dans l'objet input requis par l'API avant l'envoi : le corps transmis est {"input": {...}}, jamais un corps à plat. locationIds doit déjà être encodé en base64. Privilégiez les méthodes de création typées ci-dessus pour utiliser des arguments nommés, l'encodage automatique des ID et la validation côté client.
client.posts.create(body: dict) -> APIObjectObligatoires : postName, locationIds (base64), postType, postSites.
result = client.posts.create({ "postName": "Grand Opening", "locationIds": ["TG9jYXRpb246MTY4MDg="], "postType": "ANNOUNCEMENT", "postSites": ["GOOGLE"], "postMessage": [{"site": "GOOGLE", "message": "We are now open!"}],})print(result.socialPost.id)posts.retrieve
Récupérez une publication avec son contenu, son statut de publication par site et ses données analytiques. Après une création, répétez cet appel jusqu'à ce que status soit SUCCESS.
client.posts.retrieve(post_id: str) -> APIObjectpost = client.posts.retrieve("U29jaWFsUG9zdDo0NDEyMg==")print(post.status)for detail in post.publishDetails: print(detail.site, detail.submissionError)posts.delete
Supprimez une publication et retirez-la de tous les sites sur lesquels elle a été publiée.
client.posts.delete(post_id: str) -> APIObjectclient.posts.delete("U29jaWFsUG9zdDo0NDEyMg==")posts.list_for_location
Listez les campagnes de publication ciblant un établissement. La pagination utilise un décalage : le résultat contient .records ainsi que .pageInfo avec totalPages, totalRecords et hasNextPage. La réponse se trouve sous postsByLocation.
Cette route rejette un tag ; depuis la version 0.5.3, le SDK accepte donc cet argument pour assurer la rétrocompatibilité, mais ne le transmet jamais. Utilisez posts.bulk_list_for_location lorsque vous avez besoin de filtrer par étiquette.
client.posts.list_for_location( location_id: str | int, *, tag: str = "all", page: int | None = None, per_page: int | None = None, filters: dict | None = None, sort_fields: dict | None = None,) -> APIObjectresult = client.posts.list_for_location(16808, page=1, per_page=10)for post in result.records: print(post.id, post.name)print(result.pageInfo.totalRecords)posts.bulk_retrieve
Récupérez une campagne groupée (pour plusieurs établissements) avec le statut de publication et les données analytiques par établissement.
client.posts.bulk_retrieve(bulk_post_id: str) -> APIObjectbulk = client.posts.bulk_retrieve("QnVsa1Bvc3Q6OTk=")print(bulk.status)posts.bulk_list_for_location
Listez les campagnes groupées (pour plusieurs établissements) qui incluent un établissement. Les paramètres et la structure du résultat sont identiques à ceux de posts.list_for_location.
client.posts.bulk_list_for_location( location_id: str | int, *, tag: str = "all", page: int | None = None, per_page: int | None = None, filters: dict | None = None, sort_fields: dict | None = None,) -> APIObjectresult = client.posts.bulk_list_for_location(16808, page=1, per_page=10)for campaign in result.records: print(campaign.id, campaign.name)Voir aussi
- Établissements : créez et gérez les établissements pour lesquels vous publiez
- Fiches : vérifiez l’état de synchronisation par établissement
- Statistiques : statistiques des profils Google, Bing et Facebook