Connected accounts

Connect Google and Facebook accounts, match their listings to locations, and disconnect them with the listingsapi-js SDK.

A connected account is an OAuth grant from a Google Business Profile or Facebook Pages owner. Once the grant exists, the platform can read the listings that account owns and link each one to a location. All connected-account methods live directly on the ListingsAPI client instance.

The usual order is: mint a connect link, wait for the owner to authorize, list the accounts to pick up a connectedAccountId, trigger matching, review the suggestions, then confirm them or link a listing by hand. Every method resolves to the payload under its own response key, which each section below names.

connectGoogleAccount

Mint an account-wide OAuth link for Google Business Profile. Send the owner to the returned url; they land back on your successUrl or errorUrl when the consent screen closes.

TypeScript
const link = await client.connectGoogleAccount('https://app.example.com/onboarding/google/done','https://app.example.com/onboarding/google/failed',); console.log(link.url);

Parameters

ParameterTypeDescription
successUrlstringAbsolute URL the owner returns to after authorizing.
errorUrlstringAbsolute URL the owner returns to if they cancel or the grant fails.

Resolves to the bulkConnectLinkForGoogle payload: url, success, and errors. Check url and not only success, because an unusable redirect can come back as a success with a null url. The link is short-lived, so mint a fresh one per attempt.

connectFacebookAccount

The Facebook Pages counterpart to connectGoogleAccount, with the same two redirect arguments.

TypeScript
const link = await client.connectFacebookAccount('https://app.example.com/onboarding/facebook/done','https://app.example.com/onboarding/facebook/failed',); console.log(link.url);

Parameters

ParameterTypeDescription
successUrlstringAbsolute URL the owner returns to after authorizing.
errorUrlstringAbsolute URL the owner returns to if they cancel or the grant fails.

Resolves to the bulkConnectLinkForFacebook payload: url, success, and errors.

getOauthConnectUrl

Mint an OAuth link scoped to one location instead of a whole account. Use it when you already know which location the owner is connecting and want them back on that location's screen in your own product.

TypeScript
const link = await client.getOauthConnectUrl(1800289,'GOOGLE','https://app.example.com/locations/1800289/connected','https://app.example.com/locations/1800289/connect-failed',); console.log(link.url);

Parameters

ParameterTypeDescription
locationIdstring | numberLocation the connection attaches to. Numeric IDs are encoded for you.
sitestringPublisher to connect: 'GOOGLE', 'FACEBOOK', or 'APPLE'.
successUrlstringAbsolute URL the owner returns to after authorizing.
errorUrlstringAbsolute URL the owner returns to if the grant fails.

Resolves to the createConnectUrl payload: url, success, and errors. Both redirects are required and must be absolute. The link is single-use and tied to the location you named.

fetchConnectedAccounts

List the Google and Facebook accounts authorized on your account, with connection health and linked-location counts. This is where you get the connectedAccountId every later method needs.

TypeScript
const page1 = await client.fetchConnectedAccounts({publisher: 'GoogleAccount',status: 'Connected',page: 1,perPage: 20,}); for (const record of page1.records ?? []) {console.log(record.email, record.connectedAccountId, record.status);}

Options

ParameterTypeDescription
publisherstringAccount type, for example 'GoogleAccount' or 'FacebookAccount'.
statusstringConnection status filter: 'Connected', 'NotConnected', or 'ConnectionIssue'.
pagenumberPage number (1-based).
perPagenumberRecords per page.

Resolves to the connectedAccountsInfo payload: a records array plus pageInfo with hasNextPage, hasPreviousPage, totalPages, and totalRecords. Each record carries connectedAccountId, email, connectedAccountType, connectedLocationsCount, connectivityIssue, status, and requestMatchesStatus.

The filter and the field do not share a vocabulary. The status option takes 'Connected', 'NotConnected', or 'ConnectionIssue', while a record's own status reads CONNECTED, MATCH_IN_PROGRESS, or CONNECTIVITY_ISSUE. Feeding a record's value back in as the filter is rejected.

fetchConnectedAccountDetails

Read one account by its ID. Cheaper than paging the whole list when you already hold the ID, and the method to poll while matching runs.

TypeScript
const details = await client.fetchConnectedAccountDetails('4f712c17-4f95-42dd-90f4-97171a2e67b5',); console.log(details.details.requestMatchesStatus); // MATCH_IN_PROGRESS, then MATCH_COMPLETED

Parameters

ParameterTypeDescription
connectedAccountIdstringID of the connected account, from fetchConnectedAccounts.

Resolves to the connectedAccountDetails payload, which nests the record under details with the same fields the list returns. Watch requestMatchesStatus to know when suggestions are ready, and read status plus connectivityIssue to decide whether to prompt for a re-authorization.

fetchConnectedAccountFolders

List the Google account groups (folders) the connected account can reach. Call it before createGmbListing when the owner wants the new listing in a specific group.

TypeScript
const folders = await client.fetchConnectedAccountFolders('4f712c17-4f95-42dd-90f4-97171a2e67b5',); for (const folder of folders) {console.log(folder.folderId, folder.folderName, folder.locationCount);} // Narrow by nameconst matching = await client.fetchConnectedAccountFolders('4f712c17-4f95-42dd-90f4-97171a2e67b5',{ folderName: 'West Region' },);

Options

ParameterTypeDescription
folderNamestringNarrow the result to folders matching this name.

Resolves to the getFoldersUnderGoogleAccount array, defaulting to an empty array. Each folder carries folderId (an accounts/<id> string you pass through verbatim), folderName, and locationCount, which can be null when Google reports no count. The path is valid only for Google-type accounts.

fetchConnectedAccountListings

List the publisher listings the connected account has access to. Each record's id is exactly the connectedAccountListingId that connectListing takes, so this is how you build a listing picker.

TypeScript
const listings = await client.fetchConnectedAccountListings('4f712c17-4f95-42dd-90f4-97171a2e67b5',{ locationInfo: 'William St', page: 1, perPage: 50 },); for (const record of listings.records ?? []) {console.log(record.id, record.locationName, record.address);}

Options

ParameterTypeDescription
locationInfostringFree-text search across business name, address, locality, postal code, store code, and phone.
pagenumberPage number (1-based).
perPagenumberRecords per page. Defaults to 500, which is also the maximum.

Resolves to the connectedAccountListings payload: records plus pageInfo. Each record carries id, locationName, address, phone, liveLink, and accountTypeName. Despite being a write-shaped request underneath, this is a read: the SDK puts the account ID and paging in the request body for you, which is what the endpoint requires.

triggerConnectedAccountMatches

Queue the job that pulls every profile the given accounts can reach and matches them against your locations. Call it right after an owner finishes the consent screen, and again after you bulk-create locations.

TypeScript
const result = await client.triggerConnectedAccountMatches(['4f712c17-4f95-42dd-90f4-97171a2e67b5',]); console.log(result.success, result.failedIds);

Parameters

ParameterTypeDescription
connectedAccountIdsstring[]Accounts to run matching for.

Resolves to the connectedAccountsTriggerMatches payload: success and failedIds. A success of true means the job was queued, not that matching finished. Poll fetchConnectedAccountDetails until requestMatchesStatus reads MATCH_COMPLETED, then read the suggestions.

fetchConnectionSuggestions

Read the pairings matching produced, so an operator can compare each location against the publisher listing before anything is linked.

TypeScript
const suggestions = await client.fetchConnectionSuggestions('4f712c17-4f95-42dd-90f4-97171a2e67b5',{ page: 1, perPage: 50 },); for (const record of suggestions.records ?? []) {console.log(record.accountType, record.matchedDataDatabaseId, record.locationInfo.name);}

Options

ParameterTypeDescription
pagenumberPage number (1-based).
perPagenumberRecords per page.

Resolves to the connectionSuggestionsForAccount payload: records plus pageInfo. A suggestion record has no id field. Its identifier is matchedDataDatabaseId, and accountType (GMB, FB, or APPLE) says which kind of match record it is. Keep the two together, because confirmConnectedAccountMatches needs both to build the ID it takes. An account with no matches yet returns an empty records array.

confirmConnectedAccountMatches

Accept the reviewed pairings. Confirming links each location to its publisher listing so later location updates flow through.

Build each ID from a suggestion record: join the match-record type name and the record's matchedDataDatabaseId with a colon, then base64-encode it. GMB maps to GmbLocationMatchedData, FB to FbLocationMatchedData, and APPLE to AppleLocationMatchedData.

TypeScript
const TYPES: Record<string, string> = {GMB: 'GmbLocationMatchedData',FB: 'FbLocationMatchedData',APPLE: 'AppleLocationMatchedData',}; const matchRecordId = (record: any) =>Buffer.from(TYPES[record.accountType] + ':' + record.matchedDataDatabaseId).toString('base64'); const approved = (suggestions.records ?? []).map(matchRecordId);const result = await client.confirmConnectedAccountMatches(approved); console.log(result.success, result.failedIds);

Parameters

ParameterTypeDescription
matchRecordIdsstring[]Encoded match-record IDs to confirm. At least one is required.

Resolves to the confirmConnectMatches payload: success and failedIds. Check success on every call: an ID that does not decode to one of the three types comes back as a success-shaped response with success false and no failedIds. When some IDs fail, failedIds holds the decoded database IDs, not the encoded values you sent, so match them back against matchedDataDatabaseId.

Linking one listing to one location

Three methods finish the link between a single matched listing and a single location, and they are documented with the rest of the listing surface rather than twice:

Reach for these after confirmConnectedAccountMatches has handled the bulk of an account, when one storefront still needs pairing by hand.


oauthDisconnect

The same single-location disconnect, reached through the per-location OAuth path. It takes the identical arguments and resolves to the identical payload, so pick whichever name reads better in your code.

TypeScript
await client.oauthDisconnect(1800289, 'GOOGLE');

Parameters

ParameterTypeDescription
locationIdstring | numberLocation to disconnect.
sitestringPublisher to disconnect from.

Resolves to the disconnectConnectedAccountsLocations payload, the same key disconnectListing returns, because both paths run one shared mutation.

disconnectGoogleAccount

Tear down a whole Google account: every location linked through it stops receiving updates. Use it when a customer churns or transfers ownership.

TypeScript
await client.disconnectGoogleAccount('4f712c17-4f95-42dd-90f4-97171a2e67b5');

Parameters

ParameterTypeDescription
connectedAccountIdstringGoogle account to disconnect.

Resolves to the gmbBulkDisconnect payload, which carries success. This is all or nothing: to unlink a single location while keeping the account, use disconnectListing. A success of true is returned even for an unknown ID, so read fetchConnectedAccounts afterwards if you need certainty.

disconnectFacebookAccount

The Facebook counterpart, with the same argument and the same all-or-nothing behaviour.

TypeScript
await client.disconnectFacebookAccount('9d2b5a41-0c7e-4f83-bb16-2ac43e70d915');

Parameters

ParameterTypeDescription
connectedAccountIdstringFacebook account to disconnect.

Resolves to the fbBulkDisconnect payload, which carries success. The same caveat applies: an unknown ID still reports success, so verify with fetchConnectedAccounts.

Typical onboarding workflow

connect_google.ts
import { ListingsAPI } from 'listingsapi-js'; const client = new ListingsAPI(); // reads LISTINGSAPI_KEY from env // 1. Send the owner through the consent screenconst link = await client.connectGoogleAccount('https://app.example.com/onboarding/google/done','https://app.example.com/onboarding/google/failed',);console.log('open:', link.url); // 2. After they return, pick up the account IDconst accounts = await client.fetchConnectedAccounts({ publisher: 'GoogleAccount' });const accountId = accounts.records[0].connectedAccountId; // 3. Match its listings against your locationsawait client.triggerConnectedAccountMatches([accountId]); // 4. Poll until matching finisheslet details = await client.fetchConnectedAccountDetails(accountId);while (details.details.requestMatchesStatus !== 'MATCH_COMPLETED') {await new Promise((resolve) => setTimeout(resolve, 5000));details = await client.fetchConnectedAccountDetails(accountId);} // 5. Read the suggestions and confirm the approved onesconst suggestions = await client.fetchConnectionSuggestions(accountId, { perPage: 100 });console.log('found ' + (suggestions.records ?? []).length + ' suggested matches');