@land-catalyst/batch-data-sdk 1.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +1032 -0
- package/dist/builders.d.ts +821 -0
- package/dist/builders.js +2622 -0
- package/dist/client.d.ts +435 -0
- package/dist/client.interface.d.ts +210 -0
- package/dist/client.interface.js +2 -0
- package/dist/client.js +757 -0
- package/dist/errors.d.ts +10 -0
- package/dist/errors.js +19 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +28 -0
- package/dist/logger.interface.d.ts +19 -0
- package/dist/logger.interface.js +47 -0
- package/dist/types.d.ts +1738 -0
- package/dist/types.js +9 -0
- package/package.json +62 -0
package/dist/client.js
ADDED
|
@@ -0,0 +1,757 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.BatchDataClient = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const logger_interface_1 = require("./logger.interface");
|
|
9
|
+
const builders_1 = require("./builders");
|
|
10
|
+
/**
|
|
11
|
+
* BatchData API Client
|
|
12
|
+
*
|
|
13
|
+
* Pure API client that makes HTTP calls to BatchData.io endpoints.
|
|
14
|
+
* No business logic - just handles HTTP communication with the API.
|
|
15
|
+
*/
|
|
16
|
+
class BatchDataClient {
|
|
17
|
+
constructor(options) {
|
|
18
|
+
// Validate API key is present
|
|
19
|
+
if (!options.apiKey) {
|
|
20
|
+
throw new Error("BatchData API key is required. Please provide apiKey in options.");
|
|
21
|
+
}
|
|
22
|
+
this.v1BaseUrl = options.v1BaseUrl || "https://api.batchdata.com/api/v1";
|
|
23
|
+
this.v2BaseUrl = options.v2BaseUrl || "https://api.batchdata.com/api/v2";
|
|
24
|
+
this.v3BaseUrl = options.v3BaseUrl || "https://api.batchdata.com/api/v3";
|
|
25
|
+
this.logger = options.logger || new logger_interface_1.ConsoleLogger();
|
|
26
|
+
this.webhooks = options.webhooks;
|
|
27
|
+
this.axiosInstance = axios_1.default.create({
|
|
28
|
+
timeout: options.timeout || 30000,
|
|
29
|
+
headers: {
|
|
30
|
+
"Content-Type": "application/json",
|
|
31
|
+
Accept: "application/json",
|
|
32
|
+
Authorization: `Bearer ${options.apiKey}`,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
// Set up middleware/interceptors if provided
|
|
36
|
+
if (options.middleware) {
|
|
37
|
+
this.setupMiddleware(options.middleware);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Set up axios interceptors from middleware configuration
|
|
42
|
+
* @param middleware The middleware configuration
|
|
43
|
+
*/
|
|
44
|
+
setupMiddleware(middleware) {
|
|
45
|
+
// Request interceptors
|
|
46
|
+
if (middleware.onRequest && middleware.onRequest.length > 0) {
|
|
47
|
+
middleware.onRequest.forEach((middlewareFn) => {
|
|
48
|
+
this.axiosInstance.interceptors.request.use((config) => middlewareFn(config), undefined // Request errors are handled by response error interceptors
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
// Response interceptors
|
|
53
|
+
if (middleware.onResponse && middleware.onResponse.length > 0) {
|
|
54
|
+
middleware.onResponse.forEach((middlewareFn) => {
|
|
55
|
+
this.axiosInstance.interceptors.response.use((response) => middlewareFn(response), undefined // Errors are handled by error interceptors
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// Error interceptors
|
|
60
|
+
if (middleware.onError && middleware.onError.length > 0) {
|
|
61
|
+
middleware.onError.forEach((middlewareFn) => {
|
|
62
|
+
this.axiosInstance.interceptors.response.use(undefined, // Success responses are handled by response interceptors
|
|
63
|
+
async (error) => {
|
|
64
|
+
const result = await middlewareFn(error);
|
|
65
|
+
// If middleware returns a response, treat it as recovery
|
|
66
|
+
if (result && "status" in result && "data" in result) {
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
// Otherwise, re-throw the error
|
|
70
|
+
throw result;
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Apply default webhook URLs to an async request if they're not already set.
|
|
77
|
+
* This helper ensures that if webhook URLs are configured in the client,
|
|
78
|
+
* they will be used for async requests that don't explicitly specify webhook URLs.
|
|
79
|
+
*
|
|
80
|
+
* @param request The async request to modify
|
|
81
|
+
* @param endpointType The type of async endpoint (e.g., 'propertyLookup', 'propertySearch')
|
|
82
|
+
* @returns The request with webhook URLs applied (if needed)
|
|
83
|
+
*/
|
|
84
|
+
applyDefaultWebhookUrls(request, endpointType) {
|
|
85
|
+
// Determine which webhook URLs to use
|
|
86
|
+
let webhookUrl;
|
|
87
|
+
let errorWebhookUrl;
|
|
88
|
+
// First, try endpoint-specific webhook config
|
|
89
|
+
if (endpointType && this.webhooks?.[endpointType]) {
|
|
90
|
+
webhookUrl = this.webhooks[endpointType]?.url;
|
|
91
|
+
errorWebhookUrl = this.webhooks[endpointType]?.errorUrl;
|
|
92
|
+
}
|
|
93
|
+
// Fall back to default webhook config
|
|
94
|
+
if (!webhookUrl && this.webhooks?.default) {
|
|
95
|
+
webhookUrl = this.webhooks.default.url;
|
|
96
|
+
errorWebhookUrl = errorWebhookUrl || this.webhooks.default.errorUrl;
|
|
97
|
+
}
|
|
98
|
+
// If no webhook URLs are configured, return original request
|
|
99
|
+
if (!webhookUrl && !errorWebhookUrl) {
|
|
100
|
+
return request;
|
|
101
|
+
}
|
|
102
|
+
// If request has no options, create an empty options object
|
|
103
|
+
const options = request.options || {};
|
|
104
|
+
// Apply webhook URL if not already set
|
|
105
|
+
if (!options.webhookUrl && webhookUrl) {
|
|
106
|
+
options.webhookUrl = webhookUrl;
|
|
107
|
+
}
|
|
108
|
+
// Apply error webhook URL if not already set
|
|
109
|
+
if (!options.errorWebhookUrl && errorWebhookUrl) {
|
|
110
|
+
options.errorWebhookUrl = errorWebhookUrl;
|
|
111
|
+
}
|
|
112
|
+
// If no options were modified and request had no options, return original
|
|
113
|
+
if (!request.options && !options.webhookUrl && !options.errorWebhookUrl) {
|
|
114
|
+
return request;
|
|
115
|
+
}
|
|
116
|
+
// Return a new request object with updated options
|
|
117
|
+
return {
|
|
118
|
+
...request,
|
|
119
|
+
options: {
|
|
120
|
+
...request.options,
|
|
121
|
+
...options,
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Apply default webhook URLs to a property subscription request if they're not already set.
|
|
127
|
+
* This helper ensures that if webhook URLs are configured in the client,
|
|
128
|
+
* they will be used for property subscriptions that don't explicitly specify webhook URLs.
|
|
129
|
+
*
|
|
130
|
+
* @param request The property subscription request to modify
|
|
131
|
+
* @returns The request with webhook URLs applied (if needed)
|
|
132
|
+
*/
|
|
133
|
+
applyPropertySubscriptionWebhooks(request) {
|
|
134
|
+
// Determine which webhook URLs to use
|
|
135
|
+
let webhookUrl;
|
|
136
|
+
let errorWebhookUrl;
|
|
137
|
+
// First, try property subscription-specific webhook config
|
|
138
|
+
if (this.webhooks?.propertySubscription) {
|
|
139
|
+
webhookUrl = this.webhooks.propertySubscription.url;
|
|
140
|
+
errorWebhookUrl = this.webhooks.propertySubscription.errorUrl;
|
|
141
|
+
}
|
|
142
|
+
// Fall back to default webhook config
|
|
143
|
+
if (!webhookUrl && this.webhooks?.default) {
|
|
144
|
+
webhookUrl = this.webhooks.default.url;
|
|
145
|
+
errorWebhookUrl = errorWebhookUrl || this.webhooks.default.errorUrl;
|
|
146
|
+
}
|
|
147
|
+
// If no webhook URLs are configured, return original request
|
|
148
|
+
if (!webhookUrl && !errorWebhookUrl) {
|
|
149
|
+
return request;
|
|
150
|
+
}
|
|
151
|
+
// If deliveryConfig is not set or is not a webhook type, create/update it
|
|
152
|
+
const deliveryConfig = request.deliveryConfig || {
|
|
153
|
+
type: "webhook",
|
|
154
|
+
};
|
|
155
|
+
// Only apply defaults if deliveryConfig is a webhook type
|
|
156
|
+
if (deliveryConfig.type === "webhook") {
|
|
157
|
+
// Apply webhook URL if not already set
|
|
158
|
+
if (!deliveryConfig.url && webhookUrl) {
|
|
159
|
+
deliveryConfig.url = webhookUrl;
|
|
160
|
+
}
|
|
161
|
+
// Apply error webhook URL if not already set
|
|
162
|
+
if (!deliveryConfig.errorUrl && errorWebhookUrl) {
|
|
163
|
+
deliveryConfig.errorUrl = errorWebhookUrl;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Return a new request object with updated deliveryConfig
|
|
167
|
+
return {
|
|
168
|
+
...request,
|
|
169
|
+
deliveryConfig: {
|
|
170
|
+
...deliveryConfig,
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Add a request middleware function that executes before requests are sent.
|
|
176
|
+
* Useful for adding headers, logging, metrics, etc.
|
|
177
|
+
*
|
|
178
|
+
* @param middleware The middleware function
|
|
179
|
+
* @returns The interceptor ID (can be used to remove the interceptor later)
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```typescript
|
|
183
|
+
* const client = new BatchDataClient({ apiKey: "..." });
|
|
184
|
+
* client.addRequestMiddleware((config) => {
|
|
185
|
+
* console.log(`Making request to ${config.url}`);
|
|
186
|
+
* config.headers["X-Custom-Header"] = "value";
|
|
187
|
+
* return config;
|
|
188
|
+
* });
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
addRequestMiddleware(middleware) {
|
|
192
|
+
return this.axiosInstance.interceptors.request.use((config) => middleware(config), undefined);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Add a response middleware function that executes after successful responses.
|
|
196
|
+
* Useful for logging, metrics, response transformation, etc.
|
|
197
|
+
*
|
|
198
|
+
* @param middleware The middleware function
|
|
199
|
+
* @returns The interceptor ID (can be used to remove the interceptor later)
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```typescript
|
|
203
|
+
* const client = new BatchDataClient({ apiKey: "..." });
|
|
204
|
+
* client.addResponseMiddleware((response) => {
|
|
205
|
+
* console.log(`Received response: ${response.status}`);
|
|
206
|
+
* return response;
|
|
207
|
+
* });
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
addResponseMiddleware(middleware) {
|
|
211
|
+
return this.axiosInstance.interceptors.response.use((response) => middleware(response), undefined);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Add an error middleware function that executes when requests fail.
|
|
215
|
+
* Useful for error handling, retry logic, error transformation, etc.
|
|
216
|
+
*
|
|
217
|
+
* @param middleware The middleware function
|
|
218
|
+
* @returns The interceptor ID (can be used to remove the interceptor later)
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* ```typescript
|
|
222
|
+
* const client = new BatchDataClient({ apiKey: "..." });
|
|
223
|
+
* client.addErrorMiddleware(async (error) => {
|
|
224
|
+
* if (error.response?.status === 429) {
|
|
225
|
+
* // Retry logic here
|
|
226
|
+
* }
|
|
227
|
+
* throw error; // Re-throw to propagate
|
|
228
|
+
* });
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
addErrorMiddleware(middleware) {
|
|
232
|
+
return this.axiosInstance.interceptors.response.use(undefined, async (error) => {
|
|
233
|
+
const result = await middleware(error);
|
|
234
|
+
// If middleware returns a response, treat it as recovery
|
|
235
|
+
if (result && "status" in result && "data" in result) {
|
|
236
|
+
return result;
|
|
237
|
+
}
|
|
238
|
+
// Otherwise, re-throw the error
|
|
239
|
+
throw result;
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Remove a request interceptor by ID
|
|
244
|
+
* @param id The interceptor ID returned from addRequestMiddleware
|
|
245
|
+
*/
|
|
246
|
+
removeRequestMiddleware(id) {
|
|
247
|
+
this.axiosInstance.interceptors.request.eject(id);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Remove a response interceptor by ID
|
|
251
|
+
* @param id The interceptor ID returned from addResponseMiddleware or addErrorMiddleware
|
|
252
|
+
*/
|
|
253
|
+
removeResponseMiddleware(id) {
|
|
254
|
+
this.axiosInstance.interceptors.response.eject(id);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Wrapper for axios calls that handles error logging consistently
|
|
258
|
+
* @param axiosCall The axios call to execute
|
|
259
|
+
* @param errorMessagePrefix Prefix for the error message (e.g., "Failed to search properties")
|
|
260
|
+
* @param url The URL being called (for error details)
|
|
261
|
+
* @returns Object containing the response data and status
|
|
262
|
+
*/
|
|
263
|
+
async handleApiCall(axiosCall, errorMessagePrefix, url) {
|
|
264
|
+
try {
|
|
265
|
+
const response = await axiosCall();
|
|
266
|
+
return response;
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
const axiosError = error;
|
|
270
|
+
const errorDetails = {
|
|
271
|
+
url,
|
|
272
|
+
status: axiosError.response?.status,
|
|
273
|
+
statusText: axiosError.response?.statusText,
|
|
274
|
+
data: axiosError.response?.data,
|
|
275
|
+
headers: axiosError.response?.headers,
|
|
276
|
+
};
|
|
277
|
+
this.logger.error(`${errorMessagePrefix}: ${axiosError.response?.status} - ${axiosError.message}`, axiosError, errorDetails);
|
|
278
|
+
throw error;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Create a property subscription (v2 API)
|
|
283
|
+
* POST /api/v2/property-subscription
|
|
284
|
+
*/
|
|
285
|
+
async createPropertySubscription(request) {
|
|
286
|
+
const url = `${this.v2BaseUrl}/property-subscription`;
|
|
287
|
+
// Apply default webhook URLs if configured
|
|
288
|
+
const requestWithDefaults = this.applyPropertySubscriptionWebhooks(request);
|
|
289
|
+
this.logger.debug(`Creating property subscription: POST ${url}`, {
|
|
290
|
+
query: requestWithDefaults.searchCriteria.query,
|
|
291
|
+
});
|
|
292
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, requestWithDefaults), "Failed to create property subscription", url);
|
|
293
|
+
this.logger.debug(`Property subscription created: ${data.id}`, {
|
|
294
|
+
status,
|
|
295
|
+
});
|
|
296
|
+
return data;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Search for properties (v1 API)
|
|
300
|
+
* POST /api/v1/property/search
|
|
301
|
+
*
|
|
302
|
+
* @param searchCriteria Search criteria
|
|
303
|
+
* @param options Request options
|
|
304
|
+
* @param options.take Number of properties to return (0 for count-only)
|
|
305
|
+
* @param options.skip Number of properties to skip for pagination
|
|
306
|
+
* @returns Property search API response
|
|
307
|
+
*/
|
|
308
|
+
async searchProperties(request) {
|
|
309
|
+
const url = `${this.v1BaseUrl}/property/search`;
|
|
310
|
+
this.logger.debug(`Searching properties: POST ${url}`, {
|
|
311
|
+
query: request.searchCriteria.query,
|
|
312
|
+
take: request.options?.take,
|
|
313
|
+
skip: request.options?.skip,
|
|
314
|
+
});
|
|
315
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, request), "Failed to search properties", url);
|
|
316
|
+
this.logger.debug(`Property search completed`, {
|
|
317
|
+
status,
|
|
318
|
+
hasData: !!data,
|
|
319
|
+
});
|
|
320
|
+
return data;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Get the count of properties matching the search criteria
|
|
324
|
+
* @param searchCriteria Search criteria to match properties
|
|
325
|
+
* @returns Number of matching properties, or null if the endpoint is unavailable
|
|
326
|
+
*/
|
|
327
|
+
async getPropertyCount(searchRequest) {
|
|
328
|
+
const { searchCriteria, options } = searchRequest;
|
|
329
|
+
const lookupOptions = options
|
|
330
|
+
? builders_1.PropertyLookupOptionsBuilder.from(options).take(0)
|
|
331
|
+
: new builders_1.PropertyLookupOptionsBuilder();
|
|
332
|
+
const response = await this.searchProperties({
|
|
333
|
+
searchCriteria,
|
|
334
|
+
options: lookupOptions.build(),
|
|
335
|
+
});
|
|
336
|
+
return response.results?.meta?.results?.resultsFound ?? null;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Verify and normalize addresses (v1 API)
|
|
340
|
+
* POST /api/v1/address/verify
|
|
341
|
+
*
|
|
342
|
+
* @param request Address verification request
|
|
343
|
+
* @returns Address verification API response
|
|
344
|
+
*/
|
|
345
|
+
async verifyAddress(request) {
|
|
346
|
+
const url = `${this.v1BaseUrl}/address/verify`;
|
|
347
|
+
this.logger.debug(`Verifying addresses: POST ${url}`, {
|
|
348
|
+
requestCount: request.requests.length,
|
|
349
|
+
});
|
|
350
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, request), "Failed to verify addresses", url);
|
|
351
|
+
this.logger.debug(`Address verification completed`, {
|
|
352
|
+
status,
|
|
353
|
+
addressCount: data.results?.addresses?.length,
|
|
354
|
+
});
|
|
355
|
+
return data;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Get address autocomplete suggestions (v1 API)
|
|
359
|
+
* POST /api/v1/address/autocomplete
|
|
360
|
+
*
|
|
361
|
+
* Note: This endpoint requires a Referer header per API documentation.
|
|
362
|
+
* For server-side usage, a default Referer is set.
|
|
363
|
+
*
|
|
364
|
+
* @param request Address autocomplete request
|
|
365
|
+
* @returns Address autocomplete API response
|
|
366
|
+
*/
|
|
367
|
+
async autocompleteAddress(request) {
|
|
368
|
+
const url = `${this.v1BaseUrl}/address/autocomplete`;
|
|
369
|
+
this.logger.debug(`Autocompleting address: POST ${url}`, {
|
|
370
|
+
query: request.searchCriteria.query,
|
|
371
|
+
take: request.options?.take,
|
|
372
|
+
});
|
|
373
|
+
// Autocomplete endpoint requires Referer header per API documentation
|
|
374
|
+
// Set a default Referer for server-side SDK usage
|
|
375
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, request, {
|
|
376
|
+
headers: {
|
|
377
|
+
Referer: "https://api.batchdata.com",
|
|
378
|
+
},
|
|
379
|
+
}), "Failed to autocomplete address", url);
|
|
380
|
+
this.logger.debug(`Address autocomplete completed`, {
|
|
381
|
+
status,
|
|
382
|
+
suggestionCount: data.result?.suggestions?.length,
|
|
383
|
+
});
|
|
384
|
+
return data;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Geocode an address to coordinates (v1 API)
|
|
388
|
+
* POST /api/v1/address/geocode
|
|
389
|
+
*
|
|
390
|
+
* @param request Address geocode request
|
|
391
|
+
* @returns Address geocode API response
|
|
392
|
+
*/
|
|
393
|
+
async geocodeAddress(request) {
|
|
394
|
+
const url = `${this.v1BaseUrl}/address/geocode`;
|
|
395
|
+
this.logger.debug(`Geocoding address: POST ${url}`, {
|
|
396
|
+
requestCount: request.requests.length,
|
|
397
|
+
});
|
|
398
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, request), "Failed to geocode address", url);
|
|
399
|
+
this.logger.debug(`Address geocode completed`, {
|
|
400
|
+
status,
|
|
401
|
+
addressCount: data.result?.addresses?.length,
|
|
402
|
+
});
|
|
403
|
+
return data;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Reverse geocode coordinates to an address (v1 API)
|
|
407
|
+
* POST /api/v1/address/reverse-geocode
|
|
408
|
+
*
|
|
409
|
+
* @param request Address reverse geocode request
|
|
410
|
+
* @returns Address reverse geocode API response
|
|
411
|
+
*/
|
|
412
|
+
async reverseGeocodeAddress(request) {
|
|
413
|
+
const url = `${this.v1BaseUrl}/address/reverse-geocode`;
|
|
414
|
+
this.logger.debug(`Reverse geocoding coordinates: POST ${url}`, {
|
|
415
|
+
latitude: request.request.latitude,
|
|
416
|
+
longitude: request.request.longitude,
|
|
417
|
+
});
|
|
418
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, request), "Failed to reverse geocode address", url);
|
|
419
|
+
this.logger.debug(`Address reverse geocode completed`, {
|
|
420
|
+
status,
|
|
421
|
+
addressCount: data.result?.addresses?.length,
|
|
422
|
+
});
|
|
423
|
+
return data;
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Lookup property details by address, propertyId, hash, or APN (v1 API)
|
|
427
|
+
* POST /api/v1/property/lookup/all-attributes
|
|
428
|
+
*
|
|
429
|
+
* @param request Property lookup request
|
|
430
|
+
* @returns Property lookup API response
|
|
431
|
+
*/
|
|
432
|
+
async lookupProperty(request) {
|
|
433
|
+
const url = `${this.v1BaseUrl}/property/lookup/all-attributes`;
|
|
434
|
+
this.logger.debug(`Looking up property: POST ${url}`, {
|
|
435
|
+
requestCount: request.requests.length,
|
|
436
|
+
});
|
|
437
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, request), "Failed to lookup property", url);
|
|
438
|
+
this.logger.debug(`Property lookup completed`, {
|
|
439
|
+
status,
|
|
440
|
+
propertyCount: data.results?.properties?.length,
|
|
441
|
+
});
|
|
442
|
+
return data;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Lookup property details asynchronously (v1 API)
|
|
446
|
+
* POST /api/v1/property/lookup/async
|
|
447
|
+
*
|
|
448
|
+
* @param request Property lookup async request
|
|
449
|
+
* @returns Property lookup async API response
|
|
450
|
+
*/
|
|
451
|
+
async lookupPropertyAsync(request) {
|
|
452
|
+
const url = `${this.v1BaseUrl}/property/lookup/async`;
|
|
453
|
+
// Apply default webhook URLs if configured
|
|
454
|
+
const requestWithDefaults = this.applyDefaultWebhookUrls(request, "propertyLookup");
|
|
455
|
+
this.logger.debug(`Looking up property async: POST ${url}`, {
|
|
456
|
+
requestCount: requestWithDefaults.requests.length,
|
|
457
|
+
});
|
|
458
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, requestWithDefaults), "Failed to lookup property async", url);
|
|
459
|
+
this.logger.debug(`Property lookup async completed`, {
|
|
460
|
+
status,
|
|
461
|
+
asyncStatus: data.status?.text,
|
|
462
|
+
});
|
|
463
|
+
return data;
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Search for properties asynchronously (v1 API)
|
|
467
|
+
* POST /api/v1/property/search/async
|
|
468
|
+
*
|
|
469
|
+
* @param request Property search async request
|
|
470
|
+
* @returns Property search async API response
|
|
471
|
+
*/
|
|
472
|
+
async searchPropertiesAsync(request) {
|
|
473
|
+
const url = `${this.v1BaseUrl}/property/search/async`;
|
|
474
|
+
// Apply default webhook URLs if configured
|
|
475
|
+
const requestWithDefaults = this.applyDefaultWebhookUrls(request, "propertySearch");
|
|
476
|
+
this.logger.debug(`Searching properties async: POST ${url}`, {
|
|
477
|
+
query: requestWithDefaults.searchCriteria.query,
|
|
478
|
+
});
|
|
479
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, requestWithDefaults), "Failed to search properties async", url);
|
|
480
|
+
this.logger.debug(`Property search async completed`, {
|
|
481
|
+
status,
|
|
482
|
+
asyncStatus: data.status?.text,
|
|
483
|
+
});
|
|
484
|
+
return data;
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Skip trace property owners (v1 API)
|
|
488
|
+
* POST /api/v1/property/skip-trace
|
|
489
|
+
*
|
|
490
|
+
* @param request Property skip trace request
|
|
491
|
+
* @returns Property skip trace API response
|
|
492
|
+
*/
|
|
493
|
+
async skipTraceProperty(request) {
|
|
494
|
+
const url = `${this.v1BaseUrl}/property/skip-trace`;
|
|
495
|
+
this.logger.debug(`Skip tracing property: POST ${url}`, {
|
|
496
|
+
requestCount: request.requests.length,
|
|
497
|
+
});
|
|
498
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, request), "Failed to skip trace property", url);
|
|
499
|
+
this.logger.debug(`Property skip trace completed`, {
|
|
500
|
+
status,
|
|
501
|
+
propertyCount: data.results?.properties?.length,
|
|
502
|
+
});
|
|
503
|
+
return data;
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Skip trace property owners asynchronously (v1 API)
|
|
507
|
+
* POST /api/v1/property/skip-trace/async
|
|
508
|
+
*
|
|
509
|
+
* @param request Property skip trace async request
|
|
510
|
+
* @returns Property skip trace async API response
|
|
511
|
+
*/
|
|
512
|
+
async skipTracePropertyAsync(request) {
|
|
513
|
+
const url = `${this.v1BaseUrl}/property/skip-trace/async`;
|
|
514
|
+
// Apply default webhook URLs if configured
|
|
515
|
+
const requestWithDefaults = this.applyDefaultWebhookUrls(request, "skipTrace");
|
|
516
|
+
this.logger.debug(`Skip tracing property async: POST ${url}`, {
|
|
517
|
+
requestCount: requestWithDefaults.requests.length,
|
|
518
|
+
});
|
|
519
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, requestWithDefaults), "Failed to skip trace property async", url);
|
|
520
|
+
this.logger.debug(`Property skip trace async completed`, {
|
|
521
|
+
status,
|
|
522
|
+
asyncStatus: data.status?.text,
|
|
523
|
+
});
|
|
524
|
+
return data;
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Verify phone numbers (v1 API)
|
|
528
|
+
* POST /api/v1/phone/verification
|
|
529
|
+
*
|
|
530
|
+
* @param request Phone verification request
|
|
531
|
+
* @returns Phone verification API response
|
|
532
|
+
*/
|
|
533
|
+
async verifyPhone(request) {
|
|
534
|
+
const url = `${this.v1BaseUrl}/phone/verification`;
|
|
535
|
+
this.logger.debug(`Verifying phone: POST ${url}`, {
|
|
536
|
+
requestCount: request.requests.length,
|
|
537
|
+
});
|
|
538
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, request), "Failed to verify phone", url);
|
|
539
|
+
this.logger.debug(`Phone verification completed`, {
|
|
540
|
+
status,
|
|
541
|
+
phoneCount: data.results?.phoneNumbers?.length,
|
|
542
|
+
});
|
|
543
|
+
return data;
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Verify phone numbers asynchronously (v1 API)
|
|
547
|
+
* POST /api/v1/phone/verification/async
|
|
548
|
+
*
|
|
549
|
+
* @param request Phone verification async request
|
|
550
|
+
* @returns Phone verification async API response
|
|
551
|
+
*/
|
|
552
|
+
async verifyPhoneAsync(request) {
|
|
553
|
+
const url = `${this.v1BaseUrl}/phone/verification/async`;
|
|
554
|
+
// Apply default webhook URLs if configured
|
|
555
|
+
const requestWithDefaults = this.applyDefaultWebhookUrls(request, "phoneVerification");
|
|
556
|
+
this.logger.debug(`Verifying phone async: POST ${url}`, {
|
|
557
|
+
requestCount: requestWithDefaults.requests.length,
|
|
558
|
+
});
|
|
559
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, requestWithDefaults), "Failed to verify phone async", url);
|
|
560
|
+
this.logger.debug(`Phone verification async completed`, {
|
|
561
|
+
status,
|
|
562
|
+
asyncStatus: data.status?.text,
|
|
563
|
+
});
|
|
564
|
+
return data;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Check phone numbers against DNC (Do Not Call) list (v1 API)
|
|
568
|
+
* POST /api/v1/phone/dnc
|
|
569
|
+
*
|
|
570
|
+
* @param request Phone DNC request
|
|
571
|
+
* @returns Phone DNC API response
|
|
572
|
+
*/
|
|
573
|
+
async checkPhoneDNC(request) {
|
|
574
|
+
const url = `${this.v1BaseUrl}/phone/dnc`;
|
|
575
|
+
this.logger.debug(`Checking phone DNC: POST ${url}`, {
|
|
576
|
+
requestCount: request.requests.length,
|
|
577
|
+
});
|
|
578
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, request), "Failed to check phone DNC", url);
|
|
579
|
+
this.logger.debug(`Phone DNC check completed`, {
|
|
580
|
+
status,
|
|
581
|
+
phoneCount: data.results?.phoneNumbers?.length,
|
|
582
|
+
});
|
|
583
|
+
return data;
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Check phone numbers against DNC list asynchronously (v1 API)
|
|
587
|
+
* POST /api/v1/phone/dnc/async
|
|
588
|
+
*
|
|
589
|
+
* @param request Phone DNC async request
|
|
590
|
+
* @returns Phone DNC async API response
|
|
591
|
+
*/
|
|
592
|
+
async checkPhoneDNCAsync(request) {
|
|
593
|
+
const url = `${this.v1BaseUrl}/phone/dnc/async`;
|
|
594
|
+
// Apply default webhook URLs if configured
|
|
595
|
+
const requestWithDefaults = this.applyDefaultWebhookUrls(request, "phoneDNC");
|
|
596
|
+
this.logger.debug(`Checking phone DNC async: POST ${url}`, {
|
|
597
|
+
requestCount: requestWithDefaults.requests.length,
|
|
598
|
+
});
|
|
599
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, requestWithDefaults), "Failed to check phone DNC async", url);
|
|
600
|
+
this.logger.debug(`Phone DNC check async completed`, {
|
|
601
|
+
status,
|
|
602
|
+
asyncStatus: data.status?.text,
|
|
603
|
+
});
|
|
604
|
+
return data;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Check phone numbers for TCPA compliance (v1 API)
|
|
608
|
+
* POST /api/v1/phone/tcpa
|
|
609
|
+
*
|
|
610
|
+
* @param request Phone TCPA request
|
|
611
|
+
* @returns Phone TCPA API response
|
|
612
|
+
*/
|
|
613
|
+
async checkPhoneTCPA(request) {
|
|
614
|
+
const url = `${this.v1BaseUrl}/phone/tcpa`;
|
|
615
|
+
this.logger.debug(`Checking phone TCPA: POST ${url}`, {
|
|
616
|
+
requestCount: request.requests.length,
|
|
617
|
+
});
|
|
618
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, request), "Failed to check phone TCPA", url);
|
|
619
|
+
this.logger.debug(`Phone TCPA check completed`, {
|
|
620
|
+
status,
|
|
621
|
+
phoneCount: data.results?.phoneNumbers?.length,
|
|
622
|
+
});
|
|
623
|
+
return data;
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* Check phone numbers for TCPA compliance asynchronously (v1 API)
|
|
627
|
+
* POST /api/v1/phone/tcpa/async
|
|
628
|
+
*
|
|
629
|
+
* @param request Phone TCPA async request
|
|
630
|
+
* @returns Phone TCPA async API response
|
|
631
|
+
*/
|
|
632
|
+
async checkPhoneTCPAAsync(request) {
|
|
633
|
+
const url = `${this.v1BaseUrl}/phone/tcpa/async`;
|
|
634
|
+
// Apply default webhook URLs if configured
|
|
635
|
+
const requestWithDefaults = this.applyDefaultWebhookUrls(request, "phoneTCPA");
|
|
636
|
+
this.logger.debug(`Checking phone TCPA async: POST ${url}`, {
|
|
637
|
+
requestCount: requestWithDefaults.requests.length,
|
|
638
|
+
});
|
|
639
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, requestWithDefaults), "Failed to check phone TCPA async", url);
|
|
640
|
+
this.logger.debug(`Phone TCPA check async completed`, {
|
|
641
|
+
status,
|
|
642
|
+
asyncStatus: data.status?.text,
|
|
643
|
+
});
|
|
644
|
+
return data;
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Get all property subscriptions (v2 API)
|
|
648
|
+
* GET /api/v2/property-subscription
|
|
649
|
+
*
|
|
650
|
+
* @returns Array of property subscriptions
|
|
651
|
+
*/
|
|
652
|
+
async getPropertySubscriptions() {
|
|
653
|
+
const url = `${this.v2BaseUrl}/property-subscription`;
|
|
654
|
+
this.logger.debug(`Getting property subscriptions: GET ${url}`);
|
|
655
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.get(url), "Failed to get property subscriptions", url);
|
|
656
|
+
this.logger.debug(`Get property subscriptions completed`, {
|
|
657
|
+
status,
|
|
658
|
+
subscriptionCount: Array.isArray(data) ? data.length : 0,
|
|
659
|
+
});
|
|
660
|
+
return data;
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Get property subscription by ID (v2 API)
|
|
664
|
+
* GET /api/v2/property-subscription/{id}
|
|
665
|
+
*
|
|
666
|
+
* @param id Subscription ID
|
|
667
|
+
* @returns Property subscription detail
|
|
668
|
+
*/
|
|
669
|
+
async getPropertySubscription(id) {
|
|
670
|
+
const url = `${this.v2BaseUrl}/property-subscription/${id}`;
|
|
671
|
+
this.logger.debug(`Getting property subscription: GET ${url}`, {
|
|
672
|
+
subscriptionId: id,
|
|
673
|
+
});
|
|
674
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.get(url), "Failed to get property subscription", url);
|
|
675
|
+
this.logger.debug(`Get property subscription completed`, {
|
|
676
|
+
status,
|
|
677
|
+
hasSubscription: !!data.results?.subscription,
|
|
678
|
+
});
|
|
679
|
+
return data;
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Delete property subscription (v2 API)
|
|
683
|
+
* DELETE /api/v2/property-subscription/{id}
|
|
684
|
+
*
|
|
685
|
+
* @param id Subscription ID
|
|
686
|
+
* @returns Delete response
|
|
687
|
+
*/
|
|
688
|
+
async deletePropertySubscription(id) {
|
|
689
|
+
const url = `${this.v2BaseUrl}/property-subscription/${id}`;
|
|
690
|
+
this.logger.debug(`Deleting property subscription: DELETE ${url}`, {
|
|
691
|
+
subscriptionId: id,
|
|
692
|
+
});
|
|
693
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.delete(url), "Failed to delete property subscription", url);
|
|
694
|
+
this.logger.debug(`Delete property subscription completed`, {
|
|
695
|
+
status,
|
|
696
|
+
});
|
|
697
|
+
return data;
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Get property permits (v2 API)
|
|
701
|
+
* POST /api/v2/property/get-property-permits
|
|
702
|
+
*
|
|
703
|
+
* @param request Property permit request
|
|
704
|
+
* @returns Property permit API response
|
|
705
|
+
*/
|
|
706
|
+
async getPropertyPermit(request) {
|
|
707
|
+
const url = `${this.v2BaseUrl}/property/get-property-permits`;
|
|
708
|
+
this.logger.debug(`Getting property permits: POST ${url}`);
|
|
709
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, request), "Failed to get property permits", url);
|
|
710
|
+
this.logger.debug(`Get property permits completed`, {
|
|
711
|
+
status,
|
|
712
|
+
permitCount: data.result?.permits?.length,
|
|
713
|
+
});
|
|
714
|
+
return data;
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* Skip trace property owners (v3 API)
|
|
718
|
+
* POST /api/v3/property/skip-trace
|
|
719
|
+
*
|
|
720
|
+
* @param request Property skip trace v3 request
|
|
721
|
+
* @returns Property skip trace v3 API response
|
|
722
|
+
*/
|
|
723
|
+
async skipTracePropertyV3(request) {
|
|
724
|
+
const url = `${this.v3BaseUrl}/property/skip-trace`;
|
|
725
|
+
this.logger.debug(`Skip tracing property v3: POST ${url}`, {
|
|
726
|
+
requestCount: request.requests.length,
|
|
727
|
+
});
|
|
728
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, request), "Failed to skip trace property v3", url);
|
|
729
|
+
this.logger.debug(`Property skip trace v3 completed`, {
|
|
730
|
+
status,
|
|
731
|
+
dataCount: data.result?.data?.length,
|
|
732
|
+
});
|
|
733
|
+
return data;
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Skip trace property owners asynchronously (v3 API)
|
|
737
|
+
* POST /api/v3/property/skip-trace/async
|
|
738
|
+
*
|
|
739
|
+
* @param request Property skip trace v3 async request
|
|
740
|
+
* @returns Property skip trace v3 async API response
|
|
741
|
+
*/
|
|
742
|
+
async skipTracePropertyV3Async(request) {
|
|
743
|
+
const url = `${this.v3BaseUrl}/property/skip-trace/async`;
|
|
744
|
+
// Apply default webhook URLs if configured
|
|
745
|
+
const requestWithDefaults = this.applyDefaultWebhookUrls(request, "skipTraceV3");
|
|
746
|
+
this.logger.debug(`Skip tracing property v3 async: POST ${url}`, {
|
|
747
|
+
requestCount: requestWithDefaults.requests.length,
|
|
748
|
+
});
|
|
749
|
+
const { data, status } = await this.handleApiCall(() => this.axiosInstance.post(url, requestWithDefaults), "Failed to skip trace property v3 async", url);
|
|
750
|
+
this.logger.debug(`Property skip trace v3 async completed`, {
|
|
751
|
+
status,
|
|
752
|
+
requestId: data.result?.requestId,
|
|
753
|
+
});
|
|
754
|
+
return data;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
exports.BatchDataClient = BatchDataClient;
|