Lier Google Business Profile et importer vos établissements

Créez un lien de connexion Google, associez les fiches Google du propriétaire à vos établissements, confirmez et importez celles encore sans établissement.

Un compte Google connecté permet de publier du contenu et d’obtenir des rapports pour un établissement sur Google. Tant qu’aucun compte n’est connecté, la ligne Google Maps dans les fiches premium d’un établissement reste REQUIRING_ACTION, les avis Google ne sont pas récupérés, les publications ne peuvent pas être publiées sur GOOGLE et les données analytiques Google renvoient null. La connexion du compte résout ces quatre problèmes.

La procédure groupée (étapes 1 à 6) connecte un compte Google entier en une seule fois et recherche les correspondances entre toutes les fiches qu’il possède et vos établissements. La procédure pour un seul établissement (étape 7) connecte un établissement à la fois : le lien est associé à cet établissement, aucune étape de recherche de correspondances ne suit donc.

Le lien est limité au compte auquel appartient la clé API ; le corps de la requête contient donc uniquement vos deux URL de redirection. Dirigez le propriétaire vers url renvoyé dans la réponse ; Google le redirige vers successUrl ou errorUrl lorsqu’il termine.

Connect link
curl -X POST https://listingsapi.com/api/v4/connected-accounts/connect-google \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{  "input": {    "successUrl": "https://app.example.com/connect/google/success",    "errorUrl": "https://app.example.com/connect/google/error"  }}'
JSON
{  "data": {    "bulkConnectLinkForGoogle": {      "success": true,      "url": "https://connect.example.com/oauth?token=8f3c1d92-...",      "errors": null    }  }}

La valeur url ci-dessus est un exemple. Dirigez le propriétaire vers url renvoyé dans votre propre réponse.

Le lien est valable pendant 24 heures. Vérifiez que url n’est pas null au lieu de vous fier uniquement à success. Si les identifiants du propriétaire expirent par la suite, créez un nouveau lien de la même manière : la connexion existante est actualisée, sans être dupliquée.

2. Listez les comptes connectés après le retour OAuth

Lorsque le propriétaire arrive sur votre successUrl, listez les comptes Google. Il s’agit d’une page de résultats avec pagination par décalage : records[] et pageInfo.totalRecords, avec page et perPage pour parcourir les pages.

List accounts
curl "https://listingsapi.com/api/v4/connected-accounts?publisher=GoogleAccount&page=1&perPage=20" \-H "Authorization: API $LISTINGSAPI_KEY"
JSON
{  "data": {    "connectedAccountsInfo": {      "pageInfo": { "hasNextPage": false, "totalRecords": 1 },      "records": [        {          "connectedAccountId": "4f712c17-4f95-42dd-90f4-97171a2e67b5",          "email": "owner@brightsmile-dental.com",          "status": "CONNECTED",          "requestMatchesStatus": "MATCH_COMPLETED",          "connectedLocationsCount": 0        }      ]    }  }}

Sélectionnez l’enregistrement dont le champ email correspond au propriétaire qui vient de donner son consentement et conservez son connectedAccountId. Tous les appels suivants utilisent cet UUID.

statusSignification
CONNECTEDLes identifiants sont valides. Vous pouvez lancer la recherche de correspondances.
MATCH_IN_PROGRESSUne recherche de correspondances est en attente ou en cours.
CONNECTIVITY_ISSUEL’autorisation a expiré. connectivityIssue en indique la raison ; générez à nouveau le lien de connexion.

Le filtre de requête facultatif status utilise des termes différents (Connected, NotConnected, ConnectionIssue) ; si vous lui transmettez la valeur du champ status d’un enregistrement, l’API renvoie 400.

3. Lancez la recherche de correspondances

La recherche de correspondances récupère tous les profils auxquels le compte a accès et associe chacun d’eux à l’un de vos établissements. Elle produit uniquement des suggestions ; aucun lien n’est encore établi.

Trigger matches
curl -X POST https://listingsapi.com/api/v4/connected-accounts/trigger-matches \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "input": { "connectedAccountIds": ["4f712c17-4f95-42dd-90f4-97171a2e67b5"] } }'

La réponse est data.connectedAccountsTriggerMatches avec success et failedIds. success: true signifie que la tâche a été mise en file d’attente ; tout compte qui n’a pas pu être mis en file d’attente figure dans failedIds.

4. Interrogez régulièrement l’API jusqu’à obtenir MATCH_COMPLETED

Interrogez les détails du compte toutes les 15 secondes à l’aide d’une boucle bornée. Cet intervalle permet également de respecter la limite de 10 requêtes par minute du forfait Launch.

Poll details
curl https://listingsapi.com/api/v4/connected-accounts/4f712c17-4f95-42dd-90f4-97171a2e67b5/details \-H "Authorization: API $LISTINGSAPI_KEY"

L’enregistrement est renvoyé dans data.connectedAccountDetails.details et contient les mêmes champs qu’un enregistrement de la liste. requestMatchesStatus vaut MATCH_IN_PROGRESS pendant l’exécution de la tâche et MATCH_COMPLETED lorsque les suggestions sont prêtes. Completed signifie que la recherche de correspondances est terminée, sans qu’aucun lien soit nécessairement établi : connectedLocationsCount reste à 0 jusqu’à votre confirmation.

5. Examinez et confirmez les suggestions

Chaque suggestion associe l’un de vos établissements (locationInfo, dont le champ databaseId vaut locationId) à une fiche Google (suggestedLocationInfo). Présentez les deux éléments à un opérateur, ou acceptez automatiquement la suggestion lorsque le nom et la ville correspondent.

Suggestions
curl "https://listingsapi.com/api/v4/connected-accounts/4f712c17-4f95-42dd-90f4-97171a2e67b5/connection-suggestions?page=1&perPage=20" \-H "Authorization: API $LISTINGSAPI_KEY"
JSON
{  "data": {    "connectionSuggestionsForAccount": {      "pageInfo": { "hasNextPage": false, "totalRecords": 2 },      "records": [        {          "accountType": "GMB",          "matchedDataDatabaseId": "0d5e306f-0da0-46e3-929f-fd3c67ccd8cc",          "locationId": "73415",          "locationInfo": { "name": "My Business", "city": "Lincoln", "stateIso": "NE" },          "suggestedLocationInfo": { "locationInfo": { "name": "My Business", "city": "Lincoln" } }        }      ]    }  }}

Une suggestion ne possède pas de id. Pour la confirmer, vous construisez un identifiant d’enregistrement de correspondance : l’encodage en base64 de <MatchRecordType>:<matchedDataDatabaseId>, avec le type choisi parmi accountType. Pour Google (GMB), le type est GmbLocationMatchedData ; l’enregistrement ci-dessus est donc encodé sous la forme R21iTG9jYXRpb25NYXRjaGVkRGF0YTowZDVlMzA2Zi0wZGEwLTQ2ZTMtOTI5Zi1mZDNjNjdjY2Q4Y2M=. Facebook (FB) utilise FbLocationMatchedData et Apple (APPLE) utilise AppleLocationMatchedData.

Confirm matches
# base64 of GmbLocationMatchedData:0d5e306f-0da0-46e3-929f-fd3c67ccd8cccurl -X POST https://listingsapi.com/api/v4/connected-accounts/confirm-matches \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "input": { "matchRecordIds": ["R21iTG9jYXRpb25NYXRjaGVkRGF0YTowZDVlMzA2Zi0wZGEwLTQ2ZTMtOTI5Zi1mZDNjNjdjY2Q4Y2M="] } }'

La réponse est data.confirmConnectMatches avec success et failedIds. failedIds contient les valeurs décodées de matchedDataDatabaseId qui n’ont pas pu être confirmées, par exemple celles d’un enregistrement déjà utilisé ou d’un établissement archivé depuis la recherche de correspondances. Un identifiant construit avec un type incorrect n’entraîne pas le renvoi de 400 : l’appel renvoie 200 avec success: false et sans failedIds ; vérifiez donc success à chaque fois. Les suggestions non envoyées restent inchangées.

6. Importer les fiches qui n'ont pas encore d'établissement

La mise en correspondance associe uniquement les fiches aux établissements que vous avez déjà. Pour importer les autres, répertoriez toutes les fiches auxquelles le compte a accès, puis créez un établissement à partir de chaque fiche souhaitée.

Account listings
curl -X POST https://listingsapi.com/api/v4/connected-accounts/connected-account-listings \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "connectedAccountId": "4f712c17-4f95-42dd-90f4-97171a2e67b5", "perPage": 50 }'
JSON
{  "data": {    "connectedAccountListings": {      "pageInfo": { "hasNextPage": false, "totalRecords": 60 },      "records": [        {          "id": "R21iQnVsa0RhdGFMYWtlOjA2MDQ4NmExLTA0NzQtNDc4NS1iMjNhLTBkOGM4MzhmNGQ5OA==",          "locationName": "Trial",          "address": "123 William St, NY 10038, Manhattan, US",          "liveLink": null        }      ]    }  }}

Passez locationInfo avec un terme de recherche pour filtrer les fiches d'un compte volumineux par nom, adresse, téléphone, code postal ou code de magasin. La valeur id de chaque enregistrement correspond à la valeur connectedAccountListingId attendue par les deux appels suivants. Aucun des deux SDK ne propose encore de méthode pour create-location-from-listing ; les exemples Python et Node appellent donc REST directement avec le même en-tête.

Create from listing
curl -X POST https://listingsapi.com/api/v4/connected-accounts/create-location-from-listing \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{  "input": {    "connectedAccountId": "4f712c17-4f95-42dd-90f4-97171a2e67b5",    "connectedAccountListingId": "R21iQnVsa0RhdGFMYWtlOjA2MDQ4NmExLTA0NzQtNDc4NS1iMjNhLTBkOGM4MzhmNGQ5OA=="  }}'
JSON
{  "data": {    "createLocationFromConnectedAccountListing": { "success": true, "locationId": 88277, "errors": null }  }}

L'établissement est créé à partir des données Google (nom, adresse, horaires, catégories, téléphone, attributs) et immédiatement associé à la fiche. La fiche Google reste à l'état IN_PROGRESS jusqu'à ce que votre première mise à jour de l'établissement y soit publiée. locationId est simplement databaseId. En cas d'échec, success vaut false et errors contient un code tel que SY81067 (l'identifiant de la fiche n'a pas pu être résolu). Le champ est connectedAccountListingId ; listingId est rejeté par le schéma.

Si la fiche appartient à un établissement que vous avez déjà, associez-la à celui-ci au lieu de créer un doublon.

Link a listing
curl -X POST https://listingsapi.com/api/v4/connected-accounts/connect-listing \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{  "input": {    "locationId": "TG9jYXRpb246MTgwMDI4OQ==",    "connectedAccountId": "4f712c17-4f95-42dd-90f4-97171a2e67b5",    "connectedAccountListingId": "R21iQnVsa0RhdGFMYWtlOjA2MDQ4NmExLTA0NzQtNDc4NS1iMjNhLTBkOGM4MzhmNGQ5OA=="  }}'

Si l'association échoue, l'appel renvoie success: false avec message, par exemple Listing record not found, ou un message indiquant que la fiche est déjà associée à un autre établissement.

7. Connecter plutôt un seul établissement

Lorsque vous savez déjà quel établissement le propriétaire souhaite connecter, ignorez la mise en correspondance et créez un lien lié à cet établissement. En cas de réussite, le propriétaire revient à votre successUrl et les identifiants sont rattachés uniquement à cet établissement.

Single-location link
curl -X POST https://listingsapi.com/api/v4/locations/oauth_connect_url \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{  "input": {    "locationId": "TG9jYXRpb246MTgwMDI4OQ==",    "site": "GOOGLE",    "successUrl": "https://app.example.com/locations/1800289/connected",    "errorUrl": "https://app.example.com/locations/1800289/connect-failed"  }}'

La réponse est data.createConnectUrl avec success, url et errors. Le lien est à usage unique ; créez-en donc un nouveau à chaque tentative. Une URL de redirection relative ou impossible à analyser entraîne une réponse success: true avec null url ; vérifiez donc url. Si une clé n'est pas autorisée à accéder à cet établissement, l'appel renvoie 403 avec SY90003.

8. Ce qui se passe ensuite

Une fois la fiche associée, la ligne Google Maps dans les fiches premium de l'établissement quitte l'état REQUIRING_ACTION, passe par IN_PROGRESS et atteint l'état SYNCED avec listingUrl. Google est automatiquement ajouté comme source d'avis ; les avis commencent donc à apparaître dans la liste des interactions, et les mises à jour que vous apportez à l'établissement sont transmises au profil.

Si une URL de webhook est définie dans le tableau de bord, vous n'avez pas besoin d'interroger régulièrement l'API. Chaque charge utile contient location_id et data.connected_account_id.

ÉvénementDéclenché lorsqueAction à effectuer
connection.location_connectedUne fiche est associée à un établissement ; data.platform vaut google.Indiquez que l'établissement est connecté dans votre interface.
connection.reauth_requiredLes identifiants du compte ont été invalidés. Aucune synchronisation n'a lieu tant que l'autorisation n'a pas été renouvelée.Créez un nouveau lien (étape 1) et demandez au propriétaire de se reconnecter.
connection.listing_inaccessibleLes identifiants sont valides, mais l'accès à cette seule fiche a été supprimé.Demandez au propriétaire de rétablir l'accès sur Google, ou associez une autre fiche.

Étapes suivantes