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

bash
npm install listingsapi-js

Authenticate

Get your API key from API Keys → New key in the listingsAPI developer dashboard.

TypeScript
import { ListingsAPI } from 'listingsapi-js';
 
const client = new ListingsAPI(); // reads LISTINGSAPI_KEY from env
const explicit = new ListingsAPI({ apiKey: 'your-api-key' }); // or pass it directly

The constructor also accepts baseUrl (default https://listingsapi.com), timeout (default 240000 ms), and maxRetries (default 2). See Configuration.

Quick example

list_locations.ts
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:

MethodsWhat they manage
fetchAllLocations, searchLocations, fetchLocationsByIds, fetchLocationsByStoreCodes, createLocation, updateLocation, archiveLocations, cancelArchiveLocationsBusiness locations: list, search, create, update, archive
fetchInteractions, fetchReviewDetails, respondToReview, editReviewResponse, archiveReviewResponse, fetchReviewSettings, editReviewSettings, fetchReviewSiteConfig, fetchReviewPhrases, fetchReviewAnalyticsOverview, fetchReviewAnalyticsTimeline, fetchReviewAnalyticsSitesStatsReviews: list, reply, edit and archive responses, settings, phrase and analytics data
bulkPublish, createAnnouncement, createEvent, createOffer, createPost, fetchPost, deletePost, fetchLocationPosts, fetchBulkPost, fetchLocationBulkPostsPosts: announcements, events, and offers on Google and Facebook
fetchPremiumListings, fetchVoiceListings, fetchDuplicateListings, fetchAllDuplicateListings, markListingsAsDuplicate, markListingsAsNotDuplicateDirectory listings: premium, voice, duplicates
fetchGoogleAnalytics, fetchBingAnalytics, fetchFacebookAnalyticsGoogle, Bing, and Facebook profile analytics
fetchLocationPhotos, addLocationPhotos, removeLocationPhotos, starLocationPhotos, fetchPhotoUploadStatusLocation photos
fetchConnectedAccounts, fetchConnectedAccountDetails, fetchConnectedAccountFolders, fetchConnectedAccountListings, fetchConnectionSuggestions, connectGoogleAccount, connectFacebookAccount, disconnectGoogleAccount, disconnectFacebookAccount, triggerConnectedAccountMatches, confirmConnectedAccountMatches, getOauthConnectUrl, oauthDisconnect, connectListing, disconnectListing, createGmbListingOAuth connections to Google and Facebook, listing links
fetchPlanSites, fetchCountries, fetchSubscriptions, fetchSubcategoriesPlan directories, supported countries, subscriptions, business categories

Pagination

Methods that return lists support cursor-based pagination.

TypeScript
// Single page
const page = await client.fetchAllLocations({ first: 25 });
if (!Array.isArray(page)) {
console.log(page.locations); // Location[]
console.log(page.pageInfo); // { hasNextPage, hasPreviousPage, startCursor, endCursor }
 
// Next page
if (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.

TypeScript
import { encodeLocationId } from 'listingsapi-js';
 
// These are equivalent
await 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.

ClassThrown for
AuthenticationError401, or invalid-token error payloads
PermissionDeniedError403, or permission error payloads
NotFoundError404
ValidationError400/422, or mutations returning success: false / errors[]
RateLimitError429, carries retryAfter in seconds
InternalServerError5xx
APIConnectionErrorNetwork 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 }).

TypeScript
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