@planescrm/sdk 0.4.0 → 0.72.0
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/README.md +565 -12
- package/dist/client.d.mts +6016 -0
- package/dist/client.d.ts +6016 -0
- package/dist/client.js +3255 -0
- package/dist/client.js.map +1 -0
- package/dist/client.mjs +3232 -0
- package/dist/client.mjs.map +1 -0
- package/dist/index.d.mts +5448 -210
- package/dist/index.d.ts +5448 -210
- package/dist/index.js +2904 -157
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2842 -157
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -4
package/dist/index.js
CHANGED
|
@@ -30,38 +30,100 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
AGENT_ROLES: () => AGENT_ROLES,
|
|
34
|
+
AUTOPAY_UNAVAILABLE_REASONS: () => AUTOPAY_UNAVAILABLE_REASONS,
|
|
33
35
|
ActivityResource: () => ActivityResource,
|
|
34
36
|
AgentApp: () => AgentApp,
|
|
37
|
+
ApiResource: () => ApiResource,
|
|
35
38
|
AuthenticationError: () => AuthenticationError,
|
|
36
39
|
AuthorizationError: () => AuthorizationError,
|
|
40
|
+
BILLING_ADJUSTMENT_STATUSES: () => BILLING_ADJUSTMENT_STATUSES,
|
|
41
|
+
BILLING_ADJUSTMENT_TARGETS: () => BILLING_ADJUSTMENT_TARGETS,
|
|
42
|
+
BILLING_AUTOPAY_STATUSES: () => BILLING_AUTOPAY_STATUSES,
|
|
43
|
+
BILLING_BACKFILL_MODES: () => BILLING_BACKFILL_MODES,
|
|
44
|
+
BILLING_CADENCES: () => BILLING_CADENCES,
|
|
45
|
+
BILLING_COLLECTION_MODES: () => BILLING_COLLECTION_MODES,
|
|
46
|
+
BILLING_DELIVERY_MODES: () => BILLING_DELIVERY_MODES,
|
|
47
|
+
BILLING_DELIVERY_STATUSES: () => BILLING_DELIVERY_STATUSES,
|
|
48
|
+
BILLING_INTERVALS: () => BILLING_INTERVALS,
|
|
49
|
+
BILLING_PERIOD_STATUSES: () => BILLING_PERIOD_STATUSES,
|
|
50
|
+
BILLING_PREVIEW_PERIOD_STATUSES: () => BILLING_PREVIEW_PERIOD_STATUSES,
|
|
51
|
+
BILLING_SCHEDULE_STATUSES: () => BILLING_SCHEDULE_STATUSES,
|
|
52
|
+
BILLING_STATUSES: () => BILLING_STATUSES,
|
|
53
|
+
BILL_TIMINGS: () => BILL_TIMINGS,
|
|
37
54
|
BaseResource: () => BaseResource,
|
|
55
|
+
BillingScheduleResource: () => BillingScheduleResource,
|
|
56
|
+
CONTACT_LIST_INCLUDES: () => CONTACT_LIST_INCLUDES,
|
|
57
|
+
CONTACT_SORT_KEYS: () => CONTACT_SORT_KEYS,
|
|
58
|
+
CUSTOMER_SORT_KEYS: () => CUSTOMER_SORT_KEYS,
|
|
38
59
|
CalendarEventResource: () => CalendarEventResource,
|
|
60
|
+
CommunicationsResource: () => CommunicationsResource,
|
|
39
61
|
ContactChannelResource: () => ContactChannelResource,
|
|
40
62
|
ContactResource: () => ContactResource,
|
|
63
|
+
ContactSequencesResource: () => ContactSequencesResource,
|
|
41
64
|
ContractResource: () => ContractResource,
|
|
65
|
+
ConversationsResource: () => ConversationsResource,
|
|
66
|
+
CustomFieldsResource: () => CustomFieldsResource,
|
|
42
67
|
CustomerResource: () => CustomerResource,
|
|
43
68
|
DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
|
|
44
69
|
DEFAULT_MAX_RETRIES: () => DEFAULT_MAX_RETRIES,
|
|
45
70
|
DEFAULT_TIMEOUT: () => DEFAULT_TIMEOUT,
|
|
46
71
|
DEFAULT_TOKEN_REFRESH_SKEW_MS: () => DEFAULT_TOKEN_REFRESH_SKEW_MS,
|
|
72
|
+
DocumentsResource: () => DocumentsResource,
|
|
73
|
+
ESTIMATE_STATUSES: () => ESTIMATE_STATUSES,
|
|
74
|
+
EnrollmentsResource: () => EnrollmentsResource,
|
|
47
75
|
EstimateResource: () => EstimateResource,
|
|
76
|
+
EventAutomationsResource: () => EventAutomationsResource,
|
|
77
|
+
FEATURE_KEYS: () => FEATURE_KEYS,
|
|
78
|
+
GmailResource: () => GmailResource,
|
|
48
79
|
InventoryResource: () => InventoryResource,
|
|
80
|
+
InvoiceRemindersResource: () => InvoiceRemindersResource,
|
|
49
81
|
InvoiceResource: () => InvoiceResource,
|
|
82
|
+
InvoiceSettingsResource: () => InvoiceSettingsResource,
|
|
83
|
+
JOB_SORT_KEYS: () => JOB_SORT_KEYS,
|
|
50
84
|
JobResource: () => JobResource,
|
|
85
|
+
LeadSourcesResource: () => LeadSourcesResource,
|
|
86
|
+
ListsResource: () => ListsResource,
|
|
87
|
+
MODULE_KEYS: () => MODULE_KEYS,
|
|
88
|
+
MeResource: () => MeResource,
|
|
51
89
|
MemoryTokenStorage: () => MemoryTokenStorage,
|
|
90
|
+
ModulesResource: () => ModulesResource,
|
|
52
91
|
NotFoundError: () => NotFoundError,
|
|
53
92
|
OAuthError: () => OAuthError,
|
|
93
|
+
OPPORTUNITY_SORT_KEYS: () => OPPORTUNITY_SORT_KEYS,
|
|
94
|
+
OPPORTUNITY_STATES: () => OPPORTUNITY_STATES,
|
|
54
95
|
OpportunityResource: () => OpportunityResource,
|
|
96
|
+
OrttoResource: () => OrttoResource,
|
|
97
|
+
PLAN_KEYS: () => PLAN_KEYS,
|
|
98
|
+
PLAN_SOURCES: () => PLAN_SOURCES,
|
|
99
|
+
PlanResource: () => PlanResource,
|
|
55
100
|
Planes: () => Planes,
|
|
56
101
|
PlanesClient: () => PlanesClient,
|
|
57
102
|
PlanesError: () => PlanesError,
|
|
58
103
|
PropertyResource: () => PropertyResource,
|
|
104
|
+
RECORD_VIEW_ENTITY_TYPES: () => RECORD_VIEW_ENTITY_TYPES,
|
|
59
105
|
RateLimitError: () => RateLimitError,
|
|
106
|
+
RecordViewsResource: () => RecordViewsResource,
|
|
107
|
+
RolesResource: () => RolesResource,
|
|
60
108
|
ServerError: () => ServerError,
|
|
109
|
+
ServiceSchedulesResource: () => ServiceSchedulesResource,
|
|
110
|
+
TASK_SORT_KEYS: () => TASK_SORT_KEYS,
|
|
61
111
|
TagResource: () => TagResource,
|
|
112
|
+
TaskResource: () => TaskResource,
|
|
113
|
+
TeamsResource: () => TeamsResource,
|
|
114
|
+
UsersResource: () => UsersResource,
|
|
62
115
|
ValidationError: () => ValidationError,
|
|
116
|
+
WEBHOOK_EVENT_TYPES: () => WEBHOOK_EVENT_TYPES,
|
|
117
|
+
WORKFLOW_EVENT_RULE_CATCH_UP_EVENT_TYPES: () => WORKFLOW_EVENT_RULE_CATCH_UP_EVENT_TYPES,
|
|
118
|
+
WORKFLOW_EVENT_RULE_EVENT_TYPES: () => WORKFLOW_EVENT_RULE_EVENT_TYPES,
|
|
119
|
+
WORKFLOW_EVENT_RULE_MATCH_ALL_EVENT_TYPES: () => WORKFLOW_EVENT_RULE_MATCH_ALL_EVENT_TYPES,
|
|
120
|
+
WebFormSubmissionsResource: () => WebFormSubmissionsResource,
|
|
121
|
+
WebFormsResource: () => WebFormsResource,
|
|
63
122
|
WebhookRouter: () => WebhookRouter,
|
|
123
|
+
WebhookSubscriptionsResource: () => WebhookSubscriptionsResource,
|
|
64
124
|
WebhookVerificationError: () => WebhookVerificationError,
|
|
125
|
+
WorkflowEventRulesResource: () => WorkflowEventRulesResource,
|
|
126
|
+
WorkflowsResource: () => WorkflowsResource,
|
|
65
127
|
buildAuthorizeUrl: () => buildAuthorizeUrl,
|
|
66
128
|
clientCredentialsGrant: () => clientCredentialsGrant,
|
|
67
129
|
createAgentApp: () => createAgentApp,
|
|
@@ -240,6 +302,9 @@ var HttpClient = class {
|
|
|
240
302
|
this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
241
303
|
this.retryOnRateLimit = config.retryOnRateLimit !== false;
|
|
242
304
|
this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
305
|
+
this.getAccessToken = config.getAccessToken;
|
|
306
|
+
this.onUnauthorized = config.onUnauthorized;
|
|
307
|
+
this.fetchImpl = config.fetch;
|
|
243
308
|
if (config.clientId && config.clientSecret) {
|
|
244
309
|
this.oauth = {
|
|
245
310
|
clientId: config.clientId,
|
|
@@ -256,50 +321,68 @@ var HttpClient = class {
|
|
|
256
321
|
let lastError;
|
|
257
322
|
let didRefreshOn401 = false;
|
|
258
323
|
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
324
|
+
const authHeaders = await this.resolveAuthHeaders();
|
|
259
325
|
const headers = {
|
|
260
326
|
"Content-Type": "application/json",
|
|
261
|
-
...
|
|
327
|
+
...authHeaders,
|
|
262
328
|
...options.headers
|
|
263
329
|
};
|
|
330
|
+
if (options.idempotencyKey) headers["Idempotency-Key"] = options.idempotencyKey;
|
|
331
|
+
const timer = timeoutSignal(this.timeout);
|
|
264
332
|
const fetchOptions = {
|
|
265
333
|
method: options.method,
|
|
266
334
|
headers,
|
|
267
|
-
signal:
|
|
335
|
+
signal: timer.signal
|
|
268
336
|
};
|
|
269
337
|
if (bodyStr !== void 0) {
|
|
270
338
|
fetchOptions.body = bodyStr;
|
|
271
339
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if (response.
|
|
275
|
-
|
|
340
|
+
try {
|
|
341
|
+
const response = await (this.fetchImpl ?? fetch)(url, fetchOptions);
|
|
342
|
+
if (response.ok) {
|
|
343
|
+
if (response.status === 204) {
|
|
344
|
+
return void 0;
|
|
345
|
+
}
|
|
346
|
+
if (options.responseType === "arrayBuffer") {
|
|
347
|
+
return await response.arrayBuffer();
|
|
348
|
+
}
|
|
349
|
+
return await response.json();
|
|
276
350
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
351
|
+
if (response.status === 429 && this.retryOnRateLimit && attempt < this.maxRetries) {
|
|
352
|
+
const retryAfter = this.parseRetryAfter(response);
|
|
353
|
+
await this.sleep(retryAfter * 1e3);
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
if (response.status === 401 && this.oauth && !didRefreshOn401) {
|
|
357
|
+
didRefreshOn401 = true;
|
|
358
|
+
await this.refreshTokens();
|
|
359
|
+
attempt--;
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
if (response.status === 401 && this.onUnauthorized && !didRefreshOn401) {
|
|
363
|
+
didRefreshOn401 = true;
|
|
364
|
+
if (await this.recoverSession(authHeaders["Authorization"])) {
|
|
365
|
+
attempt--;
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
lastError = await this.mapError(response);
|
|
370
|
+
if (response.status !== 429 || !this.retryOnRateLimit) {
|
|
371
|
+
throw lastError;
|
|
372
|
+
}
|
|
373
|
+
} finally {
|
|
374
|
+
timer.clear();
|
|
293
375
|
}
|
|
294
376
|
}
|
|
295
377
|
throw lastError ?? new RateLimitError();
|
|
296
378
|
}
|
|
297
379
|
getAuthHeaders() {
|
|
380
|
+
if (this.getAccessToken) return {};
|
|
298
381
|
if (this.accessToken) {
|
|
299
382
|
return { Authorization: `Bearer ${this.accessToken}` };
|
|
300
383
|
}
|
|
301
384
|
if (this.apiKey) {
|
|
302
|
-
return {
|
|
385
|
+
return { Authorization: `Bearer ${this.apiKey}` };
|
|
303
386
|
}
|
|
304
387
|
return {};
|
|
305
388
|
}
|
|
@@ -310,6 +393,10 @@ var HttpClient = class {
|
|
|
310
393
|
* the token is within the skew window of expiry.
|
|
311
394
|
*/
|
|
312
395
|
async resolveAuthHeaders() {
|
|
396
|
+
if (this.getAccessToken) {
|
|
397
|
+
const token = await withTimeout(this.getAccessToken(), this.timeout, "getAccessToken");
|
|
398
|
+
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
399
|
+
}
|
|
313
400
|
if (!this.oauth) {
|
|
314
401
|
return this.getAuthHeaders();
|
|
315
402
|
}
|
|
@@ -373,6 +460,41 @@ var HttpClient = class {
|
|
|
373
460
|
this.refreshInFlight = void 0;
|
|
374
461
|
}
|
|
375
462
|
}
|
|
463
|
+
/**
|
|
464
|
+
* Ask the app to refresh its session after a 401. Resolves `true` when the
|
|
465
|
+
* request should be retried.
|
|
466
|
+
* - Requests that got a 401 while a refresh is running share that one call.
|
|
467
|
+
* - A request whose 401 arrives after a refresh already finished (it was
|
|
468
|
+
* sent with the old token) doesn't start a second refresh: if the current
|
|
469
|
+
* token differs from the one it sent, it just retries with the new one.
|
|
470
|
+
* - A refresh that throws, or doesn't settle within the request timeout,
|
|
471
|
+
* counts as "still signed out": the original 401 surfaces.
|
|
472
|
+
*/
|
|
473
|
+
async recoverSession(sentAuthorization) {
|
|
474
|
+
if (!this.onUnauthorized || !this.getAccessToken) return false;
|
|
475
|
+
if (!this.unauthorizedInFlight) {
|
|
476
|
+
try {
|
|
477
|
+
const current = await withTimeout(this.getAccessToken(), this.timeout, "getAccessToken");
|
|
478
|
+
if (current && `Bearer ${current}` !== sentAuthorization) return true;
|
|
479
|
+
} catch {
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (!this.unauthorizedInFlight) {
|
|
484
|
+
const call = this.onUnauthorized;
|
|
485
|
+
const inFlight = (async () => {
|
|
486
|
+
try {
|
|
487
|
+
return await withTimeout(call(), this.timeout, "onUnauthorized");
|
|
488
|
+
} catch {
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
})().finally(() => {
|
|
492
|
+
if (this.unauthorizedInFlight === inFlight) this.unauthorizedInFlight = void 0;
|
|
493
|
+
});
|
|
494
|
+
this.unauthorizedInFlight = inFlight;
|
|
495
|
+
}
|
|
496
|
+
return this.unauthorizedInFlight;
|
|
497
|
+
}
|
|
376
498
|
buildUrl(path, params) {
|
|
377
499
|
const url = new URL(`${this.baseUrl}${path}`);
|
|
378
500
|
if (params) {
|
|
@@ -400,7 +522,8 @@ var HttpClient = class {
|
|
|
400
522
|
body = await response.json();
|
|
401
523
|
} catch {
|
|
402
524
|
}
|
|
403
|
-
const
|
|
525
|
+
const envelope = body["error"];
|
|
526
|
+
const message = (typeof body["message"] === "string" ? body["message"] : void 0) ?? (typeof envelope?.message === "string" ? envelope.message : void 0) ?? response.statusText ?? "Request failed";
|
|
404
527
|
switch (response.status) {
|
|
405
528
|
case 400: {
|
|
406
529
|
const fieldErrors = body["errors"] ?? [];
|
|
@@ -423,231 +546,2483 @@ var HttpClient = class {
|
|
|
423
546
|
return new PlanesError(message, response.status, "unknown_error");
|
|
424
547
|
}
|
|
425
548
|
}
|
|
426
|
-
sleep(ms) {
|
|
427
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
549
|
+
sleep(ms) {
|
|
550
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
function timeoutSignal(ms) {
|
|
554
|
+
if (typeof AbortSignal.timeout === "function") {
|
|
555
|
+
return { signal: AbortSignal.timeout(ms), clear: () => void 0 };
|
|
556
|
+
}
|
|
557
|
+
const controller = new AbortController();
|
|
558
|
+
const timer = setTimeout(() => controller.abort(), ms);
|
|
559
|
+
return { signal: controller.signal, clear: () => clearTimeout(timer) };
|
|
560
|
+
}
|
|
561
|
+
function withTimeout(promise, ms, what) {
|
|
562
|
+
return new Promise((resolve, reject) => {
|
|
563
|
+
const timer = setTimeout(() => reject(new Error(`${what} did not settle within ${ms}ms`)), ms);
|
|
564
|
+
Promise.resolve(promise).then(
|
|
565
|
+
(value) => {
|
|
566
|
+
clearTimeout(timer);
|
|
567
|
+
resolve(value);
|
|
568
|
+
},
|
|
569
|
+
(err) => {
|
|
570
|
+
clearTimeout(timer);
|
|
571
|
+
reject(err);
|
|
572
|
+
}
|
|
573
|
+
);
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// src/resources/base-resource.ts
|
|
578
|
+
var ApiResource = class {
|
|
579
|
+
constructor(http2, basePath) {
|
|
580
|
+
this.http = http2;
|
|
581
|
+
this.basePath = basePath;
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
var BaseResource = class extends ApiResource {
|
|
585
|
+
/**
|
|
586
|
+
* List entities with optional filters and pagination.
|
|
587
|
+
*/
|
|
588
|
+
async list(params) {
|
|
589
|
+
return this.http.request({
|
|
590
|
+
method: "GET",
|
|
591
|
+
path: this.basePath,
|
|
592
|
+
params
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Get a single entity by ID.
|
|
597
|
+
*/
|
|
598
|
+
async get(id) {
|
|
599
|
+
return this.http.request({
|
|
600
|
+
method: "GET",
|
|
601
|
+
path: `${this.basePath}/${id}`
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Create a new entity. Pass `idempotencyKey` (a UUID you keep for retries) to
|
|
606
|
+
* make a retry safe on routes that honor it (customers, opportunities, contacts,
|
|
607
|
+
* tasks): a repeat returns the first response and creates nothing.
|
|
608
|
+
*/
|
|
609
|
+
async create(data, options) {
|
|
610
|
+
return this.http.request({
|
|
611
|
+
method: "POST",
|
|
612
|
+
path: this.basePath,
|
|
613
|
+
body: data,
|
|
614
|
+
...options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {}
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Update an existing entity.
|
|
619
|
+
*/
|
|
620
|
+
async update(id, data) {
|
|
621
|
+
return this.http.request({
|
|
622
|
+
method: "PATCH",
|
|
623
|
+
path: `${this.basePath}/${id}`,
|
|
624
|
+
body: data
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Delete an entity by ID.
|
|
629
|
+
*/
|
|
630
|
+
async delete(id) {
|
|
631
|
+
await this.http.request({
|
|
632
|
+
method: "DELETE",
|
|
633
|
+
path: `${this.basePath}/${id}`
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
// src/resources/query-params.ts
|
|
639
|
+
function toQueryParams(params) {
|
|
640
|
+
const out = {};
|
|
641
|
+
if (!params) return out;
|
|
642
|
+
for (const [key, value] of Object.entries(params)) {
|
|
643
|
+
if (value === void 0 || value === null) continue;
|
|
644
|
+
if (key === "customFields" && typeof value === "object" && !Array.isArray(value)) {
|
|
645
|
+
for (const [field, v] of Object.entries(value)) {
|
|
646
|
+
if (v !== void 0 && v !== null) out[`cf.${field}`] = String(v);
|
|
647
|
+
}
|
|
648
|
+
continue;
|
|
649
|
+
}
|
|
650
|
+
if (Array.isArray(value)) {
|
|
651
|
+
if (value.length === 0) continue;
|
|
652
|
+
out[key] = value.map(String).join(",");
|
|
653
|
+
} else {
|
|
654
|
+
out[key] = value;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
return out;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// src/resources/opportunities.ts
|
|
661
|
+
var OpportunityResource = class extends BaseResource {
|
|
662
|
+
constructor(http2) {
|
|
663
|
+
super(http2, "/opportunities");
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* List opportunities. `tag_ids` is ANY-of and travels as one comma-separated
|
|
667
|
+
* query value (`?tag_ids=a,b`), which is what the API's filter schema parses.
|
|
668
|
+
*/
|
|
669
|
+
async list(params) {
|
|
670
|
+
return this.http.request({
|
|
671
|
+
method: "GET",
|
|
672
|
+
path: this.basePath,
|
|
673
|
+
params: toQueryParams(params)
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* GET /opportunities/trade-options — the active trades a client can request
|
|
678
|
+
* (`requestedTradeIds` on create/update), sorted by name.
|
|
679
|
+
*/
|
|
680
|
+
async tradeOptions() {
|
|
681
|
+
return this.http.request({
|
|
682
|
+
method: "GET",
|
|
683
|
+
path: `${this.basePath}/trade-options`
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
/** PUT /opportunities/{id} — partial update; stage moves go through workflow transitions. */
|
|
687
|
+
async update(id, data) {
|
|
688
|
+
return this.http.request({
|
|
689
|
+
method: "PUT",
|
|
690
|
+
path: `${this.basePath}/${id}`,
|
|
691
|
+
body: data
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
/** GET /opportunities/:id/transitions — the pipeline moves available from the current stage, for the caller's role. */
|
|
695
|
+
async listTransitions(id) {
|
|
696
|
+
return this.http.request({ method: "GET", path: `${this.basePath}/${id}/transitions` });
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* POST /opportunities/:id/transition — take one pipeline move, as the stage button does: required
|
|
700
|
+
* fields are checked, the move is logged, and the stage's automations run (they can send email).
|
|
701
|
+
*/
|
|
702
|
+
async transition(id, data) {
|
|
703
|
+
return this.http.request({ method: "POST", path: `${this.basePath}/${id}/transition`, body: data });
|
|
704
|
+
}
|
|
705
|
+
/** GET /opportunities/:id/workflow — the pipeline instance with its transition history (404 if none). */
|
|
706
|
+
async getWorkflow(id) {
|
|
707
|
+
return this.http.request({ method: "GET", path: `${this.basePath}/${id}/workflow` });
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
|
|
711
|
+
// src/resources/customers.ts
|
|
712
|
+
var CustomerResource = class extends BaseResource {
|
|
713
|
+
constructor(http2) {
|
|
714
|
+
super(http2, "/customers");
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* Update a customer. The API route is `PUT /customers/{id}` (not PATCH like
|
|
718
|
+
* the other resources), so this overrides the base verb; the body is still a
|
|
719
|
+
* partial — send only the fields to change. See `UpdateCustomerDto.address`
|
|
720
|
+
* for how a service address resolves to a property.
|
|
721
|
+
*/
|
|
722
|
+
async update(id, data) {
|
|
723
|
+
return this.http.request({
|
|
724
|
+
method: "PUT",
|
|
725
|
+
path: `/customers/${id}`,
|
|
726
|
+
body: data
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* List customers. `tag_ids` is ANY-of and travels as one comma-separated
|
|
731
|
+
* query value (`?tag_ids=a,b`), which is what the API's filter schema parses.
|
|
732
|
+
*/
|
|
733
|
+
async list(params) {
|
|
734
|
+
return this.http.request({
|
|
735
|
+
method: "GET",
|
|
736
|
+
path: this.basePath,
|
|
737
|
+
params: toQueryParams(params)
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Fold a duplicate company (`loserId`) into a survivor (`winnerId`).
|
|
742
|
+
*
|
|
743
|
+
* Everything hanging off the loser moves to the winner, the winner's empty
|
|
744
|
+
* fields are filled from the loser, and the loser is soft-deleted with a
|
|
745
|
+
* resolvable pointer — `GET /customers/{loserId}` afterwards returns the
|
|
746
|
+
* winner's detail with a `mergedFrom` pointer, so a stored loser id keeps
|
|
747
|
+
* working. Irreversible; requires admin scope.
|
|
748
|
+
*/
|
|
749
|
+
async merge(winnerId, loserId) {
|
|
750
|
+
return this.http.request({
|
|
751
|
+
method: "POST",
|
|
752
|
+
path: `/customers/${winnerId}/merge/${loserId}`
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* POST /customers/{id}/convert-to-company — turn a person customer into a
|
|
757
|
+
* company. The person becomes the company's primary contact (their email and
|
|
758
|
+
* phone, with do-not-contact and marketing opt-outs carried over). A customer
|
|
759
|
+
* that's already a company is a 409 `ALREADY_COMPANY`.
|
|
760
|
+
*/
|
|
761
|
+
async convertToCompany(id, data = {}) {
|
|
762
|
+
return this.http.request({
|
|
763
|
+
method: "POST",
|
|
764
|
+
path: `${this.basePath}/${id}/convert-to-company`,
|
|
765
|
+
body: data
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
|
|
770
|
+
// src/resources/properties.ts
|
|
771
|
+
var PropertyResource = class extends ApiResource {
|
|
772
|
+
constructor(http2) {
|
|
773
|
+
super(http2, "/properties");
|
|
774
|
+
}
|
|
775
|
+
/** GET /customers/{customerId}/properties — paginated (`page`, `limit` ≤ 100). */
|
|
776
|
+
async list(customerId, params) {
|
|
777
|
+
return this.http.request({
|
|
778
|
+
method: "GET",
|
|
779
|
+
path: `/customers/${customerId}/properties`,
|
|
780
|
+
params: toQueryParams(params)
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
/** GET /properties/{id} — one property, without naming its customer. */
|
|
784
|
+
async get(id) {
|
|
785
|
+
return this.http.request({
|
|
786
|
+
method: "GET",
|
|
787
|
+
path: `${this.basePath}/${id}`
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
/** POST /customers/{customerId}/properties — the property inherits the customer's org path. */
|
|
791
|
+
async create(customerId, data) {
|
|
792
|
+
return this.http.request({
|
|
793
|
+
method: "POST",
|
|
794
|
+
path: `/customers/${customerId}/properties`,
|
|
795
|
+
body: data
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
/** PUT /customers/{customerId}/properties/{id} — partial update. */
|
|
799
|
+
async update(customerId, id, data) {
|
|
800
|
+
return this.http.request({
|
|
801
|
+
method: "PUT",
|
|
802
|
+
path: `/customers/${customerId}/properties/${id}`,
|
|
803
|
+
body: data
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
/** GET /customers/:customerId/properties/:id — one property, checked against its customer (404 if it isn't theirs). */
|
|
807
|
+
async getForCustomer(customerId, id) {
|
|
808
|
+
return this.http.request({
|
|
809
|
+
method: "GET",
|
|
810
|
+
path: `/customers/${customerId}/properties/${id}`
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
/** POST /properties/:id/geocode — queue a fresh geocode of the property's address. */
|
|
814
|
+
async geocode(id) {
|
|
815
|
+
return this.http.request({ method: "POST", path: `${this.basePath}/${id}/geocode` });
|
|
816
|
+
}
|
|
817
|
+
/** DELETE /customers/{customerId}/properties/{id} — soft delete (204). */
|
|
818
|
+
async delete(customerId, id) {
|
|
819
|
+
await this.http.request({
|
|
820
|
+
method: "DELETE",
|
|
821
|
+
path: `/customers/${customerId}/properties/${id}`
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
};
|
|
825
|
+
|
|
826
|
+
// src/resources/calendar-events.ts
|
|
827
|
+
var CalendarEventResource = class extends BaseResource {
|
|
828
|
+
constructor(http2) {
|
|
829
|
+
super(http2, "/events");
|
|
830
|
+
}
|
|
831
|
+
async list(params) {
|
|
832
|
+
return this.http.request({
|
|
833
|
+
method: "GET",
|
|
834
|
+
path: this.basePath,
|
|
835
|
+
params: params ?? {}
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* PATCH /events/:id. For an occurrence of a recurring event, `editMode`
|
|
840
|
+
* picks which occurrences change (`this` when omitted — the server's
|
|
841
|
+
* default); it is ignored for one-time events.
|
|
842
|
+
*/
|
|
843
|
+
async update(id, data, options = {}) {
|
|
844
|
+
return this.http.request({
|
|
845
|
+
method: "PATCH",
|
|
846
|
+
path: `${this.basePath}/${id}`,
|
|
847
|
+
params: { recurrence_edit_mode: options.editMode },
|
|
848
|
+
body: data
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* POST /events/:id/complete — marks the event completed and runs its "on
|
|
853
|
+
* complete" transition, best-effort. The event is completed even when the
|
|
854
|
+
* transition can't run; `workflow_trigger` says whether it fired, was
|
|
855
|
+
* skipped (none set, or `handled_by_pipeline_rule`: the pipeline's rule
|
|
856
|
+
* moves the record instead) or failed (with a reason).
|
|
857
|
+
*/
|
|
858
|
+
async complete(id, body = {}) {
|
|
859
|
+
return this.http.request({
|
|
860
|
+
method: "POST",
|
|
861
|
+
path: `${this.basePath}/${id}/complete`,
|
|
862
|
+
body
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* POST /events/:id/cancel. For an occurrence of a recurring event, `editMode`
|
|
867
|
+
* picks which occurrences are cancelled (`this` when omitted). 409 if already
|
|
868
|
+
* cancelled; 422 for a completed event.
|
|
869
|
+
*/
|
|
870
|
+
async cancel(id, options = {}) {
|
|
871
|
+
return this.http.request({
|
|
872
|
+
method: "POST",
|
|
873
|
+
path: `${this.basePath}/${id}/cancel`,
|
|
874
|
+
params: { recurrence_edit_mode: options.editMode }
|
|
875
|
+
});
|
|
876
|
+
}
|
|
877
|
+
/** POST /events/:id/participants — add a user, contact, crew or agent to the event. No invite is sent. */
|
|
878
|
+
async addParticipant(id, data) {
|
|
879
|
+
return this.http.request({
|
|
880
|
+
method: "POST",
|
|
881
|
+
path: `${this.basePath}/${id}/participants`,
|
|
882
|
+
body: data
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
/** PATCH /events/:id/participants/:participantId — set a participant's response. */
|
|
886
|
+
async updateParticipantStatus(id, participantId, status) {
|
|
887
|
+
return this.http.request({
|
|
888
|
+
method: "PATCH",
|
|
889
|
+
path: `${this.basePath}/${id}/participants/${participantId}`,
|
|
890
|
+
body: { status }
|
|
891
|
+
});
|
|
892
|
+
}
|
|
893
|
+
};
|
|
894
|
+
|
|
895
|
+
// src/resources/contracts.ts
|
|
896
|
+
var ContractResource = class extends BaseResource {
|
|
897
|
+
constructor(http2) {
|
|
898
|
+
super(http2, "/contracts");
|
|
899
|
+
}
|
|
900
|
+
/** POST /contracts/for-subject — a bare agreement for a customer or a service schedule (no opportunity, no line groups). */
|
|
901
|
+
async createForSubject(data) {
|
|
902
|
+
return this.http.request({ method: "POST", path: `${this.basePath}/for-subject`, body: data });
|
|
903
|
+
}
|
|
904
|
+
/** POST /contracts/flat — a contract on an opportunity with a manually entered total and a contract template, no estimates. */
|
|
905
|
+
async createFlat(data) {
|
|
906
|
+
return this.http.request({ method: "POST", path: `${this.basePath}/flat`, body: data });
|
|
907
|
+
}
|
|
908
|
+
/** POST /contracts/{id}/change-orders — a change order on a signed or fulfilled contract (409 otherwise). */
|
|
909
|
+
async createChangeOrder(id, data) {
|
|
910
|
+
return this.http.request({
|
|
911
|
+
method: "POST",
|
|
912
|
+
path: `${this.basePath}/${id}/change-orders`,
|
|
913
|
+
body: data
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* GET /contracts/{id}/change-orders — the change orders written against a
|
|
918
|
+
* contract, oldest first, each with its line groups. A change order has none
|
|
919
|
+
* of its own, so asking for one returns an empty list.
|
|
920
|
+
*/
|
|
921
|
+
async listChangeOrders(id) {
|
|
922
|
+
return this.http.request({
|
|
923
|
+
method: "GET",
|
|
924
|
+
path: `${this.basePath}/${id}/change-orders`
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
/** POST /contracts/{id}/submit — submit for approval; auto-approved when under the tenant's threshold. */
|
|
928
|
+
async submit(id) {
|
|
929
|
+
return this.http.request({ method: "POST", path: `${this.basePath}/${id}/submit` });
|
|
930
|
+
}
|
|
931
|
+
/** POST /contracts/{id}/approve — approve a contract pending approval (needs the approve grant). */
|
|
932
|
+
async approve(id) {
|
|
933
|
+
return this.http.request({ method: "POST", path: `${this.basePath}/${id}/approve` });
|
|
934
|
+
}
|
|
935
|
+
/** POST /contracts/{id}/cancel — cancel a contract in any state before it's signed. */
|
|
936
|
+
async cancel(id) {
|
|
937
|
+
return this.http.request({ method: "POST", path: `${this.basePath}/${id}/cancel` });
|
|
938
|
+
}
|
|
939
|
+
/** POST /contracts/{id}/reopen — return a kicked-back contract to draft for review and re-send. */
|
|
940
|
+
async reopen(id) {
|
|
941
|
+
return this.http.request({ method: "POST", path: `${this.basePath}/${id}/reopen` });
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* POST /contracts/{id}/send — **emails the signer a "Review & Sign" link.**
|
|
945
|
+
* Snapshots the clauses and creates the signing token. An empty body
|
|
946
|
+
* addresses the customer; `signerContactId` sends it to that contact instead.
|
|
947
|
+
* The first send of a contract uses one unit of the tenant's e-signature
|
|
948
|
+
* allowance; a re-send doesn't. Not safe to retry blindly after a timeout: a
|
|
949
|
+
* repeat emails again.
|
|
950
|
+
*/
|
|
951
|
+
async send(id, data = {}) {
|
|
952
|
+
return this.http.request({ method: "POST", path: `${this.basePath}/${id}/send`, body: data });
|
|
953
|
+
}
|
|
954
|
+
/**
|
|
955
|
+
* GET /contracts/{id}/pdf — the contract PDF bytes. `type: 'signed'` returns
|
|
956
|
+
* the stored signed copy (404 until it's signed); otherwise a preview renders.
|
|
957
|
+
*/
|
|
958
|
+
async downloadPdf(id, options = {}) {
|
|
959
|
+
return this.http.request({
|
|
960
|
+
method: "GET",
|
|
961
|
+
path: `${this.basePath}/${id}/pdf`,
|
|
962
|
+
params: options.type ? { type: options.type } : {},
|
|
963
|
+
headers: { Accept: "application/pdf" },
|
|
964
|
+
responseType: "arrayBuffer"
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
};
|
|
968
|
+
|
|
969
|
+
// src/resources/jobs.ts
|
|
970
|
+
var JobResource = class extends ApiResource {
|
|
971
|
+
constructor(http2) {
|
|
972
|
+
super(http2, "/jobs");
|
|
973
|
+
}
|
|
974
|
+
/** The jobs under one opportunity — the same route as `listForOpportunity()`. */
|
|
975
|
+
async list(opportunityId, params) {
|
|
976
|
+
return this.listForOpportunity(opportunityId, params);
|
|
977
|
+
}
|
|
978
|
+
/**
|
|
979
|
+
* List the jobs under one opportunity — `GET /opportunities/{opportunityId}/jobs`,
|
|
980
|
+
* the API's job list route. Default order is `created_at` desc;
|
|
981
|
+
* `sort_by: 'recent'` puts the calling user's most recently opened jobs first.
|
|
982
|
+
*/
|
|
983
|
+
async listForOpportunity(opportunityId, params) {
|
|
984
|
+
return this.http.request({
|
|
985
|
+
method: "GET",
|
|
986
|
+
path: `/opportunities/${opportunityId}/jobs`,
|
|
987
|
+
params: toQueryParams(params)
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
/** GET /opportunities/{opportunityId}/jobs/{id} */
|
|
991
|
+
async get(opportunityId, id) {
|
|
992
|
+
return this.http.request({
|
|
993
|
+
method: "GET",
|
|
994
|
+
path: `/opportunities/${opportunityId}/jobs/${id}`
|
|
995
|
+
});
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* POST /opportunities/{opportunityId}/jobs — 422 WORKFLOW_NOT_CONFIGURED when
|
|
999
|
+
* the trade has no published job workflow (check `getTradeCoverage()` first).
|
|
1000
|
+
*/
|
|
1001
|
+
async create(opportunityId, data) {
|
|
1002
|
+
return this.http.request({
|
|
1003
|
+
method: "POST",
|
|
1004
|
+
path: `/opportunities/${opportunityId}/jobs`,
|
|
1005
|
+
body: data
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
/** PUT /opportunities/{opportunityId}/jobs/{id} — partial update (status, notes). */
|
|
1009
|
+
async update(opportunityId, id, data) {
|
|
1010
|
+
return this.http.request({
|
|
1011
|
+
method: "PUT",
|
|
1012
|
+
path: `/opportunities/${opportunityId}/jobs/${id}`,
|
|
1013
|
+
body: data
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
1016
|
+
/** DELETE /opportunities/{opportunityId}/jobs/{id} — soft delete (204). */
|
|
1017
|
+
async delete(opportunityId, id) {
|
|
1018
|
+
await this.http.request({
|
|
1019
|
+
method: "DELETE",
|
|
1020
|
+
path: `/opportunities/${opportunityId}/jobs/${id}`
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* GET /jobs/trade-coverage — every active trade with whether a job can be
|
|
1025
|
+
* created under it (a published job workflow resolves: the trade's own or the
|
|
1026
|
+
* generic one). Check before creating a job to avoid a 422
|
|
1027
|
+
* WORKFLOW_NOT_CONFIGURED. Readable by any role that can create jobs (403
|
|
1028
|
+
* otherwise); carries no workflow details.
|
|
1029
|
+
*/
|
|
1030
|
+
async getTradeCoverage() {
|
|
1031
|
+
return this.http.request({
|
|
1032
|
+
method: "GET",
|
|
1033
|
+
path: "/jobs/trade-coverage"
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
/** GET /jobs/{id}/workflow — the job's pipeline instance with its transition history (404 if none). */
|
|
1037
|
+
async getWorkflow(id) {
|
|
1038
|
+
return this.http.request({ method: "GET", path: `${this.basePath}/${id}/workflow` });
|
|
1039
|
+
}
|
|
1040
|
+
/**
|
|
1041
|
+
* POST /jobs/{id}/transition — take one pipeline move, as the stage button
|
|
1042
|
+
* does: required fields are checked, the move is logged, and **the
|
|
1043
|
+
* transition's actions run**. A tenant can attach actions that create or send
|
|
1044
|
+
* an invoice, charge a saved card, send a contract, or send email, SMS or a
|
|
1045
|
+
* webhook. Not safe to retry blindly after a timeout: check `getWorkflow()`
|
|
1046
|
+
* first, because a repeat runs the actions again.
|
|
1047
|
+
*/
|
|
1048
|
+
async transition(id, data) {
|
|
1049
|
+
return this.http.request({ method: "POST", path: `${this.basePath}/${id}/transition`, body: data });
|
|
1050
|
+
}
|
|
1051
|
+
/** GET /jobs/{id}/transitions — the pipeline moves available from the job's current stage, for the caller's role. */
|
|
1052
|
+
async listTransitions(id) {
|
|
1053
|
+
return this.http.request({
|
|
1054
|
+
method: "GET",
|
|
1055
|
+
path: `${this.basePath}/${id}/transitions`
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1058
|
+
};
|
|
1059
|
+
|
|
1060
|
+
// src/resources/estimates.ts
|
|
1061
|
+
var EstimateResource = class extends ApiResource {
|
|
1062
|
+
constructor(http2) {
|
|
1063
|
+
super(http2, "/estimates");
|
|
1064
|
+
}
|
|
1065
|
+
/** GET /jobs/{jobId}/estimates — newest first, paginated (`page`, `limit` ≤ 100). */
|
|
1066
|
+
async list(jobId, params) {
|
|
1067
|
+
return this.http.request({
|
|
1068
|
+
method: "GET",
|
|
1069
|
+
path: `/jobs/${jobId}/estimates`,
|
|
1070
|
+
params: toQueryParams(params)
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Every estimate across all of one opportunity's jobs, in one request —
|
|
1075
|
+
* `GET /opportunities/{opportunityId}/estimates`. Newest first; each row
|
|
1076
|
+
* carries its `jobId`. Paginated with `page` / `limit` (max 100).
|
|
1077
|
+
*/
|
|
1078
|
+
async listForOpportunity(opportunityId, params) {
|
|
1079
|
+
return this.http.request({
|
|
1080
|
+
method: "GET",
|
|
1081
|
+
path: `/opportunities/${opportunityId}/estimates`,
|
|
1082
|
+
params: toQueryParams(params)
|
|
1083
|
+
});
|
|
1084
|
+
}
|
|
1085
|
+
/** GET /jobs/{jobId}/estimates/{id} — the estimate with its line items. */
|
|
1086
|
+
async get(jobId, id) {
|
|
1087
|
+
return this.http.request({
|
|
1088
|
+
method: "GET",
|
|
1089
|
+
path: `/jobs/${jobId}/estimates/${id}`
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1092
|
+
/** POST /jobs/{jobId}/estimates — optionally cloned from an estimate template. */
|
|
1093
|
+
async create(jobId, data) {
|
|
1094
|
+
return this.http.request({
|
|
1095
|
+
method: "POST",
|
|
1096
|
+
path: `/jobs/${jobId}/estimates`,
|
|
1097
|
+
body: data
|
|
1098
|
+
});
|
|
1099
|
+
}
|
|
1100
|
+
/** PUT /jobs/{jobId}/estimates/{id} — partial update (measurements, notes, discount, tax). */
|
|
1101
|
+
async update(jobId, id, data) {
|
|
1102
|
+
return this.http.request({
|
|
1103
|
+
method: "PUT",
|
|
1104
|
+
path: `/jobs/${jobId}/estimates/${id}`,
|
|
1105
|
+
body: data
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1108
|
+
/** DELETE /jobs/{jobId}/estimates/{id} — soft delete (204). */
|
|
1109
|
+
async delete(jobId, id) {
|
|
1110
|
+
await this.http.request({
|
|
1111
|
+
method: "DELETE",
|
|
1112
|
+
path: `/jobs/${jobId}/estimates/${id}`
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
/** GET /estimates/{id}/workflow — the estimate's pipeline instance with its transition history (404 if none). */
|
|
1116
|
+
async getWorkflow(id) {
|
|
1117
|
+
return this.http.request({ method: "GET", path: `${this.basePath}/${id}/workflow` });
|
|
1118
|
+
}
|
|
1119
|
+
/**
|
|
1120
|
+
* POST /estimates/{id}/transition — take one pipeline move. **The
|
|
1121
|
+
* transition's actions run**, as for `jobs.transition()`: a tenant can attach
|
|
1122
|
+
* actions that bill, charge, send a contract, or send email, SMS or a webhook.
|
|
1123
|
+
* Not safe to retry blindly after a timeout: check `getWorkflow()` first.
|
|
1124
|
+
*/
|
|
1125
|
+
async transition(id, data) {
|
|
1126
|
+
return this.http.request({ method: "POST", path: `${this.basePath}/${id}/transition`, body: data });
|
|
1127
|
+
}
|
|
1128
|
+
/**
|
|
1129
|
+
* PUT /jobs/{jobId}/estimates/{id}/status — move the estimate's status (see
|
|
1130
|
+
* `UpdateEstimateStatusDto` for the allowed moves). The route itself sends
|
|
1131
|
+
* nothing and creates no contract or invoice; a tenant's webhooks or
|
|
1132
|
+
* automations on the status change can.
|
|
1133
|
+
*/
|
|
1134
|
+
async updateStatus(jobId, id, data) {
|
|
1135
|
+
return this.http.request({
|
|
1136
|
+
method: "PUT",
|
|
1137
|
+
path: `/jobs/${jobId}/estimates/${id}/status`,
|
|
1138
|
+
body: data
|
|
1139
|
+
});
|
|
1140
|
+
}
|
|
1141
|
+
/** GET /estimates/{id}/transitions — the pipeline moves available from the estimate's current stage, for the caller's role. */
|
|
1142
|
+
async listTransitions(id) {
|
|
1143
|
+
return this.http.request({
|
|
1144
|
+
method: "GET",
|
|
1145
|
+
path: `${this.basePath}/${id}/transitions`
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
/**
|
|
1149
|
+
* POST /jobs/{jobId}/estimates/{estimateId}/line-items — add a line item. With
|
|
1150
|
+
* `materialCatalogId` or `tradeLaborItemId`, the catalog fills in description,
|
|
1151
|
+
* unit and price. The estimate's subtotal and total are recalculated.
|
|
1152
|
+
*/
|
|
1153
|
+
async createLineItem(jobId, estimateId, data) {
|
|
1154
|
+
return this.http.request({
|
|
1155
|
+
method: "POST",
|
|
1156
|
+
path: `/jobs/${jobId}/estimates/${estimateId}/line-items`,
|
|
1157
|
+
body: data
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
/** PUT /jobs/{jobId}/estimates/{estimateId}/line-items/{id} — partial update; totals are recalculated. */
|
|
1161
|
+
async updateLineItem(jobId, estimateId, id, data) {
|
|
1162
|
+
return this.http.request({
|
|
1163
|
+
method: "PUT",
|
|
1164
|
+
path: `/jobs/${jobId}/estimates/${estimateId}/line-items/${id}`,
|
|
1165
|
+
body: data
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
/** DELETE /jobs/{jobId}/estimates/{estimateId}/line-items/{id} — totals are recalculated. */
|
|
1169
|
+
async deleteLineItem(jobId, estimateId, id) {
|
|
1170
|
+
await this.http.request({
|
|
1171
|
+
method: "DELETE",
|
|
1172
|
+
path: `/jobs/${jobId}/estimates/${estimateId}/line-items/${id}`
|
|
1173
|
+
});
|
|
1174
|
+
}
|
|
1175
|
+
/** PUT /jobs/{jobId}/estimates/{estimateId}/line-items/reorder — set each item's `sortOrder` (and optionally `section`) in one call. */
|
|
1176
|
+
async reorderLineItems(jobId, estimateId, data) {
|
|
1177
|
+
return this.http.request({
|
|
1178
|
+
method: "PUT",
|
|
1179
|
+
path: `/jobs/${jobId}/estimates/${estimateId}/line-items/reorder`,
|
|
1180
|
+
body: data
|
|
1181
|
+
});
|
|
1182
|
+
}
|
|
1183
|
+
};
|
|
1184
|
+
|
|
1185
|
+
// src/resources/invoices.ts
|
|
1186
|
+
var InvoiceResource = class extends BaseResource {
|
|
1187
|
+
constructor(http2) {
|
|
1188
|
+
super(http2, "/admin/invoices");
|
|
1189
|
+
}
|
|
1190
|
+
/** List invoices, newest first. Each row carries the customer's `customerName`. */
|
|
1191
|
+
async list(params) {
|
|
1192
|
+
return this.http.request({
|
|
1193
|
+
method: "GET",
|
|
1194
|
+
path: this.basePath,
|
|
1195
|
+
params
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1198
|
+
/**
|
|
1199
|
+
* GET /admin/invoices/:id — the invoice with its line items, payments
|
|
1200
|
+
* (including any `needs_review` payment) and `payLink` state.
|
|
1201
|
+
*/
|
|
1202
|
+
async get(id) {
|
|
1203
|
+
return this.http.request({
|
|
1204
|
+
method: "GET",
|
|
1205
|
+
path: `${this.basePath}/${id}`
|
|
1206
|
+
});
|
|
1207
|
+
}
|
|
1208
|
+
/**
|
|
1209
|
+
* POST /admin/invoices/:id/pay-link — issue a fresh durable pay link for a
|
|
1210
|
+
* `sent` or `partially_paid` invoice (Send Invoice grant) and return its URL,
|
|
1211
|
+
* e.g. to share by text. Rotates: the previously emailed link stops working.
|
|
1212
|
+
* Any other status → 409 `INVOICE_NOT_PAYABLE`.
|
|
1213
|
+
*/
|
|
1214
|
+
async createPayLink(id) {
|
|
1215
|
+
return this.http.request({
|
|
1216
|
+
method: "POST",
|
|
1217
|
+
path: `${this.basePath}/${id}/pay-link`
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1220
|
+
/**
|
|
1221
|
+
* GET /admin/invoices/:id/pdf — the invoice PDF bytes (Read Invoice grant).
|
|
1222
|
+
* A sent invoice returns the copy stored when it was sent; a draft renders on
|
|
1223
|
+
* demand with a DRAFT watermark.
|
|
1224
|
+
*/
|
|
1225
|
+
async downloadPdf(id) {
|
|
1226
|
+
return this.http.request({
|
|
1227
|
+
method: "GET",
|
|
1228
|
+
path: `${this.basePath}/${id}/pdf`,
|
|
1229
|
+
headers: { Accept: "application/pdf" },
|
|
1230
|
+
responseType: "arrayBuffer"
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1233
|
+
/**
|
|
1234
|
+
* GET /admin/invoices/overdue — sent / partially paid invoices with a balance
|
|
1235
|
+
* past their due date, most overdue first, each with `daysOverdue` and the
|
|
1236
|
+
* last overdue offset reached (E56-F8-S2). Read Invoice.
|
|
1237
|
+
*/
|
|
1238
|
+
async listOverdue(params) {
|
|
1239
|
+
return this.http.request({
|
|
1240
|
+
method: "GET",
|
|
1241
|
+
path: `${this.basePath}/overdue`,
|
|
1242
|
+
params
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
/** GET /admin/invoices/{invoiceId}/payments — every payment recorded against the invoice (Read Payment). */
|
|
1246
|
+
async listPayments(invoiceId) {
|
|
1247
|
+
return this.http.request({
|
|
1248
|
+
method: "GET",
|
|
1249
|
+
path: `${this.basePath}/${invoiceId}/payments`
|
|
1250
|
+
});
|
|
1251
|
+
}
|
|
1252
|
+
/**
|
|
1253
|
+
* GET /admin/payments/recording-settings — the tenant's resolved
|
|
1254
|
+
* payment-recording settings (whether manual recording is on, and which
|
|
1255
|
+
* methods). Read Invoice.
|
|
1256
|
+
*/
|
|
1257
|
+
async getPaymentRecordingSettings() {
|
|
1258
|
+
return this.http.request({
|
|
1259
|
+
method: "GET",
|
|
1260
|
+
path: "/admin/payments/recording-settings"
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
/** GET /admin/invoices/overdue/summary — `{ count, total }` of every overdue invoice. Read Invoice. */
|
|
1264
|
+
async overdueSummary() {
|
|
1265
|
+
return this.http.request({
|
|
1266
|
+
method: "GET",
|
|
1267
|
+
path: `${this.basePath}/overdue/summary`
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
};
|
|
1271
|
+
|
|
1272
|
+
// src/resources/inventory.ts
|
|
1273
|
+
var InventoryResource = class extends BaseResource {
|
|
1274
|
+
constructor(http2) {
|
|
1275
|
+
super(http2, "/admin/inventory/items");
|
|
1276
|
+
}
|
|
1277
|
+
async list(params) {
|
|
1278
|
+
return this.http.request({
|
|
1279
|
+
method: "GET",
|
|
1280
|
+
path: this.basePath,
|
|
1281
|
+
params: toQueryParams(params)
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
/** PUT /admin/inventory/items/{id} — partial update. */
|
|
1285
|
+
async update(id, data) {
|
|
1286
|
+
return this.http.request({
|
|
1287
|
+
method: "PUT",
|
|
1288
|
+
path: `${this.basePath}/${id}`,
|
|
1289
|
+
body: data
|
|
1290
|
+
});
|
|
1291
|
+
}
|
|
1292
|
+
// ---- Material used on a job (E64-S9). The routes live under /jobs/{jobId}. ----
|
|
1293
|
+
/**
|
|
1294
|
+
* POST /jobs/{jobId}/consumption — record stock drawn from a location for a
|
|
1295
|
+
* job. Each line lowers that location's on-hand quantity.
|
|
1296
|
+
*/
|
|
1297
|
+
async recordJobConsumption(jobId, data) {
|
|
1298
|
+
return this.http.request({
|
|
1299
|
+
method: "POST",
|
|
1300
|
+
path: `/jobs/${jobId}/consumption`,
|
|
1301
|
+
body: data
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1304
|
+
/**
|
|
1305
|
+
* GET /jobs/{jobId}/consumption — one page of the job's consume and return
|
|
1306
|
+
* movements (newest first by default), the job's totals across every page,
|
|
1307
|
+
* and page metadata. The rows are under `items`, not `data`.
|
|
1308
|
+
*/
|
|
1309
|
+
async listJobConsumption(jobId, params) {
|
|
1310
|
+
return this.http.request({
|
|
1311
|
+
method: "GET",
|
|
1312
|
+
path: `/jobs/${jobId}/consumption`,
|
|
1313
|
+
params: toQueryParams(params)
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1316
|
+
/** POST /jobs/{jobId}/return — put unused stock from a job back into a location. */
|
|
1317
|
+
async returnFromJob(jobId, data) {
|
|
1318
|
+
return this.http.request({
|
|
1319
|
+
method: "POST",
|
|
1320
|
+
path: `/jobs/${jobId}/return`,
|
|
1321
|
+
body: data
|
|
1322
|
+
});
|
|
1323
|
+
}
|
|
1324
|
+
/** GET /jobs/{jobId}/material-variance — estimated vs actual material for the job. */
|
|
1325
|
+
async getJobMaterialVariance(jobId) {
|
|
1326
|
+
return this.http.request({
|
|
1327
|
+
method: "GET",
|
|
1328
|
+
path: `/jobs/${jobId}/material-variance`
|
|
1329
|
+
});
|
|
1330
|
+
}
|
|
1331
|
+
};
|
|
1332
|
+
|
|
1333
|
+
// src/resources/contacts.ts
|
|
1334
|
+
var ContactChannelResource = class {
|
|
1335
|
+
constructor(http2, contactId) {
|
|
1336
|
+
this.http = http2;
|
|
1337
|
+
this.contactId = contactId;
|
|
1338
|
+
}
|
|
1339
|
+
/** Returns `{ channel, duplicateOf }` — `duplicateOf` is the dedup signal. */
|
|
1340
|
+
async create(data) {
|
|
1341
|
+
return this.http.request({
|
|
1342
|
+
method: "POST",
|
|
1343
|
+
path: `/contacts/${this.contactId}/channels`,
|
|
1344
|
+
body: data
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
async update(channelId, data) {
|
|
1348
|
+
return this.http.request({
|
|
1349
|
+
method: "PATCH",
|
|
1350
|
+
path: `/contacts/${this.contactId}/channels/${channelId}`,
|
|
1351
|
+
body: data
|
|
1352
|
+
});
|
|
1353
|
+
}
|
|
1354
|
+
async delete(channelId) {
|
|
1355
|
+
await this.http.request({
|
|
1356
|
+
method: "DELETE",
|
|
1357
|
+
path: `/contacts/${this.contactId}/channels/${channelId}`
|
|
1358
|
+
});
|
|
1359
|
+
}
|
|
1360
|
+
};
|
|
1361
|
+
var ContactResource = class extends BaseResource {
|
|
1362
|
+
constructor(http2) {
|
|
1363
|
+
super(http2, "/contacts");
|
|
1364
|
+
}
|
|
1365
|
+
/**
|
|
1366
|
+
* List contacts. Typed against the real filter schema (customer_id /
|
|
1367
|
+
* property_id / q / sort_by / sort_order / page / limit / include) — the base
|
|
1368
|
+
* `list` would accept any key and let a typo reach the server as a 400.
|
|
1369
|
+
* `include: ['channels', 'links']` attaches each row's channels and active
|
|
1370
|
+
* links in the same response.
|
|
1371
|
+
*/
|
|
1372
|
+
async list(params) {
|
|
1373
|
+
return this.http.request({
|
|
1374
|
+
method: "GET",
|
|
1375
|
+
path: this.basePath,
|
|
1376
|
+
params: toQueryParams(params)
|
|
1377
|
+
});
|
|
1378
|
+
}
|
|
1379
|
+
async merge(winnerId, loserId) {
|
|
1380
|
+
return this.http.request({
|
|
1381
|
+
method: "POST",
|
|
1382
|
+
path: `/contacts/${winnerId}/merge/${loserId}`
|
|
1383
|
+
});
|
|
1384
|
+
}
|
|
1385
|
+
/** GET /contacts/roles — the distinct roles in use on active links, for a role picker. */
|
|
1386
|
+
async listRoles() {
|
|
1387
|
+
return this.http.request({ method: "GET", path: "/contacts/roles" });
|
|
1388
|
+
}
|
|
1389
|
+
/** GET /contacts/:id/links — every link, active and ended (history). `get()` returns active links only. */
|
|
1390
|
+
async listLinks(contactId) {
|
|
1391
|
+
return this.http.request({ method: "GET", path: `/contacts/${contactId}/links` });
|
|
1392
|
+
}
|
|
1393
|
+
/** POST /contacts/:id/links — link the contact to a customer or property. */
|
|
1394
|
+
async addLink(contactId, data) {
|
|
1395
|
+
return this.http.request({ method: "POST", path: `/contacts/${contactId}/links`, body: data });
|
|
1396
|
+
}
|
|
1397
|
+
/** PATCH /contacts/:id/links/:linkId — change role/primary, or end the link (`endedAt`). */
|
|
1398
|
+
async updateLink(contactId, linkId, data) {
|
|
1399
|
+
return this.http.request({
|
|
1400
|
+
method: "PATCH",
|
|
1401
|
+
path: `/contacts/${contactId}/links/${linkId}`,
|
|
1402
|
+
body: data
|
|
1403
|
+
});
|
|
1404
|
+
}
|
|
1405
|
+
/** POST /contacts/:id/workflow/start — opt the contact into the relationship pipeline (409 if started). */
|
|
1406
|
+
async startWorkflow(contactId) {
|
|
1407
|
+
return this.http.request({ method: "POST", path: `/contacts/${contactId}/workflow/start` });
|
|
1408
|
+
}
|
|
1409
|
+
/** GET /contacts/:id/workflow — current stage and the transitions available from it. */
|
|
1410
|
+
async getWorkflow(contactId) {
|
|
1411
|
+
return this.http.request({ method: "GET", path: `/contacts/${contactId}/workflow` });
|
|
1412
|
+
}
|
|
1413
|
+
/** POST /contacts/:id/workflow/transitions/:transitionId — 422 for an invalid move or unmet required fields. */
|
|
1414
|
+
async transition(contactId, transitionId) {
|
|
1415
|
+
return this.http.request({
|
|
1416
|
+
method: "POST",
|
|
1417
|
+
path: `/contacts/${contactId}/workflow/transitions/${transitionId}`,
|
|
1418
|
+
body: {}
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
/** GET /contacts/:id/workflow/history */
|
|
1422
|
+
async getWorkflowHistory(contactId) {
|
|
1423
|
+
return this.http.request({ method: "GET", path: `/contacts/${contactId}/workflow/history` });
|
|
1424
|
+
}
|
|
1425
|
+
channels(contactId) {
|
|
1426
|
+
return new ContactChannelResource(this.http, contactId);
|
|
1427
|
+
}
|
|
1428
|
+
};
|
|
1429
|
+
|
|
1430
|
+
// src/resources/activities.ts
|
|
1431
|
+
var ActivityResource = class {
|
|
1432
|
+
constructor(http2) {
|
|
1433
|
+
this.http = http2;
|
|
1434
|
+
}
|
|
1435
|
+
async create(data) {
|
|
1436
|
+
return this.http.request({
|
|
1437
|
+
method: "POST",
|
|
1438
|
+
path: "/activities",
|
|
1439
|
+
body: data
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
1442
|
+
async list(params) {
|
|
1443
|
+
return this.http.request({
|
|
1444
|
+
method: "GET",
|
|
1445
|
+
path: "/activities",
|
|
1446
|
+
params
|
|
1447
|
+
});
|
|
1448
|
+
}
|
|
1449
|
+
async listForEntity(entityType, entityId, params) {
|
|
1450
|
+
return this.http.request({
|
|
1451
|
+
method: "GET",
|
|
1452
|
+
path: `/${entityType}/${entityId}/activities`,
|
|
1453
|
+
params
|
|
1454
|
+
});
|
|
1455
|
+
}
|
|
1456
|
+
};
|
|
1457
|
+
|
|
1458
|
+
// src/resources/communications.ts
|
|
1459
|
+
var CommunicationsResource = class {
|
|
1460
|
+
constructor(http2) {
|
|
1461
|
+
this.http = http2;
|
|
1462
|
+
}
|
|
1463
|
+
async log(data) {
|
|
1464
|
+
return this.http.request({
|
|
1465
|
+
method: "POST",
|
|
1466
|
+
path: "/communications",
|
|
1467
|
+
body: data
|
|
1468
|
+
});
|
|
1469
|
+
}
|
|
1470
|
+
async list(params) {
|
|
1471
|
+
return this.http.request({
|
|
1472
|
+
method: "GET",
|
|
1473
|
+
path: "/communications",
|
|
1474
|
+
params
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
async get(id) {
|
|
1478
|
+
return this.http.request({
|
|
1479
|
+
method: "GET",
|
|
1480
|
+
path: `/communications/${id}`
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1483
|
+
async link(id, data) {
|
|
1484
|
+
return this.http.request({
|
|
1485
|
+
method: "POST",
|
|
1486
|
+
path: `/communications/${id}/link`,
|
|
1487
|
+
body: data
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
};
|
|
1491
|
+
|
|
1492
|
+
// src/resources/conversations.ts
|
|
1493
|
+
var ConversationsResource = class {
|
|
1494
|
+
constructor(http2) {
|
|
1495
|
+
this.http = http2;
|
|
1496
|
+
}
|
|
1497
|
+
async log(data) {
|
|
1498
|
+
return this.http.request({ method: "POST", path: "/conversations", body: data });
|
|
1499
|
+
}
|
|
1500
|
+
async list(params) {
|
|
1501
|
+
return this.http.request({ method: "GET", path: "/conversations", params });
|
|
1502
|
+
}
|
|
1503
|
+
/** The review queue: `list()` pinned to `match_status: 'needs_review'`. */
|
|
1504
|
+
async reviewQueue(params) {
|
|
1505
|
+
return this.list({ ...params, match_status: "needs_review" });
|
|
1506
|
+
}
|
|
1507
|
+
async get(id) {
|
|
1508
|
+
return this.http.request({ method: "GET", path: `/conversations/${encodeURIComponent(id)}` });
|
|
1509
|
+
}
|
|
1510
|
+
async update(id, data) {
|
|
1511
|
+
return this.http.request({ method: "PATCH", path: `/conversations/${encodeURIComponent(id)}`, body: data });
|
|
1512
|
+
}
|
|
1513
|
+
async delete(id) {
|
|
1514
|
+
await this.http.request({ method: "DELETE", path: `/conversations/${encodeURIComponent(id)}` });
|
|
1515
|
+
}
|
|
1516
|
+
async link(id, data) {
|
|
1517
|
+
return this.http.request({ method: "POST", path: `/conversations/${encodeURIComponent(id)}/links`, body: data });
|
|
1518
|
+
}
|
|
1519
|
+
async unlink(id, linkId) {
|
|
1520
|
+
return this.http.request({
|
|
1521
|
+
method: "DELETE",
|
|
1522
|
+
path: `/conversations/${encodeURIComponent(id)}/links/${encodeURIComponent(linkId)}`
|
|
1523
|
+
});
|
|
1524
|
+
}
|
|
1525
|
+
async resolve(id, data) {
|
|
1526
|
+
return this.http.request({ method: "POST", path: `/conversations/${encodeURIComponent(id)}/resolve`, body: data });
|
|
1527
|
+
}
|
|
1528
|
+
async getInternalDomains() {
|
|
1529
|
+
return this.http.request({ method: "GET", path: "/conversations/settings/internal-domains" });
|
|
1530
|
+
}
|
|
1531
|
+
/** Requires an admin: the server checks `Update` on `Subject.Tenant` (tenant-wide matching config), not `Subject.Conversation`. */
|
|
1532
|
+
async setInternalDomains(data) {
|
|
1533
|
+
return this.http.request({ method: "PUT", path: "/conversations/settings/internal-domains", body: data });
|
|
1534
|
+
}
|
|
1535
|
+
/**
|
|
1536
|
+
* E57-F2-S4 — disconnect the CALLER's own Circleback connection (Update
|
|
1537
|
+
* Conversation). Another user's connection id is a 404. Connecting is the
|
|
1538
|
+
* interactive browser OAuth flow (Settings → Conversations), not an SDK call.
|
|
1539
|
+
*/
|
|
1540
|
+
async disconnectCircleback(data) {
|
|
1541
|
+
return this.http.request({
|
|
1542
|
+
method: "POST",
|
|
1543
|
+
path: "/conversations/sources/circleback/disconnect",
|
|
1544
|
+
body: data
|
|
1545
|
+
});
|
|
1546
|
+
}
|
|
1547
|
+
/**
|
|
1548
|
+
* E57-F2-S8 — pull one company's meetings from every active teammate's
|
|
1549
|
+
* connected source (Update Conversation). 202, runs in the background.
|
|
1550
|
+
* 404 for a company you can't see; 409 `NO_SOURCES` when nobody has one.
|
|
1551
|
+
*/
|
|
1552
|
+
async pull(data) {
|
|
1553
|
+
return this.http.request({ method: "POST", path: "/conversations/pull", body: data });
|
|
1554
|
+
}
|
|
1555
|
+
/**
|
|
1556
|
+
* E57-F2-S9 — whether a Pull has finished: pass the `job_ids` `pull()`
|
|
1557
|
+
* returned (1–50). Update Conversation, like `pull()`. 404
|
|
1558
|
+
* `PULL_NOT_FOUND` when none of them is readable (expired after ~2h,
|
|
1559
|
+
* unknown) — treat that as settled.
|
|
1560
|
+
*/
|
|
1561
|
+
async getPullStatus(jobIds) {
|
|
1562
|
+
return this.http.request({
|
|
1563
|
+
method: "GET",
|
|
1564
|
+
path: "/conversations/pull/status",
|
|
1565
|
+
params: { job_ids: jobIds.join(",") }
|
|
1566
|
+
});
|
|
1567
|
+
}
|
|
1568
|
+
/** E57-F2-S8 — sync the caller's OWN Circleback connection now (deduplicated). 409 `NO_CONNECTION` when they have none. */
|
|
1569
|
+
async syncNow() {
|
|
1570
|
+
return this.http.request({ method: "POST", path: "/conversations/sources/circleback/sync-now" });
|
|
1571
|
+
}
|
|
1572
|
+
/** E57-F2-S8 — the caller's own connection, `has_sources`, and (admins only) the roster. */
|
|
1573
|
+
async syncStatus() {
|
|
1574
|
+
return this.http.request({ method: "GET", path: "/conversations/sync-status" });
|
|
1575
|
+
}
|
|
1576
|
+
/**
|
|
1577
|
+
* E57-F4-S1 — a synced meeting's transcript, fetched live from the meeting
|
|
1578
|
+
* recorder (never stored by Planes; the response is `Cache-Control:
|
|
1579
|
+
* no-store`). Read Conversation, plus the tenant's transcript-access rule:
|
|
1580
|
+
* 403 `TRANSCRIPT_OWNER_ONLY` under `owner` for a non-owner; 409
|
|
1581
|
+
* `TRANSCRIPT_SOURCE_UNAVAILABLE` (`owner_name` says who must reconnect) or
|
|
1582
|
+
* `TRANSCRIPT_NOT_AVAILABLE` (not a synced meeting); 404 when you can't see
|
|
1583
|
+
* the conversation. `segments: []` = no transcript yet.
|
|
1584
|
+
*/
|
|
1585
|
+
async getTranscript(id) {
|
|
1586
|
+
return this.http.request({
|
|
1587
|
+
method: "GET",
|
|
1588
|
+
path: `/conversations/${encodeURIComponent(id)}/transcript`
|
|
1589
|
+
});
|
|
1590
|
+
}
|
|
1591
|
+
/** E57-F4-S1 — who can view transcripts: `owner` (default) or `viewers`. Read Conversation. */
|
|
1592
|
+
async getTranscriptAccess() {
|
|
1593
|
+
return this.http.request({ method: "GET", path: "/conversations/settings/transcript-access" });
|
|
1594
|
+
}
|
|
1595
|
+
/** E57-F4-S1 — requires an admin: the server checks `Update` on `Subject.Tenant`. */
|
|
1596
|
+
async setTranscriptAccess(value) {
|
|
1597
|
+
return this.http.request({
|
|
1598
|
+
method: "PUT",
|
|
1599
|
+
path: "/conversations/settings/transcript-access",
|
|
1600
|
+
body: { transcript_access: value }
|
|
1601
|
+
});
|
|
1602
|
+
}
|
|
1603
|
+
};
|
|
1604
|
+
|
|
1605
|
+
// src/resources/gmail.ts
|
|
1606
|
+
var GmailResource = class {
|
|
1607
|
+
constructor(http2) {
|
|
1608
|
+
this.http = http2;
|
|
1609
|
+
}
|
|
1610
|
+
/**
|
|
1611
|
+
* Send an email RIGHT NOW from the connected user's real Gmail address.
|
|
1612
|
+
* Hits `POST /admin/integrations/google/gmail/send` — final per Task 4
|
|
1613
|
+
* (`apps/api/src/modules/integrations/google/google-connection.controller.ts`).
|
|
1614
|
+
*/
|
|
1615
|
+
async send(data) {
|
|
1616
|
+
return this.http.request({
|
|
1617
|
+
method: "POST",
|
|
1618
|
+
path: "/admin/integrations/google/gmail/send",
|
|
1619
|
+
body: data
|
|
1620
|
+
});
|
|
1621
|
+
}
|
|
1622
|
+
};
|
|
1623
|
+
|
|
1624
|
+
// src/resources/documents.ts
|
|
1625
|
+
var DocumentsResource = class {
|
|
1626
|
+
constructor(http2) {
|
|
1627
|
+
this.http = http2;
|
|
1628
|
+
}
|
|
1629
|
+
/** Attach an external (link-only) document — e.g. a Google Drive link — to a record. */
|
|
1630
|
+
async attachExternal(data) {
|
|
1631
|
+
return this.http.request({
|
|
1632
|
+
method: "POST",
|
|
1633
|
+
path: "/documents/external",
|
|
1634
|
+
body: data
|
|
1635
|
+
});
|
|
1636
|
+
}
|
|
1637
|
+
/** Documents filed directly on one record (uploaded + external), newest first. */
|
|
1638
|
+
async listForEntity(entityType, entityId) {
|
|
1639
|
+
return this.http.request({
|
|
1640
|
+
method: "GET",
|
|
1641
|
+
path: `/${entityType}/${entityId}/documents`
|
|
1642
|
+
});
|
|
1643
|
+
}
|
|
1644
|
+
};
|
|
1645
|
+
|
|
1646
|
+
// src/resources/tags.ts
|
|
1647
|
+
var TagResource = class extends ApiResource {
|
|
1648
|
+
constructor(http2) {
|
|
1649
|
+
super(http2, "/tags");
|
|
1650
|
+
}
|
|
1651
|
+
/** GET /tags */
|
|
1652
|
+
async list(params) {
|
|
1653
|
+
return this.http.request({
|
|
1654
|
+
method: "GET",
|
|
1655
|
+
path: this.basePath,
|
|
1656
|
+
params
|
|
1657
|
+
});
|
|
1658
|
+
}
|
|
1659
|
+
/** POST /tags — 409 on a case-insensitive duplicate name. */
|
|
1660
|
+
async create(data) {
|
|
1661
|
+
return this.http.request({ method: "POST", path: this.basePath, body: data });
|
|
1662
|
+
}
|
|
1663
|
+
/** PATCH /tags/:id — rename / recolor; 409 on a case-insensitive duplicate name. */
|
|
1664
|
+
async update(id, data) {
|
|
1665
|
+
return this.http.request({ method: "PATCH", path: `${this.basePath}/${id}`, body: data });
|
|
1666
|
+
}
|
|
1667
|
+
/** DELETE /tags/:id — cascades the tag off every record. */
|
|
1668
|
+
async delete(id) {
|
|
1669
|
+
await this.http.request({ method: "DELETE", path: `${this.basePath}/${id}` });
|
|
1670
|
+
}
|
|
1671
|
+
/**
|
|
1672
|
+
* POST /tags/:winnerId/merge/:loserId — fold a duplicate tag into another: records
|
|
1673
|
+
* move to the winner (`retagged`), duplicates are dropped (`dropped`), and the
|
|
1674
|
+
* loser is deleted. Irreversible.
|
|
1675
|
+
*/
|
|
1676
|
+
async merge(winnerId, loserId) {
|
|
1677
|
+
return this.http.request({ method: "POST", path: `${this.basePath}/${winnerId}/merge/${loserId}` });
|
|
1678
|
+
}
|
|
1679
|
+
/** `TagsService.setEntityTags()` returns the final tag set wrapped in `{ tags }`. */
|
|
1680
|
+
async setEntityTags(entityType, entityId, data) {
|
|
1681
|
+
return this.http.request({
|
|
1682
|
+
method: "PUT",
|
|
1683
|
+
path: `/entities/${entityType}/${entityId}/tags`,
|
|
1684
|
+
body: data
|
|
1685
|
+
});
|
|
1686
|
+
}
|
|
1687
|
+
/**
|
|
1688
|
+
* POST /entities/:type/:id/tags — add ONE tag, keeping the record's other tags.
|
|
1689
|
+
* Safe to call concurrently with other tag changes on the same record (unlike
|
|
1690
|
+
* read-modify-write through `setEntityTags()`). Adding a tag the record already
|
|
1691
|
+
* carries is a no-op. Returns the record's full tag set.
|
|
1692
|
+
*/
|
|
1693
|
+
async addEntityTag(entityType, entityId, ref) {
|
|
1694
|
+
const body = ref.tagId !== void 0 ? { tag_id: ref.tagId } : { tag_name: ref.tagName };
|
|
1695
|
+
return this.http.request({
|
|
1696
|
+
method: "POST",
|
|
1697
|
+
path: `/entities/${entityType}/${entityId}/tags`,
|
|
1698
|
+
body
|
|
1699
|
+
});
|
|
1700
|
+
}
|
|
1701
|
+
/**
|
|
1702
|
+
* DELETE /entities/:type/:id/tags/:tagId — remove ONE tag, keeping the rest.
|
|
1703
|
+
* Removing a tag the record doesn't carry is a no-op. Returns the record's
|
|
1704
|
+
* full tag set.
|
|
1705
|
+
*/
|
|
1706
|
+
async removeEntityTag(entityType, entityId, tagId) {
|
|
1707
|
+
return this.http.request({
|
|
1708
|
+
method: "DELETE",
|
|
1709
|
+
path: `/entities/${entityType}/${entityId}/tags/${tagId}`
|
|
1710
|
+
});
|
|
1711
|
+
}
|
|
1712
|
+
async getEntityTags(entityType, entityId) {
|
|
1713
|
+
return this.http.request({
|
|
1714
|
+
method: "GET",
|
|
1715
|
+
path: `/entities/${entityType}/${entityId}/tags`
|
|
1716
|
+
});
|
|
1717
|
+
}
|
|
1718
|
+
async getEntities(tagId, params) {
|
|
1719
|
+
return this.http.request({
|
|
1720
|
+
method: "GET",
|
|
1721
|
+
path: `/tags/${tagId}/entities`,
|
|
1722
|
+
params
|
|
1723
|
+
});
|
|
1724
|
+
}
|
|
1725
|
+
};
|
|
1726
|
+
|
|
1727
|
+
// src/resources/lists.ts
|
|
1728
|
+
var ListsResource = class extends ApiResource {
|
|
1729
|
+
constructor(http2) {
|
|
1730
|
+
super(http2, "/lists");
|
|
1731
|
+
}
|
|
1732
|
+
/** GET /lists — every list, newest first, each with `member_count`. A bare array. */
|
|
1733
|
+
async list() {
|
|
1734
|
+
return this.http.request({ method: "GET", path: this.basePath });
|
|
1735
|
+
}
|
|
1736
|
+
/**
|
|
1737
|
+
* GET /lists/filter-fields — the standard fields, their types and the operators
|
|
1738
|
+
* each accepts for a smart list of this entity type, and whether custom fields
|
|
1739
|
+
* are accepted (E66-S3). A save that breaks these rules is a 400.
|
|
1740
|
+
*/
|
|
1741
|
+
async filterFields(entityType) {
|
|
1742
|
+
return this.http.request({
|
|
1743
|
+
method: "GET",
|
|
1744
|
+
path: `${this.basePath}/filter-fields`,
|
|
1745
|
+
params: { entity_type: entityType }
|
|
1746
|
+
});
|
|
1747
|
+
}
|
|
1748
|
+
/** GET /lists/:id — one list with an on-demand `member_count`. */
|
|
1749
|
+
async get(id) {
|
|
1750
|
+
return this.http.request({ method: "GET", path: `${this.basePath}/${id}` });
|
|
1751
|
+
}
|
|
1752
|
+
/** POST /lists */
|
|
1753
|
+
async create(data) {
|
|
1754
|
+
return this.http.request({ method: "POST", path: this.basePath, body: data });
|
|
1755
|
+
}
|
|
1756
|
+
/** PATCH /lists/:id — rename, or replace a smart list's definition. */
|
|
1757
|
+
async update(id, data) {
|
|
1758
|
+
return this.http.request({ method: "PATCH", path: `${this.basePath}/${id}`, body: data });
|
|
1759
|
+
}
|
|
1760
|
+
/** DELETE /lists/:id — soft delete; the records on the list are untouched. */
|
|
1761
|
+
async delete(id) {
|
|
1762
|
+
await this.http.request({ method: "DELETE", path: `${this.basePath}/${id}` });
|
|
1763
|
+
}
|
|
1764
|
+
/** POST /lists/:id/members — static lists only; idempotent on duplicates. */
|
|
1765
|
+
async addMembers(id, members) {
|
|
1766
|
+
return this.http.request({
|
|
1767
|
+
method: "POST",
|
|
1768
|
+
path: `${this.basePath}/${id}/members`,
|
|
1769
|
+
body: { members }
|
|
1770
|
+
});
|
|
1771
|
+
}
|
|
1772
|
+
/** DELETE /lists/:id/members — static lists only. */
|
|
1773
|
+
async removeMembers(id, members) {
|
|
1774
|
+
return this.http.request({
|
|
1775
|
+
method: "DELETE",
|
|
1776
|
+
path: `${this.basePath}/${id}/members`,
|
|
1777
|
+
body: { members }
|
|
1778
|
+
});
|
|
1779
|
+
}
|
|
1780
|
+
/** GET /lists/:id/recipients — people (audience, contact and customer lists), with consent. */
|
|
1781
|
+
async getRecipients(id, params) {
|
|
1782
|
+
return this.http.request({
|
|
1783
|
+
method: "GET",
|
|
1784
|
+
path: `${this.basePath}/${id}/recipients`,
|
|
1785
|
+
params
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
/** POST /lists/:id/export — queues a CSV export; a notification links the file when it's ready. */
|
|
1789
|
+
async export(id, options) {
|
|
1790
|
+
return this.http.request({
|
|
1791
|
+
method: "POST",
|
|
1792
|
+
path: `${this.basePath}/${id}/export`,
|
|
1793
|
+
body: options ?? {}
|
|
1794
|
+
});
|
|
1795
|
+
}
|
|
1796
|
+
};
|
|
1797
|
+
|
|
1798
|
+
// src/resources/lead-sources.ts
|
|
1799
|
+
var LeadSourcesResource = class extends ApiResource {
|
|
1800
|
+
constructor(http2) {
|
|
1801
|
+
super(http2, "/lead-sources");
|
|
1802
|
+
}
|
|
1803
|
+
/** GET /lead-sources — active ones by default, in display order. */
|
|
1804
|
+
async list(options) {
|
|
1805
|
+
const res = await this.http.request({
|
|
1806
|
+
method: "GET",
|
|
1807
|
+
path: this.basePath,
|
|
1808
|
+
...options?.includeInactive ? { params: { includeInactive: "true" } } : {}
|
|
1809
|
+
});
|
|
1810
|
+
return res.data;
|
|
1811
|
+
}
|
|
1812
|
+
/** POST /lead-sources — 409 on a duplicate key. */
|
|
1813
|
+
async create(data) {
|
|
1814
|
+
const res = await this.http.request({ method: "POST", path: this.basePath, body: data });
|
|
1815
|
+
return res.data;
|
|
1816
|
+
}
|
|
1817
|
+
/** PATCH /lead-sources/:id — label, active flag or order; the key can't change. */
|
|
1818
|
+
async update(id, data) {
|
|
1819
|
+
const res = await this.http.request({
|
|
1820
|
+
method: "PATCH",
|
|
1821
|
+
path: `${this.basePath}/${id}`,
|
|
1822
|
+
body: data
|
|
1823
|
+
});
|
|
1824
|
+
return res.data;
|
|
1825
|
+
}
|
|
1826
|
+
/** DELETE /lead-sources/:id — soft delete. */
|
|
1827
|
+
async delete(id) {
|
|
1828
|
+
await this.http.request({ method: "DELETE", path: `${this.basePath}/${id}` });
|
|
1829
|
+
}
|
|
1830
|
+
};
|
|
1831
|
+
|
|
1832
|
+
// src/resources/tasks.ts
|
|
1833
|
+
var TaskResource = class extends ApiResource {
|
|
1834
|
+
constructor(http2) {
|
|
1835
|
+
super(http2, "/tasks");
|
|
1836
|
+
}
|
|
1837
|
+
async list(params) {
|
|
1838
|
+
return this.http.request({
|
|
1839
|
+
method: "GET",
|
|
1840
|
+
path: this.basePath,
|
|
1841
|
+
params
|
|
1842
|
+
});
|
|
1843
|
+
}
|
|
1844
|
+
/** GET /tasks/:id */
|
|
1845
|
+
async get(id) {
|
|
1846
|
+
return this.http.request({ method: "GET", path: `${this.basePath}/${id}` });
|
|
1847
|
+
}
|
|
1848
|
+
/** POST /tasks. Pass `idempotencyKey` to make a retry safe (E64-S6). */
|
|
1849
|
+
async create(data, options) {
|
|
1850
|
+
return this.http.request({
|
|
1851
|
+
method: "POST",
|
|
1852
|
+
path: this.basePath,
|
|
1853
|
+
body: data,
|
|
1854
|
+
...options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {}
|
|
1855
|
+
});
|
|
1856
|
+
}
|
|
1857
|
+
/** PATCH /tasks/:id — non-terminal fields only; terminal status changes use the action methods. */
|
|
1858
|
+
async update(id, data) {
|
|
1859
|
+
return this.http.request({ method: "PATCH", path: `${this.basePath}/${id}`, body: data });
|
|
1860
|
+
}
|
|
1861
|
+
/**
|
|
1862
|
+
* POST /tasks/:id/complete — fires the linked workflow transition (best-effort).
|
|
1863
|
+
* The task always completes; `workflow_trigger` says whether the next step ran.
|
|
1864
|
+
*/
|
|
1865
|
+
async complete(id) {
|
|
1866
|
+
return this.http.request({ method: "POST", path: `${this.basePath}/${id}/complete` });
|
|
1867
|
+
}
|
|
1868
|
+
/** POST /tasks/:id/cancel */
|
|
1869
|
+
async cancel(id) {
|
|
1870
|
+
return this.http.request({ method: "POST", path: `${this.basePath}/${id}/cancel` });
|
|
1871
|
+
}
|
|
1872
|
+
/** POST /tasks/:id/reopen — the sanctioned resurrect of a completed/cancelled task. */
|
|
1873
|
+
async reopen(id) {
|
|
1874
|
+
return this.http.request({ method: "POST", path: `${this.basePath}/${id}/reopen` });
|
|
1875
|
+
}
|
|
1876
|
+
};
|
|
1877
|
+
|
|
1878
|
+
// src/resources/record-views.ts
|
|
1879
|
+
var RecordViewsResource = class {
|
|
1880
|
+
constructor(http2) {
|
|
1881
|
+
this.http = http2;
|
|
1882
|
+
this.basePath = "/record-views";
|
|
1883
|
+
}
|
|
1884
|
+
/** POST /record-views — record that the calling user opened this record. Resolves on 204. */
|
|
1885
|
+
async touch(input) {
|
|
1886
|
+
await this.http.request({ method: "POST", path: this.basePath, body: input });
|
|
1887
|
+
}
|
|
1888
|
+
/** GET /record-views/recent — the calling user's most recently viewed records, newest first. */
|
|
1889
|
+
async recent(params) {
|
|
1890
|
+
return this.http.request({
|
|
1891
|
+
method: "GET",
|
|
1892
|
+
path: `${this.basePath}/recent`,
|
|
1893
|
+
params: toQueryParams(params)
|
|
1894
|
+
});
|
|
1895
|
+
}
|
|
1896
|
+
};
|
|
1897
|
+
|
|
1898
|
+
// src/resources/modules.ts
|
|
1899
|
+
var ModulesResource = class {
|
|
1900
|
+
constructor(http2) {
|
|
1901
|
+
this.http = http2;
|
|
1902
|
+
this.basePath = "/modules";
|
|
1903
|
+
}
|
|
1904
|
+
/** GET /modules — one entry per registered module key, in canonical order. */
|
|
1905
|
+
async list() {
|
|
1906
|
+
const res = await this.http.request({
|
|
1907
|
+
method: "GET",
|
|
1908
|
+
path: this.basePath
|
|
1909
|
+
});
|
|
1910
|
+
return res.data;
|
|
1911
|
+
}
|
|
1912
|
+
};
|
|
1913
|
+
|
|
1914
|
+
// src/resources/plan.ts
|
|
1915
|
+
var PlanResource = class {
|
|
1916
|
+
constructor(http2) {
|
|
1917
|
+
this.http = http2;
|
|
1918
|
+
this.basePath = "/plan";
|
|
1919
|
+
}
|
|
1920
|
+
/** GET /plan — plan, billing status and the plan's ceiling. */
|
|
1921
|
+
async get() {
|
|
1922
|
+
const res = await this.http.request({
|
|
1923
|
+
method: "GET",
|
|
1924
|
+
path: this.basePath
|
|
1925
|
+
});
|
|
1926
|
+
return res.data;
|
|
1927
|
+
}
|
|
1928
|
+
};
|
|
1929
|
+
|
|
1930
|
+
// src/resources/me.ts
|
|
1931
|
+
var MeResource = class {
|
|
1932
|
+
constructor(http2) {
|
|
1933
|
+
this.http = http2;
|
|
1934
|
+
this.basePath = "/me";
|
|
1935
|
+
}
|
|
1936
|
+
/**
|
|
1937
|
+
* GET /me/abilities — the caller's effective ability: for an API key, the key
|
|
1938
|
+
* role intersected with its acting agent's live role (`actingRole`).
|
|
1939
|
+
*/
|
|
1940
|
+
async abilities() {
|
|
1941
|
+
return this.http.request({
|
|
1942
|
+
method: "GET",
|
|
1943
|
+
path: `${this.basePath}/abilities`
|
|
1944
|
+
});
|
|
1945
|
+
}
|
|
1946
|
+
};
|
|
1947
|
+
|
|
1948
|
+
// src/resources/roles.ts
|
|
1949
|
+
var RolesResource = class {
|
|
1950
|
+
constructor(http2) {
|
|
1951
|
+
this.http = http2;
|
|
1952
|
+
this.basePath = "/roles";
|
|
1953
|
+
}
|
|
1954
|
+
/** GET /roles — every role (not `system_agent`) with user and change counts. */
|
|
1955
|
+
async list() {
|
|
1956
|
+
return this.http.request({ method: "GET", path: this.basePath });
|
|
1957
|
+
}
|
|
1958
|
+
/** GET /roles/:key — one role's permission matrix, summary and grant version. */
|
|
1959
|
+
async get(key) {
|
|
1960
|
+
return this.http.request({
|
|
1961
|
+
method: "GET",
|
|
1962
|
+
path: `${this.basePath}/${encodeURIComponent(key)}`
|
|
1963
|
+
});
|
|
1964
|
+
}
|
|
1965
|
+
/**
|
|
1966
|
+
* PUT /roles/:key/grants — sparse per-cell changes, all validated before any
|
|
1967
|
+
* is written. 422 `GRANT_REQUIRED` / `GRANT_NOT_DELEGABLE` for locked cells,
|
|
1968
|
+
* `CONFIRMATION_REQUIRED` when a money action is granted without
|
|
1969
|
+
* `confirm: true` + `reason`, `ROLE_NOT_TUNABLE` for admin; 409
|
|
1970
|
+
* `ROLE_VERSION_CONFLICT` on a stale `baseVersion`. Returns the updated role.
|
|
1971
|
+
*/
|
|
1972
|
+
async updateGrants(key, body) {
|
|
1973
|
+
return this.http.request({
|
|
1974
|
+
method: "PUT",
|
|
1975
|
+
path: `${this.basePath}/${encodeURIComponent(key)}/grants`,
|
|
1976
|
+
body
|
|
1977
|
+
});
|
|
1978
|
+
}
|
|
1979
|
+
/** DELETE /roles/:key/grants — back to the Planes defaults. Returns the reset role. */
|
|
1980
|
+
async reset(key) {
|
|
1981
|
+
return this.http.request({
|
|
1982
|
+
method: "DELETE",
|
|
1983
|
+
path: `${this.basePath}/${encodeURIComponent(key)}/grants`
|
|
1984
|
+
});
|
|
1985
|
+
}
|
|
1986
|
+
/** GET /roles/history — the change log, newest first; page with `cursor`. */
|
|
1987
|
+
async history(params) {
|
|
1988
|
+
return this.http.request({
|
|
1989
|
+
method: "GET",
|
|
1990
|
+
path: `${this.basePath}/history`,
|
|
1991
|
+
...params ? { params } : {}
|
|
1992
|
+
});
|
|
1993
|
+
}
|
|
1994
|
+
};
|
|
1995
|
+
|
|
1996
|
+
// src/resources/invoice-settings.ts
|
|
1997
|
+
var InvoiceSettingsResource = class {
|
|
1998
|
+
constructor(http2) {
|
|
1999
|
+
this.http = http2;
|
|
2000
|
+
this.basePath = "/admin/invoice-settings";
|
|
2001
|
+
}
|
|
2002
|
+
/**
|
|
2003
|
+
* GET /admin/invoice-settings/offline-instructions — the plain-text
|
|
2004
|
+
* instructions shown on the pay page when online payment is unavailable,
|
|
2005
|
+
* or null when none are set.
|
|
2006
|
+
*/
|
|
2007
|
+
async getOfflineInstructions() {
|
|
2008
|
+
const res = await this.http.request({
|
|
2009
|
+
method: "GET",
|
|
2010
|
+
path: `${this.basePath}/offline-instructions`
|
|
2011
|
+
});
|
|
2012
|
+
return res.instructions;
|
|
2013
|
+
}
|
|
2014
|
+
/**
|
|
2015
|
+
* PUT /admin/invoice-settings/offline-instructions — store plain text
|
|
2016
|
+
* (trimmed, at most 2,000 characters); null or blank clears it. Returns the
|
|
2017
|
+
* stored value.
|
|
2018
|
+
*/
|
|
2019
|
+
async setOfflineInstructions(text) {
|
|
2020
|
+
const body = { instructions: text };
|
|
2021
|
+
const res = await this.http.request({
|
|
2022
|
+
method: "PUT",
|
|
2023
|
+
path: `${this.basePath}/offline-instructions`,
|
|
2024
|
+
body
|
|
2025
|
+
});
|
|
2026
|
+
return res.instructions;
|
|
2027
|
+
}
|
|
2028
|
+
/**
|
|
2029
|
+
* GET /admin/invoice-settings/overdue-offsets — the days after the due date
|
|
2030
|
+
* at which `invoice.overdue` fires, ascending (default `[3, 7, 14]`).
|
|
2031
|
+
*/
|
|
2032
|
+
async getOverdueOffsets() {
|
|
2033
|
+
const res = await this.http.request({
|
|
2034
|
+
method: "GET",
|
|
2035
|
+
path: `${this.basePath}/overdue-offsets`
|
|
2036
|
+
});
|
|
2037
|
+
return res.offsets;
|
|
2038
|
+
}
|
|
2039
|
+
/**
|
|
2040
|
+
* PUT /admin/invoice-settings/overdue-offsets — replace the offsets: 1 to 5
|
|
2041
|
+
* unique whole days, each 1–90. Returns them sorted ascending. Admin only.
|
|
2042
|
+
*/
|
|
2043
|
+
async setOverdueOffsets(offsets) {
|
|
2044
|
+
const body = { offsets };
|
|
2045
|
+
const res = await this.http.request({
|
|
2046
|
+
method: "PUT",
|
|
2047
|
+
path: `${this.basePath}/overdue-offsets`,
|
|
2048
|
+
body
|
|
2049
|
+
});
|
|
2050
|
+
return res.offsets;
|
|
2051
|
+
}
|
|
2052
|
+
/**
|
|
2053
|
+
* GET /admin/invoice-settings/attach-pdf — whether invoice emails carry the
|
|
2054
|
+
* invoice PDF (on unless an admin turned it off).
|
|
2055
|
+
*/
|
|
2056
|
+
async getAttachPdf() {
|
|
2057
|
+
const res = await this.http.request({
|
|
2058
|
+
method: "GET",
|
|
2059
|
+
path: `${this.basePath}/attach-pdf`
|
|
2060
|
+
});
|
|
2061
|
+
return res.enabled;
|
|
2062
|
+
}
|
|
2063
|
+
/**
|
|
2064
|
+
* PUT /admin/invoice-settings/attach-pdf — turn the PDF attachment on
|
|
2065
|
+
* invoice emails on or off. Returns the stored value.
|
|
2066
|
+
*/
|
|
2067
|
+
async setAttachPdf(enabled) {
|
|
2068
|
+
const body = { enabled };
|
|
2069
|
+
const res = await this.http.request({
|
|
2070
|
+
method: "PUT",
|
|
2071
|
+
path: `${this.basePath}/attach-pdf`,
|
|
2072
|
+
body
|
|
2073
|
+
});
|
|
2074
|
+
return res.enabled;
|
|
2075
|
+
}
|
|
2076
|
+
};
|
|
2077
|
+
|
|
2078
|
+
// src/resources/invoice-reminders.ts
|
|
2079
|
+
var InvoiceRemindersResource = class {
|
|
2080
|
+
constructor(http2) {
|
|
2081
|
+
this.http = http2;
|
|
2082
|
+
this.basePath = "/admin/invoice-reminders";
|
|
2083
|
+
}
|
|
2084
|
+
/** GET /admin/invoice-reminders — the rules, ascending by offset, and the overdue offsets. */
|
|
2085
|
+
async list() {
|
|
2086
|
+
return this.http.request({
|
|
2087
|
+
method: "GET",
|
|
2088
|
+
path: this.basePath
|
|
2089
|
+
});
|
|
2090
|
+
}
|
|
2091
|
+
/**
|
|
2092
|
+
* PUT /admin/invoice-reminders — replace the WHOLE rule set (a rule left out
|
|
2093
|
+
* is deleted): up to 5 rules at unique offsets. Templates may use only
|
|
2094
|
+
* `{{customerName}}`, `{{invoiceNumber}}`, `{{amountDue}}`, `{{total}}`,
|
|
2095
|
+
* `{{dueDate}}`, `{{daysOverdue}}` and `{{companyName}}`; any other is a 422
|
|
2096
|
+
* `REMINDER_TEMPLATE_INVALID` listing each one. Returns the stored set.
|
|
2097
|
+
*/
|
|
2098
|
+
async update(rules) {
|
|
2099
|
+
return this.http.request({
|
|
2100
|
+
method: "PUT",
|
|
2101
|
+
path: this.basePath,
|
|
2102
|
+
body: { rules }
|
|
2103
|
+
});
|
|
2104
|
+
}
|
|
2105
|
+
/**
|
|
2106
|
+
* POST /admin/invoice-reminders/preview — render a subject and body exactly
|
|
2107
|
+
* as the reminder email would, against an invoice or a sample. Sends nothing.
|
|
2108
|
+
*/
|
|
2109
|
+
async preview(params) {
|
|
2110
|
+
return this.http.request({
|
|
2111
|
+
method: "POST",
|
|
2112
|
+
path: `${this.basePath}/preview`,
|
|
2113
|
+
body: params
|
|
2114
|
+
});
|
|
2115
|
+
}
|
|
2116
|
+
};
|
|
2117
|
+
|
|
2118
|
+
// src/resources/event-automations.ts
|
|
2119
|
+
var EventAutomationsResource = class {
|
|
2120
|
+
constructor(http2) {
|
|
2121
|
+
this.http = http2;
|
|
2122
|
+
}
|
|
2123
|
+
// Each request spells its path out in full (no computed base path) so the
|
|
2124
|
+
// API's SDK route-parity audit (sdk-route-parity-audit.spec.ts) can read it.
|
|
2125
|
+
/** GET — enabled and disabled automations, oldest first, optionally by event type or owner. */
|
|
2126
|
+
async list(params = {}) {
|
|
2127
|
+
const query = {};
|
|
2128
|
+
if (params.owner_tag) query["owner_tag"] = params.owner_tag;
|
|
2129
|
+
if (params.event_type) query["event_type"] = params.event_type;
|
|
2130
|
+
const res = await this.http.request({
|
|
2131
|
+
method: "GET",
|
|
2132
|
+
path: "/admin/event-automations",
|
|
2133
|
+
params: query
|
|
2134
|
+
});
|
|
2135
|
+
return res.data;
|
|
2136
|
+
}
|
|
2137
|
+
/** GET /:id — 404 when it doesn't exist or was deleted. */
|
|
2138
|
+
async get(id) {
|
|
2139
|
+
return this.http.request({
|
|
2140
|
+
method: "GET",
|
|
2141
|
+
path: `/admin/event-automations/${encodeURIComponent(id)}`
|
|
2142
|
+
});
|
|
2143
|
+
}
|
|
2144
|
+
/**
|
|
2145
|
+
* POST — create (201). 400 `VALIDATION_FAILED` for a bad body, or a 400
|
|
2146
|
+
* naming the step whose `action_type` isn't allowed in automations.
|
|
2147
|
+
*/
|
|
2148
|
+
async create(input) {
|
|
2149
|
+
return this.http.request({
|
|
2150
|
+
method: "POST",
|
|
2151
|
+
path: "/admin/event-automations",
|
|
2152
|
+
body: input
|
|
2153
|
+
});
|
|
2154
|
+
}
|
|
2155
|
+
/**
|
|
2156
|
+
* PATCH /:id — only the fields sent change. Sending `actions` replaces the
|
|
2157
|
+
* list: keep each existing step's `id` so a step that already ran isn't run
|
|
2158
|
+
* again. `{ enabled: false }` switches it off.
|
|
2159
|
+
*/
|
|
2160
|
+
async update(id, input) {
|
|
2161
|
+
return this.http.request({
|
|
2162
|
+
method: "PATCH",
|
|
2163
|
+
path: `/admin/event-automations/${encodeURIComponent(id)}`,
|
|
2164
|
+
body: input
|
|
2165
|
+
});
|
|
2166
|
+
}
|
|
2167
|
+
/** DELETE /:id — soft delete; returns `{ id }` (200). */
|
|
2168
|
+
async delete(id) {
|
|
2169
|
+
return this.http.request({
|
|
2170
|
+
method: "DELETE",
|
|
2171
|
+
path: `/admin/event-automations/${encodeURIComponent(id)}`
|
|
2172
|
+
});
|
|
2173
|
+
}
|
|
2174
|
+
};
|
|
2175
|
+
|
|
2176
|
+
// src/resources/web-forms.ts
|
|
2177
|
+
var WebFormsResource = class {
|
|
2178
|
+
constructor(http2) {
|
|
2179
|
+
this.http = http2;
|
|
2180
|
+
this.submissions = new WebFormSubmissionsResource(http2);
|
|
2181
|
+
}
|
|
2182
|
+
// Each request spells its path out in full so the API's SDK route-parity
|
|
2183
|
+
// audit (sdk-route-parity-audit.spec.ts) can read it.
|
|
2184
|
+
/** GET — every form not archived, newest first. */
|
|
2185
|
+
async list() {
|
|
2186
|
+
const res = await this.http.request({ method: "GET", path: "/admin/web-forms" });
|
|
2187
|
+
return res.data;
|
|
2188
|
+
}
|
|
2189
|
+
/** GET /trade-options — the active trades a `trade` question offers, by current name. */
|
|
2190
|
+
async tradeOptions() {
|
|
2191
|
+
const res = await this.http.request({ method: "GET", path: "/admin/web-forms/trade-options" });
|
|
2192
|
+
return res.data;
|
|
2193
|
+
}
|
|
2194
|
+
/** GET /:id */
|
|
2195
|
+
async get(id) {
|
|
2196
|
+
return this.http.request({ method: "GET", path: `/admin/web-forms/${encodeURIComponent(id)}` });
|
|
2197
|
+
}
|
|
2198
|
+
/** POST — create (201) with its default routing. Pass `recipient_agent_ids`. */
|
|
2199
|
+
async create(input) {
|
|
2200
|
+
return this.http.request({ method: "POST", path: "/admin/web-forms", body: input });
|
|
2201
|
+
}
|
|
2202
|
+
/** PATCH /:id — only the fields sent change. `active: false` switches the form off. */
|
|
2203
|
+
async update(id, input) {
|
|
2204
|
+
return this.http.request({
|
|
2205
|
+
method: "PATCH",
|
|
2206
|
+
path: `/admin/web-forms/${encodeURIComponent(id)}`,
|
|
2207
|
+
body: input
|
|
2208
|
+
});
|
|
2209
|
+
}
|
|
2210
|
+
/** DELETE /:id — archive: the public URL stops working and routing stops. Returns `{ id }`. */
|
|
2211
|
+
async archive(id) {
|
|
2212
|
+
return this.http.request({ method: "DELETE", path: `/admin/web-forms/${encodeURIComponent(id)}` });
|
|
2213
|
+
}
|
|
2214
|
+
/** POST /:id/rotate-key — a new public key; the old embed stops working at once. */
|
|
2215
|
+
async rotateKey(id) {
|
|
2216
|
+
return this.http.request({
|
|
2217
|
+
method: "POST",
|
|
2218
|
+
path: `/admin/web-forms/${encodeURIComponent(id)}/rotate-key`
|
|
2219
|
+
});
|
|
2220
|
+
}
|
|
2221
|
+
};
|
|
2222
|
+
var WebFormSubmissionsResource = class {
|
|
2223
|
+
constructor(http2) {
|
|
2224
|
+
this.http = http2;
|
|
2225
|
+
}
|
|
2226
|
+
/** GET /submissions — the first page, newest first, with routing state. Use `listPage` to read on. */
|
|
2227
|
+
async list(params = {}) {
|
|
2228
|
+
return (await this.listPage(params)).data;
|
|
2229
|
+
}
|
|
2230
|
+
/**
|
|
2231
|
+
* GET /submissions — one page plus `next`, which is null on the last page.
|
|
2232
|
+
* Pass `next`'s `before` and `before_id` back in to read the following page.
|
|
2233
|
+
*/
|
|
2234
|
+
async listPage(params = {}) {
|
|
2235
|
+
const query = {};
|
|
2236
|
+
for (const [k, v] of Object.entries(params)) if (v !== void 0) query[k] = v;
|
|
2237
|
+
const res = await this.http.request({
|
|
2238
|
+
method: "GET",
|
|
2239
|
+
path: "/admin/web-forms/submissions",
|
|
2240
|
+
params: query
|
|
2241
|
+
});
|
|
2242
|
+
return { data: res.data, next: res.next ?? null };
|
|
2243
|
+
}
|
|
2244
|
+
/** GET /submissions/:id — answers as seen, plus each routing step. */
|
|
2245
|
+
async get(id) {
|
|
2246
|
+
return this.http.request({
|
|
2247
|
+
method: "GET",
|
|
2248
|
+
path: `/admin/web-forms/submissions/${encodeURIComponent(id)}`
|
|
2249
|
+
});
|
|
2250
|
+
}
|
|
2251
|
+
/** PATCH /submissions/:id — set triage status. */
|
|
2252
|
+
async update(id, input) {
|
|
2253
|
+
return this.http.request({
|
|
2254
|
+
method: "PATCH",
|
|
2255
|
+
path: `/admin/web-forms/submissions/${encodeURIComponent(id)}`,
|
|
2256
|
+
body: input
|
|
2257
|
+
});
|
|
2258
|
+
}
|
|
2259
|
+
/** POST /submissions/:id/route — retry failed steps, run never-run ones (not email, text or webhook: `skipped`); safe to repeat. */
|
|
2260
|
+
async route(id) {
|
|
2261
|
+
return this.http.request({
|
|
2262
|
+
method: "POST",
|
|
2263
|
+
path: `/admin/web-forms/submissions/${encodeURIComponent(id)}/route`
|
|
2264
|
+
});
|
|
2265
|
+
}
|
|
2266
|
+
};
|
|
2267
|
+
|
|
2268
|
+
// src/resources/contact-sequences.ts
|
|
2269
|
+
var ContactSequencesResource = class {
|
|
2270
|
+
constructor(http2) {
|
|
2271
|
+
this.http = http2;
|
|
2272
|
+
this.basePath = "/contact-sequences";
|
|
2273
|
+
}
|
|
2274
|
+
/** GET /contact-sequences — `{ data, meta: { total } }`, name-sorted, max 100. */
|
|
2275
|
+
async list() {
|
|
2276
|
+
return this.http.request({
|
|
2277
|
+
method: "GET",
|
|
2278
|
+
path: this.basePath
|
|
2279
|
+
});
|
|
2280
|
+
}
|
|
2281
|
+
};
|
|
2282
|
+
|
|
2283
|
+
// src/resources/enrollments.ts
|
|
2284
|
+
var EnrollmentsResource = class {
|
|
2285
|
+
constructor(http2) {
|
|
2286
|
+
this.http = http2;
|
|
2287
|
+
}
|
|
2288
|
+
/**
|
|
2289
|
+
* POST /contacts/:id/enrollments — `{ workflow_id }`. 409 if the contact is
|
|
2290
|
+
* already active in the sequence; 422 if the sequence has no published version.
|
|
2291
|
+
*/
|
|
2292
|
+
async enroll(contactId, workflowId) {
|
|
2293
|
+
return this.http.request({
|
|
2294
|
+
method: "POST",
|
|
2295
|
+
path: `/contacts/${contactId}/enrollments`,
|
|
2296
|
+
body: { workflow_id: workflowId }
|
|
2297
|
+
});
|
|
2298
|
+
}
|
|
2299
|
+
/** GET /contacts/:id/enrollments — a bare array, newest first; optional `status` filter. */
|
|
2300
|
+
async list(contactId, params) {
|
|
2301
|
+
return this.http.request({
|
|
2302
|
+
method: "GET",
|
|
2303
|
+
path: `/contacts/${contactId}/enrollments`,
|
|
2304
|
+
...params ? { params } : {}
|
|
2305
|
+
});
|
|
2306
|
+
}
|
|
2307
|
+
/**
|
|
2308
|
+
* POST /enrollments/:id/exit — no body; the exit reason is recorded as
|
|
2309
|
+
* `'manual'`. Idempotent: an already-ended enrollment is returned unchanged.
|
|
2310
|
+
*/
|
|
2311
|
+
async exit(enrollmentId) {
|
|
2312
|
+
return this.http.request({
|
|
2313
|
+
method: "POST",
|
|
2314
|
+
path: `/enrollments/${enrollmentId}/exit`
|
|
2315
|
+
});
|
|
2316
|
+
}
|
|
2317
|
+
};
|
|
2318
|
+
|
|
2319
|
+
// src/resources/workflow-event-rules.ts
|
|
2320
|
+
var WorkflowEventRulesResource = class {
|
|
2321
|
+
constructor(http2, workflowId) {
|
|
2322
|
+
this.http = http2;
|
|
2323
|
+
this.workflowId = workflowId;
|
|
2324
|
+
}
|
|
2325
|
+
// Each request spells its path out in full (no computed base path) so the
|
|
2326
|
+
// API's SDK route-parity audit (sdk-route-parity-audit.spec.ts) can read it.
|
|
2327
|
+
/** GET — a bare array of the workflow's live rules, newest first. 404 `WORKFLOW_NOT_FOUND`. */
|
|
2328
|
+
async list() {
|
|
2329
|
+
return this.http.request({
|
|
2330
|
+
method: "GET",
|
|
2331
|
+
path: `/admin/workflows/${encodeURIComponent(this.workflowId)}/event-rules`
|
|
2332
|
+
});
|
|
2333
|
+
}
|
|
2334
|
+
/**
|
|
2335
|
+
* POST — add a rule (201). `when` defaults to `{}` and `enabled` to true; use
|
|
2336
|
+
* `when: {}` for the creation types in `WORKFLOW_EVENT_RULE_MATCH_ALL_EVENT_TYPES`.
|
|
2337
|
+
* 400 `VALIDATION_FAILED` for a bad body; 404 `WORKFLOW_NOT_FOUND`.
|
|
2338
|
+
*/
|
|
2339
|
+
async create(input) {
|
|
2340
|
+
return this.http.request({
|
|
2341
|
+
method: "POST",
|
|
2342
|
+
path: `/admin/workflows/${encodeURIComponent(this.workflowId)}/event-rules`,
|
|
2343
|
+
body: input
|
|
2344
|
+
});
|
|
2345
|
+
}
|
|
2346
|
+
/** PATCH /:id — only the fields sent change (at least one). 404 `EVENT_RULE_NOT_FOUND`. */
|
|
2347
|
+
async update(ruleId, input) {
|
|
2348
|
+
return this.http.request({
|
|
2349
|
+
method: "PATCH",
|
|
2350
|
+
path: `/admin/workflows/${encodeURIComponent(this.workflowId)}/event-rules/${encodeURIComponent(ruleId)}`,
|
|
2351
|
+
body: input
|
|
2352
|
+
});
|
|
2353
|
+
}
|
|
2354
|
+
/** DELETE /:id — soft delete; returns `{ id }` (200). 404 `EVENT_RULE_NOT_FOUND`. */
|
|
2355
|
+
async delete(ruleId) {
|
|
2356
|
+
return this.http.request({
|
|
2357
|
+
method: "DELETE",
|
|
2358
|
+
path: `/admin/workflows/${encodeURIComponent(this.workflowId)}/event-rules/${encodeURIComponent(ruleId)}`
|
|
2359
|
+
});
|
|
2360
|
+
}
|
|
2361
|
+
};
|
|
2362
|
+
|
|
2363
|
+
// src/resources/workflows.ts
|
|
2364
|
+
var WorkflowsResource = class {
|
|
2365
|
+
constructor(http2) {
|
|
2366
|
+
this.http = http2;
|
|
2367
|
+
this.basePath = "/workflows";
|
|
2368
|
+
this.adminPath = "/admin/workflows";
|
|
2369
|
+
}
|
|
2370
|
+
/**
|
|
2371
|
+
* GET /workflows/:id/stages — the ordered stages of one workflow version. Pass
|
|
2372
|
+
* a record's instance `workflowId` (e.g. from `GET /opportunities/:id/workflow`)
|
|
2373
|
+
* to get the stages of the version that record is pinned to, even an archived
|
|
2374
|
+
* one. 404 for an unknown or draft id; 403 if the caller cannot read the
|
|
2375
|
+
* workflow's record type.
|
|
2376
|
+
*/
|
|
2377
|
+
async getStages(workflowId) {
|
|
2378
|
+
return this.http.request({
|
|
2379
|
+
method: "GET",
|
|
2380
|
+
path: `${this.basePath}/${encodeURIComponent(workflowId)}/stages`
|
|
2381
|
+
});
|
|
2382
|
+
}
|
|
2383
|
+
/**
|
|
2384
|
+
* GET /workflows/transitions — transition summaries of every published
|
|
2385
|
+
* workflow, or with `workflowId` of that one version (published or archived;
|
|
2386
|
+
* an unknown, draft or other-tenant id returns an empty list). Each summary
|
|
2387
|
+
* carries `workflow_id`, `workflow_version`, `lineage_workflow_id` and
|
|
2388
|
+
* `automatic_only`. Only pipelines whose record type the caller can read
|
|
2389
|
+
* are listed; an unreadable `workflowId` returns an empty list, not 403.
|
|
2390
|
+
*/
|
|
2391
|
+
async listTransitions(params = {}) {
|
|
2392
|
+
const query = {};
|
|
2393
|
+
if (params.entityTypes && params.entityTypes.length > 0) query["entity_types"] = params.entityTypes.join(",");
|
|
2394
|
+
if (params.workflowId) query["workflow_id"] = params.workflowId;
|
|
2395
|
+
return this.http.request({
|
|
2396
|
+
method: "GET",
|
|
2397
|
+
path: `${this.basePath}/transitions`,
|
|
2398
|
+
params: query
|
|
2399
|
+
});
|
|
2400
|
+
}
|
|
2401
|
+
/**
|
|
2402
|
+
* POST /admin/workflows/:wid/transitions — add a transition to a draft
|
|
2403
|
+
* workflow. Pass `automaticOnly: true` for an edge only automation should
|
|
2404
|
+
* fire (e.g. an event rule advancing on "contract sent").
|
|
2405
|
+
*/
|
|
2406
|
+
async createTransition(workflowId, input) {
|
|
2407
|
+
return this.http.request({
|
|
2408
|
+
method: "POST",
|
|
2409
|
+
path: `${this.adminPath}/${encodeURIComponent(workflowId)}/transitions`,
|
|
2410
|
+
body: input
|
|
2411
|
+
});
|
|
2412
|
+
}
|
|
2413
|
+
/**
|
|
2414
|
+
* The event rules of one workflow (`/admin/workflows/:wid/event-rules`) —
|
|
2415
|
+
* "advance automatically when…". Any version's id works; rules are keyed by
|
|
2416
|
+
* the lineage root.
|
|
2417
|
+
*/
|
|
2418
|
+
eventRules(workflowId) {
|
|
2419
|
+
return new WorkflowEventRulesResource(this.http, workflowId);
|
|
2420
|
+
}
|
|
2421
|
+
/** PUT /admin/workflows/:wid/transitions/:tid — update a draft workflow's transition. */
|
|
2422
|
+
async updateTransition(workflowId, transitionId, input) {
|
|
2423
|
+
return this.http.request({
|
|
2424
|
+
method: "PUT",
|
|
2425
|
+
path: `${this.adminPath}/${encodeURIComponent(workflowId)}/transitions/${encodeURIComponent(transitionId)}`,
|
|
2426
|
+
body: input
|
|
2427
|
+
});
|
|
2428
|
+
}
|
|
2429
|
+
};
|
|
2430
|
+
|
|
2431
|
+
// src/resources/service-schedules.ts
|
|
2432
|
+
var ServiceSchedulesResource = class {
|
|
2433
|
+
constructor(http2) {
|
|
2434
|
+
this.http = http2;
|
|
2435
|
+
}
|
|
2436
|
+
// Each request spells its path out in full (no computed base path) so the
|
|
2437
|
+
// API's SDK route-parity audit (sdk-route-parity-audit.spec.ts) can read it.
|
|
2438
|
+
/** GET — the schedules of one customer or opportunity. */
|
|
2439
|
+
async list(subject_type, subject_id) {
|
|
2440
|
+
return this.http.request({
|
|
2441
|
+
method: "GET",
|
|
2442
|
+
path: "/service-schedules",
|
|
2443
|
+
params: { subject_type, subject_id }
|
|
2444
|
+
});
|
|
2445
|
+
}
|
|
2446
|
+
/** GET /:id — 404 when it doesn't exist or was deleted. */
|
|
2447
|
+
async get(id) {
|
|
2448
|
+
return this.http.request({
|
|
2449
|
+
method: "GET",
|
|
2450
|
+
path: `/service-schedules/${encodeURIComponent(id)}`
|
|
2451
|
+
});
|
|
2452
|
+
}
|
|
2453
|
+
/**
|
|
2454
|
+
* POST — create (201). The horizon's visits are generated straight away.
|
|
2455
|
+
* 400 `INVALID_RECURRENCE_RULE`, `SERVICE_TRADE_REQUIRED` or a validation error.
|
|
2456
|
+
*/
|
|
2457
|
+
async create(input) {
|
|
2458
|
+
return this.http.request({
|
|
2459
|
+
method: "POST",
|
|
2460
|
+
path: "/service-schedules",
|
|
2461
|
+
body: input
|
|
2462
|
+
});
|
|
2463
|
+
}
|
|
2464
|
+
/**
|
|
2465
|
+
* PATCH /:id — only the fields sent change. A cadence, time, crew, duration
|
|
2466
|
+
* or horizon change regenerates future visits from today (`effective_from`,
|
|
2467
|
+
* which must be today) and reports it in `regeneration`; a visit someone changed is never
|
|
2468
|
+
* touched and is listed under `regeneration.protected`. The edit and its
|
|
2469
|
+
* regeneration succeed or fail together. 400 `INVALID_EFFECTIVE_FROM` for any
|
|
2470
|
+
* date but today.
|
|
2471
|
+
*/
|
|
2472
|
+
async update(id, input) {
|
|
2473
|
+
return this.http.request({
|
|
2474
|
+
method: "PATCH",
|
|
2475
|
+
path: `/service-schedules/${encodeURIComponent(id)}`,
|
|
2476
|
+
body: input
|
|
2477
|
+
});
|
|
2478
|
+
}
|
|
2479
|
+
/** POST /:id/preview-update — what `update` with the same input would do. Writes nothing. */
|
|
2480
|
+
async previewUpdate(id, input) {
|
|
2481
|
+
return this.http.request({
|
|
2482
|
+
method: "POST",
|
|
2483
|
+
path: `/service-schedules/${encodeURIComponent(id)}/preview-update`,
|
|
2484
|
+
body: input
|
|
2485
|
+
});
|
|
2486
|
+
}
|
|
2487
|
+
/** PATCH /:id/status — pause, resume (`active`) or end. Resume generates the horizon at once. */
|
|
2488
|
+
async setStatus(id, status) {
|
|
2489
|
+
return this.http.request({
|
|
2490
|
+
method: "PATCH",
|
|
2491
|
+
path: `/service-schedules/${encodeURIComponent(id)}/status`,
|
|
2492
|
+
body: { status }
|
|
2493
|
+
});
|
|
2494
|
+
}
|
|
2495
|
+
/** DELETE /:id — soft-delete (204). */
|
|
2496
|
+
async delete(id) {
|
|
2497
|
+
await this.http.request({
|
|
2498
|
+
method: "DELETE",
|
|
2499
|
+
path: `/service-schedules/${encodeURIComponent(id)}`
|
|
2500
|
+
});
|
|
2501
|
+
}
|
|
2502
|
+
/**
|
|
2503
|
+
* POST /conflicts/preview — before booking people, see who is already on
|
|
2504
|
+
* another event (`conflicts`) and who would be outside their working hours
|
|
2505
|
+
* (`working_hours`). Read-only and warn-only: nothing is ever blocked. Give
|
|
2506
|
+
* exactly one of `windows` (single booking) or `schedule` (a cadence). 400 on
|
|
2507
|
+
* invalid input, INVALID_RECURRENCE_RULE, INVALID_TIMEZONE or
|
|
2508
|
+
* TOO_MANY_WINDOWS (> 400).
|
|
2509
|
+
*/
|
|
2510
|
+
async previewConflicts(request) {
|
|
2511
|
+
return this.http.request({
|
|
2512
|
+
method: "POST",
|
|
2513
|
+
path: "/service-schedules/conflicts/preview",
|
|
2514
|
+
body: request
|
|
2515
|
+
});
|
|
2516
|
+
}
|
|
2517
|
+
/** GET /settings/crew-roles — which agent roles count as assignable crew. */
|
|
2518
|
+
async getCrewRoles() {
|
|
2519
|
+
return this.http.request({
|
|
2520
|
+
method: "GET",
|
|
2521
|
+
path: "/service-schedules/settings/crew-roles"
|
|
2522
|
+
});
|
|
2523
|
+
}
|
|
2524
|
+
/** PUT /settings/crew-roles — set the assignable roles (an override of the default). */
|
|
2525
|
+
async setCrewRoles(roles) {
|
|
2526
|
+
return this.http.request({
|
|
2527
|
+
method: "PUT",
|
|
2528
|
+
path: "/service-schedules/settings/crew-roles",
|
|
2529
|
+
body: { roles }
|
|
2530
|
+
});
|
|
2531
|
+
}
|
|
2532
|
+
/** GET /settings/crew — assignable crew with their home-base status. */
|
|
2533
|
+
async listCrew() {
|
|
2534
|
+
const res = await this.http.request({
|
|
2535
|
+
method: "GET",
|
|
2536
|
+
path: "/service-schedules/settings/crew"
|
|
2537
|
+
});
|
|
2538
|
+
return res.crew;
|
|
2539
|
+
}
|
|
2540
|
+
/** PUT /settings/crew/:agentId/home-address — set and geocode a crew member's home base. */
|
|
2541
|
+
async setCrewHomeAddress(agentId, address) {
|
|
2542
|
+
return this.http.request({
|
|
2543
|
+
method: "PUT",
|
|
2544
|
+
path: `/service-schedules/settings/crew/${encodeURIComponent(agentId)}/home-address`,
|
|
2545
|
+
body: { address }
|
|
2546
|
+
});
|
|
2547
|
+
}
|
|
2548
|
+
};
|
|
2549
|
+
|
|
2550
|
+
// src/resources/billing-schedules.ts
|
|
2551
|
+
var BillingScheduleResource = class extends BaseResource {
|
|
2552
|
+
constructor(http2) {
|
|
2553
|
+
super(http2, "/admin/billing-schedules");
|
|
2554
|
+
}
|
|
2555
|
+
/** GET /admin/billing-schedules — list rows (no lines; `line_count` and `next_amount` instead). */
|
|
2556
|
+
async list(params) {
|
|
2557
|
+
return this.http.request({
|
|
2558
|
+
method: "GET",
|
|
2559
|
+
path: this.basePath,
|
|
2560
|
+
params: toQueryParams(params)
|
|
2561
|
+
});
|
|
2562
|
+
}
|
|
2563
|
+
/** GET /admin/billing-schedules/:id — the schedule with its lines and next 3 periods. */
|
|
2564
|
+
async get(id) {
|
|
2565
|
+
return this.http.request({
|
|
2566
|
+
method: "GET",
|
|
2567
|
+
path: `${this.basePath}/${encodeURIComponent(id)}`
|
|
2568
|
+
});
|
|
2569
|
+
}
|
|
2570
|
+
/**
|
|
2571
|
+
* POST /admin/billing-schedules. `timezone` defaults to the tenant's. A
|
|
2572
|
+
* backdated `start_date` needs `backfill` ('skip' | 'draft'), else 400
|
|
2573
|
+
* `BACKFILL_REQUIRED`; `collection: 'autopay'` without a platform-managed
|
|
2574
|
+
* Stripe connection and a saved default card is 422 `AUTOPAY_UNAVAILABLE`
|
|
2575
|
+
* (`reason` `no_connect` | `no_saved_method`).
|
|
2576
|
+
*/
|
|
2577
|
+
async create(data) {
|
|
2578
|
+
return this.http.request({
|
|
2579
|
+
method: "POST",
|
|
2580
|
+
path: this.basePath,
|
|
2581
|
+
body: data
|
|
2582
|
+
});
|
|
2583
|
+
}
|
|
2584
|
+
/**
|
|
2585
|
+
* PATCH /admin/billing-schedules/:id — partial. `lines` replaces every line
|
|
2586
|
+
* from `effective_from` (default: the next period not yet invoiced) as a new
|
|
2587
|
+
* line version. 409 `CADENCE_LOCKED`; 422 `EFFECTIVE_DATE_IN_GENERATED_PERIOD`
|
|
2588
|
+
* for a date inside an invoiced period.
|
|
2589
|
+
*/
|
|
2590
|
+
async update(id, data) {
|
|
2591
|
+
return this.http.request({
|
|
2592
|
+
method: "PATCH",
|
|
2593
|
+
path: `${this.basePath}/${encodeURIComponent(id)}`,
|
|
2594
|
+
body: data
|
|
2595
|
+
});
|
|
2596
|
+
}
|
|
2597
|
+
/** DELETE /admin/billing-schedules/:id — only a schedule that never invoiced (else 409 `SCHEDULE_HAS_INVOICES`). */
|
|
2598
|
+
async delete(id) {
|
|
2599
|
+
await this.http.request({
|
|
2600
|
+
method: "DELETE",
|
|
2601
|
+
path: `${this.basePath}/${encodeURIComponent(id)}`
|
|
2602
|
+
});
|
|
2603
|
+
}
|
|
2604
|
+
/** GET /admin/billing-schedules/:id/versions — line version history, newest effective date first. */
|
|
2605
|
+
async listVersions(id) {
|
|
2606
|
+
return this.http.request({
|
|
2607
|
+
method: "GET",
|
|
2608
|
+
path: `${this.basePath}/${encodeURIComponent(id)}/versions`
|
|
2609
|
+
});
|
|
2610
|
+
}
|
|
2611
|
+
/**
|
|
2612
|
+
* POST /admin/billing-schedules/:id/adjustments — add a one-off amount
|
|
2613
|
+
* (signed; negative is a credit) to the schedule's next generated invoice.
|
|
2614
|
+
* Billed exactly once; no automatic proration. 422 `ADJUSTMENT_INVALID`
|
|
2615
|
+
* (zero, or the next invoice would go below zero) or `SCHEDULE_NOT_ACTIVE`.
|
|
2616
|
+
*/
|
|
2617
|
+
async addAdjustment(id, data) {
|
|
2618
|
+
return this.http.request({
|
|
2619
|
+
method: "POST",
|
|
2620
|
+
path: `${this.basePath}/${encodeURIComponent(id)}/adjustments`,
|
|
2621
|
+
body: data
|
|
2622
|
+
});
|
|
2623
|
+
}
|
|
2624
|
+
/** GET /admin/billing-schedules/:id/adjustments — oldest first; default pending and consumed. */
|
|
2625
|
+
async listAdjustments(id, params) {
|
|
2626
|
+
return this.http.request({
|
|
2627
|
+
method: "GET",
|
|
2628
|
+
path: `${this.basePath}/${encodeURIComponent(id)}/adjustments`,
|
|
2629
|
+
params: toQueryParams(params)
|
|
2630
|
+
});
|
|
2631
|
+
}
|
|
2632
|
+
/**
|
|
2633
|
+
* DELETE /admin/billing-schedules/:id/adjustments/:adjustmentId — cancel a
|
|
2634
|
+
* pending adjustment (it never bills). Returns it; 409
|
|
2635
|
+
* `ADJUSTMENT_ALREADY_CONSUMED` once an invoice carries it.
|
|
2636
|
+
*/
|
|
2637
|
+
async cancelAdjustment(id, adjustmentId) {
|
|
2638
|
+
return this.http.request({
|
|
2639
|
+
method: "DELETE",
|
|
2640
|
+
path: `${this.basePath}/${encodeURIComponent(id)}/adjustments/${encodeURIComponent(adjustmentId)}`
|
|
2641
|
+
});
|
|
2642
|
+
}
|
|
2643
|
+
/** POST /admin/billing-schedules/:id/pause — 409 `INVALID_STATUS_TRANSITION` unless active. */
|
|
2644
|
+
async pause(id) {
|
|
2645
|
+
return this.http.request({
|
|
2646
|
+
method: "POST",
|
|
2647
|
+
path: `${this.basePath}/${encodeURIComponent(id)}/pause`
|
|
2648
|
+
});
|
|
2649
|
+
}
|
|
2650
|
+
/** POST /admin/billing-schedules/:id/resume — periods that fell due while paused are skipped. */
|
|
2651
|
+
async resume(id) {
|
|
2652
|
+
return this.http.request({
|
|
2653
|
+
method: "POST",
|
|
2654
|
+
path: `${this.basePath}/${encodeURIComponent(id)}/resume`
|
|
2655
|
+
});
|
|
2656
|
+
}
|
|
2657
|
+
/** POST /admin/billing-schedules/:id/end — no further periods generate. */
|
|
2658
|
+
async end(id) {
|
|
2659
|
+
return this.http.request({
|
|
2660
|
+
method: "POST",
|
|
2661
|
+
path: `${this.basePath}/${encodeURIComponent(id)}/end`
|
|
2662
|
+
});
|
|
2663
|
+
}
|
|
2664
|
+
/** GET /admin/billing-schedules/:id/preview — the next `count` (1–24, default 6) periods from the first unbilled one. */
|
|
2665
|
+
async preview(id, params) {
|
|
2666
|
+
return this.http.request({
|
|
2667
|
+
method: "GET",
|
|
2668
|
+
path: `${this.basePath}/${encodeURIComponent(id)}/preview`,
|
|
2669
|
+
params: toQueryParams(params)
|
|
2670
|
+
});
|
|
2671
|
+
}
|
|
2672
|
+
/** GET /admin/billing-schedules/:id/periods — the period ledger, newest first. */
|
|
2673
|
+
async periods(id, params) {
|
|
2674
|
+
return this.http.request({
|
|
2675
|
+
method: "GET",
|
|
2676
|
+
path: `${this.basePath}/${encodeURIComponent(id)}/periods`,
|
|
2677
|
+
params: toQueryParams(params)
|
|
2678
|
+
});
|
|
2679
|
+
}
|
|
2680
|
+
/**
|
|
2681
|
+
* GET /admin/billing-schedules/periods/needs-review — tenant-wide: needs_review
|
|
2682
|
+
* rows plus failed and stuck (pending over 2h) deliveries.
|
|
2683
|
+
*/
|
|
2684
|
+
async needsReview(params) {
|
|
2685
|
+
return this.http.request({
|
|
2686
|
+
method: "GET",
|
|
2687
|
+
path: `${this.basePath}/periods/needs-review`,
|
|
2688
|
+
params: toQueryParams(params)
|
|
2689
|
+
});
|
|
2690
|
+
}
|
|
2691
|
+
/**
|
|
2692
|
+
* GET /admin/billing-schedules/autopay-summary — what disconnecting Stripe
|
|
2693
|
+
* would touch: live autopay schedules, the distinct customers on them, and
|
|
2694
|
+
* active saved cards on the current Stripe connection. On disconnect, autopay
|
|
2695
|
+
* schedules that can no longer charge switch to emailed pay links.
|
|
2696
|
+
*/
|
|
2697
|
+
async autopaySummary() {
|
|
2698
|
+
return this.http.request({
|
|
2699
|
+
method: "GET",
|
|
2700
|
+
path: `${this.basePath}/autopay-summary`
|
|
2701
|
+
});
|
|
2702
|
+
}
|
|
2703
|
+
/**
|
|
2704
|
+
* POST /admin/billing-schedules/:id/generate-now — bill the current due
|
|
2705
|
+
* period now. Idempotent (`already_generated`); 409 `NOTHING_DUE` or
|
|
2706
|
+
* `SCHEDULE_NOT_ACTIVE`.
|
|
2707
|
+
*/
|
|
2708
|
+
async generateNow(id) {
|
|
2709
|
+
return this.http.request({
|
|
2710
|
+
method: "POST",
|
|
2711
|
+
path: `${this.basePath}/${encodeURIComponent(id)}/generate-now`
|
|
2712
|
+
});
|
|
2713
|
+
}
|
|
2714
|
+
/**
|
|
2715
|
+
* POST /admin/billing-schedules/:id/periods/:periodStart/skip — skip one
|
|
2716
|
+
* period (`periodStart` is `YYYY-MM-DD`). Returns the skipped ledger row;
|
|
2717
|
+
* 400 `NOT_A_PERIOD`, 409 `PERIOD_ALREADY_INVOICED`.
|
|
2718
|
+
*/
|
|
2719
|
+
async skipPeriod(id, periodStart, data = {}) {
|
|
2720
|
+
return this.http.request({
|
|
2721
|
+
method: "POST",
|
|
2722
|
+
path: `${this.basePath}/${encodeURIComponent(id)}/periods/${encodeURIComponent(periodStart)}/skip`,
|
|
2723
|
+
body: data
|
|
2724
|
+
});
|
|
2725
|
+
}
|
|
2726
|
+
/**
|
|
2727
|
+
* POST /admin/billing-schedules/:id/periods/:periodStart/regenerate — re-bill
|
|
2728
|
+
* a period whose invoice was voided (new draft on the same ledger row).
|
|
2729
|
+
* 409 `INVOICE_NOT_VOID` or `CHECKOUT_IN_FLIGHT`.
|
|
2730
|
+
*/
|
|
2731
|
+
async regeneratePeriod(id, periodStart) {
|
|
2732
|
+
return this.http.request({
|
|
2733
|
+
method: "POST",
|
|
2734
|
+
path: `${this.basePath}/${encodeURIComponent(id)}/periods/${encodeURIComponent(periodStart)}/regenerate`
|
|
2735
|
+
});
|
|
428
2736
|
}
|
|
429
2737
|
};
|
|
430
2738
|
|
|
431
|
-
// src/resources/
|
|
432
|
-
var
|
|
433
|
-
constructor(http2
|
|
2739
|
+
// src/resources/custom-fields.ts
|
|
2740
|
+
var CustomFieldsResource = class {
|
|
2741
|
+
constructor(http2) {
|
|
434
2742
|
this.http = http2;
|
|
435
|
-
this.basePath = basePath;
|
|
436
2743
|
}
|
|
437
|
-
/**
|
|
438
|
-
* List entities with optional filters and pagination.
|
|
439
|
-
*/
|
|
2744
|
+
/** List definitions, optionally narrowed to one entity type. */
|
|
440
2745
|
async list(params) {
|
|
441
2746
|
return this.http.request({
|
|
442
2747
|
method: "GET",
|
|
443
|
-
path:
|
|
2748
|
+
path: "/custom-fields",
|
|
444
2749
|
params
|
|
445
2750
|
});
|
|
446
2751
|
}
|
|
447
|
-
/**
|
|
448
|
-
|
|
449
|
-
|
|
2752
|
+
/** GET /admin/custom-fields — the same list through the admin route (Manage grant). */
|
|
2753
|
+
async listAll(params) {
|
|
2754
|
+
return this.http.request({
|
|
2755
|
+
method: "GET",
|
|
2756
|
+
path: "/admin/custom-fields",
|
|
2757
|
+
params
|
|
2758
|
+
});
|
|
2759
|
+
}
|
|
2760
|
+
/** GET /admin/custom-fields/:id */
|
|
450
2761
|
async get(id) {
|
|
451
2762
|
return this.http.request({
|
|
452
2763
|
method: "GET",
|
|
453
|
-
path:
|
|
2764
|
+
path: `/admin/custom-fields/${id}`
|
|
454
2765
|
});
|
|
455
2766
|
}
|
|
456
2767
|
/**
|
|
457
|
-
*
|
|
2768
|
+
* POST /admin/custom-fields — define a new field. 400 for `job`, `vendor` or
|
|
2769
|
+
* `agent` (those records can't hold values yet, PRD D6). A `fieldKey` must be
|
|
2770
|
+
* unique per entity type: check `listAll({ entity_type, include_inactive: true })` first.
|
|
458
2771
|
*/
|
|
459
2772
|
async create(data) {
|
|
460
2773
|
return this.http.request({
|
|
461
2774
|
method: "POST",
|
|
462
|
-
path:
|
|
2775
|
+
path: "/admin/custom-fields",
|
|
463
2776
|
body: data
|
|
464
2777
|
});
|
|
465
2778
|
}
|
|
466
|
-
/**
|
|
467
|
-
* Update an existing entity.
|
|
468
|
-
*/
|
|
2779
|
+
/** PATCH /admin/custom-fields/:id — `fieldKey` and `entityType` can't change. */
|
|
469
2780
|
async update(id, data) {
|
|
470
2781
|
return this.http.request({
|
|
471
2782
|
method: "PATCH",
|
|
472
|
-
path:
|
|
2783
|
+
path: `/admin/custom-fields/${id}`,
|
|
473
2784
|
body: data
|
|
474
2785
|
});
|
|
475
2786
|
}
|
|
476
2787
|
/**
|
|
477
|
-
*
|
|
2788
|
+
* DELETE /admin/custom-fields/:id — deactivates the definition (204). Records
|
|
2789
|
+
* keep their stored values; `list({ include_inactive: true })` still shows it,
|
|
2790
|
+
* and `update(id, { active: true })` brings it back.
|
|
478
2791
|
*/
|
|
479
|
-
async
|
|
2792
|
+
async deactivate(id) {
|
|
480
2793
|
await this.http.request({
|
|
481
2794
|
method: "DELETE",
|
|
482
|
-
path:
|
|
2795
|
+
path: `/admin/custom-fields/${id}`
|
|
483
2796
|
});
|
|
484
2797
|
}
|
|
485
2798
|
};
|
|
486
2799
|
|
|
487
|
-
// src/resources/
|
|
488
|
-
var
|
|
489
|
-
constructor(http2) {
|
|
490
|
-
super(http2, "/opportunities");
|
|
491
|
-
}
|
|
492
|
-
};
|
|
493
|
-
|
|
494
|
-
// src/resources/customers.ts
|
|
495
|
-
var CustomerResource = class extends BaseResource {
|
|
496
|
-
constructor(http2) {
|
|
497
|
-
super(http2, "/customers");
|
|
498
|
-
}
|
|
499
|
-
};
|
|
500
|
-
|
|
501
|
-
// src/resources/properties.ts
|
|
502
|
-
var PropertyResource = class extends BaseResource {
|
|
503
|
-
constructor(http2) {
|
|
504
|
-
super(http2, "/properties");
|
|
505
|
-
}
|
|
506
|
-
};
|
|
507
|
-
|
|
508
|
-
// src/resources/calendar-events.ts
|
|
509
|
-
var CalendarEventResource = class extends BaseResource {
|
|
510
|
-
constructor(http2) {
|
|
511
|
-
super(http2, "/calendar-events");
|
|
512
|
-
}
|
|
513
|
-
};
|
|
514
|
-
|
|
515
|
-
// src/resources/contracts.ts
|
|
516
|
-
var ContractResource = class extends BaseResource {
|
|
517
|
-
constructor(http2) {
|
|
518
|
-
super(http2, "/contracts");
|
|
519
|
-
}
|
|
520
|
-
};
|
|
521
|
-
|
|
522
|
-
// src/resources/jobs.ts
|
|
523
|
-
var JobResource = class extends BaseResource {
|
|
524
|
-
constructor(http2) {
|
|
525
|
-
super(http2, "/jobs");
|
|
526
|
-
}
|
|
527
|
-
};
|
|
528
|
-
|
|
529
|
-
// src/resources/estimates.ts
|
|
530
|
-
var EstimateResource = class extends BaseResource {
|
|
531
|
-
constructor(http2) {
|
|
532
|
-
super(http2, "/estimates");
|
|
533
|
-
}
|
|
534
|
-
};
|
|
535
|
-
|
|
536
|
-
// src/resources/invoices.ts
|
|
537
|
-
var InvoiceResource = class extends BaseResource {
|
|
2800
|
+
// src/resources/ortto.ts
|
|
2801
|
+
var OrttoResource = class {
|
|
538
2802
|
constructor(http2) {
|
|
539
|
-
|
|
2803
|
+
this.http = http2;
|
|
2804
|
+
this.basePath = "/admin/integrations/ortto";
|
|
540
2805
|
}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
2806
|
+
/** GET /admin/integrations/ortto/mappings — live mappings with their list names. */
|
|
2807
|
+
async listMappings() {
|
|
2808
|
+
const res = await this.http.request({
|
|
2809
|
+
method: "GET",
|
|
2810
|
+
path: `${this.basePath}/mappings`
|
|
2811
|
+
});
|
|
2812
|
+
return res.data;
|
|
547
2813
|
}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
2814
|
+
/** GET /admin/integrations/ortto/audiences — the connected account's audiences (cached 60 s). */
|
|
2815
|
+
async listAudiences(params) {
|
|
2816
|
+
const res = await this.http.request({
|
|
2817
|
+
method: "GET",
|
|
2818
|
+
path: `${this.basePath}/audiences`,
|
|
2819
|
+
params
|
|
2820
|
+
});
|
|
2821
|
+
return res.data;
|
|
555
2822
|
}
|
|
556
|
-
/**
|
|
557
|
-
async
|
|
558
|
-
|
|
2823
|
+
/** POST /admin/integrations/ortto/mappings — 409 when the list already has a mapping. */
|
|
2824
|
+
async createMapping(data) {
|
|
2825
|
+
const res = await this.http.request({
|
|
559
2826
|
method: "POST",
|
|
560
|
-
path: this.basePath
|
|
2827
|
+
path: `${this.basePath}/mappings`,
|
|
561
2828
|
body: data
|
|
562
2829
|
});
|
|
2830
|
+
return res.data;
|
|
563
2831
|
}
|
|
564
|
-
|
|
565
|
-
|
|
2832
|
+
/** PATCH /admin/integrations/ortto/mappings/:id — `ortto_tag` and/or `create_unmatched`. */
|
|
2833
|
+
async updateMapping(id, data) {
|
|
2834
|
+
const res = await this.http.request({
|
|
566
2835
|
method: "PATCH",
|
|
567
|
-
path: `${this.basePath}/${
|
|
2836
|
+
path: `${this.basePath}/mappings/${id}`,
|
|
568
2837
|
body: data
|
|
569
2838
|
});
|
|
2839
|
+
return res.data;
|
|
570
2840
|
}
|
|
571
|
-
|
|
2841
|
+
/**
|
|
2842
|
+
* DELETE /admin/integrations/ortto/mappings/:id (204). A pull list becomes
|
|
2843
|
+
* editable again and keeps its members; a push tag is NOT removed from Ortto.
|
|
2844
|
+
*/
|
|
2845
|
+
async deleteMapping(id) {
|
|
572
2846
|
await this.http.request({
|
|
573
2847
|
method: "DELETE",
|
|
574
|
-
path: `${this.basePath}/${
|
|
2848
|
+
path: `${this.basePath}/mappings/${id}`
|
|
575
2849
|
});
|
|
576
2850
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
return this.http.request({
|
|
2851
|
+
/**
|
|
2852
|
+
* POST /admin/integrations/ortto/sync (202) — queue a sync for one mapping or
|
|
2853
|
+
* the whole connection. Never calls Ortto in-request.
|
|
2854
|
+
*/
|
|
2855
|
+
async sync(data = {}) {
|
|
2856
|
+
const res = await this.http.request({
|
|
584
2857
|
method: "POST",
|
|
585
|
-
path:
|
|
2858
|
+
path: `${this.basePath}/sync`,
|
|
2859
|
+
body: data
|
|
586
2860
|
});
|
|
2861
|
+
return res.data;
|
|
587
2862
|
}
|
|
588
|
-
|
|
589
|
-
|
|
2863
|
+
/** GET /admin/integrations/ortto/sync-status — 404 when Ortto is not connected. */
|
|
2864
|
+
async syncStatus() {
|
|
2865
|
+
const res = await this.http.request({
|
|
2866
|
+
method: "GET",
|
|
2867
|
+
path: `${this.basePath}/sync-status`
|
|
2868
|
+
});
|
|
2869
|
+
return res.data;
|
|
590
2870
|
}
|
|
591
2871
|
};
|
|
592
2872
|
|
|
593
|
-
// src/resources/
|
|
594
|
-
var
|
|
2873
|
+
// src/resources/webhook-subscriptions.ts
|
|
2874
|
+
var WebhookSubscriptionsResource = class extends ApiResource {
|
|
595
2875
|
constructor(http2) {
|
|
596
|
-
|
|
2876
|
+
super(http2, "/admin/webhooks");
|
|
597
2877
|
}
|
|
2878
|
+
/** POST /admin/webhooks — the returned `secret` is shown only this once. */
|
|
598
2879
|
async create(data) {
|
|
599
|
-
return this.http.request({
|
|
600
|
-
method: "POST",
|
|
601
|
-
path: "/activities",
|
|
602
|
-
body: data
|
|
603
|
-
});
|
|
2880
|
+
return this.http.request({ method: "POST", path: this.basePath, body: data });
|
|
604
2881
|
}
|
|
2882
|
+
/** GET /admin/webhooks */
|
|
605
2883
|
async list(params) {
|
|
606
2884
|
return this.http.request({
|
|
607
2885
|
method: "GET",
|
|
608
|
-
path:
|
|
2886
|
+
path: this.basePath,
|
|
609
2887
|
params
|
|
610
2888
|
});
|
|
611
2889
|
}
|
|
612
|
-
|
|
2890
|
+
/** GET /admin/webhooks/:id */
|
|
2891
|
+
async get(id) {
|
|
2892
|
+
return this.http.request({ method: "GET", path: `${this.basePath}/${id}` });
|
|
2893
|
+
}
|
|
2894
|
+
/** PATCH /admin/webhooks/:id */
|
|
2895
|
+
async update(id, data) {
|
|
2896
|
+
return this.http.request({ method: "PATCH", path: `${this.basePath}/${id}`, body: data });
|
|
2897
|
+
}
|
|
2898
|
+
/** DELETE /admin/webhooks/:id */
|
|
2899
|
+
async delete(id) {
|
|
2900
|
+
return this.http.request({ method: "DELETE", path: `${this.basePath}/${id}` });
|
|
2901
|
+
}
|
|
2902
|
+
/** POST /admin/webhooks/:id/test — sends one signed test event to the URL now. */
|
|
2903
|
+
async test(id) {
|
|
2904
|
+
return this.http.request({ method: "POST", path: `${this.basePath}/${id}/test` });
|
|
2905
|
+
}
|
|
2906
|
+
/**
|
|
2907
|
+
* POST /admin/webhooks/:id/rotate-secret — replaces the signing secret and
|
|
2908
|
+
* returns the new one, shown only this once. New deliveries are signed with
|
|
2909
|
+
* it, but deliveries already queued (and their retries, for several minutes)
|
|
2910
|
+
* keep the old one. `verifyWebhookSignature` checks one secret, so for a few
|
|
2911
|
+
* minutes have your receiver try the new secret and fall back to the old one.
|
|
2912
|
+
*/
|
|
2913
|
+
async rotateSecret(id) {
|
|
2914
|
+
return this.http.request({
|
|
2915
|
+
method: "POST",
|
|
2916
|
+
path: `${this.basePath}/${id}/rotate-secret`
|
|
2917
|
+
});
|
|
2918
|
+
}
|
|
2919
|
+
/** GET /admin/webhooks/:id/deliveries — newest first. */
|
|
2920
|
+
async listDeliveries(id, params) {
|
|
613
2921
|
return this.http.request({
|
|
614
2922
|
method: "GET",
|
|
615
|
-
path:
|
|
2923
|
+
path: `${this.basePath}/${id}/deliveries`,
|
|
616
2924
|
params
|
|
617
2925
|
});
|
|
618
2926
|
}
|
|
2927
|
+
/**
|
|
2928
|
+
* POST /admin/webhooks/:id/deliveries/:deliveryId/retry — queues a new
|
|
2929
|
+
* delivery of that event (202). The receiver sees the event again, so make
|
|
2930
|
+
* it idempotent on the event id.
|
|
2931
|
+
*/
|
|
2932
|
+
async retryDelivery(id, deliveryId) {
|
|
2933
|
+
return this.http.request({
|
|
2934
|
+
method: "POST",
|
|
2935
|
+
path: `${this.basePath}/${id}/deliveries/${deliveryId}/retry`
|
|
2936
|
+
});
|
|
2937
|
+
}
|
|
619
2938
|
};
|
|
620
2939
|
|
|
621
|
-
// src/resources/
|
|
622
|
-
var
|
|
2940
|
+
// src/resources/users.ts
|
|
2941
|
+
var UsersResource = class extends ApiResource {
|
|
623
2942
|
constructor(http2) {
|
|
624
|
-
super(http2, "/
|
|
625
|
-
}
|
|
626
|
-
/** `TagsService.setEntityTags()` returns the final tag set wrapped in `{ tags }`. */
|
|
627
|
-
async setEntityTags(entityType, entityId, data) {
|
|
628
|
-
return this.http.request({
|
|
629
|
-
method: "PUT",
|
|
630
|
-
path: `/entities/${entityType}/${entityId}/tags`,
|
|
631
|
-
body: data
|
|
632
|
-
});
|
|
2943
|
+
super(http2, "/users");
|
|
633
2944
|
}
|
|
634
|
-
|
|
2945
|
+
/** GET /users — paged, with email, role, status and org fields (read grant on users). */
|
|
2946
|
+
async list(params) {
|
|
635
2947
|
return this.http.request({
|
|
636
2948
|
method: "GET",
|
|
637
|
-
path:
|
|
2949
|
+
path: this.basePath,
|
|
2950
|
+
params
|
|
638
2951
|
});
|
|
639
2952
|
}
|
|
640
|
-
|
|
2953
|
+
/**
|
|
2954
|
+
* GET /users/directory — active users' ids, names and roles, for pickers and
|
|
2955
|
+
* for resolving an assignee. Every role can read it.
|
|
2956
|
+
*/
|
|
2957
|
+
async directory(params) {
|
|
641
2958
|
return this.http.request({
|
|
642
2959
|
method: "GET",
|
|
643
|
-
path:
|
|
2960
|
+
path: `${this.basePath}/directory`,
|
|
644
2961
|
params
|
|
645
2962
|
});
|
|
646
2963
|
}
|
|
2964
|
+
/**
|
|
2965
|
+
* GET /users/:id/working-hours — the user's own weekly hours and the tenant
|
|
2966
|
+
* default. A non-admin caller may read only their own (403 otherwise).
|
|
2967
|
+
*/
|
|
2968
|
+
async getWorkingHours(id) {
|
|
2969
|
+
return this.http.request({ method: "GET", path: `${this.basePath}/${id}/working-hours` });
|
|
2970
|
+
}
|
|
2971
|
+
};
|
|
2972
|
+
|
|
2973
|
+
// src/resources/teams.ts
|
|
2974
|
+
var TeamsResource = class extends ApiResource {
|
|
2975
|
+
constructor(http2) {
|
|
2976
|
+
super(http2, "/teams");
|
|
2977
|
+
}
|
|
2978
|
+
/** GET /teams — every team, with `member_count`. */
|
|
2979
|
+
async list() {
|
|
2980
|
+
return this.http.request({ method: "GET", path: this.basePath });
|
|
2981
|
+
}
|
|
2982
|
+
/** GET /teams/:id — one team, with `members`. */
|
|
2983
|
+
async get(id) {
|
|
2984
|
+
return this.http.request({ method: "GET", path: `${this.basePath}/${id}` });
|
|
2985
|
+
}
|
|
647
2986
|
};
|
|
648
2987
|
|
|
649
2988
|
// src/webhooks.ts
|
|
650
2989
|
var import_node_crypto2 = require("crypto");
|
|
2990
|
+
var WEBHOOK_EVENT_TYPES = [
|
|
2991
|
+
"created",
|
|
2992
|
+
"updated",
|
|
2993
|
+
"deleted",
|
|
2994
|
+
"status_changed",
|
|
2995
|
+
"entity.tagged",
|
|
2996
|
+
"entity.untagged",
|
|
2997
|
+
"list.member_added",
|
|
2998
|
+
"list.member_removed",
|
|
2999
|
+
"entity.assigned",
|
|
3000
|
+
"entity.unassigned",
|
|
3001
|
+
"team.member_added",
|
|
3002
|
+
"team.member_removed",
|
|
3003
|
+
"task.created",
|
|
3004
|
+
"task.updated",
|
|
3005
|
+
"task.completed",
|
|
3006
|
+
"task.cancelled",
|
|
3007
|
+
"comment.created",
|
|
3008
|
+
"conversation.created",
|
|
3009
|
+
"conversation.matched",
|
|
3010
|
+
"conversation.deleted",
|
|
3011
|
+
"customer.merged",
|
|
3012
|
+
"workflow.instance_moved",
|
|
3013
|
+
"consent.changed",
|
|
3014
|
+
"billing_schedule.period_generated",
|
|
3015
|
+
"billing_schedule.period_needs_review",
|
|
3016
|
+
"billing_schedule.period_delivered",
|
|
3017
|
+
"billing_schedule.period_delivery_failed",
|
|
3018
|
+
"payment.on_void_invoice",
|
|
3019
|
+
"invoice.overdue",
|
|
3020
|
+
"integration_connection.deactivated",
|
|
3021
|
+
"customer_payment_method.invalidated",
|
|
3022
|
+
"invoice.autopay_succeeded",
|
|
3023
|
+
"invoice.autopay_failed",
|
|
3024
|
+
"received"
|
|
3025
|
+
];
|
|
651
3026
|
function verifyWebhookSignature(payload, signature, secret) {
|
|
652
3027
|
if (!signature || !secret || !payload) {
|
|
653
3028
|
return false;
|
|
@@ -817,12 +3192,192 @@ var PlanesClient = class {
|
|
|
817
3192
|
}
|
|
818
3193
|
return this._activities;
|
|
819
3194
|
}
|
|
3195
|
+
get communications() {
|
|
3196
|
+
if (!this._communications) {
|
|
3197
|
+
this._communications = new CommunicationsResource(this.http);
|
|
3198
|
+
}
|
|
3199
|
+
return this._communications;
|
|
3200
|
+
}
|
|
3201
|
+
/** Logged meetings — manual + provider-synced, with company matching (E55). */
|
|
3202
|
+
get conversations() {
|
|
3203
|
+
if (!this._conversations) {
|
|
3204
|
+
this._conversations = new ConversationsResource(this.http);
|
|
3205
|
+
}
|
|
3206
|
+
return this._conversations;
|
|
3207
|
+
}
|
|
3208
|
+
get gmail() {
|
|
3209
|
+
if (!this._gmail) {
|
|
3210
|
+
this._gmail = new GmailResource(this.http);
|
|
3211
|
+
}
|
|
3212
|
+
return this._gmail;
|
|
3213
|
+
}
|
|
3214
|
+
get documents() {
|
|
3215
|
+
if (!this._documents) {
|
|
3216
|
+
this._documents = new DocumentsResource(this.http);
|
|
3217
|
+
}
|
|
3218
|
+
return this._documents;
|
|
3219
|
+
}
|
|
820
3220
|
get tags() {
|
|
821
3221
|
if (!this._tags) {
|
|
822
3222
|
this._tags = new TagResource(this.http);
|
|
823
3223
|
}
|
|
824
3224
|
return this._tags;
|
|
825
3225
|
}
|
|
3226
|
+
get lists() {
|
|
3227
|
+
if (!this._lists) {
|
|
3228
|
+
this._lists = new ListsResource(this.http);
|
|
3229
|
+
}
|
|
3230
|
+
return this._lists;
|
|
3231
|
+
}
|
|
3232
|
+
get leadSources() {
|
|
3233
|
+
if (!this._leadSources) {
|
|
3234
|
+
this._leadSources = new LeadSourcesResource(this.http);
|
|
3235
|
+
}
|
|
3236
|
+
return this._leadSources;
|
|
3237
|
+
}
|
|
3238
|
+
get tasks() {
|
|
3239
|
+
if (!this._tasks) {
|
|
3240
|
+
this._tasks = new TaskResource(this.http);
|
|
3241
|
+
}
|
|
3242
|
+
return this._tasks;
|
|
3243
|
+
}
|
|
3244
|
+
/** Record views — the "recently viewed" beacon + read (E41-F7). */
|
|
3245
|
+
get recordViews() {
|
|
3246
|
+
if (!this._recordViews) {
|
|
3247
|
+
this._recordViews = new RecordViewsResource(this.http);
|
|
3248
|
+
}
|
|
3249
|
+
return this._recordViews;
|
|
3250
|
+
}
|
|
3251
|
+
/** Module status — which modules are active for the caller's tenant (E51-F1-S1). */
|
|
3252
|
+
get modules() {
|
|
3253
|
+
if (!this._modules) {
|
|
3254
|
+
this._modules = new ModulesResource(this.http);
|
|
3255
|
+
}
|
|
3256
|
+
return this._modules;
|
|
3257
|
+
}
|
|
3258
|
+
/** The tenant's plan, billing status and plan ceiling — `plan.get()` (E54-F1-S2). */
|
|
3259
|
+
get plan() {
|
|
3260
|
+
if (!this._plan) {
|
|
3261
|
+
this._plan = new PlanResource(this.http);
|
|
3262
|
+
}
|
|
3263
|
+
return this._plan;
|
|
3264
|
+
}
|
|
3265
|
+
/** The authenticated caller — `me.abilities()` (E52-F1-S3). */
|
|
3266
|
+
get me() {
|
|
3267
|
+
if (!this._me) {
|
|
3268
|
+
this._me = new MeResource(this.http);
|
|
3269
|
+
}
|
|
3270
|
+
return this._me;
|
|
3271
|
+
}
|
|
3272
|
+
/** Settings → Roles, admin only — `roles.list/get/updateGrants/reset/history` (E52-F2-S5). */
|
|
3273
|
+
get roles() {
|
|
3274
|
+
if (!this._roles) {
|
|
3275
|
+
this._roles = new RolesResource(this.http);
|
|
3276
|
+
}
|
|
3277
|
+
return this._roles;
|
|
3278
|
+
}
|
|
3279
|
+
/** Invoice settings — `invoiceSettings.getOfflineInstructions/setOfflineInstructions` (E56-F5-S4). */
|
|
3280
|
+
get invoiceSettings() {
|
|
3281
|
+
if (!this._invoiceSettings) {
|
|
3282
|
+
this._invoiceSettings = new InvoiceSettingsResource(this.http);
|
|
3283
|
+
}
|
|
3284
|
+
return this._invoiceSettings;
|
|
3285
|
+
}
|
|
3286
|
+
/** Payment reminder settings, admin only — `invoiceReminders.list/update/preview` (E56-F8-S6). */
|
|
3287
|
+
get invoiceReminders() {
|
|
3288
|
+
if (!this._invoiceReminders) {
|
|
3289
|
+
this._invoiceReminders = new InvoiceRemindersResource(this.http);
|
|
3290
|
+
}
|
|
3291
|
+
return this._invoiceReminders;
|
|
3292
|
+
}
|
|
3293
|
+
/** Event automations, admin only — `eventAutomations.list/get/create/update/delete` (E60-S2). */
|
|
3294
|
+
get eventAutomations() {
|
|
3295
|
+
if (!this._eventAutomations) {
|
|
3296
|
+
this._eventAutomations = new EventAutomationsResource(this.http);
|
|
3297
|
+
}
|
|
3298
|
+
return this._eventAutomations;
|
|
3299
|
+
}
|
|
3300
|
+
/** Web forms and their submissions, admin only — `webForms.list/get/create/update/archive/rotateKey`, `webForms.submissions.list/get/update/route` (E60-S6). */
|
|
3301
|
+
get webForms() {
|
|
3302
|
+
if (!this._webForms) {
|
|
3303
|
+
this._webForms = new WebFormsResource(this.http);
|
|
3304
|
+
}
|
|
3305
|
+
return this._webForms;
|
|
3306
|
+
}
|
|
3307
|
+
/** Published sequences a contact can be enrolled in (E51-F2-S6). */
|
|
3308
|
+
get contactSequences() {
|
|
3309
|
+
if (!this._contactSequences) {
|
|
3310
|
+
this._contactSequences = new ContactSequencesResource(this.http);
|
|
3311
|
+
}
|
|
3312
|
+
return this._contactSequences;
|
|
3313
|
+
}
|
|
3314
|
+
/** Enroll a contact in a sequence, list its enrollments, exit one (E51-F2-S8). */
|
|
3315
|
+
get enrollments() {
|
|
3316
|
+
if (!this._enrollments) {
|
|
3317
|
+
this._enrollments = new EnrollmentsResource(this.http);
|
|
3318
|
+
}
|
|
3319
|
+
return this._enrollments;
|
|
3320
|
+
}
|
|
3321
|
+
/** Tenant-readable workflow reads — a workflow version's ordered stages. */
|
|
3322
|
+
get workflows() {
|
|
3323
|
+
if (!this._workflows) {
|
|
3324
|
+
this._workflows = new WorkflowsResource(this.http);
|
|
3325
|
+
}
|
|
3326
|
+
return this._workflows;
|
|
3327
|
+
}
|
|
3328
|
+
get serviceSchedules() {
|
|
3329
|
+
if (!this._serviceSchedules) {
|
|
3330
|
+
this._serviceSchedules = new ServiceSchedulesResource(this.http);
|
|
3331
|
+
}
|
|
3332
|
+
return this._serviceSchedules;
|
|
3333
|
+
}
|
|
3334
|
+
/**
|
|
3335
|
+
* Recurring billing schedules (E56-F3) — CRUD, pause/resume/end, preview,
|
|
3336
|
+
* the period ledger, Needs review, generate-now, skip and regenerate.
|
|
3337
|
+
*/
|
|
3338
|
+
get billingSchedules() {
|
|
3339
|
+
if (!this._billingSchedules) {
|
|
3340
|
+
this._billingSchedules = new BillingScheduleResource(this.http);
|
|
3341
|
+
}
|
|
3342
|
+
return this._billingSchedules;
|
|
3343
|
+
}
|
|
3344
|
+
get customFields() {
|
|
3345
|
+
if (!this._customFields) {
|
|
3346
|
+
this._customFields = new CustomFieldsResource(this.http);
|
|
3347
|
+
}
|
|
3348
|
+
return this._customFields;
|
|
3349
|
+
}
|
|
3350
|
+
/** Ortto connector — list mappings, audiences, manual sync, sync status (E53). Admin-only. */
|
|
3351
|
+
get ortto() {
|
|
3352
|
+
if (!this._ortto) {
|
|
3353
|
+
this._ortto = new OrttoResource(this.http);
|
|
3354
|
+
}
|
|
3355
|
+
return this._ortto;
|
|
3356
|
+
}
|
|
3357
|
+
/**
|
|
3358
|
+
* Webhook subscriptions — where entity events are delivered (E64-S10). Admin
|
|
3359
|
+
* grants and the `open_api` feature. Not `webhooks`: that is the event router.
|
|
3360
|
+
*/
|
|
3361
|
+
get webhookSubscriptions() {
|
|
3362
|
+
if (!this._webhookSubscriptions) {
|
|
3363
|
+
this._webhookSubscriptions = new WebhookSubscriptionsResource(this.http);
|
|
3364
|
+
}
|
|
3365
|
+
return this._webhookSubscriptions;
|
|
3366
|
+
}
|
|
3367
|
+
/** The tenant's users, read-only: list and directory (E64-S10). */
|
|
3368
|
+
get users() {
|
|
3369
|
+
if (!this._users) {
|
|
3370
|
+
this._users = new UsersResource(this.http);
|
|
3371
|
+
}
|
|
3372
|
+
return this._users;
|
|
3373
|
+
}
|
|
3374
|
+
/** Teams, read-only (E64-S10). */
|
|
3375
|
+
get teams() {
|
|
3376
|
+
if (!this._teams) {
|
|
3377
|
+
this._teams = new TeamsResource(this.http);
|
|
3378
|
+
}
|
|
3379
|
+
return this._teams;
|
|
3380
|
+
}
|
|
826
3381
|
/**
|
|
827
3382
|
* Ergonomic webhook event router — `client.webhooks.on(pattern, handler)`
|
|
828
3383
|
* plus `client.webhooks.process({ body, signature, secret })`. Auth-independent
|
|
@@ -837,6 +3392,136 @@ var PlanesClient = class {
|
|
|
837
3392
|
}
|
|
838
3393
|
};
|
|
839
3394
|
|
|
3395
|
+
// src/types/billing-schedule-types.ts
|
|
3396
|
+
var BILLING_CADENCES = ["weekly", "every_n_weeks", "monthly", "quarterly", "annually"];
|
|
3397
|
+
var BILLING_SCHEDULE_STATUSES = ["active", "paused", "ended"];
|
|
3398
|
+
var BILL_TIMINGS = ["in_advance", "in_arrears"];
|
|
3399
|
+
var BILLING_DELIVERY_MODES = ["auto_send", "draft_for_review"];
|
|
3400
|
+
var BILLING_COLLECTION_MODES = ["send_link", "autopay"];
|
|
3401
|
+
var AUTOPAY_UNAVAILABLE_REASONS = ["no_connect", "no_saved_method"];
|
|
3402
|
+
var BILLING_AUTOPAY_STATUSES = [
|
|
3403
|
+
"not_applicable",
|
|
3404
|
+
"scheduled",
|
|
3405
|
+
"submitted",
|
|
3406
|
+
"succeeded",
|
|
3407
|
+
"failed",
|
|
3408
|
+
"auth_required",
|
|
3409
|
+
"retry_scheduled",
|
|
3410
|
+
"abandoned"
|
|
3411
|
+
];
|
|
3412
|
+
var BILLING_BACKFILL_MODES = ["skip", "draft"];
|
|
3413
|
+
var BILLING_PERIOD_STATUSES = ["generated", "skipped", "needs_review", "failed", "voided"];
|
|
3414
|
+
var BILLING_PREVIEW_PERIOD_STATUSES = [...BILLING_PERIOD_STATUSES, "upcoming"];
|
|
3415
|
+
var BILLING_DELIVERY_STATUSES = ["pending", "sent", "failed", "not_applicable"];
|
|
3416
|
+
var BILLING_ADJUSTMENT_STATUSES = ["pending", "consumed", "cancelled"];
|
|
3417
|
+
var BILLING_ADJUSTMENT_TARGETS = ["next_invoice"];
|
|
3418
|
+
|
|
3419
|
+
// src/types/contact-types.ts
|
|
3420
|
+
var CONTACT_SORT_KEYS = ["name", "created_at", "recent", "updated_at"];
|
|
3421
|
+
var CONTACT_LIST_INCLUDES = ["channels", "links"];
|
|
3422
|
+
|
|
3423
|
+
// src/types/customer-types.ts
|
|
3424
|
+
var CUSTOMER_SORT_KEYS = ["created_at", "last_name", "first_name", "email", "phone", "source", "recent", "updated_at"];
|
|
3425
|
+
|
|
3426
|
+
// src/types/opportunity-types.ts
|
|
3427
|
+
var OPPORTUNITY_SORT_KEYS = ["created_at", "total", "title", "customer_name", "stage", "priority", "recent", "updated_at"];
|
|
3428
|
+
var OPPORTUNITY_STATES = ["open", "closed", "won", "lost"];
|
|
3429
|
+
|
|
3430
|
+
// src/types/job-types.ts
|
|
3431
|
+
var JOB_SORT_KEYS = ["created_at", "recent"];
|
|
3432
|
+
|
|
3433
|
+
// src/types/estimate-types.ts
|
|
3434
|
+
var ESTIMATE_STATUSES = ["draft", "sent", "approved", "rejected"];
|
|
3435
|
+
|
|
3436
|
+
// src/types/record-view-types.ts
|
|
3437
|
+
var RECORD_VIEW_ENTITY_TYPES = ["customer", "contact", "opportunity", "job"];
|
|
3438
|
+
|
|
3439
|
+
// src/types/module-types.ts
|
|
3440
|
+
var MODULE_KEYS = [
|
|
3441
|
+
"estimates",
|
|
3442
|
+
"contracts",
|
|
3443
|
+
"inventory",
|
|
3444
|
+
"production",
|
|
3445
|
+
"production_scheduling",
|
|
3446
|
+
"calendar",
|
|
3447
|
+
"service-schedules",
|
|
3448
|
+
"marketplace",
|
|
3449
|
+
"invoicing",
|
|
3450
|
+
"knocks",
|
|
3451
|
+
"accounting",
|
|
3452
|
+
"contacts",
|
|
3453
|
+
"tasks",
|
|
3454
|
+
"comments",
|
|
3455
|
+
"conversations",
|
|
3456
|
+
"web_forms"
|
|
3457
|
+
];
|
|
3458
|
+
|
|
3459
|
+
// src/types/plan-types.ts
|
|
3460
|
+
var PLAN_KEYS = ["solo", "sales", "business", "operations", "legacy", "internal"];
|
|
3461
|
+
var BILLING_STATUSES = [
|
|
3462
|
+
"trialing",
|
|
3463
|
+
"active",
|
|
3464
|
+
"past_due",
|
|
3465
|
+
"unpaid",
|
|
3466
|
+
"paused",
|
|
3467
|
+
"canceled",
|
|
3468
|
+
"comped"
|
|
3469
|
+
];
|
|
3470
|
+
var PLAN_SOURCES = ["stripe", "manual"];
|
|
3471
|
+
var BILLING_INTERVALS = ["month", "year"];
|
|
3472
|
+
var FEATURE_KEYS = [
|
|
3473
|
+
"calendar",
|
|
3474
|
+
"estimates",
|
|
3475
|
+
"contracts",
|
|
3476
|
+
"service_dispatch",
|
|
3477
|
+
"production_scheduling",
|
|
3478
|
+
"sub_management",
|
|
3479
|
+
"reports",
|
|
3480
|
+
"open_api",
|
|
3481
|
+
"workflow_builder",
|
|
3482
|
+
"integrations.quickbooks",
|
|
3483
|
+
"integrations.stripe",
|
|
3484
|
+
"integrations.hover",
|
|
3485
|
+
"integrations.ortto",
|
|
3486
|
+
"communications.marketing",
|
|
3487
|
+
"ai.scheduling",
|
|
3488
|
+
"ai.content_assist",
|
|
3489
|
+
"ai.documents",
|
|
3490
|
+
"ai.search",
|
|
3491
|
+
"inventory_management",
|
|
3492
|
+
"workflow_execution",
|
|
3493
|
+
"marketplace"
|
|
3494
|
+
];
|
|
3495
|
+
|
|
3496
|
+
// src/types/me-types.ts
|
|
3497
|
+
var AGENT_ROLES = [
|
|
3498
|
+
"admin",
|
|
3499
|
+
"sales",
|
|
3500
|
+
"service",
|
|
3501
|
+
"production",
|
|
3502
|
+
"sub",
|
|
3503
|
+
"readonly",
|
|
3504
|
+
"system_agent"
|
|
3505
|
+
];
|
|
3506
|
+
|
|
3507
|
+
// src/types/workflow-event-rule-types.ts
|
|
3508
|
+
var WORKFLOW_EVENT_RULE_EVENT_TYPES = [
|
|
3509
|
+
"contract.status_changed",
|
|
3510
|
+
"invoice.status_changed",
|
|
3511
|
+
"calendar_event.status_changed",
|
|
3512
|
+
/** "An event is booked": one-off events and recurring series masters. */
|
|
3513
|
+
"calendar_event.created"
|
|
3514
|
+
];
|
|
3515
|
+
var WORKFLOW_EVENT_RULE_MATCH_ALL_EVENT_TYPES = [
|
|
3516
|
+
"calendar_event.created"
|
|
3517
|
+
];
|
|
3518
|
+
var WORKFLOW_EVENT_RULE_CATCH_UP_EVENT_TYPES = [
|
|
3519
|
+
"calendar_event.created"
|
|
3520
|
+
];
|
|
3521
|
+
|
|
3522
|
+
// src/types/task-types.ts
|
|
3523
|
+
var TASK_SORT_KEYS = ["due_at", "created_at", "updated_at"];
|
|
3524
|
+
|
|
840
3525
|
// src/agent.ts
|
|
841
3526
|
var http = __toESM(require("http"));
|
|
842
3527
|
function createActionServer(handlerMap, options) {
|
|
@@ -993,38 +3678,100 @@ function readBody(req) {
|
|
|
993
3678
|
}
|
|
994
3679
|
// Annotate the CommonJS export names for ESM import in node:
|
|
995
3680
|
0 && (module.exports = {
|
|
3681
|
+
AGENT_ROLES,
|
|
3682
|
+
AUTOPAY_UNAVAILABLE_REASONS,
|
|
996
3683
|
ActivityResource,
|
|
997
3684
|
AgentApp,
|
|
3685
|
+
ApiResource,
|
|
998
3686
|
AuthenticationError,
|
|
999
3687
|
AuthorizationError,
|
|
3688
|
+
BILLING_ADJUSTMENT_STATUSES,
|
|
3689
|
+
BILLING_ADJUSTMENT_TARGETS,
|
|
3690
|
+
BILLING_AUTOPAY_STATUSES,
|
|
3691
|
+
BILLING_BACKFILL_MODES,
|
|
3692
|
+
BILLING_CADENCES,
|
|
3693
|
+
BILLING_COLLECTION_MODES,
|
|
3694
|
+
BILLING_DELIVERY_MODES,
|
|
3695
|
+
BILLING_DELIVERY_STATUSES,
|
|
3696
|
+
BILLING_INTERVALS,
|
|
3697
|
+
BILLING_PERIOD_STATUSES,
|
|
3698
|
+
BILLING_PREVIEW_PERIOD_STATUSES,
|
|
3699
|
+
BILLING_SCHEDULE_STATUSES,
|
|
3700
|
+
BILLING_STATUSES,
|
|
3701
|
+
BILL_TIMINGS,
|
|
1000
3702
|
BaseResource,
|
|
3703
|
+
BillingScheduleResource,
|
|
3704
|
+
CONTACT_LIST_INCLUDES,
|
|
3705
|
+
CONTACT_SORT_KEYS,
|
|
3706
|
+
CUSTOMER_SORT_KEYS,
|
|
1001
3707
|
CalendarEventResource,
|
|
3708
|
+
CommunicationsResource,
|
|
1002
3709
|
ContactChannelResource,
|
|
1003
3710
|
ContactResource,
|
|
3711
|
+
ContactSequencesResource,
|
|
1004
3712
|
ContractResource,
|
|
3713
|
+
ConversationsResource,
|
|
3714
|
+
CustomFieldsResource,
|
|
1005
3715
|
CustomerResource,
|
|
1006
3716
|
DEFAULT_BASE_URL,
|
|
1007
3717
|
DEFAULT_MAX_RETRIES,
|
|
1008
3718
|
DEFAULT_TIMEOUT,
|
|
1009
3719
|
DEFAULT_TOKEN_REFRESH_SKEW_MS,
|
|
3720
|
+
DocumentsResource,
|
|
3721
|
+
ESTIMATE_STATUSES,
|
|
3722
|
+
EnrollmentsResource,
|
|
1010
3723
|
EstimateResource,
|
|
3724
|
+
EventAutomationsResource,
|
|
3725
|
+
FEATURE_KEYS,
|
|
3726
|
+
GmailResource,
|
|
1011
3727
|
InventoryResource,
|
|
3728
|
+
InvoiceRemindersResource,
|
|
1012
3729
|
InvoiceResource,
|
|
3730
|
+
InvoiceSettingsResource,
|
|
3731
|
+
JOB_SORT_KEYS,
|
|
1013
3732
|
JobResource,
|
|
3733
|
+
LeadSourcesResource,
|
|
3734
|
+
ListsResource,
|
|
3735
|
+
MODULE_KEYS,
|
|
3736
|
+
MeResource,
|
|
1014
3737
|
MemoryTokenStorage,
|
|
3738
|
+
ModulesResource,
|
|
1015
3739
|
NotFoundError,
|
|
1016
3740
|
OAuthError,
|
|
3741
|
+
OPPORTUNITY_SORT_KEYS,
|
|
3742
|
+
OPPORTUNITY_STATES,
|
|
1017
3743
|
OpportunityResource,
|
|
3744
|
+
OrttoResource,
|
|
3745
|
+
PLAN_KEYS,
|
|
3746
|
+
PLAN_SOURCES,
|
|
3747
|
+
PlanResource,
|
|
1018
3748
|
Planes,
|
|
1019
3749
|
PlanesClient,
|
|
1020
3750
|
PlanesError,
|
|
1021
3751
|
PropertyResource,
|
|
3752
|
+
RECORD_VIEW_ENTITY_TYPES,
|
|
1022
3753
|
RateLimitError,
|
|
3754
|
+
RecordViewsResource,
|
|
3755
|
+
RolesResource,
|
|
1023
3756
|
ServerError,
|
|
3757
|
+
ServiceSchedulesResource,
|
|
3758
|
+
TASK_SORT_KEYS,
|
|
1024
3759
|
TagResource,
|
|
3760
|
+
TaskResource,
|
|
3761
|
+
TeamsResource,
|
|
3762
|
+
UsersResource,
|
|
1025
3763
|
ValidationError,
|
|
3764
|
+
WEBHOOK_EVENT_TYPES,
|
|
3765
|
+
WORKFLOW_EVENT_RULE_CATCH_UP_EVENT_TYPES,
|
|
3766
|
+
WORKFLOW_EVENT_RULE_EVENT_TYPES,
|
|
3767
|
+
WORKFLOW_EVENT_RULE_MATCH_ALL_EVENT_TYPES,
|
|
3768
|
+
WebFormSubmissionsResource,
|
|
3769
|
+
WebFormsResource,
|
|
1026
3770
|
WebhookRouter,
|
|
3771
|
+
WebhookSubscriptionsResource,
|
|
1027
3772
|
WebhookVerificationError,
|
|
3773
|
+
WorkflowEventRulesResource,
|
|
3774
|
+
WorkflowsResource,
|
|
1028
3775
|
buildAuthorizeUrl,
|
|
1029
3776
|
clientCredentialsGrant,
|
|
1030
3777
|
createAgentApp,
|