Kasus Penggunaan

Contoh implementasi TypeScript dari awal hingga akhir yang menunjukkan cara menggabungkan sumber daya listingsapi-js menjadi integrasi nyata.

Contoh-contoh implementasi ini merupakan alur kerja lintas sumber daya, yaitu skrip yang Anda gunakan ketika satu halaman metode saja tidak cukup. Setiap contoh adalah program TypeScript lengkap yang dapat dijalankan dan menggabungkan dua sumber daya atau lebih menjadi program yang dapat Anda terapkan. Instal SDK dengan versi yang ditetapkan (npm install listingsapi-js@0.3.2), ekspor LISTINGSAPI_KEY dengan kunci dari dasbor Anda, lalu jalankan program tersebut tanpa perubahan menggunakan npx tsx <file>.ts.

Jika Anda baru menggunakan SDK ini, baca ringkasan Node SDK terlebih dahulu. Ringkasan tersebut membahas pembuatan klien, autentikasi, kesalahan, dan paginasi, yang semuanya perlu Anda pahami untuk mengikuti setiap contoh di bawah ini.

1. Panduan awal: ambil dan cetak lokasi

Integrasi paling sederhana yang dapat digunakan: lakukan autentikasi, ambil satu halaman lokasi, lalu cetak nama-namanya.

01_quickstart.ts
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);}}

Tanpa fetchAll, fetchAllLocations mengembalikan objek yang berisi locations, pageInfo, dan payload raw. Berikan pageInfo.endCursor sebagai after untuk mendapatkan halaman berikutnya.

2. Ekspor massal ke JSON

Telusuri semua halaman lokasi dalam akun secara otomatis dan tulis hasilnya ke disk.

02_bulk_export.ts
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 menelusuri halaman berbasis kursor secara otomatis dan mengembalikan Location[] yang tidak bertingkat. Untuk 10 000+ lokasi, pertahankan pageSize pada 100 (nilai bawaan) agar setiap permintaan tetap cepat.

3. Siapkan lokasi baru

Cari ID kategori yang tepat menggunakan fetchSubcategories, lalu buat lokasi. databaseId dari suatu subkategori adalah nilai yang diharapkan oleh createLocation sebagai subCategoryId. API juga mewajibkan deskripsi sepanjang 200 karakter atau lebih.

03_onboarding.ts
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);

Kegagalan validasi (kolom yang tidak diisi, deskripsi terlalu pendek, kategori tidak valid) melempar ValidationError dengan entri kesalahan platform pada err.errors, sehingga tidak ada penanda success yang perlu diperiksa.

4. Publikasikan postingan ke Google dan Facebook secara massal

bulkPublish memublikasikan satu postingan di kedua situs untuk banyak lokasi dalam satu panggilan. Metode ini memvalidasi payload di sisi klien, menyiapkan pesan untuk setiap situs, dan mengodekan ID lokasi numerik untuk Anda.

04_bulk_publish.ts
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);

Nilai bawaan sites adalah ['GOOGLE', 'FACEBOOK']. Berikan pemetaan per situs sebagai message ({ GOOGLE: '...', FACEBOOK: '...' }) jika teksnya perlu berbeda. Untuk kampanye tunggal dengan opsi bertipe, gunakan createAnnouncement, createEvent, atau createOffer sebagai gantinya.

5. Pemantauan ulasan: tandai rating rendah

Periksa setiap lokasi untuk menemukan ulasan berbintang 1 dan 2, lalu catat ulasan yang perlu diperhatikan.

05_review_monitoring.ts
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. Balas ulasan yang belum dibalas

Balas secara otomatis setiap ulasan yang belum mendapat tanggapan. Gunakan templat atau ganti buildResponse dengan panggilan LLM.

06_bulk_respond.ts
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. Laporan analitik: Google, Bing, Facebook, dan statistik ulasan

Ambil analitik profil dan statistik ulasan untuk satu lokasi secara paralel, lalu cetak ringkasan satu halaman.

07_analytics_report.ts
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));

Perhatikan perbedaan parameternya: analitik platform menggunakan fromDate/toDate, sedangkan analitik ulasan menggunakan startDate/endDate.

8. Audit profil bisnis: temukan profil yang tidak tersinkron dan profil duplikat

Periksa satu lokasi untuk menemukan profil bisnis premium yang tidak tersinkron dan profil duplikat yang ditemukan ListingsAPI, lalu tandai duplikat tersebut.

08_listings_audit.ts
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');}

Untuk pemeriksaan seluruh akun, fetchAllDuplicateListings({ page: 1 }) mengembalikan ringkasan duplikat di semua lokasi dalam akun tersebut.

9. Akun terhubung: alur Google

Hubungkan akun Google satu kali, cocokkan profil bisnisnya dengan lokasi Anda, lalu konfirmasikan kecocokan yang disarankan.

09_connected_accounts.ts
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');

Untuk menghubungkan satu lokasi saja, gunakan getOauthConnectUrl(locationId, 'GOOGLE', successUrl, errorUrl), lalu gunakan connectListing(locationId, listingId, accountId) untuk menautkan satu profil bisnis secara langsung.

10. Cari lokasi dan perbarui kolom secara massal

Cari lokasi yang cocok dengan kueri, lalu perbarui satu kolom pada setiap hasil, misalnya menerapkan nomor telepon baru ke semua lokasi tersebut di suatu kota.

10_bulk_update.ts
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');

Langkah berikutnya