Node SDK
Official TypeScript client for listingsAPI, with zero dependencies, auto-pagination, and bundled type definitions for Node 18+.
listingsapi-js is the official Node.js/TypeScript client for listingsAPI v4.
It manages locations, directory listings, reviews, posts, photos, and profile
analytics from a single flat client, with cursor-based pagination, automatic
ID encoding, built-in retries, and typed errors out of the box.
Install
npm install listingsapi-jsAuthenticate
Get your API key from API Keys → New key in the listingsAPI developer dashboard.
import { ListingsAPI } from 'listingsapi-js'; const client = new ListingsAPI(); // reads LISTINGSAPI_KEY from envconst explicit = new ListingsAPI({ apiKey: 'your-api-key' }); // or pass it directlyThe constructor also accepts baseUrl (default https://listingsapi.com),
timeout (default 240000 ms), and maxRetries (default 2). See
Configuration.
Quick example
import { ListingsAPI } from 'listingsapi-js'; const client = new ListingsAPI(); const result = await client.fetchAllLocations({ first: 5 });if (!Array.isArray(result)) {for (const location of result.locations) { console.log(location.name, '--', location.city);}}Resources
All methods live directly on the client instance:
| Methods | What they manage |
|---|---|
fetchAllLocations, searchLocations, fetchLocationsByIds, fetchLocationsByStoreCodes, createLocation, updateLocation, archiveLocations, cancelArchiveLocations | Business locations: list, search, create, update, archive |
fetchInteractions, fetchReviewDetails, respondToReview, editReviewResponse, archiveReviewResponse, fetchReviewSettings, editReviewSettings, fetchReviewSiteConfig, fetchReviewPhrases, fetchReviewAnalyticsOverview, fetchReviewAnalyticsTimeline, fetchReviewAnalyticsSitesStats | Reviews: list, reply, edit and archive responses, settings, phrase and analytics data |
bulkPublish, createAnnouncement, createEvent, createOffer, createPost, fetchPost, deletePost, fetchLocationPosts, fetchBulkPost, fetchLocationBulkPosts | Posts: announcements, events, and offers on Google and Facebook |
fetchPremiumListings, fetchVoiceListings, fetchDuplicateListings, fetchAllDuplicateListings, markListingsAsDuplicate, markListingsAsNotDuplicate | Directory listings: premium, voice, duplicates |
fetchGoogleAnalytics, fetchBingAnalytics, fetchFacebookAnalytics | Google, Bing, and Facebook profile analytics |
fetchLocationPhotos, addLocationPhotos, removeLocationPhotos, starLocationPhotos, fetchPhotoUploadStatus | Location photos |
fetchConnectedAccounts, fetchConnectedAccountDetails, fetchConnectedAccountFolders, fetchConnectedAccountListings, fetchConnectionSuggestions, connectGoogleAccount, connectFacebookAccount, disconnectGoogleAccount, disconnectFacebookAccount, triggerConnectedAccountMatches, confirmConnectedAccountMatches, getOauthConnectUrl, oauthDisconnect, connectListing, disconnectListing, createGmbListing | OAuth connections to Google and Facebook, listing links |
fetchPlanSites, fetchCountries, fetchSubscriptions, fetchSubcategories | Plan directories, supported countries, subscriptions, business categories |
Pagination
Methods that return lists support cursor-based pagination.
// Single pageconst page = await client.fetchAllLocations({ first: 25 });if (!Array.isArray(page)) {console.log(page.locations); // Location[]console.log(page.pageInfo); // { hasNextPage, hasPreviousPage, startCursor, endCursor } // Next pageif (page.pageInfo.hasNextPage) { const next = await client.fetchAllLocations({ first: 25, after: page.pageInfo.endCursor!, });}} // Auto-paginate: returns a flat Location[]const all = await client.fetchAllLocations({ fetchAll: true, pageSize: 100 });searchLocations and fetchInteractions follow the same pattern: a page
object by default, a flat array with fetchAll: true.
ID encoding
Pass numeric location IDs anywhere: the SDK base64-encodes them automatically. Already-encoded IDs are accepted as-is, and the encoder is exported if you need it yourself.
import { encodeLocationId } from 'listingsapi-js'; // These are equivalentawait client.fetchPremiumListings(16808);await client.fetchPremiumListings('TG9jYXRpb246MTY4MDg='); encodeLocationId(16808); // 'TG9jYXRpb246MTY4MDg='Error handling
Every SDK error derives from ListingsAPIError. API failures throw APIError
or one of its subclasses, whether the platform reports them as an HTTP status
or inside an HTTP 200 body (invalid tokens and mutation validation arrive as
errors[] payloads, and mutations can report success: false). The SDK
throws for all of these, so you never inspect success flags yourself.
Network failures throw APIConnectionError.
| Class | Thrown for |
|---|---|
AuthenticationError | 401, or invalid-token error payloads |
PermissionDeniedError | 403, or permission error payloads |
NotFoundError | 404 |
ValidationError | 400/422, or mutations returning success: false / errors[] |
RateLimitError | 429, carries retryAfter in seconds |
InternalServerError | 5xx |
APIConnectionError | Network failure, nothing reached the API |
Every APIError carries statusCode, responseBody, code (the first
platform error code, e.g. "SY10005"), and errors (each entry normalized
to { code, message, context }).
import { ListingsAPI, APIError, RateLimitError } from 'listingsapi-js'; const client = new ListingsAPI(); try {await client.fetchAllLocations();} catch (error) {if (error instanceof RateLimitError) { console.log(error.retryAfter); // seconds to wait} else if (error instanceof APIError) { console.log(error.statusCode); // 401, 404, 500, or 200 for payload-level errors console.log(error.code); // first platform code, e.g. 'SY10005' console.log(error.errors); // [{ code, message, context }, ...]}}The client retries 429 and 5xx responses automatically (2 attempts by
default, honoring Retry-After). See
Error handling for retry patterns and
status-code guidance.
Next steps
- Installation: version pins, ESM vs CJS
- Quickstart: your first working script
- Configuration: base URL overrides and TypeScript setup
- Use cases: ten end-to-end recipes
- Locations, Reviews, Listings, Analytics