@planescrm/sdk 0.3.0 → 0.55.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/dist/index.js CHANGED
@@ -30,39 +30,92 @@ 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
+ FEATURE_KEYS: () => FEATURE_KEYS,
77
+ GmailResource: () => GmailResource,
48
78
  InventoryResource: () => InventoryResource,
79
+ InvoiceRemindersResource: () => InvoiceRemindersResource,
49
80
  InvoiceResource: () => InvoiceResource,
81
+ InvoiceSettingsResource: () => InvoiceSettingsResource,
82
+ JOB_SORT_KEYS: () => JOB_SORT_KEYS,
50
83
  JobResource: () => JobResource,
84
+ MODULE_KEYS: () => MODULE_KEYS,
85
+ MeResource: () => MeResource,
51
86
  MemoryTokenStorage: () => MemoryTokenStorage,
87
+ ModulesResource: () => ModulesResource,
52
88
  NotFoundError: () => NotFoundError,
53
89
  OAuthError: () => OAuthError,
90
+ OPPORTUNITY_SORT_KEYS: () => OPPORTUNITY_SORT_KEYS,
91
+ OPPORTUNITY_STATES: () => OPPORTUNITY_STATES,
54
92
  OpportunityResource: () => OpportunityResource,
93
+ OrttoResource: () => OrttoResource,
94
+ PLAN_KEYS: () => PLAN_KEYS,
95
+ PLAN_SOURCES: () => PLAN_SOURCES,
96
+ PlanResource: () => PlanResource,
55
97
  Planes: () => Planes,
56
98
  PlanesClient: () => PlanesClient,
57
99
  PlanesError: () => PlanesError,
58
100
  PropertyResource: () => PropertyResource,
101
+ RECORD_VIEW_ENTITY_TYPES: () => RECORD_VIEW_ENTITY_TYPES,
59
102
  RateLimitError: () => RateLimitError,
103
+ RecordViewsResource: () => RecordViewsResource,
104
+ RolesResource: () => RolesResource,
60
105
  ServerError: () => ServerError,
106
+ ServiceSchedulesResource: () => ServiceSchedulesResource,
61
107
  TagResource: () => TagResource,
108
+ TaskResource: () => TaskResource,
62
109
  ValidationError: () => ValidationError,
110
+ WEBHOOK_EVENT_TYPES: () => WEBHOOK_EVENT_TYPES,
111
+ WORKFLOW_EVENT_RULE_EVENT_TYPES: () => WORKFLOW_EVENT_RULE_EVENT_TYPES,
112
+ WORKFLOW_EVENT_RULE_MATCH_ALL_EVENT_TYPES: () => WORKFLOW_EVENT_RULE_MATCH_ALL_EVENT_TYPES,
63
113
  WebhookRouter: () => WebhookRouter,
64
114
  WebhookVerificationError: () => WebhookVerificationError,
115
+ WorkflowEventRulesResource: () => WorkflowEventRulesResource,
116
+ WorkflowsResource: () => WorkflowsResource,
65
117
  buildAuthorizeUrl: () => buildAuthorizeUrl,
118
+ clientCredentialsGrant: () => clientCredentialsGrant,
66
119
  createAgentApp: () => createAgentApp,
67
120
  exchangeCode: () => exchangeCode,
68
121
  parseWebhookEvent: () => parseWebhookEvent,
@@ -207,6 +260,28 @@ async function refreshAccessToken(options) {
207
260
  }
208
261
  return await response.json();
209
262
  }
263
+ async function clientCredentialsGrant(options) {
264
+ const baseUrl = options.baseUrl.replace(/\/+$/, "");
265
+ const url = `${baseUrl}/oauth/token`;
266
+ const body = new URLSearchParams({
267
+ grant_type: "client_credentials",
268
+ client_id: options.clientId,
269
+ client_secret: options.clientSecret,
270
+ scope: options.scopes.join(" ")
271
+ });
272
+ const response = await fetch(url, {
273
+ method: "POST",
274
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
275
+ body: body.toString()
276
+ });
277
+ if (!response.ok) {
278
+ const errorBody = await response.json().catch(() => ({}));
279
+ const errorCode = errorBody["error"] ?? "unknown_error";
280
+ const errorDescription = errorBody["error_description"] ?? "Client credentials grant failed";
281
+ throw new OAuthError(errorCode, errorDescription);
282
+ }
283
+ return await response.json();
284
+ }
210
285
 
211
286
  // src/http.ts
212
287
  var HttpClient = class {
@@ -222,7 +297,8 @@ var HttpClient = class {
222
297
  clientId: config.clientId,
223
298
  clientSecret: config.clientSecret,
224
299
  tokenStorage: config.tokenStorage ?? new MemoryTokenStorage(),
225
- skewMs: config.tokenRefreshSkewMs ?? DEFAULT_TOKEN_REFRESH_SKEW_MS
300
+ skewMs: config.tokenRefreshSkewMs ?? DEFAULT_TOKEN_REFRESH_SKEW_MS,
301
+ scopes: config.scopes
226
302
  };
227
303
  }
228
304
  }
@@ -250,6 +326,9 @@ var HttpClient = class {
250
326
  if (response.status === 204) {
251
327
  return void 0;
252
328
  }
329
+ if (options.responseType === "arrayBuffer") {
330
+ return await response.arrayBuffer();
331
+ }
253
332
  return await response.json();
254
333
  }
255
334
  if (response.status === 429 && this.retryOnRateLimit && attempt < this.maxRetries) {
@@ -315,7 +394,19 @@ var HttpClient = class {
315
394
  this.refreshInFlight = (async () => {
316
395
  const current = await oauth.tokenStorage.getTokens();
317
396
  if (!current?.refreshToken) {
318
- throw new AuthenticationError("No refresh token available to refresh the access token");
397
+ const response2 = await clientCredentialsGrant({
398
+ baseUrl: this.baseUrl,
399
+ clientId: oauth.clientId,
400
+ clientSecret: oauth.clientSecret,
401
+ scopes: oauth.scopes ?? []
402
+ });
403
+ const next2 = {
404
+ accessToken: response2.access_token,
405
+ refreshToken: response2.refresh_token ?? null,
406
+ expiresAt: Date.now() + response2.expires_in * 1e3
407
+ };
408
+ await oauth.tokenStorage.setTokens(next2);
409
+ return next2;
319
410
  }
320
411
  const response = await refreshAccessToken({
321
412
  baseUrl: this.baseUrl,
@@ -393,11 +484,13 @@ var HttpClient = class {
393
484
  };
394
485
 
395
486
  // src/resources/base-resource.ts
396
- var BaseResource = class {
487
+ var ApiResource = class {
397
488
  constructor(http2, basePath) {
398
489
  this.http = http2;
399
490
  this.basePath = basePath;
400
491
  }
492
+ };
493
+ var BaseResource = class extends ApiResource {
401
494
  /**
402
495
  * List entities with optional filters and pagination.
403
496
  */
@@ -448,11 +541,46 @@ var BaseResource = class {
448
541
  }
449
542
  };
450
543
 
544
+ // src/resources/query-params.ts
545
+ function toQueryParams(params) {
546
+ const out = {};
547
+ if (!params) return out;
548
+ for (const [key, value] of Object.entries(params)) {
549
+ if (value === void 0 || value === null) continue;
550
+ if (Array.isArray(value)) {
551
+ if (value.length === 0) continue;
552
+ out[key] = value.map(String).join(",");
553
+ } else {
554
+ out[key] = value;
555
+ }
556
+ }
557
+ return out;
558
+ }
559
+
451
560
  // src/resources/opportunities.ts
452
561
  var OpportunityResource = class extends BaseResource {
453
562
  constructor(http2) {
454
563
  super(http2, "/opportunities");
455
564
  }
565
+ /**
566
+ * List opportunities. `tag_ids` is ANY-of and travels as one comma-separated
567
+ * query value (`?tag_ids=a,b`), which is what the API's filter schema parses.
568
+ */
569
+ async list(params) {
570
+ return this.http.request({
571
+ method: "GET",
572
+ path: this.basePath,
573
+ params: toQueryParams(params)
574
+ });
575
+ }
576
+ /** PUT /opportunities/{id} — partial update; stage moves go through workflow transitions. */
577
+ async update(id, data) {
578
+ return this.http.request({
579
+ method: "PUT",
580
+ path: `${this.basePath}/${id}`,
581
+ body: data
582
+ });
583
+ }
456
584
  };
457
585
 
458
586
  // src/resources/customers.ts
@@ -460,19 +588,125 @@ var CustomerResource = class extends BaseResource {
460
588
  constructor(http2) {
461
589
  super(http2, "/customers");
462
590
  }
591
+ /**
592
+ * Update a customer. The API route is `PUT /customers/{id}` (not PATCH like
593
+ * the other resources), so this overrides the base verb; the body is still a
594
+ * partial — send only the fields to change. See `UpdateCustomerDto.address`
595
+ * for how a service address resolves to a property.
596
+ */
597
+ async update(id, data) {
598
+ return this.http.request({
599
+ method: "PUT",
600
+ path: `/customers/${id}`,
601
+ body: data
602
+ });
603
+ }
604
+ /**
605
+ * List customers. `tag_ids` is ANY-of and travels as one comma-separated
606
+ * query value (`?tag_ids=a,b`), which is what the API's filter schema parses.
607
+ */
608
+ async list(params) {
609
+ return this.http.request({
610
+ method: "GET",
611
+ path: this.basePath,
612
+ params: toQueryParams(params)
613
+ });
614
+ }
615
+ /**
616
+ * Fold a duplicate company (`loserId`) into a survivor (`winnerId`).
617
+ *
618
+ * Everything hanging off the loser moves to the winner, the winner's empty
619
+ * fields are filled from the loser, and the loser is soft-deleted with a
620
+ * resolvable pointer — `GET /customers/{loserId}` afterwards returns the
621
+ * winner's detail with a `mergedFrom` pointer, so a stored loser id keeps
622
+ * working. Irreversible; requires admin scope.
623
+ */
624
+ async merge(winnerId, loserId) {
625
+ return this.http.request({
626
+ method: "POST",
627
+ path: `/customers/${winnerId}/merge/${loserId}`
628
+ });
629
+ }
463
630
  };
464
631
 
465
632
  // src/resources/properties.ts
466
- var PropertyResource = class extends BaseResource {
633
+ var PropertyResource = class extends ApiResource {
467
634
  constructor(http2) {
468
635
  super(http2, "/properties");
469
636
  }
637
+ /** GET /customers/{customerId}/properties — paginated (`page`, `limit` ≤ 100). */
638
+ async list(customerId, params) {
639
+ return this.http.request({
640
+ method: "GET",
641
+ path: `/customers/${customerId}/properties`,
642
+ params: toQueryParams(params)
643
+ });
644
+ }
645
+ /** GET /properties/{id} — one property, without naming its customer. */
646
+ async get(id) {
647
+ return this.http.request({
648
+ method: "GET",
649
+ path: `${this.basePath}/${id}`
650
+ });
651
+ }
652
+ /** POST /customers/{customerId}/properties — the property inherits the customer's org path. */
653
+ async create(customerId, data) {
654
+ return this.http.request({
655
+ method: "POST",
656
+ path: `/customers/${customerId}/properties`,
657
+ body: data
658
+ });
659
+ }
660
+ /** PUT /customers/{customerId}/properties/{id} — partial update. */
661
+ async update(customerId, id, data) {
662
+ return this.http.request({
663
+ method: "PUT",
664
+ path: `/customers/${customerId}/properties/${id}`,
665
+ body: data
666
+ });
667
+ }
668
+ /** DELETE /customers/{customerId}/properties/{id} — soft delete (204). */
669
+ async delete(customerId, id) {
670
+ await this.http.request({
671
+ method: "DELETE",
672
+ path: `/customers/${customerId}/properties/${id}`
673
+ });
674
+ }
470
675
  };
471
676
 
472
677
  // src/resources/calendar-events.ts
473
678
  var CalendarEventResource = class extends BaseResource {
474
679
  constructor(http2) {
475
- super(http2, "/calendar-events");
680
+ super(http2, "/events");
681
+ }
682
+ async list(params) {
683
+ return super.list(params);
684
+ }
685
+ /**
686
+ * PATCH /events/:id. For an occurrence of a recurring event, `editMode`
687
+ * picks which occurrences change (`this` when omitted — the server's
688
+ * default); it is ignored for one-time events.
689
+ */
690
+ async update(id, data, options = {}) {
691
+ return this.http.request({
692
+ method: "PATCH",
693
+ path: `${this.basePath}/${id}`,
694
+ params: { recurrence_edit_mode: options.editMode },
695
+ body: data
696
+ });
697
+ }
698
+ /**
699
+ * POST /events/:id/complete — marks the event completed and runs its "on
700
+ * complete" transition, best-effort. The event is completed even when the
701
+ * transition can't run; `workflow_trigger` says whether it fired, was
702
+ * skipped (none set) or failed (with a reason).
703
+ */
704
+ async complete(id, body = {}) {
705
+ return this.http.request({
706
+ method: "POST",
707
+ path: `${this.basePath}/${id}/complete`,
708
+ body
709
+ });
476
710
  }
477
711
  };
478
712
 
@@ -484,30 +718,219 @@ var ContractResource = class extends BaseResource {
484
718
  };
485
719
 
486
720
  // src/resources/jobs.ts
487
- var JobResource = class extends BaseResource {
721
+ var JobResource = class extends ApiResource {
488
722
  constructor(http2) {
489
723
  super(http2, "/jobs");
490
724
  }
725
+ /** The jobs under one opportunity — the same route as `listForOpportunity()`. */
726
+ async list(opportunityId, params) {
727
+ return this.listForOpportunity(opportunityId, params);
728
+ }
729
+ /**
730
+ * List the jobs under one opportunity — `GET /opportunities/{opportunityId}/jobs`,
731
+ * the API's job list route. Default order is `created_at` desc;
732
+ * `sort_by: 'recent'` puts the calling user's most recently opened jobs first.
733
+ */
734
+ async listForOpportunity(opportunityId, params) {
735
+ return this.http.request({
736
+ method: "GET",
737
+ path: `/opportunities/${opportunityId}/jobs`,
738
+ params: toQueryParams(params)
739
+ });
740
+ }
741
+ /** GET /opportunities/{opportunityId}/jobs/{id} */
742
+ async get(opportunityId, id) {
743
+ return this.http.request({
744
+ method: "GET",
745
+ path: `/opportunities/${opportunityId}/jobs/${id}`
746
+ });
747
+ }
748
+ /**
749
+ * POST /opportunities/{opportunityId}/jobs — 422 WORKFLOW_NOT_CONFIGURED when
750
+ * the trade has no published job workflow (check `getTradeCoverage()` first).
751
+ */
752
+ async create(opportunityId, data) {
753
+ return this.http.request({
754
+ method: "POST",
755
+ path: `/opportunities/${opportunityId}/jobs`,
756
+ body: data
757
+ });
758
+ }
759
+ /** PUT /opportunities/{opportunityId}/jobs/{id} — partial update (status, notes). */
760
+ async update(opportunityId, id, data) {
761
+ return this.http.request({
762
+ method: "PUT",
763
+ path: `/opportunities/${opportunityId}/jobs/${id}`,
764
+ body: data
765
+ });
766
+ }
767
+ /** DELETE /opportunities/{opportunityId}/jobs/{id} — soft delete (204). */
768
+ async delete(opportunityId, id) {
769
+ await this.http.request({
770
+ method: "DELETE",
771
+ path: `/opportunities/${opportunityId}/jobs/${id}`
772
+ });
773
+ }
774
+ /**
775
+ * GET /jobs/trade-coverage — every active trade with whether a job can be
776
+ * created under it (a published job workflow resolves: the trade's own or the
777
+ * generic one). Check before creating a job to avoid a 422
778
+ * WORKFLOW_NOT_CONFIGURED. Readable by any role that can create jobs (403
779
+ * otherwise); carries no workflow details.
780
+ */
781
+ async getTradeCoverage() {
782
+ return this.http.request({
783
+ method: "GET",
784
+ path: "/jobs/trade-coverage"
785
+ });
786
+ }
491
787
  };
492
788
 
493
789
  // src/resources/estimates.ts
494
- var EstimateResource = class extends BaseResource {
790
+ var EstimateResource = class extends ApiResource {
495
791
  constructor(http2) {
496
792
  super(http2, "/estimates");
497
793
  }
794
+ /** GET /jobs/{jobId}/estimates — newest first, paginated (`page`, `limit` ≤ 100). */
795
+ async list(jobId, params) {
796
+ return this.http.request({
797
+ method: "GET",
798
+ path: `/jobs/${jobId}/estimates`,
799
+ params: toQueryParams(params)
800
+ });
801
+ }
802
+ /**
803
+ * Every estimate across all of one opportunity's jobs, in one request —
804
+ * `GET /opportunities/{opportunityId}/estimates`. Newest first; each row
805
+ * carries its `jobId`. Paginated with `page` / `limit` (max 100).
806
+ */
807
+ async listForOpportunity(opportunityId, params) {
808
+ return this.http.request({
809
+ method: "GET",
810
+ path: `/opportunities/${opportunityId}/estimates`,
811
+ params: toQueryParams(params)
812
+ });
813
+ }
814
+ /** GET /jobs/{jobId}/estimates/{id} — the estimate with its line items. */
815
+ async get(jobId, id) {
816
+ return this.http.request({
817
+ method: "GET",
818
+ path: `/jobs/${jobId}/estimates/${id}`
819
+ });
820
+ }
821
+ /** POST /jobs/{jobId}/estimates — optionally cloned from an estimate template. */
822
+ async create(jobId, data) {
823
+ return this.http.request({
824
+ method: "POST",
825
+ path: `/jobs/${jobId}/estimates`,
826
+ body: data
827
+ });
828
+ }
829
+ /** PUT /jobs/{jobId}/estimates/{id} — partial update (measurements, notes, discount, tax). */
830
+ async update(jobId, id, data) {
831
+ return this.http.request({
832
+ method: "PUT",
833
+ path: `/jobs/${jobId}/estimates/${id}`,
834
+ body: data
835
+ });
836
+ }
837
+ /** DELETE /jobs/{jobId}/estimates/{id} — soft delete (204). */
838
+ async delete(jobId, id) {
839
+ await this.http.request({
840
+ method: "DELETE",
841
+ path: `/jobs/${jobId}/estimates/${id}`
842
+ });
843
+ }
498
844
  };
499
845
 
500
846
  // src/resources/invoices.ts
501
847
  var InvoiceResource = class extends BaseResource {
502
848
  constructor(http2) {
503
- super(http2, "/invoices");
849
+ super(http2, "/admin/invoices");
850
+ }
851
+ /** List invoices, newest first. Each row carries the customer's `customerName`. */
852
+ async list(params) {
853
+ return this.http.request({
854
+ method: "GET",
855
+ path: this.basePath,
856
+ params
857
+ });
858
+ }
859
+ /**
860
+ * GET /admin/invoices/:id — the invoice with its line items, payments
861
+ * (including any `needs_review` payment) and `payLink` state.
862
+ */
863
+ async get(id) {
864
+ return this.http.request({
865
+ method: "GET",
866
+ path: `${this.basePath}/${id}`
867
+ });
868
+ }
869
+ /**
870
+ * POST /admin/invoices/:id/pay-link — issue a fresh durable pay link for a
871
+ * `sent` or `partially_paid` invoice (Send Invoice grant) and return its URL,
872
+ * e.g. to share by text. Rotates: the previously emailed link stops working.
873
+ * Any other status → 409 `INVOICE_NOT_PAYABLE`.
874
+ */
875
+ async createPayLink(id) {
876
+ return this.http.request({
877
+ method: "POST",
878
+ path: `${this.basePath}/${id}/pay-link`
879
+ });
880
+ }
881
+ /**
882
+ * GET /admin/invoices/:id/pdf — the invoice PDF bytes (Read Invoice grant).
883
+ * A sent invoice returns the copy stored when it was sent; a draft renders on
884
+ * demand with a DRAFT watermark.
885
+ */
886
+ async downloadPdf(id) {
887
+ return this.http.request({
888
+ method: "GET",
889
+ path: `${this.basePath}/${id}/pdf`,
890
+ headers: { Accept: "application/pdf" },
891
+ responseType: "arrayBuffer"
892
+ });
893
+ }
894
+ /**
895
+ * GET /admin/invoices/overdue — sent / partially paid invoices with a balance
896
+ * past their due date, most overdue first, each with `daysOverdue` and the
897
+ * last overdue offset reached (E56-F8-S2). Read Invoice.
898
+ */
899
+ async listOverdue(params) {
900
+ return this.http.request({
901
+ method: "GET",
902
+ path: `${this.basePath}/overdue`,
903
+ params
904
+ });
905
+ }
906
+ /** GET /admin/invoices/overdue/summary — `{ count, total }` of every overdue invoice. Read Invoice. */
907
+ async overdueSummary() {
908
+ return this.http.request({
909
+ method: "GET",
910
+ path: `${this.basePath}/overdue/summary`
911
+ });
504
912
  }
505
913
  };
506
914
 
507
915
  // src/resources/inventory.ts
508
916
  var InventoryResource = class extends BaseResource {
509
917
  constructor(http2) {
510
- super(http2, "/inventory/items");
918
+ super(http2, "/admin/inventory/items");
919
+ }
920
+ async list(params) {
921
+ return this.http.request({
922
+ method: "GET",
923
+ path: this.basePath,
924
+ params: toQueryParams(params)
925
+ });
926
+ }
927
+ /** PUT /admin/inventory/items/{id} — partial update. */
928
+ async update(id, data) {
929
+ return this.http.request({
930
+ method: "PUT",
931
+ path: `${this.basePath}/${id}`,
932
+ body: data
933
+ });
511
934
  }
512
935
  };
513
936
 
@@ -543,6 +966,20 @@ var ContactResource = class extends BaseResource {
543
966
  constructor(http2) {
544
967
  super(http2, "/contacts");
545
968
  }
969
+ /**
970
+ * List contacts. Typed against the real filter schema (customer_id /
971
+ * property_id / q / sort_by / sort_order / page / limit / include) — the base
972
+ * `list` would accept any key and let a typo reach the server as a 400.
973
+ * `include: ['channels', 'links']` attaches each row's channels and active
974
+ * links in the same response.
975
+ */
976
+ async list(params) {
977
+ return this.http.request({
978
+ method: "GET",
979
+ path: this.basePath,
980
+ params: toQueryParams(params)
981
+ });
982
+ }
546
983
  async merge(winnerId, loserId) {
547
984
  return this.http.request({
548
985
  method: "POST",
@@ -582,43 +1019,1030 @@ var ActivityResource = class {
582
1019
  }
583
1020
  };
584
1021
 
585
- // src/resources/tags.ts
586
- var TagResource = class extends BaseResource {
1022
+ // src/resources/communications.ts
1023
+ var CommunicationsResource = class {
587
1024
  constructor(http2) {
588
- super(http2, "/tags");
1025
+ this.http = http2;
589
1026
  }
590
- /** `TagsService.setEntityTags()` returns the final tag set wrapped in `{ tags }`. */
591
- async setEntityTags(entityType, entityId, data) {
1027
+ async log(data) {
592
1028
  return this.http.request({
593
- method: "PUT",
594
- path: `/entities/${entityType}/${entityId}/tags`,
1029
+ method: "POST",
1030
+ path: "/communications",
595
1031
  body: data
596
1032
  });
597
1033
  }
598
- async getEntityTags(entityType, entityId) {
1034
+ async list(params) {
599
1035
  return this.http.request({
600
1036
  method: "GET",
601
- path: `/entities/${entityType}/${entityId}/tags`
1037
+ path: "/communications",
1038
+ params
602
1039
  });
603
1040
  }
604
- async getEntities(tagId, params) {
1041
+ async get(id) {
605
1042
  return this.http.request({
606
1043
  method: "GET",
607
- path: `/tags/${tagId}/entities`,
608
- params
1044
+ path: `/communications/${id}`
1045
+ });
1046
+ }
1047
+ async link(id, data) {
1048
+ return this.http.request({
1049
+ method: "POST",
1050
+ path: `/communications/${id}/link`,
1051
+ body: data
609
1052
  });
610
1053
  }
611
1054
  };
612
1055
 
613
- // src/webhooks.ts
614
- var import_node_crypto2 = require("crypto");
615
- function verifyWebhookSignature(payload, signature, secret) {
616
- if (!signature || !secret || !payload) {
617
- return false;
1056
+ // src/resources/conversations.ts
1057
+ var ConversationsResource = class {
1058
+ constructor(http2) {
1059
+ this.http = http2;
618
1060
  }
619
- const prefix = "sha256=";
620
- if (!signature.startsWith(prefix)) {
621
- return false;
1061
+ async log(data) {
1062
+ return this.http.request({ method: "POST", path: "/conversations", body: data });
1063
+ }
1064
+ async list(params) {
1065
+ return this.http.request({ method: "GET", path: "/conversations", params });
1066
+ }
1067
+ /** The review queue: `list()` pinned to `match_status: 'needs_review'`. */
1068
+ async reviewQueue(params) {
1069
+ return this.list({ ...params, match_status: "needs_review" });
1070
+ }
1071
+ async get(id) {
1072
+ return this.http.request({ method: "GET", path: `/conversations/${encodeURIComponent(id)}` });
1073
+ }
1074
+ async update(id, data) {
1075
+ return this.http.request({ method: "PATCH", path: `/conversations/${encodeURIComponent(id)}`, body: data });
1076
+ }
1077
+ async delete(id) {
1078
+ await this.http.request({ method: "DELETE", path: `/conversations/${encodeURIComponent(id)}` });
1079
+ }
1080
+ async link(id, data) {
1081
+ return this.http.request({ method: "POST", path: `/conversations/${encodeURIComponent(id)}/links`, body: data });
1082
+ }
1083
+ async unlink(id, linkId) {
1084
+ return this.http.request({
1085
+ method: "DELETE",
1086
+ path: `/conversations/${encodeURIComponent(id)}/links/${encodeURIComponent(linkId)}`
1087
+ });
1088
+ }
1089
+ async resolve(id, data) {
1090
+ return this.http.request({ method: "POST", path: `/conversations/${encodeURIComponent(id)}/resolve`, body: data });
1091
+ }
1092
+ async getInternalDomains() {
1093
+ return this.http.request({ method: "GET", path: "/conversations/settings/internal-domains" });
1094
+ }
1095
+ /** Requires an admin: the server checks `Update` on `Subject.Tenant` (tenant-wide matching config), not `Subject.Conversation`. */
1096
+ async setInternalDomains(data) {
1097
+ return this.http.request({ method: "PUT", path: "/conversations/settings/internal-domains", body: data });
1098
+ }
1099
+ /**
1100
+ * E57-F2-S4 — disconnect the CALLER's own Circleback connection (Update
1101
+ * Conversation). Another user's connection id is a 404. Connecting is the
1102
+ * interactive browser OAuth flow (Settings → Conversations), not an SDK call.
1103
+ */
1104
+ async disconnectCircleback(data) {
1105
+ return this.http.request({
1106
+ method: "POST",
1107
+ path: "/conversations/sources/circleback/disconnect",
1108
+ body: data
1109
+ });
1110
+ }
1111
+ /**
1112
+ * E57-F2-S8 — pull one company's meetings from every active teammate's
1113
+ * connected source (Update Conversation). 202, runs in the background.
1114
+ * 404 for a company you can't see; 409 `NO_SOURCES` when nobody has one.
1115
+ */
1116
+ async pull(data) {
1117
+ return this.http.request({ method: "POST", path: "/conversations/pull", body: data });
1118
+ }
1119
+ /**
1120
+ * E57-F2-S9 — whether a Pull has finished: pass the `job_ids` `pull()`
1121
+ * returned (1–50). Update Conversation, like `pull()`. 404
1122
+ * `PULL_NOT_FOUND` when none of them is readable (expired after ~2h,
1123
+ * unknown) — treat that as settled.
1124
+ */
1125
+ async getPullStatus(jobIds) {
1126
+ return this.http.request({
1127
+ method: "GET",
1128
+ path: "/conversations/pull/status",
1129
+ params: { job_ids: jobIds.join(",") }
1130
+ });
1131
+ }
1132
+ /** E57-F2-S8 — sync the caller's OWN Circleback connection now (deduplicated). 409 `NO_CONNECTION` when they have none. */
1133
+ async syncNow() {
1134
+ return this.http.request({ method: "POST", path: "/conversations/sources/circleback/sync-now" });
1135
+ }
1136
+ /** E57-F2-S8 — the caller's own connection, `has_sources`, and (admins only) the roster. */
1137
+ async syncStatus() {
1138
+ return this.http.request({ method: "GET", path: "/conversations/sync-status" });
1139
+ }
1140
+ /**
1141
+ * E57-F4-S1 — a synced meeting's transcript, fetched live from the meeting
1142
+ * recorder (never stored by Planes; the response is `Cache-Control:
1143
+ * no-store`). Read Conversation, plus the tenant's transcript-access rule:
1144
+ * 403 `TRANSCRIPT_OWNER_ONLY` under `owner` for a non-owner; 409
1145
+ * `TRANSCRIPT_SOURCE_UNAVAILABLE` (`owner_name` says who must reconnect) or
1146
+ * `TRANSCRIPT_NOT_AVAILABLE` (not a synced meeting); 404 when you can't see
1147
+ * the conversation. `segments: []` = no transcript yet.
1148
+ */
1149
+ async getTranscript(id) {
1150
+ return this.http.request({
1151
+ method: "GET",
1152
+ path: `/conversations/${encodeURIComponent(id)}/transcript`
1153
+ });
1154
+ }
1155
+ /** E57-F4-S1 — who can view transcripts: `owner` (default) or `viewers`. Read Conversation. */
1156
+ async getTranscriptAccess() {
1157
+ return this.http.request({ method: "GET", path: "/conversations/settings/transcript-access" });
1158
+ }
1159
+ /** E57-F4-S1 — requires an admin: the server checks `Update` on `Subject.Tenant`. */
1160
+ async setTranscriptAccess(value) {
1161
+ return this.http.request({
1162
+ method: "PUT",
1163
+ path: "/conversations/settings/transcript-access",
1164
+ body: { transcript_access: value }
1165
+ });
1166
+ }
1167
+ };
1168
+
1169
+ // src/resources/gmail.ts
1170
+ var GmailResource = class {
1171
+ constructor(http2) {
1172
+ this.http = http2;
1173
+ }
1174
+ /**
1175
+ * Send an email RIGHT NOW from the connected user's real Gmail address.
1176
+ * Hits `POST /admin/integrations/google/gmail/send` — final per Task 4
1177
+ * (`apps/api/src/modules/integrations/google/google-connection.controller.ts`).
1178
+ */
1179
+ async send(data) {
1180
+ return this.http.request({
1181
+ method: "POST",
1182
+ path: "/admin/integrations/google/gmail/send",
1183
+ body: data
1184
+ });
1185
+ }
1186
+ };
1187
+
1188
+ // src/resources/documents.ts
1189
+ var DocumentsResource = class {
1190
+ constructor(http2) {
1191
+ this.http = http2;
1192
+ }
1193
+ /** Attach an external (link-only) document — e.g. a Google Drive link — to a record. */
1194
+ async attachExternal(data) {
1195
+ return this.http.request({
1196
+ method: "POST",
1197
+ path: "/documents/external",
1198
+ body: data
1199
+ });
1200
+ }
1201
+ /** Documents filed directly on one record (uploaded + external), newest first. */
1202
+ async listForEntity(entityType, entityId) {
1203
+ return this.http.request({
1204
+ method: "GET",
1205
+ path: `/${entityType}/${entityId}/documents`
1206
+ });
1207
+ }
1208
+ };
1209
+
1210
+ // src/resources/tags.ts
1211
+ var TagResource = class extends ApiResource {
1212
+ constructor(http2) {
1213
+ super(http2, "/tags");
1214
+ }
1215
+ /** GET /tags */
1216
+ async list(params) {
1217
+ return this.http.request({
1218
+ method: "GET",
1219
+ path: this.basePath,
1220
+ params
1221
+ });
1222
+ }
1223
+ /** POST /tags — 409 on a case-insensitive duplicate name. */
1224
+ async create(data) {
1225
+ return this.http.request({ method: "POST", path: this.basePath, body: data });
1226
+ }
1227
+ /** PATCH /tags/:id — rename / recolor; 409 on a case-insensitive duplicate name. */
1228
+ async update(id, data) {
1229
+ return this.http.request({ method: "PATCH", path: `${this.basePath}/${id}`, body: data });
1230
+ }
1231
+ /** DELETE /tags/:id — cascades the tag off every record. */
1232
+ async delete(id) {
1233
+ await this.http.request({ method: "DELETE", path: `${this.basePath}/${id}` });
1234
+ }
1235
+ /** `TagsService.setEntityTags()` returns the final tag set wrapped in `{ tags }`. */
1236
+ async setEntityTags(entityType, entityId, data) {
1237
+ return this.http.request({
1238
+ method: "PUT",
1239
+ path: `/entities/${entityType}/${entityId}/tags`,
1240
+ body: data
1241
+ });
1242
+ }
1243
+ async getEntityTags(entityType, entityId) {
1244
+ return this.http.request({
1245
+ method: "GET",
1246
+ path: `/entities/${entityType}/${entityId}/tags`
1247
+ });
1248
+ }
1249
+ async getEntities(tagId, params) {
1250
+ return this.http.request({
1251
+ method: "GET",
1252
+ path: `/tags/${tagId}/entities`,
1253
+ params
1254
+ });
1255
+ }
1256
+ };
1257
+
1258
+ // src/resources/tasks.ts
1259
+ var TaskResource = class extends ApiResource {
1260
+ constructor(http2) {
1261
+ super(http2, "/tasks");
1262
+ }
1263
+ async list(params) {
1264
+ return this.http.request({
1265
+ method: "GET",
1266
+ path: this.basePath,
1267
+ params
1268
+ });
1269
+ }
1270
+ /** GET /tasks/:id */
1271
+ async get(id) {
1272
+ return this.http.request({ method: "GET", path: `${this.basePath}/${id}` });
1273
+ }
1274
+ /** POST /tasks */
1275
+ async create(data) {
1276
+ return this.http.request({ method: "POST", path: this.basePath, body: data });
1277
+ }
1278
+ /** PATCH /tasks/:id — non-terminal fields only; terminal status changes use the action methods. */
1279
+ async update(id, data) {
1280
+ return this.http.request({ method: "PATCH", path: `${this.basePath}/${id}`, body: data });
1281
+ }
1282
+ /**
1283
+ * POST /tasks/:id/complete — fires the linked workflow transition (best-effort).
1284
+ * The task always completes; `workflow_trigger` says whether the next step ran.
1285
+ */
1286
+ async complete(id) {
1287
+ return this.http.request({ method: "POST", path: `${this.basePath}/${id}/complete` });
1288
+ }
1289
+ /** POST /tasks/:id/cancel */
1290
+ async cancel(id) {
1291
+ return this.http.request({ method: "POST", path: `${this.basePath}/${id}/cancel` });
1292
+ }
1293
+ /** POST /tasks/:id/reopen — the sanctioned resurrect of a completed/cancelled task. */
1294
+ async reopen(id) {
1295
+ return this.http.request({ method: "POST", path: `${this.basePath}/${id}/reopen` });
1296
+ }
1297
+ };
1298
+
1299
+ // src/resources/record-views.ts
1300
+ var RecordViewsResource = class {
1301
+ constructor(http2) {
1302
+ this.http = http2;
1303
+ this.basePath = "/record-views";
1304
+ }
1305
+ /** POST /record-views — record that the calling user opened this record. Resolves on 204. */
1306
+ async touch(input) {
1307
+ await this.http.request({ method: "POST", path: this.basePath, body: input });
1308
+ }
1309
+ /** GET /record-views/recent — the calling user's most recently viewed records, newest first. */
1310
+ async recent(params) {
1311
+ return this.http.request({
1312
+ method: "GET",
1313
+ path: `${this.basePath}/recent`,
1314
+ params: toQueryParams(params)
1315
+ });
1316
+ }
1317
+ };
1318
+
1319
+ // src/resources/modules.ts
1320
+ var ModulesResource = class {
1321
+ constructor(http2) {
1322
+ this.http = http2;
1323
+ this.basePath = "/modules";
1324
+ }
1325
+ /** GET /modules — one entry per registered module key, in canonical order. */
1326
+ async list() {
1327
+ const res = await this.http.request({
1328
+ method: "GET",
1329
+ path: this.basePath
1330
+ });
1331
+ return res.data;
1332
+ }
1333
+ };
1334
+
1335
+ // src/resources/plan.ts
1336
+ var PlanResource = class {
1337
+ constructor(http2) {
1338
+ this.http = http2;
1339
+ this.basePath = "/plan";
1340
+ }
1341
+ /** GET /plan — plan, billing status and the plan's ceiling. */
1342
+ async get() {
1343
+ const res = await this.http.request({
1344
+ method: "GET",
1345
+ path: this.basePath
1346
+ });
1347
+ return res.data;
1348
+ }
1349
+ };
1350
+
1351
+ // src/resources/me.ts
1352
+ var MeResource = class {
1353
+ constructor(http2) {
1354
+ this.http = http2;
1355
+ this.basePath = "/me";
1356
+ }
1357
+ /**
1358
+ * GET /me/abilities — the caller's effective ability: for an API key, the key
1359
+ * role intersected with its acting agent's live role (`actingRole`).
1360
+ */
1361
+ async abilities() {
1362
+ return this.http.request({
1363
+ method: "GET",
1364
+ path: `${this.basePath}/abilities`
1365
+ });
1366
+ }
1367
+ };
1368
+
1369
+ // src/resources/roles.ts
1370
+ var RolesResource = class {
1371
+ constructor(http2) {
1372
+ this.http = http2;
1373
+ this.basePath = "/roles";
1374
+ }
1375
+ /** GET /roles — every role (not `system_agent`) with user and change counts. */
1376
+ async list() {
1377
+ return this.http.request({ method: "GET", path: this.basePath });
1378
+ }
1379
+ /** GET /roles/:key — one role's permission matrix, summary and grant version. */
1380
+ async get(key) {
1381
+ return this.http.request({
1382
+ method: "GET",
1383
+ path: `${this.basePath}/${encodeURIComponent(key)}`
1384
+ });
1385
+ }
1386
+ /**
1387
+ * PUT /roles/:key/grants — sparse per-cell changes, all validated before any
1388
+ * is written. 422 `GRANT_REQUIRED` / `GRANT_NOT_DELEGABLE` for locked cells,
1389
+ * `CONFIRMATION_REQUIRED` when a money action is granted without
1390
+ * `confirm: true` + `reason`, `ROLE_NOT_TUNABLE` for admin; 409
1391
+ * `ROLE_VERSION_CONFLICT` on a stale `baseVersion`. Returns the updated role.
1392
+ */
1393
+ async updateGrants(key, body) {
1394
+ return this.http.request({
1395
+ method: "PUT",
1396
+ path: `${this.basePath}/${encodeURIComponent(key)}/grants`,
1397
+ body
1398
+ });
1399
+ }
1400
+ /** DELETE /roles/:key/grants — back to the Planes defaults. Returns the reset role. */
1401
+ async reset(key) {
1402
+ return this.http.request({
1403
+ method: "DELETE",
1404
+ path: `${this.basePath}/${encodeURIComponent(key)}/grants`
1405
+ });
1406
+ }
1407
+ /** GET /roles/history — the change log, newest first; page with `cursor`. */
1408
+ async history(params) {
1409
+ return this.http.request({
1410
+ method: "GET",
1411
+ path: `${this.basePath}/history`,
1412
+ ...params ? { params } : {}
1413
+ });
1414
+ }
1415
+ };
1416
+
1417
+ // src/resources/invoice-settings.ts
1418
+ var InvoiceSettingsResource = class {
1419
+ constructor(http2) {
1420
+ this.http = http2;
1421
+ this.basePath = "/admin/invoice-settings";
1422
+ }
1423
+ /**
1424
+ * GET /admin/invoice-settings/offline-instructions — the plain-text
1425
+ * instructions shown on the pay page when online payment is unavailable,
1426
+ * or null when none are set.
1427
+ */
1428
+ async getOfflineInstructions() {
1429
+ const res = await this.http.request({
1430
+ method: "GET",
1431
+ path: `${this.basePath}/offline-instructions`
1432
+ });
1433
+ return res.instructions;
1434
+ }
1435
+ /**
1436
+ * PUT /admin/invoice-settings/offline-instructions — store plain text
1437
+ * (trimmed, at most 2,000 characters); null or blank clears it. Returns the
1438
+ * stored value.
1439
+ */
1440
+ async setOfflineInstructions(text) {
1441
+ const body = { instructions: text };
1442
+ const res = await this.http.request({
1443
+ method: "PUT",
1444
+ path: `${this.basePath}/offline-instructions`,
1445
+ body
1446
+ });
1447
+ return res.instructions;
1448
+ }
1449
+ /**
1450
+ * GET /admin/invoice-settings/overdue-offsets — the days after the due date
1451
+ * at which `invoice.overdue` fires, ascending (default `[3, 7, 14]`).
1452
+ */
1453
+ async getOverdueOffsets() {
1454
+ const res = await this.http.request({
1455
+ method: "GET",
1456
+ path: `${this.basePath}/overdue-offsets`
1457
+ });
1458
+ return res.offsets;
1459
+ }
1460
+ /**
1461
+ * PUT /admin/invoice-settings/overdue-offsets — replace the offsets: 1 to 5
1462
+ * unique whole days, each 1–90. Returns them sorted ascending. Admin only.
1463
+ */
1464
+ async setOverdueOffsets(offsets) {
1465
+ const body = { offsets };
1466
+ const res = await this.http.request({
1467
+ method: "PUT",
1468
+ path: `${this.basePath}/overdue-offsets`,
1469
+ body
1470
+ });
1471
+ return res.offsets;
1472
+ }
1473
+ /**
1474
+ * GET /admin/invoice-settings/attach-pdf — whether invoice emails carry the
1475
+ * invoice PDF (on unless an admin turned it off).
1476
+ */
1477
+ async getAttachPdf() {
1478
+ const res = await this.http.request({
1479
+ method: "GET",
1480
+ path: `${this.basePath}/attach-pdf`
1481
+ });
1482
+ return res.enabled;
1483
+ }
1484
+ /**
1485
+ * PUT /admin/invoice-settings/attach-pdf — turn the PDF attachment on
1486
+ * invoice emails on or off. Returns the stored value.
1487
+ */
1488
+ async setAttachPdf(enabled) {
1489
+ const body = { enabled };
1490
+ const res = await this.http.request({
1491
+ method: "PUT",
1492
+ path: `${this.basePath}/attach-pdf`,
1493
+ body
1494
+ });
1495
+ return res.enabled;
1496
+ }
1497
+ };
1498
+
1499
+ // src/resources/invoice-reminders.ts
1500
+ var InvoiceRemindersResource = class {
1501
+ constructor(http2) {
1502
+ this.http = http2;
1503
+ this.basePath = "/admin/invoice-reminders";
1504
+ }
1505
+ /** GET /admin/invoice-reminders — the rules, ascending by offset, and the overdue offsets. */
1506
+ async list() {
1507
+ return this.http.request({
1508
+ method: "GET",
1509
+ path: this.basePath
1510
+ });
1511
+ }
1512
+ /**
1513
+ * PUT /admin/invoice-reminders — replace the WHOLE rule set (a rule left out
1514
+ * is deleted): up to 5 rules at unique offsets. Templates may use only
1515
+ * `{{customerName}}`, `{{invoiceNumber}}`, `{{amountDue}}`, `{{total}}`,
1516
+ * `{{dueDate}}`, `{{daysOverdue}}` and `{{companyName}}`; any other is a 422
1517
+ * `REMINDER_TEMPLATE_INVALID` listing each one. Returns the stored set.
1518
+ */
1519
+ async update(rules) {
1520
+ return this.http.request({
1521
+ method: "PUT",
1522
+ path: this.basePath,
1523
+ body: { rules }
1524
+ });
1525
+ }
1526
+ /**
1527
+ * POST /admin/invoice-reminders/preview — render a subject and body exactly
1528
+ * as the reminder email would, against an invoice or a sample. Sends nothing.
1529
+ */
1530
+ async preview(params) {
1531
+ return this.http.request({
1532
+ method: "POST",
1533
+ path: `${this.basePath}/preview`,
1534
+ body: params
1535
+ });
1536
+ }
1537
+ };
1538
+
1539
+ // src/resources/contact-sequences.ts
1540
+ var ContactSequencesResource = class {
1541
+ constructor(http2) {
1542
+ this.http = http2;
1543
+ this.basePath = "/contact-sequences";
1544
+ }
1545
+ /** GET /contact-sequences — `{ data, meta: { total } }`, name-sorted, max 100. */
1546
+ async list() {
1547
+ return this.http.request({
1548
+ method: "GET",
1549
+ path: this.basePath
1550
+ });
1551
+ }
1552
+ };
1553
+
1554
+ // src/resources/enrollments.ts
1555
+ var EnrollmentsResource = class {
1556
+ constructor(http2) {
1557
+ this.http = http2;
1558
+ }
1559
+ /**
1560
+ * POST /contacts/:id/enrollments — `{ workflow_id }`. 409 if the contact is
1561
+ * already active in the sequence; 422 if the sequence has no published version.
1562
+ */
1563
+ async enroll(contactId, workflowId) {
1564
+ return this.http.request({
1565
+ method: "POST",
1566
+ path: `/contacts/${contactId}/enrollments`,
1567
+ body: { workflow_id: workflowId }
1568
+ });
1569
+ }
1570
+ /** GET /contacts/:id/enrollments — a bare array, newest first; optional `status` filter. */
1571
+ async list(contactId, params) {
1572
+ return this.http.request({
1573
+ method: "GET",
1574
+ path: `/contacts/${contactId}/enrollments`,
1575
+ ...params ? { params } : {}
1576
+ });
1577
+ }
1578
+ /**
1579
+ * POST /enrollments/:id/exit — no body; the exit reason is recorded as
1580
+ * `'manual'`. Idempotent: an already-ended enrollment is returned unchanged.
1581
+ */
1582
+ async exit(enrollmentId) {
1583
+ return this.http.request({
1584
+ method: "POST",
1585
+ path: `/enrollments/${enrollmentId}/exit`
1586
+ });
1587
+ }
1588
+ };
1589
+
1590
+ // src/resources/workflow-event-rules.ts
1591
+ var WorkflowEventRulesResource = class {
1592
+ constructor(http2, workflowId) {
1593
+ this.http = http2;
1594
+ this.workflowId = workflowId;
1595
+ }
1596
+ // Each request spells its path out in full (no computed base path) so the
1597
+ // API's SDK route-parity audit (sdk-route-parity-audit.spec.ts) can read it.
1598
+ /** GET — a bare array of the workflow's live rules, newest first. 404 `WORKFLOW_NOT_FOUND`. */
1599
+ async list() {
1600
+ return this.http.request({
1601
+ method: "GET",
1602
+ path: `/admin/workflows/${encodeURIComponent(this.workflowId)}/event-rules`
1603
+ });
1604
+ }
1605
+ /**
1606
+ * POST — add a rule (201). `when` defaults to `{}` and `enabled` to true; use
1607
+ * `when: {}` for the creation types in `WORKFLOW_EVENT_RULE_MATCH_ALL_EVENT_TYPES`.
1608
+ * 400 `VALIDATION_FAILED` for a bad body; 404 `WORKFLOW_NOT_FOUND`.
1609
+ */
1610
+ async create(input) {
1611
+ return this.http.request({
1612
+ method: "POST",
1613
+ path: `/admin/workflows/${encodeURIComponent(this.workflowId)}/event-rules`,
1614
+ body: input
1615
+ });
1616
+ }
1617
+ /** PATCH /:id — only the fields sent change (at least one). 404 `EVENT_RULE_NOT_FOUND`. */
1618
+ async update(ruleId, input) {
1619
+ return this.http.request({
1620
+ method: "PATCH",
1621
+ path: `/admin/workflows/${encodeURIComponent(this.workflowId)}/event-rules/${encodeURIComponent(ruleId)}`,
1622
+ body: input
1623
+ });
1624
+ }
1625
+ /** DELETE /:id — soft delete; returns `{ id }` (200). 404 `EVENT_RULE_NOT_FOUND`. */
1626
+ async delete(ruleId) {
1627
+ return this.http.request({
1628
+ method: "DELETE",
1629
+ path: `/admin/workflows/${encodeURIComponent(this.workflowId)}/event-rules/${encodeURIComponent(ruleId)}`
1630
+ });
1631
+ }
1632
+ };
1633
+
1634
+ // src/resources/workflows.ts
1635
+ var WorkflowsResource = class {
1636
+ constructor(http2) {
1637
+ this.http = http2;
1638
+ this.basePath = "/workflows";
1639
+ this.adminPath = "/admin/workflows";
1640
+ }
1641
+ /**
1642
+ * GET /workflows/:id/stages — the ordered stages of one workflow version. Pass
1643
+ * a record's instance `workflowId` (e.g. from `GET /opportunities/:id/workflow`)
1644
+ * to get the stages of the version that record is pinned to, even an archived
1645
+ * one. 404 for an unknown or draft id; 403 if the caller cannot read the
1646
+ * workflow's record type.
1647
+ */
1648
+ async getStages(workflowId) {
1649
+ return this.http.request({
1650
+ method: "GET",
1651
+ path: `${this.basePath}/${encodeURIComponent(workflowId)}/stages`
1652
+ });
1653
+ }
1654
+ /**
1655
+ * GET /workflows/transitions — transition summaries of every published
1656
+ * workflow, or with `workflowId` of that one version (published or archived;
1657
+ * an unknown, draft or other-tenant id returns an empty list). Each summary
1658
+ * carries `workflow_id`, `workflow_version`, `lineage_workflow_id` and
1659
+ * `automatic_only`. Only pipelines whose record type the caller can read
1660
+ * are listed; an unreadable `workflowId` returns an empty list, not 403.
1661
+ */
1662
+ async listTransitions(params = {}) {
1663
+ const query = {};
1664
+ if (params.entityTypes && params.entityTypes.length > 0) query["entity_types"] = params.entityTypes.join(",");
1665
+ if (params.workflowId) query["workflow_id"] = params.workflowId;
1666
+ return this.http.request({
1667
+ method: "GET",
1668
+ path: `${this.basePath}/transitions`,
1669
+ params: query
1670
+ });
1671
+ }
1672
+ /**
1673
+ * POST /admin/workflows/:wid/transitions — add a transition to a draft
1674
+ * workflow. Pass `automaticOnly: true` for an edge only automation should
1675
+ * fire (e.g. an event rule advancing on "contract sent").
1676
+ */
1677
+ async createTransition(workflowId, input) {
1678
+ return this.http.request({
1679
+ method: "POST",
1680
+ path: `${this.adminPath}/${encodeURIComponent(workflowId)}/transitions`,
1681
+ body: input
1682
+ });
1683
+ }
1684
+ /**
1685
+ * The event rules of one workflow (`/admin/workflows/:wid/event-rules`) —
1686
+ * "advance automatically when…". Any version's id works; rules are keyed by
1687
+ * the lineage root.
1688
+ */
1689
+ eventRules(workflowId) {
1690
+ return new WorkflowEventRulesResource(this.http, workflowId);
1691
+ }
1692
+ /** PUT /admin/workflows/:wid/transitions/:tid — update a draft workflow's transition. */
1693
+ async updateTransition(workflowId, transitionId, input) {
1694
+ return this.http.request({
1695
+ method: "PUT",
1696
+ path: `${this.adminPath}/${encodeURIComponent(workflowId)}/transitions/${encodeURIComponent(transitionId)}`,
1697
+ body: input
1698
+ });
1699
+ }
1700
+ };
1701
+
1702
+ // src/resources/service-schedules.ts
1703
+ var ServiceSchedulesResource = class {
1704
+ constructor(http2) {
1705
+ this.http = http2;
1706
+ this.basePath = "/service-schedules";
1707
+ }
1708
+ /**
1709
+ * POST /service-schedules/conflicts/preview — before booking people, see
1710
+ * who is already on another event (`conflicts`) and who would be outside
1711
+ * their working hours (`working_hours`). Read-only and warn-only: nothing
1712
+ * is ever blocked. Give exactly one of `windows` (single booking) or
1713
+ * `schedule` (a cadence). 400 on invalid input, INVALID_RECURRENCE_RULE,
1714
+ * INVALID_TIMEZONE or TOO_MANY_WINDOWS (> 400).
1715
+ */
1716
+ async previewConflicts(request) {
1717
+ return this.http.request({
1718
+ method: "POST",
1719
+ path: `${this.basePath}/conflicts/preview`,
1720
+ body: request
1721
+ });
1722
+ }
1723
+ };
1724
+
1725
+ // src/resources/billing-schedules.ts
1726
+ var BillingScheduleResource = class extends BaseResource {
1727
+ constructor(http2) {
1728
+ super(http2, "/admin/billing-schedules");
1729
+ }
1730
+ /** GET /admin/billing-schedules — list rows (no lines; `line_count` and `next_amount` instead). */
1731
+ async list(params) {
1732
+ return this.http.request({
1733
+ method: "GET",
1734
+ path: this.basePath,
1735
+ params: toQueryParams(params)
1736
+ });
1737
+ }
1738
+ /** GET /admin/billing-schedules/:id — the schedule with its lines and next 3 periods. */
1739
+ async get(id) {
1740
+ return this.http.request({
1741
+ method: "GET",
1742
+ path: `${this.basePath}/${encodeURIComponent(id)}`
1743
+ });
1744
+ }
1745
+ /**
1746
+ * POST /admin/billing-schedules. `timezone` defaults to the tenant's. A
1747
+ * backdated `start_date` needs `backfill` ('skip' | 'draft'), else 400
1748
+ * `BACKFILL_REQUIRED`; `collection: 'autopay'` without a platform-managed
1749
+ * Stripe connection and a saved default card is 422 `AUTOPAY_UNAVAILABLE`
1750
+ * (`reason` `no_connect` | `no_saved_method`).
1751
+ */
1752
+ async create(data) {
1753
+ return this.http.request({
1754
+ method: "POST",
1755
+ path: this.basePath,
1756
+ body: data
1757
+ });
1758
+ }
1759
+ /**
1760
+ * PATCH /admin/billing-schedules/:id — partial. `lines` replaces every line
1761
+ * from `effective_from` (default: the next period not yet invoiced) as a new
1762
+ * line version. 409 `CADENCE_LOCKED`; 422 `EFFECTIVE_DATE_IN_GENERATED_PERIOD`
1763
+ * for a date inside an invoiced period.
1764
+ */
1765
+ async update(id, data) {
1766
+ return this.http.request({
1767
+ method: "PATCH",
1768
+ path: `${this.basePath}/${encodeURIComponent(id)}`,
1769
+ body: data
1770
+ });
1771
+ }
1772
+ /** DELETE /admin/billing-schedules/:id — only a schedule that never invoiced (else 409 `SCHEDULE_HAS_INVOICES`). */
1773
+ async delete(id) {
1774
+ await this.http.request({
1775
+ method: "DELETE",
1776
+ path: `${this.basePath}/${encodeURIComponent(id)}`
1777
+ });
1778
+ }
1779
+ /** GET /admin/billing-schedules/:id/versions — line version history, newest effective date first. */
1780
+ async listVersions(id) {
1781
+ return this.http.request({
1782
+ method: "GET",
1783
+ path: `${this.basePath}/${encodeURIComponent(id)}/versions`
1784
+ });
1785
+ }
1786
+ /**
1787
+ * POST /admin/billing-schedules/:id/adjustments — add a one-off amount
1788
+ * (signed; negative is a credit) to the schedule's next generated invoice.
1789
+ * Billed exactly once; no automatic proration. 422 `ADJUSTMENT_INVALID`
1790
+ * (zero, or the next invoice would go below zero) or `SCHEDULE_NOT_ACTIVE`.
1791
+ */
1792
+ async addAdjustment(id, data) {
1793
+ return this.http.request({
1794
+ method: "POST",
1795
+ path: `${this.basePath}/${encodeURIComponent(id)}/adjustments`,
1796
+ body: data
1797
+ });
1798
+ }
1799
+ /** GET /admin/billing-schedules/:id/adjustments — oldest first; default pending and consumed. */
1800
+ async listAdjustments(id, params) {
1801
+ return this.http.request({
1802
+ method: "GET",
1803
+ path: `${this.basePath}/${encodeURIComponent(id)}/adjustments`,
1804
+ params: toQueryParams(params)
1805
+ });
1806
+ }
1807
+ /**
1808
+ * DELETE /admin/billing-schedules/:id/adjustments/:adjustmentId — cancel a
1809
+ * pending adjustment (it never bills). Returns it; 409
1810
+ * `ADJUSTMENT_ALREADY_CONSUMED` once an invoice carries it.
1811
+ */
1812
+ async cancelAdjustment(id, adjustmentId) {
1813
+ return this.http.request({
1814
+ method: "DELETE",
1815
+ path: `${this.basePath}/${encodeURIComponent(id)}/adjustments/${encodeURIComponent(adjustmentId)}`
1816
+ });
1817
+ }
1818
+ /** POST /admin/billing-schedules/:id/pause — 409 `INVALID_STATUS_TRANSITION` unless active. */
1819
+ async pause(id) {
1820
+ return this.http.request({
1821
+ method: "POST",
1822
+ path: `${this.basePath}/${encodeURIComponent(id)}/pause`
1823
+ });
1824
+ }
1825
+ /** POST /admin/billing-schedules/:id/resume — periods that fell due while paused are skipped. */
1826
+ async resume(id) {
1827
+ return this.http.request({
1828
+ method: "POST",
1829
+ path: `${this.basePath}/${encodeURIComponent(id)}/resume`
1830
+ });
1831
+ }
1832
+ /** POST /admin/billing-schedules/:id/end — no further periods generate. */
1833
+ async end(id) {
1834
+ return this.http.request({
1835
+ method: "POST",
1836
+ path: `${this.basePath}/${encodeURIComponent(id)}/end`
1837
+ });
1838
+ }
1839
+ /** GET /admin/billing-schedules/:id/preview — the next `count` (1–24, default 6) periods from the first unbilled one. */
1840
+ async preview(id, params) {
1841
+ return this.http.request({
1842
+ method: "GET",
1843
+ path: `${this.basePath}/${encodeURIComponent(id)}/preview`,
1844
+ params: toQueryParams(params)
1845
+ });
1846
+ }
1847
+ /** GET /admin/billing-schedules/:id/periods — the period ledger, newest first. */
1848
+ async periods(id, params) {
1849
+ return this.http.request({
1850
+ method: "GET",
1851
+ path: `${this.basePath}/${encodeURIComponent(id)}/periods`,
1852
+ params: toQueryParams(params)
1853
+ });
1854
+ }
1855
+ /**
1856
+ * GET /admin/billing-schedules/periods/needs-review — tenant-wide: needs_review
1857
+ * rows plus failed and stuck (pending over 2h) deliveries.
1858
+ */
1859
+ async needsReview(params) {
1860
+ return this.http.request({
1861
+ method: "GET",
1862
+ path: `${this.basePath}/periods/needs-review`,
1863
+ params: toQueryParams(params)
1864
+ });
1865
+ }
1866
+ /**
1867
+ * GET /admin/billing-schedules/autopay-summary — what disconnecting Stripe
1868
+ * would touch: live autopay schedules, the distinct customers on them, and
1869
+ * active saved cards on the current Stripe connection. On disconnect, autopay
1870
+ * schedules that can no longer charge switch to emailed pay links.
1871
+ */
1872
+ async autopaySummary() {
1873
+ return this.http.request({
1874
+ method: "GET",
1875
+ path: `${this.basePath}/autopay-summary`
1876
+ });
1877
+ }
1878
+ /**
1879
+ * POST /admin/billing-schedules/:id/generate-now — bill the current due
1880
+ * period now. Idempotent (`already_generated`); 409 `NOTHING_DUE` or
1881
+ * `SCHEDULE_NOT_ACTIVE`.
1882
+ */
1883
+ async generateNow(id) {
1884
+ return this.http.request({
1885
+ method: "POST",
1886
+ path: `${this.basePath}/${encodeURIComponent(id)}/generate-now`
1887
+ });
1888
+ }
1889
+ /**
1890
+ * POST /admin/billing-schedules/:id/periods/:periodStart/skip — skip one
1891
+ * period (`periodStart` is `YYYY-MM-DD`). Returns the skipped ledger row;
1892
+ * 400 `NOT_A_PERIOD`, 409 `PERIOD_ALREADY_INVOICED`.
1893
+ */
1894
+ async skipPeriod(id, periodStart, data = {}) {
1895
+ return this.http.request({
1896
+ method: "POST",
1897
+ path: `${this.basePath}/${encodeURIComponent(id)}/periods/${encodeURIComponent(periodStart)}/skip`,
1898
+ body: data
1899
+ });
1900
+ }
1901
+ /**
1902
+ * POST /admin/billing-schedules/:id/periods/:periodStart/regenerate — re-bill
1903
+ * a period whose invoice was voided (new draft on the same ledger row).
1904
+ * 409 `INVOICE_NOT_VOID` or `CHECKOUT_IN_FLIGHT`.
1905
+ */
1906
+ async regeneratePeriod(id, periodStart) {
1907
+ return this.http.request({
1908
+ method: "POST",
1909
+ path: `${this.basePath}/${encodeURIComponent(id)}/periods/${encodeURIComponent(periodStart)}/regenerate`
1910
+ });
1911
+ }
1912
+ };
1913
+
1914
+ // src/resources/custom-fields.ts
1915
+ var CustomFieldsResource = class {
1916
+ constructor(http2) {
1917
+ this.http = http2;
1918
+ }
1919
+ /** List definitions, optionally narrowed to one entity type. */
1920
+ async list(params) {
1921
+ return this.http.request({
1922
+ method: "GET",
1923
+ path: "/custom-fields",
1924
+ params
1925
+ });
1926
+ }
1927
+ };
1928
+
1929
+ // src/resources/ortto.ts
1930
+ var OrttoResource = class {
1931
+ constructor(http2) {
1932
+ this.http = http2;
1933
+ this.basePath = "/admin/integrations/ortto";
1934
+ }
1935
+ /** GET /admin/integrations/ortto/mappings — live mappings with their list names. */
1936
+ async listMappings() {
1937
+ const res = await this.http.request({
1938
+ method: "GET",
1939
+ path: `${this.basePath}/mappings`
1940
+ });
1941
+ return res.data;
1942
+ }
1943
+ /** GET /admin/integrations/ortto/audiences — the connected account's audiences (cached 60 s). */
1944
+ async listAudiences(params) {
1945
+ const res = await this.http.request({
1946
+ method: "GET",
1947
+ path: `${this.basePath}/audiences`,
1948
+ params
1949
+ });
1950
+ return res.data;
1951
+ }
1952
+ /** POST /admin/integrations/ortto/mappings — 409 when the list already has a mapping. */
1953
+ async createMapping(data) {
1954
+ const res = await this.http.request({
1955
+ method: "POST",
1956
+ path: `${this.basePath}/mappings`,
1957
+ body: data
1958
+ });
1959
+ return res.data;
1960
+ }
1961
+ /** PATCH /admin/integrations/ortto/mappings/:id — `ortto_tag` and/or `create_unmatched`. */
1962
+ async updateMapping(id, data) {
1963
+ const res = await this.http.request({
1964
+ method: "PATCH",
1965
+ path: `${this.basePath}/mappings/${id}`,
1966
+ body: data
1967
+ });
1968
+ return res.data;
1969
+ }
1970
+ /**
1971
+ * DELETE /admin/integrations/ortto/mappings/:id (204). A pull list becomes
1972
+ * editable again and keeps its members; a push tag is NOT removed from Ortto.
1973
+ */
1974
+ async deleteMapping(id) {
1975
+ await this.http.request({
1976
+ method: "DELETE",
1977
+ path: `${this.basePath}/mappings/${id}`
1978
+ });
1979
+ }
1980
+ /**
1981
+ * POST /admin/integrations/ortto/sync (202) — queue a sync for one mapping or
1982
+ * the whole connection. Never calls Ortto in-request.
1983
+ */
1984
+ async sync(data = {}) {
1985
+ const res = await this.http.request({
1986
+ method: "POST",
1987
+ path: `${this.basePath}/sync`,
1988
+ body: data
1989
+ });
1990
+ return res.data;
1991
+ }
1992
+ /** GET /admin/integrations/ortto/sync-status — 404 when Ortto is not connected. */
1993
+ async syncStatus() {
1994
+ const res = await this.http.request({
1995
+ method: "GET",
1996
+ path: `${this.basePath}/sync-status`
1997
+ });
1998
+ return res.data;
1999
+ }
2000
+ };
2001
+
2002
+ // src/webhooks.ts
2003
+ var import_node_crypto2 = require("crypto");
2004
+ var WEBHOOK_EVENT_TYPES = [
2005
+ "created",
2006
+ "updated",
2007
+ "deleted",
2008
+ "status_changed",
2009
+ "entity.tagged",
2010
+ "entity.untagged",
2011
+ "list.member_added",
2012
+ "list.member_removed",
2013
+ "entity.assigned",
2014
+ "entity.unassigned",
2015
+ "team.member_added",
2016
+ "team.member_removed",
2017
+ "task.created",
2018
+ "task.updated",
2019
+ "task.completed",
2020
+ "task.cancelled",
2021
+ "comment.created",
2022
+ "conversation.created",
2023
+ "conversation.matched",
2024
+ "conversation.deleted",
2025
+ "customer.merged",
2026
+ "workflow.instance_moved",
2027
+ "consent.changed",
2028
+ "billing_schedule.period_generated",
2029
+ "billing_schedule.period_needs_review",
2030
+ "billing_schedule.period_delivered",
2031
+ "billing_schedule.period_delivery_failed",
2032
+ "payment.on_void_invoice",
2033
+ "invoice.overdue",
2034
+ "integration_connection.deactivated",
2035
+ "customer_payment_method.invalidated",
2036
+ "invoice.autopay_succeeded",
2037
+ "invoice.autopay_failed"
2038
+ ];
2039
+ function verifyWebhookSignature(payload, signature, secret) {
2040
+ if (!signature || !secret || !payload) {
2041
+ return false;
2042
+ }
2043
+ const prefix = "sha256=";
2044
+ if (!signature.startsWith(prefix)) {
2045
+ return false;
622
2046
  }
623
2047
  const receivedHex = signature.slice(prefix.length);
624
2048
  if (!receivedHex) {
@@ -781,12 +2205,142 @@ var PlanesClient = class {
781
2205
  }
782
2206
  return this._activities;
783
2207
  }
2208
+ get communications() {
2209
+ if (!this._communications) {
2210
+ this._communications = new CommunicationsResource(this.http);
2211
+ }
2212
+ return this._communications;
2213
+ }
2214
+ /** Logged meetings — manual + provider-synced, with company matching (E55). */
2215
+ get conversations() {
2216
+ if (!this._conversations) {
2217
+ this._conversations = new ConversationsResource(this.http);
2218
+ }
2219
+ return this._conversations;
2220
+ }
2221
+ get gmail() {
2222
+ if (!this._gmail) {
2223
+ this._gmail = new GmailResource(this.http);
2224
+ }
2225
+ return this._gmail;
2226
+ }
2227
+ get documents() {
2228
+ if (!this._documents) {
2229
+ this._documents = new DocumentsResource(this.http);
2230
+ }
2231
+ return this._documents;
2232
+ }
784
2233
  get tags() {
785
2234
  if (!this._tags) {
786
2235
  this._tags = new TagResource(this.http);
787
2236
  }
788
2237
  return this._tags;
789
2238
  }
2239
+ get tasks() {
2240
+ if (!this._tasks) {
2241
+ this._tasks = new TaskResource(this.http);
2242
+ }
2243
+ return this._tasks;
2244
+ }
2245
+ /** Record views — the "recently viewed" beacon + read (E41-F7). */
2246
+ get recordViews() {
2247
+ if (!this._recordViews) {
2248
+ this._recordViews = new RecordViewsResource(this.http);
2249
+ }
2250
+ return this._recordViews;
2251
+ }
2252
+ /** Module status — which modules are active for the caller's tenant (E51-F1-S1). */
2253
+ get modules() {
2254
+ if (!this._modules) {
2255
+ this._modules = new ModulesResource(this.http);
2256
+ }
2257
+ return this._modules;
2258
+ }
2259
+ /** The tenant's plan, billing status and plan ceiling — `plan.get()` (E54-F1-S2). */
2260
+ get plan() {
2261
+ if (!this._plan) {
2262
+ this._plan = new PlanResource(this.http);
2263
+ }
2264
+ return this._plan;
2265
+ }
2266
+ /** The authenticated caller — `me.abilities()` (E52-F1-S3). */
2267
+ get me() {
2268
+ if (!this._me) {
2269
+ this._me = new MeResource(this.http);
2270
+ }
2271
+ return this._me;
2272
+ }
2273
+ /** Settings → Roles, admin only — `roles.list/get/updateGrants/reset/history` (E52-F2-S5). */
2274
+ get roles() {
2275
+ if (!this._roles) {
2276
+ this._roles = new RolesResource(this.http);
2277
+ }
2278
+ return this._roles;
2279
+ }
2280
+ /** Invoice settings — `invoiceSettings.getOfflineInstructions/setOfflineInstructions` (E56-F5-S4). */
2281
+ get invoiceSettings() {
2282
+ if (!this._invoiceSettings) {
2283
+ this._invoiceSettings = new InvoiceSettingsResource(this.http);
2284
+ }
2285
+ return this._invoiceSettings;
2286
+ }
2287
+ /** Payment reminder settings, admin only — `invoiceReminders.list/update/preview` (E56-F8-S6). */
2288
+ get invoiceReminders() {
2289
+ if (!this._invoiceReminders) {
2290
+ this._invoiceReminders = new InvoiceRemindersResource(this.http);
2291
+ }
2292
+ return this._invoiceReminders;
2293
+ }
2294
+ /** Published sequences a contact can be enrolled in (E51-F2-S6). */
2295
+ get contactSequences() {
2296
+ if (!this._contactSequences) {
2297
+ this._contactSequences = new ContactSequencesResource(this.http);
2298
+ }
2299
+ return this._contactSequences;
2300
+ }
2301
+ /** Enroll a contact in a sequence, list its enrollments, exit one (E51-F2-S8). */
2302
+ get enrollments() {
2303
+ if (!this._enrollments) {
2304
+ this._enrollments = new EnrollmentsResource(this.http);
2305
+ }
2306
+ return this._enrollments;
2307
+ }
2308
+ /** Tenant-readable workflow reads — a workflow version's ordered stages. */
2309
+ get workflows() {
2310
+ if (!this._workflows) {
2311
+ this._workflows = new WorkflowsResource(this.http);
2312
+ }
2313
+ return this._workflows;
2314
+ }
2315
+ get serviceSchedules() {
2316
+ if (!this._serviceSchedules) {
2317
+ this._serviceSchedules = new ServiceSchedulesResource(this.http);
2318
+ }
2319
+ return this._serviceSchedules;
2320
+ }
2321
+ /**
2322
+ * Recurring billing schedules (E56-F3) — CRUD, pause/resume/end, preview,
2323
+ * the period ledger, Needs review, generate-now, skip and regenerate.
2324
+ */
2325
+ get billingSchedules() {
2326
+ if (!this._billingSchedules) {
2327
+ this._billingSchedules = new BillingScheduleResource(this.http);
2328
+ }
2329
+ return this._billingSchedules;
2330
+ }
2331
+ get customFields() {
2332
+ if (!this._customFields) {
2333
+ this._customFields = new CustomFieldsResource(this.http);
2334
+ }
2335
+ return this._customFields;
2336
+ }
2337
+ /** Ortto connector — list mappings, audiences, manual sync, sync status (E53). Admin-only. */
2338
+ get ortto() {
2339
+ if (!this._ortto) {
2340
+ this._ortto = new OrttoResource(this.http);
2341
+ }
2342
+ return this._ortto;
2343
+ }
790
2344
  /**
791
2345
  * Ergonomic webhook event router — `client.webhooks.on(pattern, handler)`
792
2346
  * plus `client.webhooks.process({ body, signature, secret })`. Auth-independent
@@ -801,6 +2355,129 @@ var PlanesClient = class {
801
2355
  }
802
2356
  };
803
2357
 
2358
+ // src/types/billing-schedule-types.ts
2359
+ var BILLING_CADENCES = ["weekly", "every_n_weeks", "monthly", "quarterly", "annually"];
2360
+ var BILLING_SCHEDULE_STATUSES = ["active", "paused", "ended"];
2361
+ var BILL_TIMINGS = ["in_advance", "in_arrears"];
2362
+ var BILLING_DELIVERY_MODES = ["auto_send", "draft_for_review"];
2363
+ var BILLING_COLLECTION_MODES = ["send_link", "autopay"];
2364
+ var AUTOPAY_UNAVAILABLE_REASONS = ["no_connect", "no_saved_method"];
2365
+ var BILLING_AUTOPAY_STATUSES = [
2366
+ "not_applicable",
2367
+ "scheduled",
2368
+ "submitted",
2369
+ "succeeded",
2370
+ "failed",
2371
+ "auth_required",
2372
+ "retry_scheduled",
2373
+ "abandoned"
2374
+ ];
2375
+ var BILLING_BACKFILL_MODES = ["skip", "draft"];
2376
+ var BILLING_PERIOD_STATUSES = ["generated", "skipped", "needs_review", "failed", "voided"];
2377
+ var BILLING_PREVIEW_PERIOD_STATUSES = [...BILLING_PERIOD_STATUSES, "upcoming"];
2378
+ var BILLING_DELIVERY_STATUSES = ["pending", "sent", "failed", "not_applicable"];
2379
+ var BILLING_ADJUSTMENT_STATUSES = ["pending", "consumed", "cancelled"];
2380
+ var BILLING_ADJUSTMENT_TARGETS = ["next_invoice"];
2381
+
2382
+ // src/types/contact-types.ts
2383
+ var CONTACT_SORT_KEYS = ["name", "created_at", "recent"];
2384
+ var CONTACT_LIST_INCLUDES = ["channels", "links"];
2385
+
2386
+ // src/types/customer-types.ts
2387
+ var CUSTOMER_SORT_KEYS = ["created_at", "last_name", "first_name", "email", "phone", "source", "recent"];
2388
+
2389
+ // src/types/opportunity-types.ts
2390
+ var OPPORTUNITY_SORT_KEYS = ["created_at", "total", "title", "customer_name", "stage", "priority", "recent"];
2391
+ var OPPORTUNITY_STATES = ["open", "closed", "won", "lost"];
2392
+
2393
+ // src/types/job-types.ts
2394
+ var JOB_SORT_KEYS = ["created_at", "recent"];
2395
+
2396
+ // src/types/estimate-types.ts
2397
+ var ESTIMATE_STATUSES = ["draft", "sent", "approved", "rejected"];
2398
+
2399
+ // src/types/record-view-types.ts
2400
+ var RECORD_VIEW_ENTITY_TYPES = ["customer", "contact", "opportunity", "job"];
2401
+
2402
+ // src/types/module-types.ts
2403
+ var MODULE_KEYS = [
2404
+ "estimates",
2405
+ "contracts",
2406
+ "inventory",
2407
+ "production",
2408
+ "production_scheduling",
2409
+ "calendar",
2410
+ "service-schedules",
2411
+ "marketplace",
2412
+ "invoicing",
2413
+ "knocks",
2414
+ "accounting",
2415
+ "contacts",
2416
+ "tasks",
2417
+ "comments",
2418
+ "conversations"
2419
+ ];
2420
+
2421
+ // src/types/plan-types.ts
2422
+ var PLAN_KEYS = ["solo", "sales", "business", "operations", "legacy", "internal"];
2423
+ var BILLING_STATUSES = [
2424
+ "trialing",
2425
+ "active",
2426
+ "past_due",
2427
+ "unpaid",
2428
+ "paused",
2429
+ "canceled",
2430
+ "comped"
2431
+ ];
2432
+ var PLAN_SOURCES = ["stripe", "manual"];
2433
+ var BILLING_INTERVALS = ["month", "year"];
2434
+ var FEATURE_KEYS = [
2435
+ "calendar",
2436
+ "estimates",
2437
+ "contracts",
2438
+ "service_dispatch",
2439
+ "production_scheduling",
2440
+ "sub_management",
2441
+ "reports",
2442
+ "open_api",
2443
+ "workflow_builder",
2444
+ "integrations.quickbooks",
2445
+ "integrations.stripe",
2446
+ "integrations.hover",
2447
+ "integrations.ortto",
2448
+ "communications.marketing",
2449
+ "ai.scheduling",
2450
+ "ai.content_assist",
2451
+ "ai.documents",
2452
+ "ai.search",
2453
+ "inventory_management",
2454
+ "workflow_execution",
2455
+ "marketplace"
2456
+ ];
2457
+
2458
+ // src/types/me-types.ts
2459
+ var AGENT_ROLES = [
2460
+ "admin",
2461
+ "sales",
2462
+ "service",
2463
+ "production",
2464
+ "sub",
2465
+ "readonly",
2466
+ "system_agent"
2467
+ ];
2468
+
2469
+ // src/types/workflow-event-rule-types.ts
2470
+ var WORKFLOW_EVENT_RULE_EVENT_TYPES = [
2471
+ "contract.status_changed",
2472
+ "invoice.status_changed",
2473
+ "calendar_event.status_changed",
2474
+ /** "An event is booked": one-off events and recurring series masters. */
2475
+ "calendar_event.created"
2476
+ ];
2477
+ var WORKFLOW_EVENT_RULE_MATCH_ALL_EVENT_TYPES = [
2478
+ "calendar_event.created"
2479
+ ];
2480
+
804
2481
  // src/agent.ts
805
2482
  var http = __toESM(require("http"));
806
2483
  function createActionServer(handlerMap, options) {
@@ -957,39 +2634,92 @@ function readBody(req) {
957
2634
  }
958
2635
  // Annotate the CommonJS export names for ESM import in node:
959
2636
  0 && (module.exports = {
2637
+ AGENT_ROLES,
2638
+ AUTOPAY_UNAVAILABLE_REASONS,
960
2639
  ActivityResource,
961
2640
  AgentApp,
2641
+ ApiResource,
962
2642
  AuthenticationError,
963
2643
  AuthorizationError,
2644
+ BILLING_ADJUSTMENT_STATUSES,
2645
+ BILLING_ADJUSTMENT_TARGETS,
2646
+ BILLING_AUTOPAY_STATUSES,
2647
+ BILLING_BACKFILL_MODES,
2648
+ BILLING_CADENCES,
2649
+ BILLING_COLLECTION_MODES,
2650
+ BILLING_DELIVERY_MODES,
2651
+ BILLING_DELIVERY_STATUSES,
2652
+ BILLING_INTERVALS,
2653
+ BILLING_PERIOD_STATUSES,
2654
+ BILLING_PREVIEW_PERIOD_STATUSES,
2655
+ BILLING_SCHEDULE_STATUSES,
2656
+ BILLING_STATUSES,
2657
+ BILL_TIMINGS,
964
2658
  BaseResource,
2659
+ BillingScheduleResource,
2660
+ CONTACT_LIST_INCLUDES,
2661
+ CONTACT_SORT_KEYS,
2662
+ CUSTOMER_SORT_KEYS,
965
2663
  CalendarEventResource,
2664
+ CommunicationsResource,
966
2665
  ContactChannelResource,
967
2666
  ContactResource,
2667
+ ContactSequencesResource,
968
2668
  ContractResource,
2669
+ ConversationsResource,
2670
+ CustomFieldsResource,
969
2671
  CustomerResource,
970
2672
  DEFAULT_BASE_URL,
971
2673
  DEFAULT_MAX_RETRIES,
972
2674
  DEFAULT_TIMEOUT,
973
2675
  DEFAULT_TOKEN_REFRESH_SKEW_MS,
2676
+ DocumentsResource,
2677
+ ESTIMATE_STATUSES,
2678
+ EnrollmentsResource,
974
2679
  EstimateResource,
2680
+ FEATURE_KEYS,
2681
+ GmailResource,
975
2682
  InventoryResource,
2683
+ InvoiceRemindersResource,
976
2684
  InvoiceResource,
2685
+ InvoiceSettingsResource,
2686
+ JOB_SORT_KEYS,
977
2687
  JobResource,
2688
+ MODULE_KEYS,
2689
+ MeResource,
978
2690
  MemoryTokenStorage,
2691
+ ModulesResource,
979
2692
  NotFoundError,
980
2693
  OAuthError,
2694
+ OPPORTUNITY_SORT_KEYS,
2695
+ OPPORTUNITY_STATES,
981
2696
  OpportunityResource,
2697
+ OrttoResource,
2698
+ PLAN_KEYS,
2699
+ PLAN_SOURCES,
2700
+ PlanResource,
982
2701
  Planes,
983
2702
  PlanesClient,
984
2703
  PlanesError,
985
2704
  PropertyResource,
2705
+ RECORD_VIEW_ENTITY_TYPES,
986
2706
  RateLimitError,
2707
+ RecordViewsResource,
2708
+ RolesResource,
987
2709
  ServerError,
2710
+ ServiceSchedulesResource,
988
2711
  TagResource,
2712
+ TaskResource,
989
2713
  ValidationError,
2714
+ WEBHOOK_EVENT_TYPES,
2715
+ WORKFLOW_EVENT_RULE_EVENT_TYPES,
2716
+ WORKFLOW_EVENT_RULE_MATCH_ALL_EVENT_TYPES,
990
2717
  WebhookRouter,
991
2718
  WebhookVerificationError,
2719
+ WorkflowEventRulesResource,
2720
+ WorkflowsResource,
992
2721
  buildAuthorizeUrl,
2722
+ clientCredentialsGrant,
993
2723
  createAgentApp,
994
2724
  exchangeCode,
995
2725
  parseWebhookEvent,