Casi d'uso
Esempi completi in TypeScript che mostrano come combinare le risorse di listingsapi-js per creare integrazioni reali.
Questi esempi mostrano flussi di lavoro che coinvolgono più risorse, utili quando la documentazione di un singolo metodo non basta. Ognuno è un programma TypeScript completo ed eseguibile che combina due o più risorse per un uso concreto in produzione. Installa una versione specifica dell'SDK (npm install listingsapi-js@0.3.2), esporta LISTINGSAPI_KEY con una chiave dalla tua dashboard e puoi eseguirli senza modifiche con npx tsx <file>.ts.
Se non hai mai usato l'SDK, leggi prima la panoramica dell'Node SDK. Descrive la creazione del client, l'autenticazione, gli errori e la paginazione, argomenti che tutti gli esempi seguenti danno per acquisiti.
1. Guida rapida: recuperare e stampare le sedi
L'integrazione minima: autenticati, recupera una pagina di sedi e stampane i nomi.
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);}}Senza fetchAll, fetchAllLocations restituisce un oggetto con locations, pageInfo e il payload raw. Passa pageInfo.endCursor come after per ottenere la pagina successiva.
2. Esportazione in blocco in JSON
Recupera tutte le sedi dell'account con la paginazione automatica e scrivi i risultati su 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 scorre automaticamente le pagine tramite cursore e restituisce un Location[] senza annidamenti. Per 10 000 o più sedi, mantieni pageSize a 100 (il valore predefinito) per mantenere rapide le singole richieste.
3. Configurare una nuova sede
Trova l'ID della categoria corretta con fetchSubcategories, poi crea la sede. createLocation richiede il valore databaseId di una sottocategoria come subCategoryId. L'API richiede anche una descrizione di almeno 200 caratteri.
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);Un errore di validazione (campo mancante, descrizione troppo breve, categoria non valida) genera un'eccezione ValidationError con i dettagli degli errori della piattaforma in err.errors, quindi non c'è alcun flag success da controllare.
4. Pubblicare un post su Google e Facebook in blocco
bulkPublish pubblica un post su entrambi i siti per più sedi con una sola chiamata. Valida il payload lato client, prepara il messaggio per ciascun sito e codifica gli ID numerici delle sedi per te.
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);Il valore predefinito di sites è ['GOOGLE', 'FACEBOOK']. Passa una mappa per sito come message ({ GOOGLE: '...', FACEBOOK: '...' }) quando il testo deve essere diverso. Per singole campagne con opzioni tipizzate, usa invece createAnnouncement, createEvent o createOffer.
5. Monitoraggio delle recensioni: segnalare le valutazioni basse
Cerca le recensioni a 1 e 2 stelle per ogni sede e registra nei log quelle che richiedono attenzione.
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. Rispondere alle recensioni senza risposta
Rispondi automaticamente a ogni recensione che non ha ancora una risposta. Usa un modello di risposta o sostituisci buildResponse con una chiamata a un 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. Report di analisi: Google, Bing, Facebook e statistiche delle recensioni
Recupera in parallelo i dati di analisi del profilo e le statistiche delle recensioni per una singola sede e stampa un riepilogo di una pagina.
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));Nota la differenza tra i parametri: le analisi delle piattaforme usano fromDate/toDate, mentre quelle delle recensioni usano startDate/endDate.
8. Verifica delle schede: trovare profili non sincronizzati e duplicati
Controlla una sede per individuare le schede premium non sincronizzate e i profili duplicati trovati da ListingsAPI, poi contrassegna i duplicati.
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');}Per un controllo esteso all'intero account, fetchAllDuplicateListings({ page: 1 }) restituisce un riepilogo dei duplicati di tutte le sedi.
9. Account collegati: la procedura per Google
Collega un account Google una sola volta, associa le sue schede alle tue sedi e conferma le associazioni suggerite.
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');Per collegare invece una singola sede, usa getOauthConnectUrl(locationId, 'GOOGLE', successUrl, errorUrl) e connectListing(locationId, listingId, accountId) per collegare direttamente una scheda.
10. Cercare sedi e aggiornare un campo in blocco
Cerca le sedi che corrispondono a una query, poi aggiorna un campo per ogni risultato, ad esempio impostando un nuovo numero di telefono per tutte le sedi di una città.
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');Passaggi successivi
- Sedi: documentazione completa dei metodi con tabelle dei parametri
- Recensioni: analisi, impostazioni, analisi delle frasi
- Schede: premium, vocali, duplicati
- Analisi: dati di Google, Bing e Facebook
- Gestione degli errori: sottoclassi di
APIErrore strategia per i nuovi tentativi