Casos de uso
Exemplos completos em TypeScript que mostram como combinar recursos do listingsapi-js em integrações reais.
Estes exemplos mostram fluxos de trabalho que combinam recursos, o tipo de script que você usa quando a página de um único método não é suficiente. Cada exemplo é um programa TypeScript completo e executável que combina dois ou mais recursos para realizar uma tarefa que você poderia colocar em produção. Instale uma versão fixa do SDK (npm install listingsapi-js@0.3.2), exporte LISTINGSAPI_KEY com uma chave do seu painel e você poderá executá-los sem alterações com npx tsx <file>.ts.
Se você está começando a usar o SDK, leia primeiro a visão geral do Node SDK. Ela aborda a criação do cliente, a autenticação, os erros e a paginação, conhecimentos necessários para todos os exemplos abaixo.
1. Início rápido: buscar e imprimir locais
A integração mínima viável: autentique-se, obtenha uma página de locais e imprima seus nomes.
import { ListingsAPI } from 'listingsapi-js'; const client = new ListingsAPI(); // reads LISTINGSAPI_KEY from env const page = await client.fetchAllLocations({ first: 5 });if (!Array.isArray(page)) {for (const loc of page.locations) { console.log(loc.name + ' - ' + loc.city);}}Sem fetchAll, fetchAllLocations retorna um objeto com locations, pageInfo e o conteúdo de raw. Passe pageInfo.endCursor como after para obter a próxima página.
2. Exportação em massa para JSON
Percorra automaticamente todas as páginas de locais da conta e grave os resultados em disco.
import { writeFileSync } from 'fs';import { ListingsAPI } from 'listingsapi-js';import type { Location } from 'listingsapi-js'; const client = new ListingsAPI(); const locations = (await client.fetchAllLocations({fetchAll: true,pageSize: 100,})) as Location[]; writeFileSync('locations.json', JSON.stringify(locations, null, 2));console.log('Exported ' + locations.length + ' locations to locations.json');fetchAll: true percorre automaticamente as páginas usando cursores e retorna um Location[] sem aninhamento. Para 10 000 locais ou mais, mantenha pageSize em 100 (o valor padrão) para que as requisições individuais continuem rápidas.
3. Cadastrar um novo local
Consulte o ID da categoria correta com fetchSubcategories e crie o local em seguida. O valor de databaseId de uma subcategoria é o que createLocation espera como subCategoryId. A API também exige uma descrição com 200 caracteres ou mais.
import { ListingsAPI } from 'listingsapi-js'; const client = new ListingsAPI(); const categories = await client.fetchSubcategories();const dentist = categories.find((c) => c.name === 'Dentist');if (!dentist) throw new Error('Category not found'); const description ='Acme Dental is a family-owned dental practice in downtown New York ' +'offering preventive care, cosmetic dentistry, orthodontics, and ' +'emergency appointments. Our team has served the neighborhood for over ' +'twenty years with same-week scheduling and weekend hours.'; const created = await client.createLocation({name: 'Acme Dental',storeId: 'ACME-NY-001',street: '123 Jump Street',city: 'New York',stateIso: 'NY',postalCode: '10013',countryIso: 'US',phone: '6443859313',subCategoryId: dentist.databaseId,description: description,}); console.log('Created location', created.location?.id);Uma falha de validação (campo ausente, descrição curta, categoria inválida) lança uma exceção ValidationError com os registros de erro da plataforma em err.errors, portanto não há um indicador success para verificar.
4. Publicar uma postagem no Google e no Facebook em massa
bulkPublish publica uma postagem nos dois sites para vários locais em uma única chamada. Ele valida os dados no cliente, gera a mensagem para cada site e codifica os IDs numéricos dos locais para você.
import { ListingsAPI } from 'listingsapi-js'; const client = new ListingsAPI(); const result = await client.bulkPublish({name: 'Holiday hours',locationIds: [16808, 16809, 16810],message: 'Open until 10pm through the holidays!',mediaUrl: 'https://cdn.example.com/holiday.jpg',ctaType: 'LEARN_MORE',ctaUrl: 'https://example.com/holiday-hours',}); console.log('Campaign:', result.socialPost?.id, result.socialPost?.status); // Publishing is asynchronous; poll the bulk campaign for per-location statusconst bulk = await client.fetchBulkPost(result.socialPost.id);console.log(bulk);sites usa ['GOOGLE', 'FACEBOOK'] por padrão. Passe um mapa por site como message ({ GOOGLE: '...', FACEBOOK: '...' }) quando o texto precisar ser diferente. Para campanhas individuais com opções tipadas, use createAnnouncement, createEvent ou createOffer.
5. Monitoramento de avaliações: sinalizar notas baixas
Verifique todos os locais em busca de avaliações de 1 e 2 estrelas e registre as que precisam de atenção.
import { ListingsAPI, APIError } from 'listingsapi-js';import type { Interaction, Location } from 'listingsapi-js'; const client = new ListingsAPI(); const locations = (await client.fetchAllLocations({ fetchAll: true })) as Location[]; for (const loc of locations) {let reviews: Interaction[];try { reviews = (await client.fetchInteractions(loc.id, { fetchAll: true, startDate: '2026-01-01', ratingFilters: [1, 2], })) as Interaction[];} catch (err) { if (err instanceof APIError) { console.error(loc.name + ': ' + err.statusCode); continue; } throw err;} for (const review of reviews) { const who = review.reviewerName ?? 'Anonymous'; console.log('NEEDS ATTENTION [' + loc.name + '] ' + who + ' (' + review.rating + ' stars)');}}6. Responder a avaliações sem resposta
Responda automaticamente a todas as avaliações que ainda não têm resposta. Use um modelo de texto ou substitua buildResponse por uma chamada a um LLM.
import { ListingsAPI } from 'listingsapi-js';import type { Interaction } from 'listingsapi-js'; const client = new ListingsAPI();const LOCATION_ID = 16808; function buildResponse(review: Interaction): string {const name = review.reviewerName ?? 'there';if ((review.rating ?? 5) <= 2) { return 'Hi ' + name + ', we are sorry to hear about your experience. Our team will reach out shortly.';}return 'Hi ' + name + ', thank you for the kind words. We look forward to seeing you again!';} const reviews = (await client.fetchInteractions(LOCATION_ID, {fetchAll: true,startDate: '2026-01-01',})) as Interaction[]; let responded = 0;for (const review of reviews) {if (review.responses && review.responses.length > 0) continue;await client.respondToReview(review.id, buildResponse(review));responded++;}console.log('Responded to ' + responded + ' reviews');7. Relatório de análise: Google, Bing, Facebook e estatísticas de avaliações
Obtenha em paralelo os dados de análise do perfil e as estatísticas de avaliações de um único local e imprima um resumo de uma página.
import { ListingsAPI } from 'listingsapi-js'; const client = new ListingsAPI();const LOCATION_ID = 16808;const range = { fromDate: '2026-01-01', toDate: '2026-06-30' }; const [google, bing, facebook, reviewOverview] = await Promise.all([client.fetchGoogleAnalytics(LOCATION_ID, range),client.fetchBingAnalytics(LOCATION_ID, range),client.fetchFacebookAnalytics(LOCATION_ID, range),client.fetchReviewAnalyticsOverview(LOCATION_ID, { startDate: range.fromDate, endDate: range.toDate,}),]); console.log('Google insights:', JSON.stringify(google));console.log('Bing insights:', JSON.stringify(bing));console.log('Facebook insights:', JSON.stringify(facebook));console.log('Review overview:', JSON.stringify(reviewOverview));Observe a diferença entre os parâmetros: as análises das plataformas usam fromDate/toDate, enquanto as análises de avaliações usam startDate/endDate.
8. Auditoria de listagens: encontrar perfis não sincronizados e duplicados
Verifique um local em busca de listagens premium que não estão sincronizadas e de perfis duplicados que a ListingsAPI encontrou e, em seguida, marque os duplicados.
import { ListingsAPI } from 'listingsapi-js'; const client = new ListingsAPI();const LOCATION_ID = 16808; const [premium, voice, duplicates] = await Promise.all([client.fetchPremiumListings(LOCATION_ID),client.fetchVoiceListings(LOCATION_ID),client.fetchDuplicateListings(LOCATION_ID),]); for (const l of premium) {if (l.syncStatus !== 'SYNCED') { console.log('Not synced: ' + l.site + ' - ' + l.syncStatus);}} console.log('Voice listings: ' + voice.length);console.log('Duplicates detected: ' + duplicates.length); const ids = duplicates.map((d) => d.id).filter((id): id is string => typeof id === 'string'); if (ids.length > 0) {await client.markListingsAsDuplicate(LOCATION_ID, ids);console.log('Marked ' + ids.length + ' listings as duplicate');}Para uma verificação de toda a conta, fetchAllDuplicateListings({ page: 1 }) retorna um consolidado dos duplicados de todos os locais.
9. Contas conectadas: o fluxo do Google
Conecte uma conta do Google uma vez, associe suas listagens aos seus locais e confirme as associações sugeridas.
import { ListingsAPI } from 'listingsapi-js'; const client = new ListingsAPI(); // 1. Get an OAuth URL and send the account owner thereconst connect = await client.connectGoogleAccount('https://example.com/connected','https://example.com/connect-error',);console.log('Send the owner to:', JSON.stringify(connect)); // 2. After the owner completes OAuth, list connected accountsconst accounts = await client.fetchConnectedAccounts({ page: 1, perPage: 25 });console.log(JSON.stringify(accounts)); // 3. Trigger matching between the account's listings and your locationsconst accountId = 'connected-account-uuid';await client.triggerConnectedAccountMatches([accountId]); const suggestions = await client.fetchConnectionSuggestions(accountId, {page: 1,perPage: 25,});console.log(JSON.stringify(suggestions)); // 4. Confirm the matches you agree withawait client.confirmConnectedAccountMatches(['match-record-id-1','match-record-id-2',]);console.log('Matches confirmed');Para conectar apenas um local, use getOauthConnectUrl(locationId, 'GOOGLE', successUrl, errorUrl) e use connectListing(locationId, listingId, accountId) para vincular uma listagem diretamente.
10. Pesquisar locais e atualizar um campo em massa
Pesquise locais que correspondam a uma consulta e atualize um campo em cada resultado, por exemplo, aplicando um novo número de telefone aos locais de uma cidade.
import { ListingsAPI } from 'listingsapi-js';import type { Location } from 'listingsapi-js'; const client = new ListingsAPI(); const matches = (await client.searchLocations('Brooklyn', { fetchAll: true })) as Location[]; let updated = 0;for (const loc of matches) {await client.updateLocation({ id: loc.id, phone: '7185550100',});updated++;}console.log('Updated phone on ' + updated + ' Brooklyn locations');Próximos passos
- Locais: referência completa dos métodos com tabelas de parâmetros
- Avaliações: análises, configurações, análise de frases
- Listagens: premium, voz, duplicados
- Análises: dados do Google, Bing e Facebook
- Tratamento de erros: subclasses de
APIErrore estratégia de novas tentativas