已連接的帳戶
每個已連結帳戶端點皆附有 cURL、Python 和 Node 範例:連結 Google 和 Facebook、列出帳戶、配對與連結商家資訊、資料夾、建立 GMB、中斷連線。
已連結帳戶是 Google Business Profile 或 Facebook 粉絲專頁擁有者授予的 OAuth 授權,讓 API 能讀取及管理該帳戶可存取的商家資訊。此資源涵蓋 3 項工作:建立 OAuth 連結、將帳戶的商家資訊與您的地點配對或連結,以及解除連線。用於讀取清單與詳細資料的 2 個 GET 可使用 Read(讀取)金鑰;每個 POST 都需要 Write(寫入)金鑰,包括僅讀取商家資訊的擷取操作,而使用 Read 金鑰執行寫入操作時,端點會傳回 HTTP 400,並包含 SY90016。
以下每個範例都假設用戶端已依照第 1 個範例的方式建立一次,並從環境變數讀取 LISTINGSAPI_KEY。識別碼包括清單端點傳回的 connectedAccountId UUID,以及 base64 地點識別碼(TG9jYXRpb246MTgwMDI4OQ==);兩者都不可進行 URL 編碼。
端點總覽
建立 Google 連結網址
POST /connected-accounts/connect-google
傳回有效期限較短的 OAuth URL。將帳戶擁有者重新導向至該 URL;Google 會將其導回您的 successUrl 或 errorUrl。此連結的範圍限於擁有 API 金鑰的帳戶,因此主體僅包含您的 2 個重新導向網址。若帳戶的授權已過期,重新發出連結會更新現有連線,而不會建立重複連線。
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" }}'{ "data": { "bulkConnectLinkForGoogle": { "success": true, "url": "https://connect.example.com/oauth?token=8f3c1d92-...", "errors": null } }}上述 url 是預留位置。請將擁有者導向您實際收到的回應中所傳回的 url。
此連結的有效期限為 24 小時。errors 只有在產生失敗時才會填入值,因此請確認 url 不為 null。若主體未使用外層物件包覆,或包含 accountId,請求會遭到拒絕,並傳回 HTTP 400。
建立 Facebook 連結網址
POST /connected-accounts/connect-facebook
這是對應的 Facebook 操作,使用相同的主體。流程中,擁有者會接受 Facebook 的條款,並授予 API 所需的粉絲專頁管理權限;若擁有者略過任何一項權限,該連線就無法同步,因此請重新發出連結,讓擁有者再次同意授權。
curl -X POST https://listingsapi.com/api/v4/connected-accounts/connect-facebook \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "input": { "successUrl": "https://app.example.com/connect/facebook/success", "errorUrl": "https://app.example.com/connect/facebook/error" }}'{ "data": { "bulkConnectLinkForFacebook": { "success": true, "url": "https://connect.example.com/oauth?token=8f3c1d92-...", "errors": null } }}上述 url 是預留位置。請將擁有者導向您實際收到的回應中所傳回的 url。
回應中的鍵為 bulkConnectLinkForFacebook;其餘讀取方式與 Google 連結完全相同。擁有者完成流程後,該帳戶就會在清單端點中以 FacebookAccount 的形式顯示。
為單一地點建立連結用的連結
POST /locations/oauth_connect_url
當您已經知道擁有者要連結哪個地點時,請使用此方式。此連結會綁定您指定的地點,因此後續不會進行配對:擁有者同意授權後,憑證就會直接附加至該地點。上述 2 種批次連結則都是連結整個帳號。
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" }}'{ "data": { "createConnectUrl": { "success": true, "url": "https://connect.example.com/oauth?token=8f3c1d92-...", "errors": null } }}上述 url 是預留位置。請將擁有者導向您實際收到的回應中所傳回的 url。
此連結只能使用 1 次,因此每次嘗試時都應建立新連結,不要快取。若重新導向 URL 是相對 URL 或無法剖析,會傳回 success: true,並帶有 null url,因此請檢查 url,不要只檢查 success。若金鑰無權存取此地點,會收到 403,並帶有 SY90003。SDK 會自動將 site 轉為大寫。
列出已連結的帳號
GET /connected-accounts
傳回已對您的 API 帳號授權的所有帳號,並附上連線健康狀態及各帳號連結的地點數量。此回應採用位移量分頁:records[] 加上 pageInfo.totalRecords,並透過未巢狀封裝的 page 和 perPage 查詢參數分頁。排序固定依帳號電子郵件地址遞增排列。
curl "https://listingsapi.com/api/v4/connected-accounts?publisher=GoogleAccount&status=Connected&page=1&perPage=20" \-H "Authorization: API $LISTINGSAPI_KEY"{ "data": { "connectedAccountsInfo": { "pageInfo": { "hasNextPage": false, "hasPreviousPage": false, "totalPages": 1, "totalRecords": 1 }, "records": [ { "connectedAccountId": "4f712c17-4f95-42dd-90f4-97171a2e67b5", "connectedAccountType": "GoogleAccount", "email": "owner@brightsmile-dental.com", "status": "CONNECTED", "connectivityIssue": null, "connectedLocationsCount": 0, "requestMatchesStatus": "MATCH_COMPLETED", "lastFetchMatchesRequestedAt": "2026-07-06 21:43:07 UTC" } ] } }}選取 email 對應至同意授權之擁有者的紀錄,並保留其 connectedAccountId;後續每次呼叫都需要此值。這 4 個查詢參數以外的內容都會被忽略,而不會遭到拒絕,因此傳入 JSON pageInfo 時,會直接傳回第 1 頁,不會報錯。
status 篩選條件與紀錄的 status 欄位使用不同的值。將 CONNECTED 傳回作為篩選條件時,會被視為無效的列舉值,並傳回 400。
取得單一帳號的詳細資料
GET /connected-accounts/{connectedAccountId}/details
傳回與清單中單筆紀錄相同的欄位,範圍限於單一帳號。觸發配對後,可用此端點輪詢 requestMatchesStatus,或在透過該帳號推送更新前,檢查 status 和 connectivityIssue。
curl https://listingsapi.com/api/v4/connected-accounts/4f712c17-4f95-42dd-90f4-97171a2e67b5/details \-H "Authorization: API $LISTINGSAPI_KEY"{ "data": { "connectedAccountDetails": { "details": { "connectedAccountId": "4f712c17-4f95-42dd-90f4-97171a2e67b5", "connectedAccountType": "GoogleAccount", "status": "CONNECTED", "connectivityIssue": null, "connectedLocationsCount": 0, "requestMatchesStatus": "MATCH_COMPLETED" } } }}紀錄位於下一層的 data.connectedAccountDetails.details。建議結果準備就緒時,requestMatchesStatus 會從 MATCH_IN_PROGRESS 變為 MATCH_COMPLETED。Completed 表示配對程序已完成,並不表示已連結任何商家資訊:在您確認或連結商家資訊之前,connectedLocationsCount 會維持為 0。
取得帳號可存取的商家資訊
POST /connected-accounts/connected-account-listings
列出該帳號有權存取的所有 Google Business Profile 或 Facebook 商家資訊,無論是否已連結至您的某個地點。每筆紀錄的 id 就是 connect-listing 和 create-location-from-listing 接受的 connectedAccountListingId。這是僅執行讀取的 POST,傳回的資料採用位移量分頁:records[] 加上 pageInfo,並透過主體中未巢狀封裝的 page 和 perPage 索引鍵分頁。
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, "locationInfo": "William St" }'{ "data": { "connectedAccountListings": { "pageInfo": { "hasNextPage": false, "totalPages": 1, "totalRecords": 60 }, "records": [ { "id": "R21iQnVsa0RhdGFMYWtlOjA2MDQ4NmExLTA0NzQtNDc4NS1iMjNhLTBkOGM4MzhmNGQ5OA==", "accountTypeName": "Google", "locationName": "Trial", "address": "123 William St, NY 10038, Manhattan, US", "phone": "(718) 667-7787", "liveLink": null } ] } }}使用 pageInfo.hasNextPage 和 pageInfo.totalPages 逐頁讀取整組資料。SDK 會自動將 connectedAccountId 放入主體,因此這只影響手動撰寫的 REST 呼叫。
觸發配對
POST /connected-accounts/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"] } }'{ "data": { "connectedAccountsTriggerMatches": { "success": true, "failedIds": null } }}success: true 表示工作已加入佇列,並不表示配對已完成。任何無法加入佇列的帳戶都會列在 failedIds 中,且 success 會是 false。請輪詢詳細資料端點,直到 requestMatchesStatus 為 MATCH_COMPLETED 後再讀取建議;使用有次數上限的迴圈,每 15 秒輪詢一次,即可讓 Launch 方案的請求量維持在每分鐘 10 次的限制內。
讀取連結建議
GET /connected-accounts/{connectedAccountId}/connection-suggestions
傳回配對程序提出的配對:一方是您的地點(locationInfo,其 databaseId 為 locationId),另一方是發布平台上的商家資訊(suggestedLocationInfo)。此端點採用偏移量分頁,透過非巢狀的 page 和 perPage 查詢參數換頁;排序固定為依地點資訊遞增排列。
curl "https://listingsapi.com/api/v4/connected-accounts/4f712c17-4f95-42dd-90f4-97171a2e67b5/connection-suggestions?page=1&perPage=20" \-H "Authorization: API $LISTINGSAPI_KEY"{ "data": { "connectionSuggestionsForAccount": { "pageInfo": { "hasNextPage": false, "totalPages": 1, "totalRecords": 2 }, "records": [ { "accountType": "GMB", "matchedDataDatabaseId": "0d5e306f-0da0-46e3-929f-fd3c67ccd8cc", "connectedAccountId": "4f712c17-4f95-42dd-90f4-97171a2e67b5", "locationId": "73415", "locationInfo": { "name": "My Business", "city": "Lincoln", "stateIso": "NE" }, "suggestedLocationInfo": { "locationInfo": { "name": "My Business", "city": "Lincoln" } } } ] } }}建議沒有 id。請一併保留 matchedDataDatabaseId 和 accountType;confirm-matches 需要兩者才能組成其 id。如果過早讀取,也就是在 MATCH_COMPLETED 之前,端點會傳回 records: [],並附帶 totalRecords: 0,看起來與「沒有任何配對結果」完全相同。
確認配對
POST /connected-accounts/confirm-matches
接受您核准的建議,並建立實際連結。每個 id 都是 <MatchRecordType>:<matchedDataDatabaseId> 的 base64 編碼,其中的類型需從上表選取。帳戶會根據記錄推定,因此沒有 connectedAccountId 欄位;若 input 內含未知欄位,請求會遭到拒絕,並傳回 400。
# 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="] } }'{ "data": { "confirmConnectMatches": { "success": true, "failedIds": null } }}failedIds 包含無法確認的解碼後 matchedDataDatabaseId 值,例如記錄已使用,或地點在配對後已封存,因此請將這些值與建議記錄比對。未送出的建議會維持原狀。確認會將地點連結至商家資訊;此操作本身不會將資料推送至發布平台。
將一筆商家資訊連結至一個地點
POST /connected-accounts/connect-listing
將您已選定的一筆商家資訊連結至一個地點,不需經過建議或確認步驟。當配對結果不明確時,例如附近有 2 家名稱相似的店面,而操作人員從帳戶的商家資訊中選出正確的一筆,即可使用此操作。
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==" }}'{ "data": { "connectListing": { "success": true, "message": null } }}連結失敗時會傳回 success: false,並包含非 null 的 message,例如無法根據商家資訊 id 找到對應記錄時的 Listing record not found,或指出該商家資訊已連結至另一個地點的說明。在這 2 個 SDK 中,此方法都位於商家資訊資源,而非已連結帳戶資源。
中斷一筆商家資訊與地點的連結
POST /connected-accounts/disconnect-listing
中斷一個地點與一個發布平台之間的連結。地點及其資料會保留;只會停止向該發布平台同步資料。這不是批次端點,因此請使用迴圈逐一處理地點。若要將店家改為連結至另一個 Google 帳戶,請先在此中斷連結,再透過新帳戶進行配對或連結。
curl -X POST https://listingsapi.com/api/v4/connected-accounts/disconnect-listing \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "input": { "locationId": "TG9jYXRpb246MTgwMDI4OQ==", "site": "GOOGLE" } }'{ "data": { "disconnectConnectedAccountsLocations": { "clientMutationId": null, "success": true, "errors": null } }}若未傳送 site 或 providerId 中的任何一個,會傳回 SY10056。若地點與該網站之間沒有有效連結,會傳回 SY10057,而不會直接回報成功,因此 success: true 確實表示已移除連結。SDK 僅接受 site,並將其轉為大寫。
從商家資訊建立地點
POST /connected-accounts/create-location-from-listing
比對功能只會將商家資訊與您現有的地點配對。對於尚未對應地點的商家資訊,此操作會使用發布平台的資料建立地點,並立即將新地點連結至該商家資訊。Google 匯入的資料包括名稱、地址、座標、電話、網站、說明、一般與特殊營業時間、類別、開業日期、商店代碼和時區,以及從商家資訊的 Google 屬性取得的付款方式和社群連結。Facebook 匯入的資料包括名稱、地點、營業時間、類別、說明和聯絡資訊。
從 Google 匯入時,資料不會重新提交至 Google,因此該商家資訊會維持在 IN_PROGRESS,直到您首次更新地點並將更新發布至該商家資訊。其他所有發布平台都會正常收到提交資料,而且此端點不接受網站範圍設定,因此建立地點時會使用您帳戶的完整發布平台集合。請在建立後立即使用 enabledSiteIds 縮小範圍,並立即送出該更新:其他發布平台的訂單項目會在建立後不久產生,而更新不會撤回任何已產生的項目。
2 個 SDK 目前都尚未封裝此端點,因此 Python 和 Node 範例會使用相同的標頭呼叫 REST。
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==" }}'{ "data": { "createLocationFromConnectedAccountListing": { "success": true, "locationId": 88277, "errors": null } }}locationId 是新地點的原始 databaseId。失敗時,success 為 false,locationId 為 null,而 errors 會包含表示原因的代碼,例如 SY81067(無法根據商家資訊 id 找到對應資料);其他原因包括商家資訊已連結至另一個地點,或帳戶的憑證已過期。建立後,您可以像管理其他地點一樣管理此地點。
列出 Google 帳戶的資料夾
GET /connected-accounts/{connectedAccountId}/folders
傳回已連線的 Google 帳戶可存取的 Google Business Profile 帳戶群組(資料夾)。請在建立 GMB 商家資訊之前使用此端點,讓新商家檔案建立在擁有者預期的群組中。回應中的 getFoldersUnderGoogleAccount 是一般陣列,並非分頁資料。此路徑僅適用於 GoogleAccount 連線。
curl https://listingsapi.com/api/v4/connected-accounts/4f712c17-4f95-42dd-90f4-97171a2e67b5/folders \-H "Authorization: API $LISTINGSAPI_KEY"{ "data": { "getFoldersUnderGoogleAccount": [ { "folderId": "accounts/104890024806530350198", "folderName": "Bright Smile Dental", "locationCount": null } ] }}請原樣使用 folderId;它是 accounts/{id} 字串,不是數字。Google 未回報 locationCount 時,其值可能為 null,因此請將其視為選用欄位。
為地點建立 Google Business Profile
POST /locations/create/gmb-listing
在已連線的 Google 帳戶下,為尚無 Google 商家資訊的地點建立全新的 Google 商家資訊,並可選擇將其放入資料夾。相較之下,connect-listing 會連結既有的商家資訊。地點必須已具備名稱、地址和電話,且每個地點只能有 1 筆 Google 商家資訊。
curl -X POST https://listingsapi.com/api/v4/locations/create/gmb-listing \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "input": { "locationId": "TG9jYXRpb246MTgwMDI4OQ==", "connectedAccountId": "4f712c17-4f95-42dd-90f4-97171a2e67b5", "folderId": "accounts/104890024806530350198" }}'{ "data": { "createGmbListingForLocation": { "clientMutationId": null, "success": true, "errors": null } }}建立作業以非同步方式執行:success: true 表示請求已被接受,而 Google 會在發布新的商家檔案之前進行審核。當 success 為 false 時,errors 會說明原因:缺少必填欄位、已有 Google 商家資訊、地點已封存,或帳戶未啟用。
中斷整個 Google 帳戶的連線
POST /connected-accounts/disconnect-google
中斷整個帳戶的連線:透過此帳戶連結的所有地點都會停止同步。此操作沒有 locationIds 欄位;若要解除單一地點的連結並保留帳戶,請改用 disconnect-listing。當客戶離開,或授權發生問題且無法清除,而您想使用新的連線連結重新開始時,請使用此操作。
curl -X POST https://listingsapi.com/api/v4/connected-accounts/disconnect-google \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "input": { "connectedAccountId": "d2397854-52c2-41d7-95f1-b90cba16498d" } }'{ "data": { "gmbBulkDisconnect": { "success": true } }}即使 connectedAccountId 不存在,也會傳回 success: true,因此這表示「請求已處理」,而非「已移除有效連線」。如果您需要確認,請重新列出已連線的帳戶。
中斷整個 Facebook 帳戶的連線
POST /connected-accounts/disconnect-facebook
這是對應的 Facebook 操作,使用相同的請求主體。透過此帳戶連結的粉絲專頁會停止同步,Facebook 互動也會停止顯示。
curl -X POST https://listingsapi.com/api/v4/connected-accounts/disconnect-facebook \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "input": { "connectedAccountId": "d2397854-52c2-41d7-95f1-b90cba16498d" } }'{ "data": { "fbBulkDisconnect": { "success": true } }}回應中的鍵為 fbBulkDisconnect。與 Google 相同,對於不存在的 id,success: true 表示已處理,而非已移除。
中斷單一地點與發布平台的連線
POST /locations/oauth-disconnect
這是個別地點 OAuth 流程中負責中斷連線的部分。它透過另一個路徑提供與 disconnect-listing 相同的操作:input 請求主體完全相同,回應中的鍵也同樣是 disconnectConnectedAccountsLocations。請選擇在您的整合程式中較容易理解的路徑。
curl -X POST https://listingsapi.com/api/v4/locations/oauth-disconnect \-H "Authorization: API $LISTINGSAPI_KEY" \-H "Content-Type: application/json" \-d '{ "input": { "locationId": "TG9jYXRpb246MTgwMDI4OQ==", "site": "GOOGLE" } }'{ "data": { "disconnectConnectedAccountsLocations": { "clientMutationId": null, "success": true, "errors": null } }}同樣適用 SY10056 和 SY10057 的規則,而無權操作此地點的金鑰會收到 403,並附有 SY90003。中斷連線後,地點及其資料仍會完整保留;只有向該發布平台傳送資料的同步作業會停止。之後,請讓擁有者重新透過連線 URL 完成流程,或執行比對及 connect-listing,以連結正確的商家資訊。
您會遇到的錯誤
格式錯誤的請求和無效的金鑰會導致傳回 4xx,並附有頂層的 errors[],其中的 message 以錯誤碼開頭。寫入操作也可能傳回 200,並附有 success: false,而原因則位於 data.<operation> 內,因此請檢查每次寫入的回應主體。完整清單請參閱錯誤碼。
後續步驟
- 連線 Google 並匯入地點:完整的 Google 批次操作流程,包含輪詢和 webhook 事件。
- 連線 Facebook 粉絲專頁:適用於 Facebook 的相同流程,包含中斷帳戶連線。
- 建立 Google Business Profile:為沒有 Google 商家資訊的地點建立資料夾和 GMB。
- 檢查商家資訊狀態和已上線的連結:觀察連結建立後,Google 資料列的狀態如何變為
SYNCED。 - 參考文件索引:已連線的帳戶;SDK 頁面:Python 已連線的帳戶、Node 已連線的帳戶、Python 商家資訊、Node 商家資訊。