拠点
拠点の全エンドポイントを、cURL、Python、Nodeのサンプルとともに、利用順に紹介します。一覧取得、検索、idと店舗コードによる取得、作成、更新、アーカイブ、写真管理を扱います。
掲載情報、レビュー、投稿、分析データは、すべて拠点IDに紐づいています。拠点リソースには13のエンドポイントがあり、拠点を検索・取得する4つの読み取りエンドポイント、拠点を作成・変更・アーカイブする4つの書き込みエンドポイント、写真を管理する5つのエンドポイントで構成されています。読み取りにはRead(読み取り)キーを使用できます。すべてのPOSTにはWrite(書き込み)キーが必要で、書き込みにReadキーを使用すると、HTTP 400とSY90016が返されます。
このガイドに登場するidはすべてbase64形式のRelay idです。たとえば、TG9jYXRpb246MTgwMDI4OQ==はLocation:1800289にデコードされます。両方のSDKは数値のdatabaseIdも受け付け、自動的にエンコードします。
エンドポイント一覧
すべての拠点の一覧を取得する
GET /locationsは、アカウント内のすべての拠点を新しい順にページ単位で取得します。カーソル形式のコネクションで、edges[].nodeに各レコードが格納され、pageInfo.endCursorの値を次のページのafterパラメーターに渡します。アカウント全体を独自のシステムに同期する際に使用します。
パラメーター
curl "https://listingsapi.com/api/v4/locations?first=50" \-H "Authorization: API $LISTINGSAPI_KEY"{ "data": { "allLocations": { "edges": [ { "cursor": "TG9jYXRpb246MTgwMDI4OQ==", "node": { "id": "TG9jYXRpb246MTgwMDI4OQ==", "databaseId": 1800289, "name": "Jenny Home", "storeId": null, "approved": "APPROVED", "archived": false, "archivalScheduledAt": null, "city": "Austin", "stateIso": "TX", "countryIso": "US", "subCategoryId": 1432, "planName": "Launch", "placeActionLinks": [], "discoveredPlaceActionLinks": [] } } ], "pageInfo": { "hasNextPage": false, "hasPreviousPage": false, "endCursor": "TG9jYXRpb246MTgwMDI4OQ==", "total": 1 } } }}pageInfo.hasNextPageを読み取り、falseになったら停止します。ページ単位の件数はpageInfo.totalです。ノードのidは、他のすべてのエンドポイントが受け付ける識別子です。
拠点を検索する
GET /locations/searchは、拠点名、番地・通り名、市区町村、店舗idを対象にキーワードを照合します。一覧取得と同じedges[].nodeおよびpageInfo.endCursorの構造を持つ、カーソル形式のコネクションです。入力に応じて候補を表示する選択UIや、店舗を作成する前にその店舗が存在するかを確認する用途に使用します。
パラメーター
両方のSDKはfieldsのリストも受け付け、照合対象を特定のフィールド(たとえばnameのみ)に限定できます。
curl "https://listingsapi.com/api/v4/locations/search?query=Jenny&first=10" \-H "Authorization: API $LISTINGSAPI_KEY"{ "data": { "searchLocations": { "edges": [ { "cursor": "TG9jYXRpb246MTgwMDI4OQ==", "node": { "id": "TG9jYXRpb246MTgwMDI4OQ==", "databaseId": 1800289, "name": "Jenny Home", "storeId": null, "street": "600 Congress Ave, Suite 200", "city": "Austin", "approved": "APPROVED", "archived": false } } ], "pageInfo": { "endCursor": "TG9jYXRpb246MTgwMDI4OQ==", "hasNextPage": false, "hasPreviousPage": false, "total": 1 } } }}edges配列が空の場合、一致する結果がなかったことを意味します。ノードには完全な住所、カテゴリ、approvedの状態が含まれるため、結果行を表示するために再度取得する必要はありません。
IDで拠点を取得する
GET /locations-by-idsは、複数のbase64 IDに対応する完全なレコードを1回の呼び出しで返すため、拠点ごとに呼び出す場合よりリクエスト数を減らせます。有効な拠点とアーカイブ済みの拠点の両方を取得できます。コネクションではなく、通常の配列を返します。Webhookのペイロードや独自のストアにあるIDから完全なレコードを取得するために使用します。
パラメーター
curl -G https://listingsapi.com/api/v4/locations-by-ids \--data-urlencode 'ids=["TG9jYXRpb246MTgwMDI4OQ==","TG9jYXRpb246MTgwMDI5MA=="]' \-H "Authorization: API $LISTINGSAPI_KEY"{ "data": { "getLocationsByIds": [ { "id": "TG9jYXRpb246MTgwMDI4OQ==", "databaseId": 1800289, "storeId": null, "name": "Jenny Home", "archived": false, "archivedAt": null, "city": "Austin", "stateIso": "TX", "countryIso": "US", "subCategoryId": 1432, "businessHours": [], "locationPhotos": [], "placeActionLinks": [], "discoveredPlaceActionLinks": [] } ] }}アカウント内に存在しないIDは、エラーにならずに除外されます。返された件数と送信した件数を比較すると、無効になったIDを検出できます。
店舗コードで拠点を取得する
GET /locations-by-store-codesは逆引きを行い、独自の店舗コードから完全なレコードを取得します。通常の配列を返します。POSやフランチャイズの店舗台帳で店舗コードを拠点のキーとして使用しており、Listings APIのIDを保存していない場合に使用します。
パラメーター
curl -G https://listingsapi.com/api/v4/locations-by-store-codes \--data-urlencode 'storeCodes=["ACME01","ACME02"]' \-H "Authorization: API $LISTINGSAPI_KEY"{ "data": { "getLocationsByStoreCodes": [ { "id": "TG9jYXRpb246MTgwMDI4OQ==", "databaseId": 1800289, "storeId": "ACME01", "name": "Jenny Home", "archived": false, "city": "Austin", "countryIso": "US", "planName": "Launch" } ] }}各オブジェクトのstoreIdを店舗台帳と照合してください。一致するものがないコードは含まれません。拠点に店舗コードがあるのは、作成時または更新時にstoreIdが設定された場合のみです。
拠点を作成する
POST /locationsは拠点を作成し、プランに含まれるすべての掲載先への送信キューに追加します。ただし、enabledSiteIdsフィールドを渡した場合は、そのフィールドで指定した掲載先のみが対象になります。すべてのフィールドはinputの下に配置します。10個のフィールドが必須で、残りは任意です。省略したフィールドは掲載先で空欄として表示されます。
パラメーター
このほか、リファレンスページに記載されている任意のフィールドとして、Google GCIDカテゴリ、ソーシャルURL、座標、オーナーの連絡先、支払い方法、サービス提供地域などがあります。
curl -X POST https://listingsapi.com/api/v4/locations \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "input": { "name": "Acme Kitchen", "description": "Acme Kitchen is a family-owned neighborhood restaurant in downtown New York serving wood-fired pizza, hand-rolled pasta, and a short seasonal menu built around produce from nearby growers. Our dining room seats forty, takeout and delivery run until close, and the bar pours regional wine and beer on tap.", "storeId": "ACME01", "street": "123 Jump Street", "city": "New York", "stateIso": "NY", "postalCode": "10013", "countryIso": "US", "phone": "6443859313", "bizUrl": "https://acmekitchen.example.com", "subCategoryId": 1432, "businessHours": [ { "day": "MONDAY", "type": "OPEN", "slots": [{ "start": "09:00am", "end": "05:00pm" }] }, { "day": "TUESDAY", "type": "OPEN", "slots": [{ "start": "09:00am", "end": "05:00pm" }] }, { "day": "WEDNESDAY", "type": "OPEN", "slots": [{ "start": "09:00am", "end": "05:00pm" }] }, { "day": "THURSDAY", "type": "OPEN", "slots": [{ "start": "09:00am", "end": "05:00pm" }] }, { "day": "FRIDAY", "type": "OPEN", "slots": [{ "start": "09:00am", "end": "05:00pm" }] }, { "day": "SATURDAY", "type": "OPEN", "slots": [{ "start": "10:00am", "end": "02:00pm" }] }, { "day": "SUNDAY", "type": "CLOSED", "slots": [] } ], "placeActionLinks": [ { "placeActionType": "FOOD_ORDERING", "uri": "https://order.acmekitchen.example.com", "isPreferred": true } ] }}'{ "data": { "createLocation": { "clientMutationId": null, "success": true, "errors": null, "location": { "id": "TG9jYXRpb246MTgwMDI5MA==", "databaseId": 1800290, "storeId": "ACME01", "name": "Acme Kitchen", "city": "New York", "countryIso": "US", "status": "PENDING", "placeActionLinks": [ { "placeActionType": "FOOD_ORDERING", "uri": "https://order.acmekitchen.example.com", "isPreferred": true, "name": null, "submissionStatus": null } ], "discoveredPlaceActionLinks": [] } } }}両方のIDを保持してください。base64のidは以降のすべての書き込みに必要で、databaseIdはダッシュボードやWebhookに表示される番号です。statusはPENDINGで始まり、追加のAPI呼び出しなしで次の状態に進みます。プレイスアクションリンクのnameとsubmissionStatusは、Googleと同期されるまでnullのままです。Pythonのlocations.add()は必須フィールドをローカルで検証し、ネットワーク呼び出しの前にValidationErrorを送出します。一方、locations.create(input)はcamelCaseのdictをそのまま受け取ります。
拠点を更新する
POST /locations/updateは部分更新です。必須フィールドはinput.idのみで、送信したフィールドだけが変更されます。同じ呼び出しで、電話番号の修正も週間スケジュールの書き換えもできます。Pythonのlocations.update()とNodeのupdateLocation()は、どちらも1つのcamelCaseオブジェクトを受け取ります。
パラメーター
このほか、リファレンスページに記載されている任意フィールドも使用できます。
curl -X POST https://listingsapi.com/api/v4/locations/update \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "input": { "id": "TG9jYXRpb246MTgwMDI4OQ==", "phone": "5125550199", "bizUrl": "https://acmekitchen.example.com", "primaryGbpSiteCategoryId": "gcid:restaurant", "businessHours": [ { "day": "MONDAY", "type": "OPEN", "slots": [{ "start": "09:00am", "end": "05:00pm" }] }, { "day": "TUESDAY", "type": "OPEN", "slots": [{ "start": "09:00am", "end": "05:00pm" }] }, { "day": "WEDNESDAY", "type": "OPEN", "slots": [{ "start": "09:00am", "end": "05:00pm" }] }, { "day": "THURSDAY", "type": "OPEN", "slots": [{ "start": "09:00am", "end": "05:00pm" }] }, { "day": "FRIDAY", "type": "OPEN", "slots": [{ "start": "09:00am", "end": "05:00pm" }] }, { "day": "SATURDAY", "type": "OPEN", "slots": [{ "start": "10:00am", "end": "02:00pm" }] }, { "day": "SUNDAY", "type": "CLOSED", "slots": [] } ] }}'{ "data": { "updateLocation": { "clientMutationId": null, "success": true, "errors": null, "location": { "id": "TG9jYXRpb246MTgwMDI4OQ==", "databaseId": 1800289, "name": "Jenny Home", "phone": "5125550199", "status": "APPROVED", "placeActionLinks": [ { "placeActionType": "FOOD_ORDERING", "uri": "https://order.example.com", "isPreferred": true, "name": null, "submissionStatus": null } ], "discoveredPlaceActionLinks": [] } } }}レスポンスには更新後の拠点が返されるため、新しい値が適用されたことを確認できます。更新のたびに、その拠点の現在のplaceActionLinksの完全なセットが返されます。リンクのURLを変更するには、同じリクエストで古いリンクのdeleteと新しいリンクのaddを送信してください。
拠点をアーカイブする
POST /locations/archiveは、1つ以上の拠点のアーカイブを予約します。アーカイブは即時には行われず、各拠点はARCHIVE_SCHEDULEDに移行し、現在の請求サイクルが終了するまで公開と課金が継続され、次の請求書が生成されるときにアーカイブされます。閉鎖した支店の利用を一括で終了する際に使用してください。
パラメーター
curl -X POST https://listingsapi.com/api/v4/locations/archive \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "input": { "locationIds": ["TG9jYXRpb246MTgwMDI4OQ==", "TG9jYXRpb246MTgwMDI5MA=="] }}'{ "data": { "archiveLocations": { "clientMutationId": null, "bulkEditTaskId": null, "errors": null, "success": null, "result": [ { "locationId": "TG9jYXRpb246MTgwMDI4OQ==", "status": "ARCHIVE_SCHEDULED", "success": true, "errors": null }, { "locationId": "TG9jYXRpb246MTgwMDI5MA==", "status": "ARCHIVE_SCHEDULED", "success": true, "errors": null } ] } }}最上位のsuccessはnullです。代わりに各result[]エントリ固有のsuccessを確認することで、1つの不正なidによってバッチの残りの処理が妨げられるのを防げます。
アーカイブが予約されている間は、一覧と検索の結果で拠点のarchivalScheduledAtが設定されます。アーカイブされた拠点は、再有効化するまで更新できません。
アーカイブの予約を取り消す
POST /locations/cancel_archiveは、ARCHIVE_SCHEDULEDの拠点をACTIVEに戻し、課金は継続されます。この呼び出しは請求サイクルが終了していない間のみ有効で、拠点が完全にアーカイブされると、その拠点に対して404を返します。
パラメーター
curl -X POST https://listingsapi.com/api/v4/locations/cancel_archive \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "input": { "locationIds": ["TG9jYXRpb246MTgwMDI4OQ=="] } }'{ "data": { "cancelLocationsArchive": { "clientMutationId": null, "bulkEditTaskId": null, "errors": null, "success": null, "result": [ { "locationId": "TG9jYXRpb246MTgwMDI4OQ==", "status": "ACTIVE", "success": true, "errors": null } ] } }}各result[]エントリで、拠点がACTIVEに戻ったことを確認できます。どちらのSDKも、追加の位置引数として選択タイプとchangedBy識別子の2つを必要とし、これらをlocationIdsと一緒に送信しますが、RESTのbodyに必要なのはidのみです。
拠点に写真をアップロードする
POST /locations/photosは公開URLを使って画像を添付します。画像は利用者側でホストし、APIが取得して保存します。拠点には、LOGOを1枚、COVERを1枚、ADDITIONALの写真を任意の枚数保存できます。ロゴまたはカバーを再アップロードすると、既存のものが置き換えられます。
パラメーター
curl -X POST https://listingsapi.com/api/v4/locations/photos \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "input": { "locationId": "TG9jYXRpb246MTgwMDI4OQ==", "photos": [ { "photo": "https://cdn.example.com/jenny-home/logo.png", "type": "LOGO" }, { "photo": "https://cdn.example.com/jenny-home/storefront.jpg", "type": "ADDITIONAL" } ] }}'{ "data": { "addLocationPhotos": { "clientMutationId": null, "success": true, "request": {}, "photos": [ { "id": "TWVkaWFGaWxlOjU4Nzg5MzE=", "databaseId": 5878931, "type": "LOGO", "starred": false, "url": "https://sy-media-store.s3-us-west-2.amazonaws.com/f868bb3f/59c670a3/f47d62a6.png" }, { "id": "TWVkaWFGaWxlOjU4Nzg5MzI=", "databaseId": 5878932, "type": "ADDITIONAL", "starred": false, "url": "https://sy-media-store.s3-us-west-2.amazonaws.com/f868bb3f/59c670a3/ef4ffb12.jpg" } ], "errors": null } }}各写真のidを保存してください。スター付与と削除のエンドポイントで使用します。これは小規模なバッチ向けのインライン形式です。大規模なバッチは代わりにキューに登録され、photosは空で返され、request.requestIdが設定されるので、そのidを使って次のエンドポイントをポーリングします。しきい値はサーバー側の設定で決まるため、request.requestIdの有無で処理を分岐してください。
写真の一括アップロードのステータスを確認する
GET /locations/photos/requests/{requestId} は、キューに入ったアップロードの処理が確定するまでポーリングし、その後、画像ごとの結果を報告します。進捗バーを更新し、どのファイルがどのような理由で拒否されたかを正確に表示するために使用します。
パラメーター
curl https://listingsapi.com/api/v4/locations/photos/requests/e6c2d9d9-9a18-4015-88cf-9a4e19a6f49a \-H "Authorization: API $LISTINGSAPI_KEY"{ "data": { "getLocationPhotosUploadStatus": { "requestId": "e6c2d9d9-9a18-4015-88cf-9a4e19a6f49a", "status": "SUCCESS", "photos": [ { "mediaId": "TWVkaWFGaWxlOjkxODI3", "locationId": "TG9jYXRpb246MTgwMDI4OQ==", "status": "SUCCESS", "errorMessage": null }, { "mediaId": null, "locationId": "TG9jYXRpb246MTgwMDI4OQ==", "status": "ERROR", "errorMessage": "Image dimensions below the minimum 250x250." } ] } }}ジョブのステータスが示すのは処理の完了だけであり、すべての画像が正常に追加されたことではありません。ポーリングの間隔は数秒空けてください。間隔を空けずに繰り返すと、すぐに 429 が返されます。
拠点の写真を取得する
GET /locations/{locationId}/photos は、拠点のすべてのメディアファイルを通常の配列として返します。これにはロゴ、カバー、追加画像が含まれ、それぞれに公開 url、thumbnailUrl、カテゴリ、starred フラグ、全期間の viewsCount が含まれます。アップロード前に呼び出して、どの枠が空いているかを確認し、スターの付与や削除の呼び出しに使用する id を収集してください。
パラメーター
curl https://listingsapi.com/api/v4/locations/TG9jYXRpb246MTgwMDI4OQ==/photos \-H "Authorization: API $LISTINGSAPI_KEY"{ "data": { "mediaFilesOfLocation": [ { "id": "TWVkaWFGaWxlOjU4Nzg5MzE=", "categoryName": "Logo", "categoryId": "4", "fileType": "image", "starred": false, "viewsCount": 0, "url": "https://sy-media-store.s3-us-west-2.amazonaws.com/f868bb3f/59c670a3/f47d62a6.jpg", "thumbnailUrl": "https://sy-media-store.s3-us-west-2.amazonaws.com/f868bb3f/59c670a3/thumbnail_f47d62a6.jpg" }, { "id": "TWVkaWFGaWxlOjU4Nzg5MzI=", "categoryName": "Additional", "categoryId": "12", "fileType": "image", "starred": true, "viewsCount": 143, "url": "https://sy-media-store.s3-us-west-2.amazonaws.com/f868bb3f/59c670a3/ef4ffb12.jpg", "thumbnailUrl": "https://sy-media-store.s3-us-west-2.amazonaws.com/f868bb3f/59c670a3/thumbnail_ef4ffb12.jpg" } ] }}categoryName は、Logo、Cover、または Additional です。グリッド表示には thumbnailUrl を、フルサイズ表示には url を使用してください。メディアがない拠点では、エラーではなく空の配列が返されます。
拠点の写真にスターを付ける
POST /locations/photos/star は、注目画像に対応する掲載先で優先的に表示されるように、追加写真に印を付けます。スターを付けられるのは ADDITIONAL の写真のみで、拠点ごとに最大 4 枚です。スターの解除も同じ仕組みで、body 内の starred フラグによって動作が決まります。
パラメーター
curl -X POST https://listingsapi.com/api/v4/locations/photos/star \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "input": { "locationId": "TG9jYXRpb246MTgwMDI4OQ==", "photoIds": ["TWVkaWFGaWxlOjU4Nzg5MzI="], "starred": true }}'{ "data": { "starUnstarLocationPhotos": { "success": true, "photos": [ { "id": "TWVkaWFGaWxlOjU4Nzg5MzI=", "databaseId": 5878932, "type": "ADDITIONAL", "starred": true } ], "error": null } }}どちらのパスでもレスポンスキーは starUnstarLocationPhotos で、その値は errors の配列ではなく単一の error です。スター付きの写真が 5 枚目になると、呼び出し全体が SY15012 で失敗します。このチェックでは、すでにスターが付いている写真と、このリクエストに含まれる写真の合計を数えます。
拠点から写真を削除する
POST /locations/photos/remove は、メディアの id を指定して追加写真の関連付けを解除します。古くなった店舗外観の画像を取り除いたり、誤った一括インポートを取り消したりするために使用します。削除できるのは ADDITIONAL の写真のみで、ロゴやカバーを置き換えるには、該当する type を指定して新しい画像をアップロードしてください。
パラメーター
curl -X POST https://listingsapi.com/api/v4/locations/photos/remove \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "input": { "locationId": "TG9jYXRpb246MTgwMDI4OQ==", "photoIds": ["TWVkaWFGaWxlOjU4Nzg5MzI="] }}'{ "data": { "removeLocationPhotos": { "clientMutationId": null, "removedCount": 1, "errors": null } }}removedCount は実際に関連付けが解除されたファイル数を報告するため、0 で errors: null の場合、それらの id はいずれもこの拠点に関連付けられていなかったことを意味します。削除によってファイルの関連付けは解除されますが、メディアライブラリから完全に削除されるとは限りません。
発生するエラー
書き込みでは、success: false と、data.<operation>.errors に詳細を含む HTTP 200 が返される場合もあります。完全な一覧は エラーコード に記載されています。
次の手順
- 拠点を追加する、拠点を更新する、拠点の写真をアップロードする、拠点を検索してアーカイブする:これらのエンドポイントを使用するタスクガイドです。
- 国とカテゴリを検索する:作成に必要な
countryIso、stateIso、subCategoryIdの値を確認できます。 - プレイスアクションリンク:作成時と更新時に使用するGoogleのアクションボタンの完全なモデルです。
- 拠点:リソースのトップページと、PythonおよびNodeのSDKリファレンスです。
- 写真のメソッドには専用のSDKページがあります:Pythonの写真メソッドとNodeの写真メソッドです。