@planescrm/sdk 0.55.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/dist/index.d.ts CHANGED
@@ -77,6 +77,28 @@ interface PlanesConfig {
77
77
  retryOnRateLimit?: boolean;
78
78
  /** Maximum number of retries for rate-limited requests (default 3) */
79
79
  maxRetries?: number;
80
+ /**
81
+ * User-session mode (E67): called before every request for the current
82
+ * access token, so the caller owns storage (the phone app keeps tokens in
83
+ * the device keychain). `null` sends the request with no Authorization
84
+ * header. When set, it takes the place of `accessToken`.
85
+ *
86
+ * Use it through `@planescrm/sdk/client`, whose `PlanesClient` takes only
87
+ * these session options.
88
+ */
89
+ getAccessToken?: () => Promise<string | null>;
90
+ /**
91
+ * User-session mode: called once when a request comes back 401. Refresh the
92
+ * session and resolve `true` to have that request retried once with a fresh
93
+ * `getAccessToken()`; resolve `false` (signed out, refresh refused) to let
94
+ * the 401 surface as an `AuthenticationError`. Concurrent 401s share one call.
95
+ */
96
+ onUnauthorized?: () => Promise<boolean>;
97
+ /**
98
+ * The `fetch` to use instead of the global one (React Native, tests, or a
99
+ * wrapper that adds client headers).
100
+ */
101
+ fetch?: typeof fetch;
80
102
  }
81
103
  declare const DEFAULT_BASE_URL = "https://api.planescrm.com/api/v1";
82
104
  declare const DEFAULT_TIMEOUT = 30000;
@@ -89,6 +111,12 @@ interface HttpRequestOptions {
89
111
  body?: unknown;
90
112
  params?: Record<string, unknown>;
91
113
  headers?: Record<string, string>;
114
+ /**
115
+ * Sent as `Idempotency-Key` (E64-S6). The same key on every retry of one
116
+ * logical request makes the retry safe: a create the server already did
117
+ * returns its first response instead of making a second record.
118
+ */
119
+ idempotencyKey?: string;
92
120
  /** 'arrayBuffer' returns the raw response body (binary downloads); default 'json'. */
93
121
  responseType?: 'json' | 'arrayBuffer';
94
122
  }
@@ -106,6 +134,11 @@ declare class HttpClient {
106
134
  private readonly oauth;
107
135
  /** Single-flight guard so concurrent requests share one refresh. */
108
136
  private refreshInFlight;
137
+ private readonly getAccessToken;
138
+ private readonly onUnauthorized;
139
+ /** Single-flight guard so concurrent 401s share one `onUnauthorized` call. */
140
+ private unauthorizedInFlight;
141
+ private readonly fetchImpl;
109
142
  constructor(config: PlanesConfig);
110
143
  request<T>(options: HttpRequestOptions): Promise<T>;
111
144
  getAuthHeaders(): Record<string, string>;
@@ -122,6 +155,17 @@ declare class HttpClient {
122
155
  * a single in-flight refresh.
123
156
  */
124
157
  private refreshTokens;
158
+ /**
159
+ * Ask the app to refresh its session after a 401. Resolves `true` when the
160
+ * request should be retried.
161
+ * - Requests that got a 401 while a refresh is running share that one call.
162
+ * - A request whose 401 arrives after a refresh already finished (it was
163
+ * sent with the old token) doesn't start a second refresh: if the current
164
+ * token differs from the one it sent, it just retries with the new one.
165
+ * - A refresh that throws, or doesn't settle within the request timeout,
166
+ * counts as "still signed out": the original 401 surfaces.
167
+ */
168
+ private recoverSession;
125
169
  private buildUrl;
126
170
  private parseRetryAfter;
127
171
  private mapError;
@@ -183,9 +227,13 @@ declare abstract class BaseResource<TEntity = Record<string, unknown>, TCreate =
183
227
  */
184
228
  get(id: string): Promise<TEntity>;
185
229
  /**
186
- * Create a new entity.
230
+ * Create a new entity. Pass `idempotencyKey` (a UUID you keep for retries) to
231
+ * make a retry safe on routes that honor it (customers, opportunities, contacts,
232
+ * tasks): a repeat returns the first response and creates nothing.
187
233
  */
188
- create(data: TCreate): Promise<TEntity>;
234
+ create(data: TCreate, options?: {
235
+ idempotencyKey?: string;
236
+ }): Promise<TEntity>;
189
237
  /**
190
238
  * Update an existing entity.
191
239
  */
@@ -203,7 +251,7 @@ declare abstract class BaseResource<TEntity = Record<string, unknown>, TCreate =
203
251
  * Extends the generic `ListParams` so it stays assignable to `BaseResource.list`.
204
252
  */
205
253
  /** Sortable columns on `GET /opportunities` (kept in lockstep with the server enum by the SDK's wire-contract spec). */
206
- declare const OPPORTUNITY_SORT_KEYS: readonly ["created_at", "total", "title", "customer_name", "stage", "priority", "recent"];
254
+ declare const OPPORTUNITY_SORT_KEYS: readonly ["created_at", "total", "title", "customer_name", "stage", "priority", "recent", "updated_at"];
207
255
  type OpportunitySortKey = (typeof OPPORTUNITY_SORT_KEYS)[number];
208
256
  /**
209
257
  * Lifecycle states on `GET /opportunities` (kept in lockstep with the server's
@@ -226,6 +274,29 @@ interface OpportunityListParams extends ListParams {
226
274
  priority?: 'low' | 'normal' | 'high' | 'urgent';
227
275
  source?: string;
228
276
  tag_ids?: string[];
277
+ /**
278
+ * Only records updated at or after this instant (inclusive), as an ISO-8601
279
+ * datetime with a timezone, e.g. `2026-11-10T14:00:00Z` (E64-S5). Rows come
280
+ * in `updatedAt`, then `id`, order. Page with the last row's `updatedAt` as
281
+ * `updated_since` and its `id` as `after_id` (not an offset) until a page is
282
+ * short. For the next sync, start from the time this one **started**, minus
283
+ * a few minutes, not the newest `updatedAt` seen. Treat repeats as no-ops.
284
+ */
285
+ updated_since?: string;
286
+ /** With `updated_since`: continue after this id (the last row of the previous page). Replaces page/offset; `total` then counts the rows still to come. */
287
+ after_id?: string;
288
+ /**
289
+ * Exact-match filters by custom field value, sent as `cf.<key>=<value>` (E64-S3).
290
+ * Several are ANDed. The field must be marked searchable, or the API returns
291
+ * 400 `CUSTOM_FIELD_NOT_FILTERABLE`. A multi-select matches a record whose list
292
+ * includes the value.
293
+ */
294
+ customFields?: Record<string, string | number | boolean>;
295
+ /**
296
+ * Opportunities whose trades include this trade id: requested by the client,
297
+ * or on one of its live jobs (the same rule as `OpportunityTrade`).
298
+ */
299
+ trade_id?: string;
229
300
  /**
230
301
  * Mirrors `OPPORTUNITY_SORT_KEYS`. `customer_name` orders by the customer's
231
302
  * display name, `stage` by pipeline position (stage-less rows last),
@@ -256,7 +327,33 @@ interface UpdateOpportunityDto$1 {
256
327
  closedAt?: string | null | undefined;
257
328
  closedReason?: string | null | undefined;
258
329
  primaryContactId?: string | null | undefined;
259
- customFields?: Record<string, unknown> | null | undefined;
330
+ /**
331
+ * Custom-field values to change. Merged into the record's stored values:
332
+ * keys you leave out are kept, and a key set to `null` (or `''`) is cleared.
333
+ * Sending `customFields: null` is rejected with 400.
334
+ */
335
+ customFields?: Record<string, unknown> | undefined;
336
+ /**
337
+ * Replaces the trades the client asked for (active trade ids); `[]` clears
338
+ * them. Jobs' trades are unaffected. Also accepted on create.
339
+ */
340
+ requestedTradeIds?: string[] | undefined;
341
+ }
342
+ /**
343
+ * One entry of `trades` on `GET /opportunities/{id}`. An opportunity's trades
344
+ * are derived, never stored: its requested trades plus the trades of its live
345
+ * jobs. Adding a job in a new trade adds it; deleting the job removes it unless
346
+ * it was requested. `requested_trades` on the same response lists `{ id, name }`
347
+ * for the requested ones.
348
+ */
349
+ interface OpportunityTrade {
350
+ id: string;
351
+ name: string;
352
+ icon: string | null;
353
+ /** The client asked for this trade. */
354
+ requested: boolean;
355
+ /** A live job on the opportunity is in this trade. */
356
+ from_jobs: boolean;
260
357
  }
261
358
 
262
359
  /** Opportunity resource — CRUD operations on /opportunities (updates are PUT). */
@@ -267,8 +364,34 @@ declare class OpportunityResource extends BaseResource {
267
364
  * query value (`?tag_ids=a,b`), which is what the API's filter schema parses.
268
365
  */
269
366
  list(params?: OpportunityListParams): Promise<PaginatedResponse<Record<string, unknown>>>;
367
+ /**
368
+ * GET /opportunities/trade-options — the active trades a client can request
369
+ * (`requestedTradeIds` on create/update), sorted by name.
370
+ */
371
+ tradeOptions(): Promise<{
372
+ data: Array<{
373
+ id: string;
374
+ name: string;
375
+ icon: string | null;
376
+ }>;
377
+ }>;
270
378
  /** PUT /opportunities/{id} — partial update; stage moves go through workflow transitions. */
271
379
  update(id: string, data: UpdateOpportunityDto$1): Promise<Record<string, unknown>>;
380
+ /** GET /opportunities/:id/transitions — the pipeline moves available from the current stage, for the caller's role. */
381
+ listTransitions(id: string): Promise<{
382
+ transitions: Array<Record<string, unknown>>;
383
+ }>;
384
+ /**
385
+ * POST /opportunities/:id/transition — take one pipeline move, as the stage button does: required
386
+ * fields are checked, the move is logged, and the stage's automations run (they can send email).
387
+ */
388
+ transition(id: string, data: {
389
+ transition_id: string;
390
+ notes?: string;
391
+ entity_data?: Record<string, unknown>;
392
+ }): Promise<Record<string, unknown>>;
393
+ /** GET /opportunities/:id/workflow — the pipeline instance with its transition history (404 if none). */
394
+ getWorkflow(id: string): Promise<Record<string, unknown>>;
272
395
  }
273
396
 
274
397
  /**
@@ -325,7 +448,12 @@ interface UpdateCustomerDto {
325
448
  notes?: string | null;
326
449
  source?: string | null;
327
450
  address?: CustomerAddressInput;
328
- customFields?: Record<string, unknown> | null;
451
+ /**
452
+ * Custom-field values to change. Merged into the record's stored values:
453
+ * keys you leave out are kept, and a key set to `null` (or `''`) is cleared.
454
+ * Sending `customFields: null` is rejected with 400.
455
+ */
456
+ customFields?: Record<string, unknown>;
329
457
  }
330
458
  /**
331
459
  * Query params for `GET /customers` — mirrors `customerFilterSchema` in
@@ -334,15 +462,37 @@ interface UpdateCustomerDto {
334
462
  * Extends the generic `ListParams` so it stays assignable to `BaseResource.list`.
335
463
  */
336
464
  /** Sortable columns on `GET /customers` (kept in lockstep with the server enum by the SDK's wire-contract spec). */
337
- declare const CUSTOMER_SORT_KEYS: readonly ["created_at", "last_name", "first_name", "email", "phone", "source", "recent"];
465
+ declare const CUSTOMER_SORT_KEYS: readonly ["created_at", "last_name", "first_name", "email", "phone", "source", "recent", "updated_at"];
338
466
  type CustomerSortKey = (typeof CUSTOMER_SORT_KEYS)[number];
339
467
  interface CustomerListParams extends ListParams {
340
- /** Person or company name; every word must match, so a full name works in either order. */
468
+ /**
469
+ * Name, company, email or phone; every word must match, so a full name works in
470
+ * either order. A word starting with `@` (`@acme.com`) matches the email domain
471
+ * exactly (E64-S4).
472
+ */
341
473
  search?: string;
342
474
  notes_contains?: string;
343
475
  source?: string;
344
476
  kind?: 'person' | 'company';
345
477
  tag_ids?: string[];
478
+ /**
479
+ * Only records updated at or after this instant (inclusive), as an ISO-8601
480
+ * datetime with a timezone, e.g. `2026-11-10T14:00:00Z` (E64-S5). Rows come
481
+ * in `updatedAt`, then `id`, order. Page with the last row's `updatedAt` as
482
+ * `updated_since` and its `id` as `after_id` (not an offset) until a page is
483
+ * short. For the next sync, start from the time this one **started**, minus
484
+ * a few minutes, not the newest `updatedAt` seen. Treat repeats as no-ops.
485
+ */
486
+ updated_since?: string;
487
+ /** With `updated_since`: continue after this id (the last row of the previous page). Replaces page/offset; `total` then counts the rows still to come. */
488
+ after_id?: string;
489
+ /**
490
+ * Exact-match filters by custom field value, sent as `cf.<key>=<value>` (E64-S3).
491
+ * Several are ANDed. The field must be marked searchable, or the API returns
492
+ * 400 `CUSTOM_FIELD_NOT_FILTERABLE`. A multi-select matches a record whose list
493
+ * includes the value.
494
+ */
495
+ customFields?: Record<string, string | number | boolean>;
346
496
  /**
347
497
  * Mirrors `CUSTOMER_SORT_KEYS`. `last_name` sorts companies by company name.
348
498
  * email / phone / source are nullable and sort NULLs last in both directions.
@@ -354,6 +504,13 @@ interface CustomerListParams extends ListParams {
354
504
  page?: number;
355
505
  limit?: number;
356
506
  }
507
+ /**
508
+ * `POST /customers/{id}/convert-to-company` body — mirrors
509
+ * `convertCustomerToCompanySchema`. Omit `companyName` to keep the current name.
510
+ */
511
+ interface ConvertCustomerToCompanyDto {
512
+ companyName?: string | undefined;
513
+ }
357
514
 
358
515
  /** Customer resource — CRUD operations on /customers. */
359
516
  declare class CustomerResource extends BaseResource {
@@ -380,6 +537,13 @@ declare class CustomerResource extends BaseResource {
380
537
  * working. Irreversible; requires admin scope.
381
538
  */
382
539
  merge(winnerId: string, loserId: string): Promise<CustomerMergeResult>;
540
+ /**
541
+ * POST /customers/{id}/convert-to-company — turn a person customer into a
542
+ * company. The person becomes the company's primary contact (their email and
543
+ * phone, with do-not-contact and marketing opt-outs carried over). A customer
544
+ * that's already a company is a 409 `ALREADY_COMPANY`.
545
+ */
546
+ convertToCompany(id: string, data?: ConvertCustomerToCompanyDto): Promise<Record<string, unknown>>;
383
547
  }
384
548
 
385
549
  /**
@@ -434,6 +598,12 @@ declare class PropertyResource extends ApiResource {
434
598
  create(customerId: string, data: CreatePropertyDto): Promise<Record<string, unknown>>;
435
599
  /** PUT /customers/{customerId}/properties/{id} — partial update. */
436
600
  update(customerId: string, id: string, data: UpdatePropertyDto): Promise<Record<string, unknown>>;
601
+ /** GET /customers/:customerId/properties/:id — one property, checked against its customer (404 if it isn't theirs). */
602
+ getForCustomer(customerId: string, id: string): Promise<Record<string, unknown>>;
603
+ /** POST /properties/:id/geocode — queue a fresh geocode of the property's address. */
604
+ geocode(id: string): Promise<{
605
+ status: 'queued';
606
+ }>;
437
607
  /** DELETE /customers/{customerId}/properties/{id} — soft delete (204). */
438
608
  delete(customerId: string, id: string): Promise<void>;
439
609
  }
@@ -451,7 +621,7 @@ declare class PropertyResource extends ApiResource {
451
621
  */
452
622
  /** Whether the event's "on complete" transition ran. */
453
623
  type CompletionTriggerStatus = 'fired' | 'skipped' | 'failed';
454
- type CompletionTriggerReason = 'no_completion_transition' | 'executor_unavailable' | 'no_linked_record' | 'no_workflow_instance' | 'transition_not_found' | 'wrong_pipeline' | 'no_equivalent_in_version' | 'not_valid_from_current_stage' | 'role_not_allowed' | 'missing_required_fields' | 'transition_error';
624
+ type CompletionTriggerReason = 'no_completion_transition' | 'executor_unavailable' | 'no_linked_record' | 'no_workflow_instance' | 'transition_not_found' | 'wrong_pipeline' | 'no_equivalent_in_version' | 'handled_by_pipeline_rule' | 'not_valid_from_current_stage' | 'role_not_allowed' | 'missing_required_fields' | 'transition_error';
455
625
  /** A pipeline stage, named as the record's pipeline version names it (0.55.0). */
456
626
  interface CompletionTriggerStage {
457
627
  id: string;
@@ -546,6 +716,14 @@ interface UpdateCalendarEventOptions {
546
716
  /** Defaults to `this` on the server when omitted. */
547
717
  editMode?: RecurrenceEditMode | undefined;
548
718
  }
719
+ /** A participant's response — mirrors `PARTICIPANT_STATUSES`. */
720
+ type CalendarParticipantStatus = 'invited' | 'accepted' | 'declined' | 'tentative';
721
+ /** `POST /events/{id}/participants` body — mirrors `addParticipantSchema` (status is required here). */
722
+ interface AddCalendarParticipantDto {
723
+ type: 'user' | 'contact' | 'crew' | 'agent';
724
+ id: string;
725
+ status: CalendarParticipantStatus;
726
+ }
549
727
 
550
728
  /**
551
729
  * Query filters for `GET /events`. Mirrors the API's
@@ -600,14 +778,123 @@ declare class CalendarEventResource extends BaseResource<Record<string, unknown>
600
778
  * POST /events/:id/complete — marks the event completed and runs its "on
601
779
  * complete" transition, best-effort. The event is completed even when the
602
780
  * transition can't run; `workflow_trigger` says whether it fired, was
603
- * skipped (none set) or failed (with a reason).
781
+ * skipped (none set, or `handled_by_pipeline_rule`: the pipeline's rule
782
+ * moves the record instead) or failed (with a reason).
604
783
  */
605
784
  complete(id: string, body?: CompleteCalendarEventDto): Promise<CompleteCalendarEventResponse>;
785
+ /**
786
+ * POST /events/:id/cancel. For an occurrence of a recurring event, `editMode`
787
+ * picks which occurrences are cancelled (`this` when omitted). 409 if already
788
+ * cancelled; 422 for a completed event.
789
+ */
790
+ cancel(id: string, options?: UpdateCalendarEventOptions): Promise<Record<string, unknown>>;
791
+ /** POST /events/:id/participants — add a user, contact, crew or agent to the event. No invite is sent. */
792
+ addParticipant(id: string, data: AddCalendarParticipantDto): Promise<Record<string, unknown>>;
793
+ /** PATCH /events/:id/participants/:participantId — set a participant's response. */
794
+ updateParticipantStatus(id: string, participantId: string, status: CalendarParticipantStatus): Promise<Record<string, unknown>>;
606
795
  }
607
796
 
608
- /** Contract resource — CRUD operations on /contracts. */
797
+ /**
798
+ * Wire shapes for the contract write routes (E64-S9). Mirror the schemas in
799
+ * `packages/shared/src/validation/contract.ts`, redefined here so the
800
+ * published package carries no dependency on `@blueprint/shared`;
801
+ * `contract-types.parity.ts` fails the build when the two drift.
802
+ */
803
+ /**
804
+ * `POST /contracts/for-subject` body: a bare agreement for a customer or a
805
+ * service schedule, with no opportunity and no line groups.
806
+ */
807
+ interface CreateContractForSubjectDto {
808
+ subjectType: 'service_schedule' | 'customer';
809
+ subjectId: string;
810
+ notes?: string | undefined;
811
+ /**
812
+ * This contract's deposit, % of total (0 < n ≤ 100, 2 dp). Omit to take the
813
+ * template's; null for no deposit rule.
814
+ */
815
+ depositPercent?: number | null | undefined;
816
+ }
817
+ /**
818
+ * `POST /contracts/flat` body: a contract on an opportunity with a manually
819
+ * entered total and a contract template for its clauses, no estimates.
820
+ */
821
+ interface CreateFlatContractDto {
822
+ opportunityId: string;
823
+ contractTemplateId: string;
824
+ /** Decimal string greater than zero, up to 2 dp (`"4850.00"`). */
825
+ totalAmount: string;
826
+ notes?: string | undefined;
827
+ depositPercent?: number | null | undefined;
828
+ }
829
+ /** `POST /contracts/{id}/change-orders` body. The parent must be signed or fulfilled. */
830
+ interface CreateChangeOrderDto {
831
+ /** At least one approved estimate, by job. */
832
+ lineGroups: Array<{
833
+ jobId: string;
834
+ estimateId: string;
835
+ }>;
836
+ supersededClauseIds?: string[] | undefined;
837
+ notes?: string | undefined;
838
+ }
839
+ /**
840
+ * `POST /contracts/{id}/send` body. All optional: an empty body addresses the
841
+ * customer. Name a contact to have them sign instead.
842
+ */
843
+ interface SendContractDto {
844
+ signerContactId?: string | null | undefined;
845
+ signerName?: string | null | undefined;
846
+ signerTitle?: string | null | undefined;
847
+ }
848
+
849
+ /**
850
+ * Contract resource — CRUD operations on /contracts, plus the lifecycle:
851
+ * draft → submit (approval, or auto-approved under the threshold) → send →
852
+ * signed. In-person signing isn't here: it captures the signer on the rep's
853
+ * device in the app, and an integration has no signer present (E64-S9).
854
+ */
609
855
  declare class ContractResource extends BaseResource {
610
856
  constructor(http: ConstructorParameters<typeof BaseResource>[0]);
857
+ /** POST /contracts/for-subject — a bare agreement for a customer or a service schedule (no opportunity, no line groups). */
858
+ createForSubject(data: CreateContractForSubjectDto): Promise<Record<string, unknown>>;
859
+ /** POST /contracts/flat — a contract on an opportunity with a manually entered total and a contract template, no estimates. */
860
+ createFlat(data: CreateFlatContractDto): Promise<Record<string, unknown>>;
861
+ /** POST /contracts/{id}/change-orders — a change order on a signed or fulfilled contract (409 otherwise). */
862
+ createChangeOrder(id: string, data: CreateChangeOrderDto): Promise<Record<string, unknown>>;
863
+ /**
864
+ * GET /contracts/{id}/change-orders — the change orders written against a
865
+ * contract, oldest first, each with its line groups. A change order has none
866
+ * of its own, so asking for one returns an empty list.
867
+ */
868
+ listChangeOrders(id: string): Promise<{
869
+ data: Array<Record<string, unknown>>;
870
+ meta: {
871
+ total: number;
872
+ };
873
+ }>;
874
+ /** POST /contracts/{id}/submit — submit for approval; auto-approved when under the tenant's threshold. */
875
+ submit(id: string): Promise<Record<string, unknown>>;
876
+ /** POST /contracts/{id}/approve — approve a contract pending approval (needs the approve grant). */
877
+ approve(id: string): Promise<Record<string, unknown>>;
878
+ /** POST /contracts/{id}/cancel — cancel a contract in any state before it's signed. */
879
+ cancel(id: string): Promise<Record<string, unknown>>;
880
+ /** POST /contracts/{id}/reopen — return a kicked-back contract to draft for review and re-send. */
881
+ reopen(id: string): Promise<Record<string, unknown>>;
882
+ /**
883
+ * POST /contracts/{id}/send — **emails the signer a "Review & Sign" link.**
884
+ * Snapshots the clauses and creates the signing token. An empty body
885
+ * addresses the customer; `signerContactId` sends it to that contact instead.
886
+ * The first send of a contract uses one unit of the tenant's e-signature
887
+ * allowance; a re-send doesn't. Not safe to retry blindly after a timeout: a
888
+ * repeat emails again.
889
+ */
890
+ send(id: string, data?: SendContractDto): Promise<Record<string, unknown>>;
891
+ /**
892
+ * GET /contracts/{id}/pdf — the contract PDF bytes. `type: 'signed'` returns
893
+ * the stored signed copy (404 until it's signed); otherwise a preview renders.
894
+ */
895
+ downloadPdf(id: string, options?: {
896
+ type?: 'signed';
897
+ }): Promise<ArrayBuffer>;
611
898
  }
612
899
 
613
900
  /**
@@ -699,6 +986,25 @@ declare class JobResource extends ApiResource {
699
986
  * otherwise); carries no workflow details.
700
987
  */
701
988
  getTradeCoverage(): Promise<JobTradeCoverageResponse>;
989
+ /** GET /jobs/{id}/workflow — the job's pipeline instance with its transition history (404 if none). */
990
+ getWorkflow(id: string): Promise<Record<string, unknown>>;
991
+ /**
992
+ * POST /jobs/{id}/transition — take one pipeline move, as the stage button
993
+ * does: required fields are checked, the move is logged, and **the
994
+ * transition's actions run**. A tenant can attach actions that create or send
995
+ * an invoice, charge a saved card, send a contract, or send email, SMS or a
996
+ * webhook. Not safe to retry blindly after a timeout: check `getWorkflow()`
997
+ * first, because a repeat runs the actions again.
998
+ */
999
+ transition(id: string, data: {
1000
+ transition_id: string;
1001
+ notes?: string;
1002
+ entity_data?: Record<string, unknown>;
1003
+ }): Promise<Record<string, unknown>>;
1004
+ /** GET /jobs/{id}/transitions — the pipeline moves available from the job's current stage, for the caller's role. */
1005
+ listTransitions(id: string): Promise<{
1006
+ transitions: Array<Record<string, unknown>>;
1007
+ }>;
702
1008
  }
703
1009
 
704
1010
  /** Estimate statuses — mirrors `ESTIMATE_STATUSES` in `packages/shared/src/validation/estimate.ts` (runtime parity spec). */
@@ -754,6 +1060,64 @@ interface UpdateEstimateDto {
754
1060
  discountValue?: number | null | undefined;
755
1061
  taxRate?: number | null | undefined;
756
1062
  }
1063
+ /** Estimate line item kinds — mirrors `LINE_ITEM_TYPES` in `packages/shared/src/validation/estimate.ts`. */
1064
+ type EstimateLineItemType = 'material' | 'labor' | 'other';
1065
+ /**
1066
+ * `POST /jobs/{jobId}/estimates/{estimateId}/line-items` body. Mirrors the
1067
+ * controller's `createEstimateLineItemSchema` with `description`, `unit`,
1068
+ * `unitPrice` and `lineItemType` optional (a catalog item fills them in).
1069
+ * Amounts are numbers; the estimate's subtotal and total are recalculated.
1070
+ */
1071
+ interface CreateEstimateLineItemDto {
1072
+ lineItemType?: EstimateLineItemType;
1073
+ materialCatalogId?: string;
1074
+ tradeLaborItemId?: string;
1075
+ description?: string;
1076
+ baseQuantity: number;
1077
+ /** Percent, 0–100. Defaults to 0. */
1078
+ wastePct?: number;
1079
+ unit?: string;
1080
+ unitPrice?: number;
1081
+ /** Percent, 0–100. Defaults to 0. */
1082
+ markupPct?: number;
1083
+ section?: string;
1084
+ sortOrder: number;
1085
+ metadata?: Record<string, unknown>;
1086
+ }
1087
+ /** `PUT /jobs/{jobId}/estimates/{estimateId}/line-items/{id}` body — mirrors `updateEstimateLineItemSchema`; only the fields sent change. */
1088
+ interface UpdateEstimateLineItemDto {
1089
+ lineItemType?: EstimateLineItemType;
1090
+ materialCatalogId?: string | null;
1091
+ tradeLaborItemId?: string | null;
1092
+ description?: string;
1093
+ baseQuantity?: number;
1094
+ wastePct?: number;
1095
+ unit?: string;
1096
+ unitPrice?: number;
1097
+ markupPct?: number;
1098
+ section?: string | null;
1099
+ sortOrder?: number;
1100
+ metadata?: Record<string, unknown> | null;
1101
+ }
1102
+ /** `PUT /jobs/{jobId}/estimates/{estimateId}/line-items/reorder` body — mirrors `reorderEstimateLineItemsSchema`. */
1103
+ interface ReorderEstimateLineItemsDto {
1104
+ /** At least one. */
1105
+ items: Array<{
1106
+ id: string;
1107
+ sortOrder: number;
1108
+ section?: string | null | undefined;
1109
+ }>;
1110
+ }
1111
+ /**
1112
+ * `PUT /jobs/{jobId}/estimates/{id}/status` body — mirrors
1113
+ * `updateEstimateStatusSchema`. Allowed moves: draft → sent, sent → approved or
1114
+ * rejected, approved or rejected → draft. One approved estimate per job.
1115
+ * "sent" only changes the status: the route emails nothing (a tenant's
1116
+ * webhooks or automations on the status change can).
1117
+ */
1118
+ interface UpdateEstimateStatusDto {
1119
+ status: EstimateStatus;
1120
+ }
757
1121
 
758
1122
  /**
759
1123
  * Estimates. CRUD is nested under the parent job (`/jobs/{jobId}/estimates`);
@@ -778,6 +1142,42 @@ declare class EstimateResource extends ApiResource {
778
1142
  update(jobId: string, id: string, data: UpdateEstimateDto): Promise<Record<string, unknown>>;
779
1143
  /** DELETE /jobs/{jobId}/estimates/{id} — soft delete (204). */
780
1144
  delete(jobId: string, id: string): Promise<void>;
1145
+ /** GET /estimates/{id}/workflow — the estimate's pipeline instance with its transition history (404 if none). */
1146
+ getWorkflow(id: string): Promise<Record<string, unknown>>;
1147
+ /**
1148
+ * POST /estimates/{id}/transition — take one pipeline move. **The
1149
+ * transition's actions run**, as for `jobs.transition()`: a tenant can attach
1150
+ * actions that bill, charge, send a contract, or send email, SMS or a webhook.
1151
+ * Not safe to retry blindly after a timeout: check `getWorkflow()` first.
1152
+ */
1153
+ transition(id: string, data: {
1154
+ transition_id: string;
1155
+ notes?: string;
1156
+ entity_data?: Record<string, unknown>;
1157
+ }): Promise<Record<string, unknown>>;
1158
+ /**
1159
+ * PUT /jobs/{jobId}/estimates/{id}/status — move the estimate's status (see
1160
+ * `UpdateEstimateStatusDto` for the allowed moves). The route itself sends
1161
+ * nothing and creates no contract or invoice; a tenant's webhooks or
1162
+ * automations on the status change can.
1163
+ */
1164
+ updateStatus(jobId: string, id: string, data: UpdateEstimateStatusDto): Promise<Record<string, unknown>>;
1165
+ /** GET /estimates/{id}/transitions — the pipeline moves available from the estimate's current stage, for the caller's role. */
1166
+ listTransitions(id: string): Promise<{
1167
+ transitions: Array<Record<string, unknown>>;
1168
+ }>;
1169
+ /**
1170
+ * POST /jobs/{jobId}/estimates/{estimateId}/line-items — add a line item. With
1171
+ * `materialCatalogId` or `tradeLaborItemId`, the catalog fills in description,
1172
+ * unit and price. The estimate's subtotal and total are recalculated.
1173
+ */
1174
+ createLineItem(jobId: string, estimateId: string, data: CreateEstimateLineItemDto): Promise<Record<string, unknown>>;
1175
+ /** PUT /jobs/{jobId}/estimates/{estimateId}/line-items/{id} — partial update; totals are recalculated. */
1176
+ updateLineItem(jobId: string, estimateId: string, id: string, data: UpdateEstimateLineItemDto): Promise<Record<string, unknown>>;
1177
+ /** DELETE /jobs/{jobId}/estimates/{estimateId}/line-items/{id} — totals are recalculated. */
1178
+ deleteLineItem(jobId: string, estimateId: string, id: string): Promise<void>;
1179
+ /** PUT /jobs/{jobId}/estimates/{estimateId}/line-items/reorder — set each item's `sortOrder` (and optionally `section`) in one call. */
1180
+ reorderLineItems(jobId: string, estimateId: string, data: ReorderEstimateLineItemsDto): Promise<Array<Record<string, unknown>>>;
781
1181
  }
782
1182
 
783
1183
  /**
@@ -970,6 +1370,14 @@ declare class InvoiceResource extends BaseResource<Record<string, unknown>, Reco
970
1370
  * last overdue offset reached (E56-F8-S2). Read Invoice.
971
1371
  */
972
1372
  listOverdue(params?: OverdueInvoiceListParams): Promise<PaginatedResponse<OverdueInvoiceDto>>;
1373
+ /** GET /admin/invoices/{invoiceId}/payments — every payment recorded against the invoice (Read Payment). */
1374
+ listPayments(invoiceId: string): Promise<Array<Record<string, unknown>>>;
1375
+ /**
1376
+ * GET /admin/payments/recording-settings — the tenant's resolved
1377
+ * payment-recording settings (whether manual recording is on, and which
1378
+ * methods). Read Invoice.
1379
+ */
1380
+ getPaymentRecordingSettings(): Promise<Record<string, unknown>>;
973
1381
  /** GET /admin/invoices/overdue/summary — `{ count, total }` of every overdue invoice. Read Invoice. */
974
1382
  overdueSummary(): Promise<InvoiceOverdueSummaryDto>;
975
1383
  }
@@ -1016,6 +1424,84 @@ type InventoryItemListParams = {
1016
1424
  page?: number | undefined;
1017
1425
  limit?: number | undefined;
1018
1426
  };
1427
+ /** One line of `POST /jobs/{jobId}/consumption` — mirrors `consumeItemSchema`. */
1428
+ interface JobConsumptionItemDto {
1429
+ itemId: string;
1430
+ /** Positive. */
1431
+ quantity: number;
1432
+ /** The stock location it's drawn from. */
1433
+ locationId: string;
1434
+ }
1435
+ /** `POST /jobs/{jobId}/consumption` body — mirrors `jobConsumptionSchema` (at least one item). */
1436
+ interface RecordJobConsumptionDto {
1437
+ items: JobConsumptionItemDto[];
1438
+ }
1439
+ /** `POST /jobs/{jobId}/return` body — mirrors `returnFromJobSchema` (at least one item). */
1440
+ interface ReturnFromJobDto {
1441
+ items: Array<{
1442
+ itemId: string;
1443
+ quantity: number;
1444
+ toLocationId: string;
1445
+ }>;
1446
+ }
1447
+ /** `GET /jobs/{jobId}/consumption` query — mirrors `jobConsumptionQuerySchema` (`limit` ≤ 100, default 50). */
1448
+ interface JobConsumptionListParams {
1449
+ itemId?: string | undefined;
1450
+ locationId?: string | undefined;
1451
+ /** ISO timestamp with offset. */
1452
+ startDate?: string | undefined;
1453
+ endDate?: string | undefined;
1454
+ page?: number | undefined;
1455
+ limit?: number | undefined;
1456
+ sortOrder?: 'asc' | 'desc' | undefined;
1457
+ }
1458
+ /** One movement in `GET /jobs/{jobId}/consumption`. Money and quantities are decimal strings. */
1459
+ interface JobConsumptionMovementDto {
1460
+ movementId: string;
1461
+ /** `'consume'` or `'return_from_job'` (a free-text column, so typed as string). */
1462
+ movementType: string;
1463
+ itemId: string;
1464
+ itemName: string;
1465
+ itemSku: string | null;
1466
+ productGroup: string | null;
1467
+ unitOfMeasure: string;
1468
+ quantity: string;
1469
+ unitCost: string;
1470
+ totalCost: string;
1471
+ fromLocationId: string | null;
1472
+ fromLocationName: string | null;
1473
+ fromLocationType: string | null;
1474
+ toLocationId: string | null;
1475
+ toLocationName: string | null;
1476
+ toLocationType: string | null;
1477
+ performedBy: string;
1478
+ performedByName: string;
1479
+ /** ISO timestamp. */
1480
+ createdAt: string;
1481
+ }
1482
+ /**
1483
+ * What `GET /jobs/{jobId}/consumption` returns: one page of movements, the
1484
+ * job's totals across every page, and page metadata. Not the `{ data, meta }`
1485
+ * list shape.
1486
+ */
1487
+ interface JobConsumptionHistoryDto {
1488
+ items: JobConsumptionMovementDto[];
1489
+ totals: {
1490
+ /** Cost of everything consumed, as a decimal string. */
1491
+ totalConsumeCost: string;
1492
+ /** Credit for everything returned. */
1493
+ totalReturnCredit: string;
1494
+ /** Consumed minus returned. */
1495
+ totalMaterialCost: string;
1496
+ itemCount: number;
1497
+ };
1498
+ meta: {
1499
+ page: number;
1500
+ limit: number;
1501
+ total: number;
1502
+ totalPages: number;
1503
+ };
1504
+ }
1019
1505
 
1020
1506
  /** Inventory items — CRUD on /admin/inventory/items (updates are PUT). */
1021
1507
  declare class InventoryResource extends BaseResource<Record<string, unknown>, CreateInventoryItemDto, UpdateInventoryItemDto> {
@@ -1023,6 +1509,21 @@ declare class InventoryResource extends BaseResource<Record<string, unknown>, Cr
1023
1509
  list(params?: InventoryItemListParams): Promise<PaginatedResponse<Record<string, unknown>>>;
1024
1510
  /** PUT /admin/inventory/items/{id} — partial update. */
1025
1511
  update(id: string, data: UpdateInventoryItemDto): Promise<Record<string, unknown>>;
1512
+ /**
1513
+ * POST /jobs/{jobId}/consumption — record stock drawn from a location for a
1514
+ * job. Each line lowers that location's on-hand quantity.
1515
+ */
1516
+ recordJobConsumption(jobId: string, data: RecordJobConsumptionDto): Promise<Record<string, unknown>>;
1517
+ /**
1518
+ * GET /jobs/{jobId}/consumption — one page of the job's consume and return
1519
+ * movements (newest first by default), the job's totals across every page,
1520
+ * and page metadata. The rows are under `items`, not `data`.
1521
+ */
1522
+ listJobConsumption(jobId: string, params?: JobConsumptionListParams): Promise<JobConsumptionHistoryDto>;
1523
+ /** POST /jobs/{jobId}/return — put unused stock from a job back into a location. */
1524
+ returnFromJob(jobId: string, data: ReturnFromJobDto): Promise<Record<string, unknown>>;
1525
+ /** GET /jobs/{jobId}/material-variance — estimated vs actual material for the job. */
1526
+ getJobMaterialVariance(jobId: string): Promise<Record<string, unknown>>;
1026
1527
  }
1027
1528
 
1028
1529
  /**
@@ -1072,7 +1573,7 @@ interface ConsentStateDto {
1072
1573
  * `CustomerDto` for the house style.
1073
1574
  */
1074
1575
 
1075
- type ContactSource = 'manual' | 'import' | 'convert_from_customer';
1576
+ type ContactSource = 'manual' | 'import' | 'convert_from_customer' | 'web_form';
1076
1577
  /**
1077
1578
  * Query params for `GET /contacts` — mirrors `contactFilterSchema` in
1078
1579
  * `@blueprint/shared`. `customer_id` / `property_id` return only contacts with
@@ -1083,7 +1584,7 @@ type ContactSource = 'manual' | 'import' | 'convert_from_customer';
1083
1584
  * to `BaseResource.list`.
1084
1585
  */
1085
1586
  /** Sortable columns on `GET /contacts` (kept in lockstep with the server enum by the SDK's wire-contract spec). */
1086
- declare const CONTACT_SORT_KEYS: readonly ["name", "created_at", "recent"];
1587
+ declare const CONTACT_SORT_KEYS: readonly ["name", "created_at", "recent", "updated_at"];
1087
1588
  type ContactSortKey = (typeof CONTACT_SORT_KEYS)[number];
1088
1589
  /**
1089
1590
  * Related collections `GET /contacts?include=` eager-loads onto each row
@@ -1096,6 +1597,24 @@ interface ContactListParams extends ListParams {
1096
1597
  customer_id?: string;
1097
1598
  property_id?: string;
1098
1599
  q?: string;
1600
+ /**
1601
+ * Only records updated at or after this instant (inclusive), as an ISO-8601
1602
+ * datetime with a timezone, e.g. `2026-11-10T14:00:00Z` (E64-S5). Rows come
1603
+ * in `updatedAt`, then `id`, order. Page with the last row's `updatedAt` as
1604
+ * `updated_since` and its `id` as `after_id` (not an offset) until a page is
1605
+ * short. For the next sync, start from the time this one **started**, minus
1606
+ * a few minutes, not the newest `updatedAt` seen. Treat repeats as no-ops.
1607
+ */
1608
+ updated_since?: string;
1609
+ /** With `updated_since`: continue after this id (the last row of the previous page). Replaces page/offset; `total` then counts the rows still to come. */
1610
+ after_id?: string;
1611
+ /**
1612
+ * Exact-match filters by custom field value, sent as `cf.<key>=<value>` (E64-S3).
1613
+ * Several are ANDed. The field must be marked searchable, or the API returns
1614
+ * 400 `CUSTOM_FIELD_NOT_FILTERABLE`. A multi-select matches a record whose list
1615
+ * includes the value.
1616
+ */
1617
+ customFields?: Record<string, string | number | boolean>;
1099
1618
  /** Mirrors `CONTACT_SORT_KEYS`. `recent` = the calling user's last view, newest first; ignores `sort_order`. */
1100
1619
  sort_by?: ContactSortKey;
1101
1620
  sort_order?: 'asc' | 'desc';
@@ -1129,7 +1648,12 @@ interface UpdateContactDto {
1129
1648
  firstName?: string;
1130
1649
  lastName?: string | null;
1131
1650
  notes?: string | null;
1132
- customFields?: Record<string, unknown> | null;
1651
+ /**
1652
+ * Custom-field values to change. Merged into the record's stored values:
1653
+ * keys you leave out are kept, and a key set to `null` (or `''`) is cleared.
1654
+ * Sending `customFields: null` is rejected with 400.
1655
+ */
1656
+ customFields?: Record<string, unknown>;
1133
1657
  source?: ContactSource | null;
1134
1658
  }
1135
1659
  type ContactChannelType = 'email' | 'phone' | 'url';
@@ -1210,6 +1734,37 @@ interface ContactMergeResult {
1210
1734
  winnerId: string;
1211
1735
  loserId: string;
1212
1736
  }
1737
+ /** POST /contacts/:id/links (E63-S2 SDK method). */
1738
+ interface CreateContactLinkDto {
1739
+ targetType: ContactLinkTargetType;
1740
+ targetId: string;
1741
+ role?: string | null;
1742
+ isPrimary?: boolean;
1743
+ }
1744
+ /** PATCH /contacts/:id/links/:linkId. End-dating a link is setting `endedAt`; there is no DELETE. */
1745
+ interface UpdateContactLinkDto {
1746
+ endedAt?: string | null;
1747
+ role?: string | null;
1748
+ isPrimary?: boolean;
1749
+ }
1750
+ /**
1751
+ * GET /contacts/:id/workflow: the opt-in relationship pipeline (E38).
1752
+ * `instance` is null until the pipeline is started; `transitions` are the
1753
+ * moves available from the current stage (pass an `id` to `transition()`).
1754
+ * Stage, instance and transition rows are the workflow engine's own shapes,
1755
+ * left open here.
1756
+ */
1757
+ interface ContactWorkflowDto {
1758
+ pipelineAvailable: boolean;
1759
+ stages: Array<Record<string, unknown>>;
1760
+ instance: Record<string, unknown> | null;
1761
+ transitions: Array<Record<string, unknown>>;
1762
+ }
1763
+ /** GET /contacts/:id/workflow/history */
1764
+ interface ContactWorkflowHistoryDto {
1765
+ instance: Record<string, unknown> | null;
1766
+ history: Array<Record<string, unknown>>;
1767
+ }
1213
1768
 
1214
1769
  /**
1215
1770
  * `/contacts/:id/channels` — POST/PATCH/DELETE only. There is no list/get
@@ -1219,7 +1774,7 @@ interface ContactMergeResult {
1219
1774
  */
1220
1775
  declare class ContactChannelResource {
1221
1776
  private readonly http;
1222
- private readonly basePath;
1777
+ private readonly contactId;
1223
1778
  constructor(http: HttpClient, contactId: string);
1224
1779
  /** Returns `{ channel, duplicateOf }` — `duplicateOf` is the dedup signal. */
1225
1780
  create(data: CreateContactChannelDto): Promise<AddContactChannelResult>;
@@ -1237,6 +1792,22 @@ declare class ContactResource extends BaseResource<ContactDto, CreateContactDto,
1237
1792
  */
1238
1793
  list(params?: ContactListParams): Promise<PaginatedResponse<ContactListItemDto>>;
1239
1794
  merge(winnerId: string, loserId: string): Promise<ContactMergeResult>;
1795
+ /** GET /contacts/roles — the distinct roles in use on active links, for a role picker. */
1796
+ listRoles(): Promise<string[]>;
1797
+ /** GET /contacts/:id/links — every link, active and ended (history). `get()` returns active links only. */
1798
+ listLinks(contactId: string): Promise<ContactLinkDto[]>;
1799
+ /** POST /contacts/:id/links — link the contact to a customer or property. */
1800
+ addLink(contactId: string, data: CreateContactLinkDto): Promise<ContactLinkDto>;
1801
+ /** PATCH /contacts/:id/links/:linkId — change role/primary, or end the link (`endedAt`). */
1802
+ updateLink(contactId: string, linkId: string, data: UpdateContactLinkDto): Promise<ContactLinkDto>;
1803
+ /** POST /contacts/:id/workflow/start — opt the contact into the relationship pipeline (409 if started). */
1804
+ startWorkflow(contactId: string): Promise<ContactWorkflowDto>;
1805
+ /** GET /contacts/:id/workflow — current stage and the transitions available from it. */
1806
+ getWorkflow(contactId: string): Promise<ContactWorkflowDto>;
1807
+ /** POST /contacts/:id/workflow/transitions/:transitionId — 422 for an invalid move or unmet required fields. */
1808
+ transition(contactId: string, transitionId: string): Promise<Record<string, unknown>>;
1809
+ /** GET /contacts/:id/workflow/history */
1810
+ getWorkflowHistory(contactId: string): Promise<ContactWorkflowHistoryDto>;
1240
1811
  channels(contactId: string): ContactChannelResource;
1241
1812
  }
1242
1813
 
@@ -1896,6 +2467,24 @@ interface SetEntityTagsDto {
1896
2467
  tag_ids?: string[];
1897
2468
  tag_names?: string[];
1898
2469
  }
2470
+ /**
2471
+ * Which tag to add with `addEntityTag()` (E64-S2). Exactly one of `tagId` (an
2472
+ * existing tag) or `tagName` (reused case-insensitively, or created). Sent as
2473
+ * `{ tag_id }` or `{ tag_name }`, mirroring `addEntityTagSchema`.
2474
+ */
2475
+ type AddEntityTagRef = {
2476
+ tagId: string;
2477
+ tagName?: never;
2478
+ } | {
2479
+ tagName: string;
2480
+ tagId?: never;
2481
+ };
2482
+ /** Body of `POST /entities/:type/:id/tags`. */
2483
+ type AddEntityTagDto = {
2484
+ tag_id: string;
2485
+ } | {
2486
+ tag_name: string;
2487
+ };
1899
2488
  interface EntityTagDto {
1900
2489
  id: string;
1901
2490
  name: string;
@@ -1911,6 +2500,15 @@ interface TagEntitiesPage {
1911
2500
  limit: number;
1912
2501
  total: number;
1913
2502
  }
2503
+ /** POST /tags/:winnerId/merge/:loserId (E63-S7 SDK method). */
2504
+ interface TagMergeResult {
2505
+ winnerId: string;
2506
+ loserId: string;
2507
+ /** Records moved from the loser to the winner. */
2508
+ retagged: number;
2509
+ /** Loser memberships dropped because the record already had the winner. */
2510
+ dropped: number;
2511
+ }
1914
2512
 
1915
2513
  /**
1916
2514
  * Tags. There is no single-tag read: `list()` returns every tag (with usage
@@ -1926,14 +2524,236 @@ declare class TagResource extends ApiResource {
1926
2524
  update(id: string, data: UpdateTagDto): Promise<TagDto>;
1927
2525
  /** DELETE /tags/:id — cascades the tag off every record. */
1928
2526
  delete(id: string): Promise<void>;
2527
+ /**
2528
+ * POST /tags/:winnerId/merge/:loserId — fold a duplicate tag into another: records
2529
+ * move to the winner (`retagged`), duplicates are dropped (`dropped`), and the
2530
+ * loser is deleted. Irreversible.
2531
+ */
2532
+ merge(winnerId: string, loserId: string): Promise<TagMergeResult>;
1929
2533
  /** `TagsService.setEntityTags()` returns the final tag set wrapped in `{ tags }`. */
1930
2534
  setEntityTags(entityType: string, entityId: string, data: SetEntityTagsDto): Promise<{
1931
2535
  tags: TagDto[];
1932
2536
  }>;
2537
+ /**
2538
+ * POST /entities/:type/:id/tags — add ONE tag, keeping the record's other tags.
2539
+ * Safe to call concurrently with other tag changes on the same record (unlike
2540
+ * read-modify-write through `setEntityTags()`). Adding a tag the record already
2541
+ * carries is a no-op. Returns the record's full tag set.
2542
+ */
2543
+ addEntityTag(entityType: string, entityId: string, ref: AddEntityTagRef): Promise<{
2544
+ tags: TagDto[];
2545
+ }>;
2546
+ /**
2547
+ * DELETE /entities/:type/:id/tags/:tagId — remove ONE tag, keeping the rest.
2548
+ * Removing a tag the record doesn't carry is a no-op. Returns the record's
2549
+ * full tag set.
2550
+ */
2551
+ removeEntityTag(entityType: string, entityId: string, tagId: string): Promise<{
2552
+ tags: TagDto[];
2553
+ }>;
1933
2554
  getEntityTags(entityType: string, entityId: string): Promise<EntityTagDto[]>;
1934
2555
  getEntities(tagId: string, params?: Record<string, unknown>): Promise<TagEntitiesPage>;
1935
2556
  }
1936
2557
 
2558
+ /**
2559
+ * Lists (E38-F6; SDK resource E63-S1) — mirrors `ListDto` and the list
2560
+ * request schemas in `@blueprint/shared` (`validation/lists.ts`). Parity is
2561
+ * checked at compile time in `list-types.parity.ts`.
2562
+ */
2563
+ /** A list holds one record type, or `audience` (person customers + contacts). */
2564
+ type ListEntityType = 'contact' | 'customer' | 'property' | 'opportunity' | 'job' | 'audience';
2565
+ /** A member's record type (never `audience`). */
2566
+ type ListMemberEntityType = Exclude<ListEntityType, 'audience'>;
2567
+ /** `static` holds explicit members; `smart` evaluates its definition when read. */
2568
+ type ListKind = 'static' | 'smart';
2569
+ type SmartFilterOp = 'eq' | 'neq' | 'contains' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'is_set' | 'is_not_set';
2570
+ interface SmartFilter {
2571
+ field: string;
2572
+ op: SmartFilterOp;
2573
+ value?: unknown;
2574
+ }
2575
+ interface SmartListDefinition {
2576
+ tags_any: string[];
2577
+ tags_all: string[];
2578
+ filters: SmartFilter[];
2579
+ }
2580
+ interface ListDto {
2581
+ id: string;
2582
+ name: string;
2583
+ entity_type: ListEntityType;
2584
+ kind: ListKind;
2585
+ definition: SmartListDefinition | null;
2586
+ /** Integration that owns membership (e.g. `integration:ortto`); its members and definition are read-only. */
2587
+ managed_by?: string | null;
2588
+ /** `null` when a smart list's definition can't be evaluated; see `definition_error`. */
2589
+ member_count?: number | null;
2590
+ /** Why a smart list's stored definition can't be evaluated, on listing and detail reads; otherwise null. */
2591
+ definition_error?: ListDefinitionError | null;
2592
+ created_at: string;
2593
+ /** Moves when the name or (smart) rule changes, and for a static list when members are added or removed. */
2594
+ updated_at: string;
2595
+ }
2596
+ /** Why a stored smart-list definition can't be evaluated. */
2597
+ interface ListDefinitionError {
2598
+ /** The evaluator's code (e.g. `SMART_LIST_UNKNOWN_FIELD`), or `SMART_LIST_EVAL_FAILED` when Postgres rejected it. */
2599
+ code: string;
2600
+ message: string;
2601
+ }
2602
+ interface CreateListDto {
2603
+ name: string;
2604
+ entity_type: ListEntityType;
2605
+ kind: ListKind;
2606
+ /** Smart lists only. */
2607
+ definition?: SmartListDefinition | null;
2608
+ }
2609
+ interface UpdateListDto {
2610
+ name?: string;
2611
+ /** Smart lists only; a managed list refuses a definition change. */
2612
+ definition?: SmartListDefinition | null;
2613
+ }
2614
+ interface ListMemberRef {
2615
+ entity_type: ListMemberEntityType;
2616
+ entity_id: string;
2617
+ }
2618
+ interface ListRecipientsParams {
2619
+ page?: number;
2620
+ limit?: number;
2621
+ }
2622
+ interface ListRecipientDto {
2623
+ source: {
2624
+ entityType: 'customer' | 'contact';
2625
+ entityId: string;
2626
+ };
2627
+ displayName: string;
2628
+ firstName?: string;
2629
+ lastName?: string;
2630
+ email?: string;
2631
+ /** E.164. */
2632
+ phone?: string;
2633
+ consent: {
2634
+ sms: boolean;
2635
+ marketingEmail: boolean;
2636
+ };
2637
+ viaCompany: {
2638
+ customerId: string;
2639
+ customerName: string;
2640
+ } | null;
2641
+ }
2642
+ interface ListRecipientsPage {
2643
+ data: ListRecipientDto[];
2644
+ page: number;
2645
+ limit: number;
2646
+ total: number;
2647
+ }
2648
+ interface ListExportHandle {
2649
+ jobId: string;
2650
+ status: 'queued';
2651
+ listId: string;
2652
+ includeSuppressed: boolean;
2653
+ }
2654
+ /** A standard field a smart-list filter may name (E66-S3). */
2655
+ interface ListFilterField {
2656
+ name: string;
2657
+ /** `numeric` fields take range operators and numeric values; `text` fields take `contains`. */
2658
+ type: 'text' | 'numeric';
2659
+ /** The operators this field accepts. */
2660
+ ops: SmartFilterOp[];
2661
+ }
2662
+ /** `GET /lists/filter-fields` — what a smart list of one entity type can filter on (E66-S3). */
2663
+ interface ListFilterFieldsDto {
2664
+ entity_type: ListEntityType;
2665
+ fields: ListFilterField[];
2666
+ /** Whether `custom_fields.<key>` filters are accepted. They take every operator. */
2667
+ custom_fields: boolean;
2668
+ /** Where the custom-field keys come from, when `custom_fields` is true; otherwise null. */
2669
+ custom_field_keys: string | null;
2670
+ }
2671
+
2672
+ /**
2673
+ * Lists (E38-F6; SDK E63-S1): static and smart lists of records, and
2674
+ * audiences of people. Every `/lists` route has a method here
2675
+ * (`SDK_COVERED_CONTROLLERS` in the API's route-parity audit).
2676
+ */
2677
+ declare class ListsResource extends ApiResource {
2678
+ constructor(http: ConstructorParameters<typeof ApiResource>[0]);
2679
+ /** GET /lists — every list, newest first, each with `member_count`. A bare array. */
2680
+ list(): Promise<ListDto[]>;
2681
+ /**
2682
+ * GET /lists/filter-fields — the standard fields, their types and the operators
2683
+ * each accepts for a smart list of this entity type, and whether custom fields
2684
+ * are accepted (E66-S3). A save that breaks these rules is a 400.
2685
+ */
2686
+ filterFields(entityType: ListEntityType): Promise<ListFilterFieldsDto>;
2687
+ /** GET /lists/:id — one list with an on-demand `member_count`. */
2688
+ get(id: string): Promise<ListDto>;
2689
+ /** POST /lists */
2690
+ create(data: CreateListDto): Promise<ListDto>;
2691
+ /** PATCH /lists/:id — rename, or replace a smart list's definition. */
2692
+ update(id: string, data: UpdateListDto): Promise<ListDto>;
2693
+ /** DELETE /lists/:id — soft delete; the records on the list are untouched. */
2694
+ delete(id: string): Promise<void>;
2695
+ /** POST /lists/:id/members — static lists only; idempotent on duplicates. */
2696
+ addMembers(id: string, members: ListMemberRef[]): Promise<{
2697
+ added: number;
2698
+ }>;
2699
+ /** DELETE /lists/:id/members — static lists only. */
2700
+ removeMembers(id: string, members: ListMemberRef[]): Promise<{
2701
+ removed: number;
2702
+ }>;
2703
+ /** GET /lists/:id/recipients — people (audience, contact and customer lists), with consent. */
2704
+ getRecipients(id: string, params?: ListRecipientsParams): Promise<ListRecipientsPage>;
2705
+ /** POST /lists/:id/export — queues a CSV export; a notification links the file when it's ready. */
2706
+ export(id: string, options?: {
2707
+ include_suppressed?: boolean;
2708
+ }): Promise<ListExportHandle>;
2709
+ }
2710
+
2711
+ /**
2712
+ * Lead sources (how a customer was acquired). SDK resource E63-S3; mirrors
2713
+ * `createLeadSourceSchema` / `updateLeadSourceSchema` in `@blueprint/shared`
2714
+ * (`validation/lead-source.ts`), checked in `lead-source-types.parity.ts`.
2715
+ */
2716
+ interface LeadSourceDto {
2717
+ id: string;
2718
+ /** Immutable once created; what a customer's `source` holds. */
2719
+ key: string;
2720
+ label: string;
2721
+ isActive: boolean;
2722
+ sortOrder: number;
2723
+ createdAt: string;
2724
+ updatedAt: string;
2725
+ }
2726
+ interface CreateLeadSourceDto {
2727
+ label: string;
2728
+ /** Lowercase letters, digits and `_`. Derived from the label when omitted. */
2729
+ key?: string;
2730
+ }
2731
+ /** `key` can't change. */
2732
+ interface UpdateLeadSourceDto {
2733
+ label?: string;
2734
+ isActive?: boolean;
2735
+ sortOrder?: number;
2736
+ }
2737
+
2738
+ /**
2739
+ * Lead sources (E63-S3): the keys a customer's `source` takes. Every
2740
+ * `/lead-sources` route has a method here (the API's route-parity audit).
2741
+ * Responses are wrapped as `{ data }`; the methods unwrap them.
2742
+ */
2743
+ declare class LeadSourcesResource extends ApiResource {
2744
+ constructor(http: ConstructorParameters<typeof ApiResource>[0]);
2745
+ /** GET /lead-sources — active ones by default, in display order. */
2746
+ list(options?: {
2747
+ includeInactive?: boolean;
2748
+ }): Promise<LeadSourceDto[]>;
2749
+ /** POST /lead-sources — 409 on a duplicate key. */
2750
+ create(data: CreateLeadSourceDto): Promise<LeadSourceDto>;
2751
+ /** PATCH /lead-sources/:id — label, active flag or order; the key can't change. */
2752
+ update(id: string, data: UpdateLeadSourceDto): Promise<LeadSourceDto>;
2753
+ /** DELETE /lead-sources/:id — soft delete. */
2754
+ delete(id: string): Promise<void>;
2755
+ }
2756
+
1937
2757
  /**
1938
2758
  * Wire shapes for the Tasks API (`/api/v1/tasks`, E41-F3).
1939
2759
  *
@@ -2034,6 +2854,9 @@ interface UpdateTaskDto {
2034
2854
  */
2035
2855
  completion_transition_id?: string | null;
2036
2856
  }
2857
+ /** Sortable columns on `GET /tasks` (kept in lockstep with the server's `TASK_SORT_KEYS`). */
2858
+ declare const TASK_SORT_KEYS: readonly ["due_at", "created_at", "updated_at"];
2859
+ type TaskSortKey = (typeof TASK_SORT_KEYS)[number];
2037
2860
  interface ListTasksParams {
2038
2861
  status?: TaskStatus;
2039
2862
  priority?: TaskPriority;
@@ -2051,6 +2874,20 @@ interface ListTasksParams {
2051
2874
  /** ISO 8601. */
2052
2875
  due_after?: string;
2053
2876
  overdue?: boolean;
2877
+ /**
2878
+ * Only records updated at or after this instant (inclusive), as an ISO-8601
2879
+ * datetime with a timezone, e.g. `2026-11-10T14:00:00Z` (E64-S5). Rows come
2880
+ * in `updatedAt`, then `id`, order. Page with the last row's `updatedAt` as
2881
+ * `updated_since` and its `id` as `after_id` (not an offset) until a page is
2882
+ * short. For the next sync, start from the time this one **started**, minus
2883
+ * a few minutes, not the newest `updatedAt` seen. Treat repeats as no-ops.
2884
+ */
2885
+ updated_since?: string;
2886
+ /** With `updated_since`: continue after this id (the last row of the previous page). Replaces `offset`. */
2887
+ after_id?: string;
2888
+ /** Default `due_at` ascending; `created_at` and `updated_at` default to descending, except that with `updated_since` the list walks `updated_at` ascending. */
2889
+ sort_by?: TaskSortKey;
2890
+ sort_order?: 'asc' | 'desc';
2054
2891
  /** 1–500, default 100. */
2055
2892
  limit?: number;
2056
2893
  offset?: number;
@@ -2068,8 +2905,10 @@ declare class TaskResource extends ApiResource {
2068
2905
  list(params?: ListTasksParams): Promise<TaskDto[]>;
2069
2906
  /** GET /tasks/:id */
2070
2907
  get(id: string): Promise<TaskDto>;
2071
- /** POST /tasks */
2072
- create(data: CreateTaskDto): Promise<TaskDto>;
2908
+ /** POST /tasks. Pass `idempotencyKey` to make a retry safe (E64-S6). */
2909
+ create(data: CreateTaskDto, options?: {
2910
+ idempotencyKey?: string;
2911
+ }): Promise<TaskDto>;
2073
2912
  /** PATCH /tasks/:id — non-terminal fields only; terminal status changes use the action methods. */
2074
2913
  update(id: string, data: UpdateTaskDto): Promise<TaskDto>;
2075
2914
  /**
@@ -2145,7 +2984,7 @@ declare class RecordViewsResource {
2145
2984
  * response with the REAL shared schema.
2146
2985
  */
2147
2986
  /** Every registered module key, in the server's canonical order. */
2148
- declare const MODULE_KEYS: readonly ["estimates", "contracts", "inventory", "production", "production_scheduling", "calendar", "service-schedules", "marketplace", "invoicing", "knocks", "accounting", "contacts", "tasks", "comments", "conversations"];
2987
+ declare const MODULE_KEYS: readonly ["estimates", "contracts", "inventory", "production", "production_scheduling", "calendar", "service-schedules", "marketplace", "invoicing", "knocks", "accounting", "contacts", "tasks", "comments", "conversations", "web_forms"];
2149
2988
  type ModuleKey = (typeof MODULE_KEYS)[number];
2150
2989
  /** One entry of `GET /modules` — whether a module is on for the caller's tenant. */
2151
2990
  interface TenantModuleStatusDto {
@@ -2536,6 +3375,366 @@ declare class InvoiceRemindersResource {
2536
3375
  preview(params: InvoiceReminderPreviewParams): Promise<InvoiceReminderPreviewDto>;
2537
3376
  }
2538
3377
 
3378
+ /**
3379
+ * Wire shapes for event automations on the admin API
3380
+ * (`/api/v1/admin/event-automations`, E60-S2) — "when <event> happens and its
3381
+ * changes match <when>, run these steps".
3382
+ *
3383
+ * Mirrors `event-automation.ts` in `packages/shared`. Redefined here (not
3384
+ * imported) so the published package carries no dependency on
3385
+ * `@blueprint/shared`; `event-automation-types.parity.ts` fails the build when
3386
+ * the two drift, and `event-automations.spec.ts` parses every sent body with
3387
+ * the REAL shared schemas.
3388
+ */
3389
+ /**
3390
+ * Equality matcher over the event's `changes` map:
3391
+ * `{ status: { new: 'paid' } }` matches an event whose
3392
+ * `changes.status.new === 'paid'`. Each entry must name `old`, `new` or both;
3393
+ * `{}` matches every event of the type.
3394
+ */
3395
+ type EventAutomationWhen = Record<string, {
3396
+ old?: unknown;
3397
+ new?: unknown;
3398
+ }>;
3399
+ /** One step as sent on create / update. */
3400
+ interface EventAutomationActionInput {
3401
+ /**
3402
+ * Keep it when editing, so a step that already ran for an event isn't run
3403
+ * again. Omitted: a new step (on update, the id of the existing step at the
3404
+ * same position with the same action type). `[A-Za-z0-9_-]`, ≤ 64 chars.
3405
+ */
3406
+ id?: string | null | undefined;
3407
+ /** One of: notification, send_email, send_sms, create_task, webhook_outbound, upsert_contact, upsert_customer, open_opportunity. */
3408
+ action_type: string;
3409
+ config: Record<string, unknown>;
3410
+ /**
3411
+ * Run only after this earlier step (by id) completes; its config may then use
3412
+ * `{{steps.<id>.output.<field>}}`. If that step fails, this one never runs.
3413
+ * Omitted: runs as soon as the event fires.
3414
+ */
3415
+ after?: string | null | undefined;
3416
+ }
3417
+ /** Body of `POST /admin/event-automations`. The steps run as the caller. */
3418
+ interface CreateEventAutomationInput {
3419
+ name: string;
3420
+ /** `<entity_type>.<event_type>`, e.g. `web_form_submission.received`. */
3421
+ event_type: string;
3422
+ /** Defaults to `{}` (every event of the type). */
3423
+ when?: EventAutomationWhen | undefined;
3424
+ /** 1–10 steps. They run at once unless a step sets `after`. */
3425
+ actions: EventAutomationActionInput[];
3426
+ /** Defaults to true. */
3427
+ enabled?: boolean | undefined;
3428
+ }
3429
+ /**
3430
+ * Body of `PATCH /admin/event-automations/:id` — at least one field; only the
3431
+ * fields sent change. `actions` replaces the whole list.
3432
+ */
3433
+ interface UpdateEventAutomationInput {
3434
+ name?: string | undefined;
3435
+ event_type?: string | undefined;
3436
+ when?: EventAutomationWhen | undefined;
3437
+ actions?: EventAutomationActionInput[] | undefined;
3438
+ enabled?: boolean | undefined;
3439
+ }
3440
+ /** Query of `GET /admin/event-automations`. */
3441
+ interface ListEventAutomationsParams {
3442
+ owner_tag?: string | undefined;
3443
+ event_type?: string | undefined;
3444
+ }
3445
+ /** An automation as the admin API returns it: every column except tenant and soft-delete stamp. */
3446
+ interface EventAutomationDto {
3447
+ id: string;
3448
+ name: string;
3449
+ event_type: string;
3450
+ when: EventAutomationWhen;
3451
+ /** `after` is present only on a step that waits for an earlier one. */
3452
+ actions: Array<{
3453
+ id: string;
3454
+ action_type: string;
3455
+ config: Record<string, unknown>;
3456
+ after?: string | undefined;
3457
+ }>;
3458
+ enabled: boolean;
3459
+ /** Set when a feature owns it, e.g. `web_forms:<form id>`; read-only through the API. */
3460
+ owner_tag: string | null;
3461
+ /** The agent the steps run as: the creator, or the last admin who changed its event, filter or steps. */
3462
+ created_by: string | null;
3463
+ created_at: string;
3464
+ updated_at: string;
3465
+ }
3466
+ /** Response of `DELETE /admin/event-automations/:id` (200; the delete is soft). */
3467
+ interface DeleteEventAutomationResult {
3468
+ id: string;
3469
+ }
3470
+
3471
+ /**
3472
+ * Event automations (`/api/v1/admin/event-automations`, E60-S2): "when
3473
+ * <event> happens, run these steps". Admin only (Update Tenant) and gated on
3474
+ * the `workflow_execution` feature. A created automation's steps run as the
3475
+ * caller. Responses use snake_case, matching the stored rows. Lists are
3476
+ * wrapped (`{ data }`) and unpaginated, so this does NOT extend `BaseResource`.
3477
+ */
3478
+ declare class EventAutomationsResource {
3479
+ private readonly http;
3480
+ constructor(http: HttpClient);
3481
+ /** GET — enabled and disabled automations, oldest first, optionally by event type or owner. */
3482
+ list(params?: ListEventAutomationsParams): Promise<EventAutomationDto[]>;
3483
+ /** GET /:id — 404 when it doesn't exist or was deleted. */
3484
+ get(id: string): Promise<EventAutomationDto>;
3485
+ /**
3486
+ * POST — create (201). 400 `VALIDATION_FAILED` for a bad body, or a 400
3487
+ * naming the step whose `action_type` isn't allowed in automations.
3488
+ */
3489
+ create(input: CreateEventAutomationInput): Promise<EventAutomationDto>;
3490
+ /**
3491
+ * PATCH /:id — only the fields sent change. Sending `actions` replaces the
3492
+ * list: keep each existing step's `id` so a step that already ran isn't run
3493
+ * again. `{ enabled: false }` switches it off.
3494
+ */
3495
+ update(id: string, input: UpdateEventAutomationInput): Promise<EventAutomationDto>;
3496
+ /** DELETE /:id — soft delete; returns `{ id }` (200). */
3497
+ delete(id: string): Promise<DeleteEventAutomationResult>;
3498
+ }
3499
+
3500
+ /**
3501
+ * Wire shapes for web forms on the admin API (`/api/v1/admin/web-forms`,
3502
+ * E60-S6). Mirrors `web-form.ts` in `packages/shared`; redefined here so the
3503
+ * published package has no dependency on `@blueprint/shared`.
3504
+ * `web-form-types.parity.ts` fails the build when the two drift.
3505
+ */
3506
+ type WebFormCoreKey = 'first_name' | 'last_name' | 'email' | 'phone' | 'address' | 'message';
3507
+ type WebFormQuestionType = 'short_text' | 'long_text' | 'email' | 'phone' | 'address' | 'dropdown' | 'checkboxes' | 'date' | 'number' | 'yes_no'
3508
+ /**
3509
+ * The company's active trades, several allowed; it takes no `options`
3510
+ * (choices are read live, see `webForms.tradeOptions()`). One per form.
3511
+ */
3512
+ | 'trade';
3513
+ /** One question. `id` is stable: keep it when renaming or reordering. */
3514
+ interface WebFormQuestion {
3515
+ id: string;
3516
+ kind: 'core' | 'custom';
3517
+ /** Core questions only. The six core questions can be hidden but never removed. */
3518
+ core_key?: WebFormCoreKey | undefined;
3519
+ type: WebFormQuestionType;
3520
+ label: string;
3521
+ required: boolean;
3522
+ hidden: boolean;
3523
+ /** dropdown and checkboxes only. */
3524
+ options?: string[] | undefined;
3525
+ }
3526
+ /** Questions in display order. */
3527
+ interface WebFormDefinition {
3528
+ questions: WebFormQuestion[];
3529
+ }
3530
+ /**
3531
+ * The visitor's confirmation email (on by default for new forms). Subject and
3532
+ * body are plain text; only `{{company_name}}` and `{{form_name}}` can be
3533
+ * filled in, never the visitor's answers. Replace the whole object to change it.
3534
+ */
3535
+ interface WebFormConfirmation {
3536
+ enabled: boolean;
3537
+ subject?: string | undefined;
3538
+ body?: string | undefined;
3539
+ }
3540
+ interface WebFormDto {
3541
+ id: string;
3542
+ name: string;
3543
+ /** The key in the embed code (`wf_…`); `rotateKey()` replaces it. */
3544
+ public_key: string;
3545
+ definition: WebFormDefinition;
3546
+ success_message: string;
3547
+ redirect_url: string | null;
3548
+ recipient_agent_ids: string[];
3549
+ /** Who owns and creates the client and opportunity its routing makes; null = the first recipient. */
3550
+ lead_owner_agent_id: string | null;
3551
+ confirmation: WebFormConfirmation;
3552
+ turnstile_enabled: boolean;
3553
+ allowed_origins: string[];
3554
+ consent_text: string | null;
3555
+ active: boolean;
3556
+ /** The form's default routing (an event automation). */
3557
+ automation_id: string | null;
3558
+ created_at: string;
3559
+ updated_at: string;
3560
+ }
3561
+ /**
3562
+ * Body of `POST /admin/web-forms`. `recipient_agent_ids` is optional in the type
3563
+ * (it mirrors the shared schema) but an API-key call without it is a 400 (D2).
3564
+ */
3565
+ interface CreateWebFormInput {
3566
+ name: string;
3567
+ definition?: WebFormDefinition | undefined;
3568
+ success_message?: string | undefined;
3569
+ redirect_url?: string | null | undefined;
3570
+ recipient_agent_ids?: string[] | undefined;
3571
+ /** Who owns and creates the client and opportunity; null = the first recipient. */
3572
+ lead_owner_agent_id?: string | null | undefined;
3573
+ confirmation?: WebFormConfirmation | undefined;
3574
+ /** Cloudflare Turnstile bot check. Defaults to `true` for a new form. */
3575
+ turnstile_enabled?: boolean | undefined;
3576
+ allowed_origins?: string[] | undefined;
3577
+ consent_text?: string | null | undefined;
3578
+ }
3579
+ /** Body of `PATCH /admin/web-forms/:id` — at least one field. */
3580
+ interface UpdateWebFormInput {
3581
+ name?: string | undefined;
3582
+ definition?: WebFormDefinition | undefined;
3583
+ success_message?: string | undefined;
3584
+ redirect_url?: string | null | undefined;
3585
+ recipient_agent_ids?: string[] | undefined;
3586
+ /** Who owns and creates the client and opportunity; null = the first recipient. */
3587
+ lead_owner_agent_id?: string | null | undefined;
3588
+ confirmation?: WebFormConfirmation | undefined;
3589
+ turnstile_enabled?: boolean | undefined;
3590
+ allowed_origins?: string[] | undefined;
3591
+ consent_text?: string | null | undefined;
3592
+ active?: boolean | undefined;
3593
+ }
3594
+ type WebFormTriageStatus = 'new' | 'reviewed' | 'spam' | 'archived';
3595
+ type WebFormRoutingState = 'not_routed' | 'routing' | 'routed' | 'failed';
3596
+ /** Why intake held a submission (stored, not routed). */
3597
+ type WebFormHoldReason = 'flood' | 'limits_unavailable' | 'unverified' | 'turnstile_unavailable';
3598
+ interface ListWebFormSubmissionsParams {
3599
+ form_id?: string | undefined;
3600
+ triage_status?: WebFormTriageStatus | undefined;
3601
+ /** Only submissions held for this reason — e.g. `limits_unavailable`, to route them again. */
3602
+ hold_reason?: WebFormHoldReason | undefined;
3603
+ routing?: WebFormRoutingState | undefined;
3604
+ limit?: number | undefined;
3605
+ /** Paging: the previous page's `next.before`. */
3606
+ before?: string | undefined;
3607
+ /** Paging: the previous page's `next.before_id` (needs `before`). */
3608
+ before_id?: string | undefined;
3609
+ }
3610
+ /** One answered question, as the visitor saw it. */
3611
+ interface WebFormAnswer {
3612
+ label: string;
3613
+ type: WebFormQuestionType;
3614
+ options?: string[];
3615
+ /** For a `trade` question, the trade names as shown. */
3616
+ value: string | number | boolean | string[];
3617
+ /** A `trade` question's picked trade ids. */
3618
+ trade_ids?: string[];
3619
+ }
3620
+ /** One choice of a `trade` question: an active trade, by its current name. */
3621
+ interface WebFormTradeOption {
3622
+ id: string;
3623
+ name: string;
3624
+ }
3625
+ /** A record routing created or matched: a contact, a client (`customer`) or an opportunity. */
3626
+ interface WebFormRecordLink {
3627
+ entity_type: string;
3628
+ id: string;
3629
+ /** `created`, `matched_existing` or `matched_open`. */
3630
+ result: string;
3631
+ /** The routing step that made it. */
3632
+ action_id: string | null;
3633
+ }
3634
+ interface WebFormSubmissionDto {
3635
+ id: string;
3636
+ form_id: string;
3637
+ form_name: string;
3638
+ answers: Record<string, WebFormAnswer>;
3639
+ core: Partial<Record<WebFormCoreKey, string>>;
3640
+ consent: {
3641
+ text: string;
3642
+ checked: boolean;
3643
+ at: string;
3644
+ } | null;
3645
+ origin: string | null;
3646
+ referrer: string | null;
3647
+ source_channel: string;
3648
+ triage_status: WebFormTriageStatus;
3649
+ /** Why intake held it (not routed), or null. */
3650
+ hold_reason: WebFormHoldReason | null;
3651
+ routing: WebFormRoutingState;
3652
+ contact_id: string | null;
3653
+ /** Every record routing created or matched, in step order. */
3654
+ links: WebFormRecordLink[];
3655
+ created_at: string;
3656
+ }
3657
+ interface WebFormRoutingStepDto {
3658
+ action_id: string | null;
3659
+ action_type: string | null;
3660
+ status: string;
3661
+ output: unknown;
3662
+ error: string | null;
3663
+ created_at: string;
3664
+ }
3665
+ interface WebFormSubmissionDetailDto extends WebFormSubmissionDto {
3666
+ /** The visitor's browser as it reported itself. Visitor-supplied: show as text only. */
3667
+ user_agent: string | null;
3668
+ routing_steps: WebFormRoutingStepDto[];
3669
+ }
3670
+ /** Where the next page starts. */
3671
+ interface WebFormSubmissionsCursor {
3672
+ before: string;
3673
+ before_id: string;
3674
+ }
3675
+ /** One page of the inbox; `next` is null on the last page. */
3676
+ interface WebFormSubmissionsPage {
3677
+ data: WebFormSubmissionDto[];
3678
+ next: WebFormSubmissionsCursor | null;
3679
+ }
3680
+ interface RouteSubmissionResult {
3681
+ /** Failed steps queued to run again. */
3682
+ redispatched: number;
3683
+ /** Steps that never ran, now queued. */
3684
+ dispatched: number;
3685
+ /** Email, text and webhook steps that never ran and were left undone (route again never sends them late). */
3686
+ skipped: number;
3687
+ }
3688
+
3689
+ /**
3690
+ * Web forms (`/api/v1/admin/web-forms`, E60-S6): website lead forms and their
3691
+ * submissions. Admin only (Update Tenant) and gated on the `web_forms` module.
3692
+ * Creating a form also creates its default routing (a client and opportunity, or
3693
+ * a contact on a company with Contacts on, plus the alert). Not a
3694
+ * `BaseResource`: lists are wrapped (`{ data }`) and archive is a soft delete.
3695
+ */
3696
+ declare class WebFormsResource {
3697
+ private readonly http;
3698
+ /** The submissions inbox: list, get, set triage status, route again. */
3699
+ readonly submissions: WebFormSubmissionsResource;
3700
+ constructor(http: HttpClient);
3701
+ /** GET — every form not archived, newest first. */
3702
+ list(): Promise<WebFormDto[]>;
3703
+ /** GET /trade-options — the active trades a `trade` question offers, by current name. */
3704
+ tradeOptions(): Promise<WebFormTradeOption[]>;
3705
+ /** GET /:id */
3706
+ get(id: string): Promise<WebFormDto>;
3707
+ /** POST — create (201) with its default routing. Pass `recipient_agent_ids`. */
3708
+ create(input: CreateWebFormInput): Promise<WebFormDto>;
3709
+ /** PATCH /:id — only the fields sent change. `active: false` switches the form off. */
3710
+ update(id: string, input: UpdateWebFormInput): Promise<WebFormDto>;
3711
+ /** DELETE /:id — archive: the public URL stops working and routing stops. Returns `{ id }`. */
3712
+ archive(id: string): Promise<{
3713
+ id: string;
3714
+ }>;
3715
+ /** POST /:id/rotate-key — a new public key; the old embed stops working at once. */
3716
+ rotateKey(id: string): Promise<WebFormDto>;
3717
+ }
3718
+ declare class WebFormSubmissionsResource {
3719
+ private readonly http;
3720
+ constructor(http: HttpClient);
3721
+ /** GET /submissions — the first page, newest first, with routing state. Use `listPage` to read on. */
3722
+ list(params?: ListWebFormSubmissionsParams): Promise<WebFormSubmissionDto[]>;
3723
+ /**
3724
+ * GET /submissions — one page plus `next`, which is null on the last page.
3725
+ * Pass `next`'s `before` and `before_id` back in to read the following page.
3726
+ */
3727
+ listPage(params?: ListWebFormSubmissionsParams): Promise<WebFormSubmissionsPage>;
3728
+ /** GET /submissions/:id — answers as seen, plus each routing step. */
3729
+ get(id: string): Promise<WebFormSubmissionDetailDto>;
3730
+ /** PATCH /submissions/:id — set triage status. */
3731
+ update(id: string, input: {
3732
+ triage_status: WebFormTriageStatus;
3733
+ }): Promise<WebFormSubmissionDetailDto>;
3734
+ /** POST /submissions/:id/route — retry failed steps, run never-run ones (not email, text or webhook: `skipped`); safe to repeat. */
3735
+ route(id: string): Promise<RouteSubmissionResult>;
3736
+ }
3737
+
2539
3738
  /**
2540
3739
  * Wire shapes for enrollable sequences (`GET /api/v1/contact-sequences`,
2541
3740
  * E51-F2-S6).
@@ -2670,6 +3869,13 @@ type WorkflowEventRuleEventType = (typeof WORKFLOW_EVENT_RULE_EVENT_TYPES)[numbe
2670
3869
  * matcher that can match is `when: {}`.
2671
3870
  */
2672
3871
  declare const WORKFLOW_EVENT_RULE_MATCH_ALL_EVENT_TYPES: readonly WorkflowEventRuleEventType[];
3872
+ /**
3873
+ * Event types a rule can **catch up** on (0.65.0): with `catchUp` on, a record
3874
+ * that arrives at the rule's from-stage after its event already happened still
3875
+ * moves. Must equal the shared `WORKFLOW_EVENT_RULE_CATCH_UP_EVENT_TYPES`.
3876
+ * `catchUp: true` on any other type is a 400 `EVENT_RULE_CATCH_UP_UNSUPPORTED`.
3877
+ */
3878
+ declare const WORKFLOW_EVENT_RULE_CATCH_UP_EVENT_TYPES: readonly ["calendar_event.created"];
2673
3879
  /**
2674
3880
  * Equality matcher over the event's `changes` map:
2675
3881
  * `{ status: { new: 'sent' } }` matches an event whose
@@ -2696,6 +3902,12 @@ interface CreateWorkflowEventRuleInput {
2696
3902
  transitionRef: WorkflowTransitionRef;
2697
3903
  /** Defaults to true. */
2698
3904
  enabled?: boolean | undefined;
3905
+ /**
3906
+ * Also move records that ARRIVE at the from-stage after the event already
3907
+ * happened (0.65.0). Defaults to false. Only for
3908
+ * {@link WORKFLOW_EVENT_RULE_CATCH_UP_EVENT_TYPES}.
3909
+ */
3910
+ catchUp?: boolean | undefined;
2699
3911
  }
2700
3912
  /** Body of `PATCH /admin/workflows/:workflowId/event-rules/:id` — at least one field; only the fields sent change. */
2701
3913
  interface UpdateWorkflowEventRuleInput {
@@ -2703,6 +3915,8 @@ interface UpdateWorkflowEventRuleInput {
2703
3915
  when?: WorkflowEventRuleWhen | undefined;
2704
3916
  transitionRef?: WorkflowTransitionRef | undefined;
2705
3917
  enabled?: boolean | undefined;
3918
+ /** See {@link CreateWorkflowEventRuleInput.catchUp}; checked against the rule as it will be stored. */
3919
+ catchUp?: boolean | undefined;
2706
3920
  }
2707
3921
  /**
2708
3922
  * An event rule as the admin API returns it (list, create, update) — exactly
@@ -2718,6 +3932,8 @@ interface WorkflowEventRuleDto {
2718
3932
  when: WorkflowEventRuleWhen;
2719
3933
  transitionRef: WorkflowTransitionRef;
2720
3934
  enabled: boolean;
3935
+ /** The rule also moves records that arrive after its event happened (0.65.0). */
3936
+ catchUp: boolean;
2721
3937
  createdAt: string;
2722
3938
  updatedAt: string;
2723
3939
  }
@@ -3013,25 +4229,166 @@ interface ConflictPreviewResponse {
3013
4229
  /** How many windows were expanded and checked (0 conflicts ≠ 0 windows). */
3014
4230
  windows_checked: number;
3015
4231
  }
4232
+ type ServiceScheduleStatus = 'active' | 'paused' | 'ended';
4233
+ type ServiceScheduleSubjectType = 'customer' | 'opportunity';
4234
+ interface ServiceScheduleParticipant {
4235
+ type: 'user' | 'contact' | 'crew' | 'agent';
4236
+ id: string;
4237
+ role?: string;
4238
+ }
4239
+ interface ServiceScheduleDto {
4240
+ id: string;
4241
+ tenant_id: string;
4242
+ org_path: string | null;
4243
+ subject_type: ServiceScheduleSubjectType;
4244
+ subject_id: string;
4245
+ dtstart: string | null;
4246
+ recurrence_rule: string;
4247
+ recurrence_exceptions: string[];
4248
+ timezone: string;
4249
+ default_participants: ServiceScheduleParticipant[] | null;
4250
+ default_duration_min: number;
4251
+ default_price: string | null;
4252
+ title: string | null;
4253
+ default_scope: string | null;
4254
+ service_trade_id: string | null;
4255
+ property_id: string | null;
4256
+ status: ServiceScheduleStatus;
4257
+ horizon_weeks: number;
4258
+ import_job_id: string | null;
4259
+ created_by: string;
4260
+ created_at: string;
4261
+ updated_at: string;
4262
+ deleted_at: string | null;
4263
+ }
4264
+ interface CreateServiceScheduleInput {
4265
+ subject_type: ServiceScheduleSubjectType;
4266
+ subject_id: string;
4267
+ /** RRULE, e.g. `FREQ=WEEKLY;INTERVAL=2`. */
4268
+ recurrence_rule: string;
4269
+ /** First visit, ISO datetime with offset; its local time is the time-of-day. */
4270
+ dtstart?: string;
4271
+ recurrence_exceptions?: string[];
4272
+ timezone: string;
4273
+ default_participants?: ServiceScheduleParticipant[];
4274
+ default_duration_min: number;
4275
+ default_price?: string;
4276
+ title?: string;
4277
+ default_scope?: string;
4278
+ service_trade_id?: string;
4279
+ property_id?: string;
4280
+ status?: ServiceScheduleStatus;
4281
+ horizon_weeks?: number;
4282
+ }
4283
+ interface UpdateServiceScheduleInput {
4284
+ recurrence_rule?: string;
4285
+ dtstart?: string | null;
4286
+ recurrence_exceptions?: string[];
4287
+ timezone?: string;
4288
+ default_participants?: ServiceScheduleParticipant[];
4289
+ default_duration_min?: number;
4290
+ default_price?: string | null;
4291
+ title?: string | null;
4292
+ default_scope?: string | null;
4293
+ service_trade_id?: string | null;
4294
+ property_id?: string | null;
4295
+ horizon_weeks?: number;
4296
+ /** YYYY-MM-DD in the schedule's timezone. Must be today (the default); any other date is a 400. */
4297
+ effective_from?: string;
4298
+ }
4299
+ type ProtectedReason = 'time_moved' | 'crew_changed' | 'status' | 'workflow_advanced' | 'invoiced' | 'billable_changed';
4300
+ /** What an edit does (or would do) to the visits already on the calendar. */
4301
+ interface ScheduleUpdateResult {
4302
+ effective_from: string;
4303
+ removed: number;
4304
+ added: number;
4305
+ updated: number;
4306
+ /** Days added to the skipped dates because a hand-moved visit already covers them. */
4307
+ skipped: string[];
4308
+ /** Visits someone changed that the edit leaves alone though they differ from the new plan. */
4309
+ protected: Array<{
4310
+ visit_id: string;
4311
+ job_id: string;
4312
+ day: string;
4313
+ starts_at: string;
4314
+ reasons: ProtectedReason[];
4315
+ }>;
4316
+ }
4317
+ interface ServiceScheduleUpdateResult extends ServiceScheduleDto {
4318
+ /** Null when the edit changed nothing that regenerates visits. */
4319
+ regeneration: ScheduleUpdateResult | null;
4320
+ }
4321
+ interface CrewRolesDto {
4322
+ roles: string[];
4323
+ source: 'default' | 'override';
4324
+ }
4325
+ interface CrewHomeAddressResult {
4326
+ agentId: string;
4327
+ geocoded: boolean;
4328
+ }
4329
+ interface DispatchCrewDto {
4330
+ agentId: string;
4331
+ displayName: string | null;
4332
+ role: string;
4333
+ homeAddress: string | null;
4334
+ hasCoords: boolean;
4335
+ }
3016
4336
 
3017
4337
  /**
3018
- * Recurring-service scheduling reads (`/api/v1/service-schedules`). Only the
3019
- * crew conflict preview for now. Not a CRUD resource, so it does NOT extend
3020
- * `BaseResource`.
4338
+ * Recurring service schedules (`/api/v1/service-schedules`): the agreement
4339
+ * that generates a client's visits, plus the dispatch settings that sit on the
4340
+ * same controller. Gated on the `service-schedules` module. Responses use
4341
+ * snake_case, matching the API. Not a paginated CRUD resource, so it does NOT
4342
+ * extend `BaseResource`.
4343
+ *
4344
+ * Editing the cadence, time, crew, duration or horizon regenerates the visits
4345
+ * already on the calendar (E25-S1, decision #65): call `previewUpdate` to see
4346
+ * what an edit would do, then `update` to do it.
3021
4347
  */
3022
4348
  declare class ServiceSchedulesResource {
3023
4349
  private readonly http;
3024
- private readonly basePath;
3025
4350
  constructor(http: HttpClient);
4351
+ /** GET — the schedules of one customer or opportunity. */
4352
+ list(subject_type: ServiceScheduleSubjectType, subject_id: string): Promise<ServiceScheduleDto[]>;
4353
+ /** GET /:id — 404 when it doesn't exist or was deleted. */
4354
+ get(id: string): Promise<ServiceScheduleDto>;
4355
+ /**
4356
+ * POST — create (201). The horizon's visits are generated straight away.
4357
+ * 400 `INVALID_RECURRENCE_RULE`, `SERVICE_TRADE_REQUIRED` or a validation error.
4358
+ */
4359
+ create(input: CreateServiceScheduleInput): Promise<ServiceScheduleDto>;
3026
4360
  /**
3027
- * POST /service-schedules/conflicts/preview — before booking people, see
3028
- * who is already on another event (`conflicts`) and who would be outside
3029
- * their working hours (`working_hours`). Read-only and warn-only: nothing
3030
- * is ever blocked. Give exactly one of `windows` (single booking) or
3031
- * `schedule` (a cadence). 400 on invalid input, INVALID_RECURRENCE_RULE,
3032
- * INVALID_TIMEZONE or TOO_MANY_WINDOWS (> 400).
4361
+ * PATCH /:id — only the fields sent change. A cadence, time, crew, duration
4362
+ * or horizon change regenerates future visits from today (`effective_from`,
4363
+ * which must be today) and reports it in `regeneration`; a visit someone changed is never
4364
+ * touched and is listed under `regeneration.protected`. The edit and its
4365
+ * regeneration succeed or fail together. 400 `INVALID_EFFECTIVE_FROM` for any
4366
+ * date but today.
4367
+ */
4368
+ update(id: string, input: UpdateServiceScheduleInput): Promise<ServiceScheduleUpdateResult>;
4369
+ /** POST /:id/preview-update — what `update` with the same input would do. Writes nothing. */
4370
+ previewUpdate(id: string, input: UpdateServiceScheduleInput): Promise<ScheduleUpdateResult>;
4371
+ /** PATCH /:id/status — pause, resume (`active`) or end. Resume generates the horizon at once. */
4372
+ setStatus(id: string, status: ServiceScheduleStatus): Promise<ServiceScheduleDto>;
4373
+ /** DELETE /:id — soft-delete (204). */
4374
+ delete(id: string): Promise<void>;
4375
+ /**
4376
+ * POST /conflicts/preview — before booking people, see who is already on
4377
+ * another event (`conflicts`) and who would be outside their working hours
4378
+ * (`working_hours`). Read-only and warn-only: nothing is ever blocked. Give
4379
+ * exactly one of `windows` (single booking) or `schedule` (a cadence). 400 on
4380
+ * invalid input, INVALID_RECURRENCE_RULE, INVALID_TIMEZONE or
4381
+ * TOO_MANY_WINDOWS (> 400).
3033
4382
  */
3034
4383
  previewConflicts(request: ConflictPreviewRequest): Promise<ConflictPreviewResponse>;
4384
+ /** GET /settings/crew-roles — which agent roles count as assignable crew. */
4385
+ getCrewRoles(): Promise<CrewRolesDto>;
4386
+ /** PUT /settings/crew-roles — set the assignable roles (an override of the default). */
4387
+ setCrewRoles(roles: string[]): Promise<CrewRolesDto>;
4388
+ /** GET /settings/crew — assignable crew with their home-base status. */
4389
+ listCrew(): Promise<DispatchCrewDto[]>;
4390
+ /** PUT /settings/crew/:agentId/home-address — set and geocode a crew member's home base. */
4391
+ setCrewHomeAddress(agentId: string, address: string): Promise<CrewHomeAddressResult>;
3035
4392
  }
3036
4393
 
3037
4394
  /**
@@ -3524,6 +4881,49 @@ interface CustomFieldValidationRules {
3524
4881
  /** text/regex pattern */
3525
4882
  pattern?: string;
3526
4883
  }
4884
+ /** `validationRules` as a write body takes it (E64-S10); see `CustomFieldValidationRules`. */
4885
+ interface CustomFieldValidationRulesInput {
4886
+ required?: boolean | undefined;
4887
+ min?: number | undefined;
4888
+ max?: number | undefined;
4889
+ pattern?: string | undefined;
4890
+ }
4891
+ /**
4892
+ * Body of `POST /admin/custom-fields` (E64-S10). `fieldKey` is lower_snake_case
4893
+ * starting with a letter; `fieldKey` and `entityType` can't change later.
4894
+ * The API refuses new definitions for `job`, `vendor` and `agent` (PRD D6):
4895
+ * those records have nowhere to store or show the values yet.
4896
+ */
4897
+ interface CreateCustomFieldDefinitionDto {
4898
+ entityType: CustomFieldEntityType;
4899
+ fieldKey: string;
4900
+ label: string;
4901
+ fieldType: CustomFieldType;
4902
+ /** Choices for `select` and `multi_select`. */
4903
+ options?: string[] | null | undefined;
4904
+ validationRules?: CustomFieldValidationRulesInput | null | undefined;
4905
+ defaultValue?: unknown;
4906
+ displayOrder?: number | undefined;
4907
+ section?: string | null | undefined;
4908
+ searchable?: boolean | undefined;
4909
+ showInList?: boolean | undefined;
4910
+ showInReports?: boolean | undefined;
4911
+ active?: boolean | undefined;
4912
+ }
4913
+ /** Body of `PATCH /admin/custom-fields/:id`. Omitted fields are unchanged. */
4914
+ interface UpdateCustomFieldDefinitionDto {
4915
+ label?: string | undefined;
4916
+ fieldType?: CustomFieldType | undefined;
4917
+ options?: string[] | null | undefined;
4918
+ validationRules?: CustomFieldValidationRulesInput | null | undefined;
4919
+ defaultValue?: unknown;
4920
+ displayOrder?: number | undefined;
4921
+ section?: string | null | undefined;
4922
+ searchable?: boolean | undefined;
4923
+ showInList?: boolean | undefined;
4924
+ showInReports?: boolean | undefined;
4925
+ active?: boolean | undefined;
4926
+ }
3527
4927
 
3528
4928
  /** A custom-field definition as returned by `GET /custom-fields`. */
3529
4929
  interface CustomFieldDefinitionDto {
@@ -3551,18 +4951,40 @@ interface ListCustomFieldDefinitionsParams {
3551
4951
  include_inactive?: boolean;
3552
4952
  }
3553
4953
  /**
3554
- * Read-only view of a tenant's custom-field definitions — the shape of its
3555
- * records. Needed to know which keys a `custom_fields` payload may carry before
3556
- * writing a customer, contact or opportunity.
4954
+ * A tenant's custom-field definitions: the shape of its records. `list()` tells
4955
+ * you which keys a `custom_fields` payload may carry before writing a customer,
4956
+ * contact or opportunity.
3557
4957
  *
3558
- * Read-only by design: configuring definitions is an admin action on
3559
- * `/admin/custom-fields` and is deliberately not exposed here.
4958
+ * The definition writes (`create`, `update`, `deactivate`) and the admin reads
4959
+ * (`listAll`, `get`) go through `/admin/custom-fields` and need the Manage grant
4960
+ * on custom field definitions, which only admins hold by default (E64-S10, PRD
4961
+ * D4; this reverses E63-S3's read-only SDK surface). Use an API key or a user's
4962
+ * token for those: an OAuth app token's role has no Manage grant. A definition is never
4963
+ * deleted: `deactivate()` hides it, and the values already on records stay valid.
3560
4964
  */
3561
4965
  declare class CustomFieldsResource {
3562
4966
  private readonly http;
3563
4967
  constructor(http: HttpClient);
3564
4968
  /** List definitions, optionally narrowed to one entity type. */
3565
4969
  list(params?: ListCustomFieldDefinitionsParams): Promise<CustomFieldDefinitionDto[]>;
4970
+ /** GET /admin/custom-fields — the same list through the admin route (Manage grant). */
4971
+ listAll(params?: ListCustomFieldDefinitionsParams): Promise<CustomFieldDefinitionDto[]>;
4972
+ /** GET /admin/custom-fields/:id */
4973
+ get(id: string): Promise<CustomFieldDefinitionDto>;
4974
+ /**
4975
+ * POST /admin/custom-fields — define a new field. 400 for `job`, `vendor` or
4976
+ * `agent` (those records can't hold values yet, PRD D6). A `fieldKey` must be
4977
+ * unique per entity type: check `listAll({ entity_type, include_inactive: true })` first.
4978
+ */
4979
+ create(data: CreateCustomFieldDefinitionDto): Promise<CustomFieldDefinitionDto>;
4980
+ /** PATCH /admin/custom-fields/:id — `fieldKey` and `entityType` can't change. */
4981
+ update(id: string, data: UpdateCustomFieldDefinitionDto): Promise<CustomFieldDefinitionDto>;
4982
+ /**
4983
+ * DELETE /admin/custom-fields/:id — deactivates the definition (204). Records
4984
+ * keep their stored values; `list({ include_inactive: true })` still shows it,
4985
+ * and `update(id, { active: true })` brings it back.
4986
+ */
4987
+ deactivate(id: string): Promise<void>;
3566
4988
  }
3567
4989
 
3568
4990
  /**
@@ -3745,7 +5167,7 @@ declare class OrttoResource {
3745
5167
  * `packages/shared` — the SDK must not depend on `@blueprint/shared`.
3746
5168
  * `webhooks.spec.ts` asserts runtime parity, so drift fails there.
3747
5169
  */
3748
- declare const WEBHOOK_EVENT_TYPES: readonly ["created", "updated", "deleted", "status_changed", "entity.tagged", "entity.untagged", "list.member_added", "list.member_removed", "entity.assigned", "entity.unassigned", "team.member_added", "team.member_removed", "task.created", "task.updated", "task.completed", "task.cancelled", "comment.created", "conversation.created", "conversation.matched", "conversation.deleted", "customer.merged", "workflow.instance_moved", "consent.changed", "billing_schedule.period_generated", "billing_schedule.period_needs_review", "billing_schedule.period_delivered", "billing_schedule.period_delivery_failed", "payment.on_void_invoice", "invoice.overdue", "integration_connection.deactivated", "customer_payment_method.invalidated", "invoice.autopay_succeeded", "invoice.autopay_failed"];
5170
+ declare const WEBHOOK_EVENT_TYPES: readonly ["created", "updated", "deleted", "status_changed", "entity.tagged", "entity.untagged", "list.member_added", "list.member_removed", "entity.assigned", "entity.unassigned", "team.member_added", "team.member_removed", "task.created", "task.updated", "task.completed", "task.cancelled", "comment.created", "conversation.created", "conversation.matched", "conversation.deleted", "customer.merged", "workflow.instance_moved", "consent.changed", "billing_schedule.period_generated", "billing_schedule.period_needs_review", "billing_schedule.period_delivered", "billing_schedule.period_delivery_failed", "payment.on_void_invoice", "invoice.overdue", "integration_connection.deactivated", "customer_payment_method.invalidated", "invoice.autopay_succeeded", "invoice.autopay_failed", "received"];
3749
5171
  /** The kinds of change a webhook event can describe. */
3750
5172
  type EntityEventType = (typeof WEBHOOK_EVENT_TYPES)[number];
3751
5173
  /**
@@ -3754,7 +5176,7 @@ type EntityEventType = (typeof WEBHOOK_EVENT_TYPES)[number];
3754
5176
  * Mirrored (self-contained, NOT imported) from
3755
5177
  * `packages/shared/src/types/entity-events.ts`. Keep byte-identical.
3756
5178
  */
3757
- type EntityType = 'customer' | 'opportunity' | 'job' | 'estimate' | 'contract' | 'property' | 'inventory_item' | 'agent_execution' | 'calendar_event' | 'invoice' | 'payment' | 'billing_schedule' | 'integration_connection';
5179
+ type EntityType = 'customer' | 'opportunity' | 'job' | 'estimate' | 'contract' | 'property' | 'inventory_item' | 'agent_execution' | 'calendar_event' | 'invoice' | 'payment' | 'billing_schedule' | 'integration_connection' | 'web_form_submission';
3758
5180
  /**
3759
5181
  * A single entity-change event as emitted onto the Planes event bus and
3760
5182
  * delivered inside a {@link WebhookDelivery}.
@@ -3763,6 +5185,8 @@ type EntityType = 'customer' | 'opportunity' | 'job' | 'estimate' | 'contract' |
3763
5185
  * `packages/shared/src/types/entity-events.ts`.
3764
5186
  */
3765
5187
  interface EntityEvent {
5188
+ /** Unique ID of this event; the same event delivered twice carries the same ID. */
5189
+ event_id?: string;
3766
5190
  /** What happened (e.g. 'created', 'status_changed'). */
3767
5191
  event_type: EntityEventType;
3768
5192
  /** The kind of record this event is about. */
@@ -3782,6 +5206,12 @@ interface EntityEvent {
3782
5206
  timestamp: string;
3783
5207
  /** Correlation ID linking related events/actions. */
3784
5208
  correlation_id: string;
5209
+ /**
5210
+ * Present when an event-automation step caused this event: that step's
5211
+ * execution id. Planes never starts an automation from such an event; your
5212
+ * own integrations can use it the same way to avoid loops.
5213
+ */
5214
+ caused_by_action_execution_id?: string;
3785
5215
  }
3786
5216
  /**
3787
5217
  * `event.snapshot` of an `invoice.overdue` event (E56-F8-S2). Planes' daily
@@ -3962,6 +5392,306 @@ declare function verifyWebhookSignature(payload: string | Buffer, signature: str
3962
5392
  */
3963
5393
  declare function parseWebhookEvent(body: string, signature: string, secret: string): WebhookDelivery;
3964
5394
 
5395
+ /**
5396
+ * Webhook subscriptions over `/admin/webhooks` (E64-S10, PRD O8).
5397
+ *
5398
+ * Mirrors `WebhookSubscriptionE15Dto` and the E15 subscription schemas in
5399
+ * `packages/shared/src/validation/webhook-subscriptions.ts`. Redefined here so
5400
+ * the published package carries no dependency on `@blueprint/shared`;
5401
+ * `webhook-subscription-types.parity.ts` fails the build when either side drifts.
5402
+ */
5403
+
5404
+ /**
5405
+ * Entity kinds a subscription can narrow to. Not the same list as the
5406
+ * `EntityType` an event carries: it includes `task` and leaves out the
5407
+ * entity kinds a subscriber can't filter on.
5408
+ */
5409
+ type WebhookSubscriptionEntityType = 'customer' | 'opportunity' | 'job' | 'estimate' | 'contract' | 'property' | 'inventory_item' | 'agent_execution' | 'task' | 'billing_schedule' | 'web_form_submission';
5410
+ type WebhookSubscriptionStatus = 'active' | 'paused' | 'disabled';
5411
+ /** A subscription. The signing secret is never returned after it is created or rotated. */
5412
+ interface WebhookSubscriptionDto {
5413
+ id: string;
5414
+ tenant_id: string;
5415
+ url: string;
5416
+ event_types: string[];
5417
+ entity_types: string[];
5418
+ /** `disabled`: the API turned it off after repeated delivery failures. */
5419
+ status: WebhookSubscriptionStatus;
5420
+ failure_count: number;
5421
+ last_delivered_at: string | null;
5422
+ created_at: string;
5423
+ updated_at: string;
5424
+ }
5425
+ /**
5426
+ * Body of `POST /admin/webhooks`. `url` must be `https://`. An empty
5427
+ * `event_types` or `entity_types` list means every event or entity kind.
5428
+ * The API always generates the `whsec_` signing secret and returns it once;
5429
+ * you can't choose it (use `rotateSecret()` to replace it).
5430
+ */
5431
+ interface CreateWebhookSubscriptionDto {
5432
+ url: string;
5433
+ event_types?: EntityEventType[] | undefined;
5434
+ entity_types?: WebhookSubscriptionEntityType[] | undefined;
5435
+ status?: 'active' | 'paused' | undefined;
5436
+ }
5437
+ /**
5438
+ * Body of `PATCH /admin/webhooks/:id`. The URL can't change (create a new
5439
+ * subscription), and the secret changes only through `rotateSecret()`.
5440
+ */
5441
+ interface UpdateWebhookSubscriptionDto {
5442
+ event_types?: EntityEventType[] | undefined;
5443
+ entity_types?: WebhookSubscriptionEntityType[] | undefined;
5444
+ status?: 'active' | 'paused' | undefined;
5445
+ }
5446
+ /** `create()` result. `secret` is shown this once: store it to verify signatures. */
5447
+ interface CreatedWebhookSubscription {
5448
+ subscription: WebhookSubscriptionDto;
5449
+ secret: string;
5450
+ }
5451
+ interface ListWebhookSubscriptionsParams {
5452
+ status?: WebhookSubscriptionStatus;
5453
+ /** Default 1. */
5454
+ page?: number;
5455
+ /** Default 20, at most 100. */
5456
+ limit?: number;
5457
+ }
5458
+ interface WebhookSubscriptionList {
5459
+ data: WebhookSubscriptionDto[];
5460
+ total: number;
5461
+ }
5462
+ /** `test()` result: one signed test event sent to the subscription URL. */
5463
+ interface WebhookTestResult {
5464
+ success: boolean;
5465
+ status_code?: number;
5466
+ error?: string;
5467
+ }
5468
+ type WebhookDeliveryStatus = 'success' | 'failed' | 'pending';
5469
+ interface WebhookDeliveryLogDto {
5470
+ id: string;
5471
+ tenant_id: string;
5472
+ webhook_subscription_id: string;
5473
+ event_type: string;
5474
+ entity_type: string;
5475
+ entity_id: string | null;
5476
+ correlation_id: string | null;
5477
+ status_code: number | null;
5478
+ response_time_ms: number | null;
5479
+ attempt: number;
5480
+ status: WebhookDeliveryStatus;
5481
+ error_message: string | null;
5482
+ payload: unknown;
5483
+ next_retry_at: string | null;
5484
+ created_at: string;
5485
+ }
5486
+ interface ListWebhookDeliveriesParams {
5487
+ status?: WebhookDeliveryStatus;
5488
+ page?: number;
5489
+ limit?: number;
5490
+ }
5491
+ interface WebhookDeliveryLogPage {
5492
+ data: WebhookDeliveryLogDto[];
5493
+ meta: {
5494
+ page: number;
5495
+ limit: number;
5496
+ total: number;
5497
+ total_pages: number;
5498
+ };
5499
+ subscription_id: string;
5500
+ }
5501
+ interface WebhookRetryResult {
5502
+ queued: boolean;
5503
+ new_delivery_id: string;
5504
+ }
5505
+
5506
+ /**
5507
+ * Webhook subscriptions (E64-S10): where the tenant's entity events are
5508
+ * delivered, signed with the subscription's `whsec_` secret. Verify and route
5509
+ * deliveries with `verifyWebhookSignature` / `client.webhooks`.
5510
+ *
5511
+ * Needs the `open_api` feature and the webhook-subscription grants (admin by
5512
+ * default), so use an API key or a user's token: an OAuth app token is refused.
5513
+ * Deliveries go only to the subscription's own `https://` URL.
5514
+ */
5515
+ declare class WebhookSubscriptionsResource extends ApiResource {
5516
+ constructor(http: ConstructorParameters<typeof ApiResource>[0]);
5517
+ /** POST /admin/webhooks — the returned `secret` is shown only this once. */
5518
+ create(data: CreateWebhookSubscriptionDto): Promise<CreatedWebhookSubscription>;
5519
+ /** GET /admin/webhooks */
5520
+ list(params?: ListWebhookSubscriptionsParams): Promise<WebhookSubscriptionList>;
5521
+ /** GET /admin/webhooks/:id */
5522
+ get(id: string): Promise<WebhookSubscriptionDto>;
5523
+ /** PATCH /admin/webhooks/:id */
5524
+ update(id: string, data: UpdateWebhookSubscriptionDto): Promise<WebhookSubscriptionDto>;
5525
+ /** DELETE /admin/webhooks/:id */
5526
+ delete(id: string): Promise<{
5527
+ message: string;
5528
+ }>;
5529
+ /** POST /admin/webhooks/:id/test — sends one signed test event to the URL now. */
5530
+ test(id: string): Promise<WebhookTestResult>;
5531
+ /**
5532
+ * POST /admin/webhooks/:id/rotate-secret — replaces the signing secret and
5533
+ * returns the new one, shown only this once. New deliveries are signed with
5534
+ * it, but deliveries already queued (and their retries, for several minutes)
5535
+ * keep the old one. `verifyWebhookSignature` checks one secret, so for a few
5536
+ * minutes have your receiver try the new secret and fall back to the old one.
5537
+ */
5538
+ rotateSecret(id: string): Promise<{
5539
+ data: {
5540
+ secret: string;
5541
+ };
5542
+ }>;
5543
+ /** GET /admin/webhooks/:id/deliveries — newest first. */
5544
+ listDeliveries(id: string, params?: ListWebhookDeliveriesParams): Promise<WebhookDeliveryLogPage>;
5545
+ /**
5546
+ * POST /admin/webhooks/:id/deliveries/:deliveryId/retry — queues a new
5547
+ * delivery of that event (202). The receiver sees the event again, so make
5548
+ * it idempotent on the event id.
5549
+ */
5550
+ retryDelivery(id: string, deliveryId: string): Promise<WebhookRetryResult>;
5551
+ }
5552
+
5553
+ /**
5554
+ * Users (the tenant's people) and teams, read-only (E64-S10, PRD D4: "users
5555
+ * and teams reads"). Shapes follow `UsersService.findAll` / `directory` and
5556
+ * `TeamsService.listTeams` / `getTeam`. The query params are checked against
5557
+ * the shared schemas in `user-team-types.parity.ts`; the responses were checked
5558
+ * by hand against the services.
5559
+ */
5560
+ /** A role a user can hold and be filtered by. A `UserDto` can also be a `system_agent`. */
5561
+ type UserRole = 'admin' | 'sales' | 'service' | 'production' | 'sub' | 'readonly';
5562
+ type UserStatus = 'active' | 'deactivated' | 'invited';
5563
+ /** A row of `GET /users`. Needs the read grant on users (admin and readonly by default). */
5564
+ interface UserDto {
5565
+ /** The user's id in this tenant: the id tasks, assignments and teams refer to. */
5566
+ id: string;
5567
+ /** Login identity; null for a user with no login (e.g. imported). */
5568
+ platformUserId: string | null;
5569
+ email: string | null;
5570
+ role: UserRole | 'system_agent';
5571
+ status: UserStatus;
5572
+ displayName: string | null;
5573
+ timezone: string | null;
5574
+ primaryOrgNodeId: string | null;
5575
+ primaryOrgNodeName: string | null;
5576
+ /** Per-user override for service assignment: true, false, or null for the role default. */
5577
+ serviceAssignable: boolean | null;
5578
+ /** Default hourly rate as a decimal string, or null. */
5579
+ hourlyRate: string | null;
5580
+ /** False for a user who can't sign in (no login, or an import placeholder email). */
5581
+ hasValidLogin: boolean;
5582
+ createdAt: string;
5583
+ updatedAt: string;
5584
+ }
5585
+ interface ListUsersParams {
5586
+ /** Matches the display name. */
5587
+ search?: string;
5588
+ role?: UserRole;
5589
+ status?: UserStatus;
5590
+ /** Users whose primary org node is this id. */
5591
+ org_node_id?: string;
5592
+ sort_by?: 'created_at' | 'display_name' | 'role';
5593
+ sort_order?: 'asc' | 'desc';
5594
+ /** Default 1. */
5595
+ page?: number;
5596
+ /** Default 25, at most 100. */
5597
+ limit?: number;
5598
+ }
5599
+ interface UserPage {
5600
+ data: UserDto[];
5601
+ meta: {
5602
+ page: number;
5603
+ limit: number;
5604
+ total: number;
5605
+ totalPages: number;
5606
+ };
5607
+ }
5608
+ /**
5609
+ * A row of `GET /users/directory`: active users only, name order. Readable by
5610
+ * every role, and carries no email, rate or org fields.
5611
+ */
5612
+ interface UserDirectoryEntry {
5613
+ id: string;
5614
+ display_name: string | null;
5615
+ role: string;
5616
+ }
5617
+ interface UserDirectoryParams {
5618
+ /** Matches the display name. */
5619
+ search?: string;
5620
+ /** Default 25, at most 100. */
5621
+ limit?: number;
5622
+ }
5623
+ type TeamMemberRole = 'lead' | 'member';
5624
+ interface TeamMemberDto {
5625
+ /** Membership id. */
5626
+ id: string;
5627
+ /** The member's user id (`UserDto.id`). */
5628
+ agent_id: string;
5629
+ role: TeamMemberRole;
5630
+ added_at: string;
5631
+ }
5632
+ /** `list()` rows carry `member_count`; `get()` carries `members`. */
5633
+ interface TeamDto {
5634
+ id: string;
5635
+ name: string;
5636
+ description: string | null;
5637
+ color: string | null;
5638
+ created_at: string;
5639
+ updated_at: string;
5640
+ member_count?: number;
5641
+ members?: TeamMemberDto[];
5642
+ }
5643
+ /** One working day: `dayOfWeek` 0 = Sunday … 6 = Saturday, times `HH:mm` in the user's timezone. */
5644
+ interface WorkingHoursEntry {
5645
+ dayOfWeek: number;
5646
+ startTime: string;
5647
+ endTime: string;
5648
+ }
5649
+ /**
5650
+ * `GET /users/:id/working-hours`. An empty `schedule` means the user has none
5651
+ * of their own and the tenant default applies (null when there is none).
5652
+ */
5653
+ interface UserWorkingHours {
5654
+ schedule: WorkingHoursEntry[];
5655
+ tenantDefault: {
5656
+ days: number[];
5657
+ start: string;
5658
+ end: string;
5659
+ } | null;
5660
+ }
5661
+
5662
+ /**
5663
+ * The tenant's users, read-only (E64-S10, PRD D4). Inviting, editing, removing
5664
+ * users, signing out their devices and setting working hours stay in the app.
5665
+ */
5666
+ declare class UsersResource extends ApiResource {
5667
+ constructor(http: ConstructorParameters<typeof ApiResource>[0]);
5668
+ /** GET /users — paged, with email, role, status and org fields (read grant on users). */
5669
+ list(params?: ListUsersParams): Promise<UserPage>;
5670
+ /**
5671
+ * GET /users/directory — active users' ids, names and roles, for pickers and
5672
+ * for resolving an assignee. Every role can read it.
5673
+ */
5674
+ directory(params?: UserDirectoryParams): Promise<UserDirectoryEntry[]>;
5675
+ /**
5676
+ * GET /users/:id/working-hours — the user's own weekly hours and the tenant
5677
+ * default. A non-admin caller may read only their own (403 otherwise).
5678
+ */
5679
+ getWorkingHours(id: string): Promise<UserWorkingHours>;
5680
+ }
5681
+
5682
+ /**
5683
+ * Teams, read-only (E64-S10, PRD D4). Creating teams and changing membership
5684
+ * stay in the app. Use an API key or a user's token: an OAuth app token is
5685
+ * refused even with the `teams:read` scope, because its role has no team grant.
5686
+ */
5687
+ declare class TeamsResource extends ApiResource {
5688
+ constructor(http: ConstructorParameters<typeof ApiResource>[0]);
5689
+ /** GET /teams — every team, with `member_count`. */
5690
+ list(): Promise<TeamDto[]>;
5691
+ /** GET /teams/:id — one team, with `members`. */
5692
+ get(id: string): Promise<TeamDto>;
5693
+ }
5694
+
3965
5695
  /**
3966
5696
  * A handler invoked for a matching webhook delivery. May be sync or async;
3967
5697
  * async handlers are awaited by {@link WebhookRouter.process}.
@@ -4069,6 +5799,8 @@ declare class PlanesClient {
4069
5799
  private _gmail?;
4070
5800
  private _documents?;
4071
5801
  private _tags?;
5802
+ private _lists?;
5803
+ private _leadSources?;
4072
5804
  private _tasks?;
4073
5805
  private _recordViews?;
4074
5806
  private _modules?;
@@ -4077,6 +5809,8 @@ declare class PlanesClient {
4077
5809
  private _roles?;
4078
5810
  private _invoiceSettings?;
4079
5811
  private _invoiceReminders?;
5812
+ private _eventAutomations?;
5813
+ private _webForms?;
4080
5814
  private _contactSequences?;
4081
5815
  private _enrollments?;
4082
5816
  private _workflows?;
@@ -4084,6 +5818,9 @@ declare class PlanesClient {
4084
5818
  private _billingSchedules?;
4085
5819
  private _customFields?;
4086
5820
  private _ortto?;
5821
+ private _webhookSubscriptions?;
5822
+ private _users?;
5823
+ private _teams?;
4087
5824
  private _webhooks?;
4088
5825
  constructor(config: PlanesConfig);
4089
5826
  get opportunities(): OpportunityResource;
@@ -4103,6 +5840,8 @@ declare class PlanesClient {
4103
5840
  get gmail(): GmailResource;
4104
5841
  get documents(): DocumentsResource;
4105
5842
  get tags(): TagResource;
5843
+ get lists(): ListsResource;
5844
+ get leadSources(): LeadSourcesResource;
4106
5845
  get tasks(): TaskResource;
4107
5846
  /** Record views — the "recently viewed" beacon + read (E41-F7). */
4108
5847
  get recordViews(): RecordViewsResource;
@@ -4118,6 +5857,10 @@ declare class PlanesClient {
4118
5857
  get invoiceSettings(): InvoiceSettingsResource;
4119
5858
  /** Payment reminder settings, admin only — `invoiceReminders.list/update/preview` (E56-F8-S6). */
4120
5859
  get invoiceReminders(): InvoiceRemindersResource;
5860
+ /** Event automations, admin only — `eventAutomations.list/get/create/update/delete` (E60-S2). */
5861
+ get eventAutomations(): EventAutomationsResource;
5862
+ /** Web forms and their submissions, admin only — `webForms.list/get/create/update/archive/rotateKey`, `webForms.submissions.list/get/update/route` (E60-S6). */
5863
+ get webForms(): WebFormsResource;
4121
5864
  /** Published sequences a contact can be enrolled in (E51-F2-S6). */
4122
5865
  get contactSequences(): ContactSequencesResource;
4123
5866
  /** Enroll a contact in a sequence, list its enrollments, exit one (E51-F2-S8). */
@@ -4133,6 +5876,15 @@ declare class PlanesClient {
4133
5876
  get customFields(): CustomFieldsResource;
4134
5877
  /** Ortto connector — list mappings, audiences, manual sync, sync status (E53). Admin-only. */
4135
5878
  get ortto(): OrttoResource;
5879
+ /**
5880
+ * Webhook subscriptions — where entity events are delivered (E64-S10). Admin
5881
+ * grants and the `open_api` feature. Not `webhooks`: that is the event router.
5882
+ */
5883
+ get webhookSubscriptions(): WebhookSubscriptionsResource;
5884
+ /** The tenant's users, read-only: list and directory (E64-S10). */
5885
+ get users(): UsersResource;
5886
+ /** Teams, read-only (E64-S10). */
5887
+ get teams(): TeamsResource;
4136
5888
  /**
4137
5889
  * Ergonomic webhook event router — `client.webhooks.on(pattern, handler)`
4138
5890
  * plus `client.webhooks.process({ body, signature, secret })`. Auth-independent
@@ -4658,4 +6410,4 @@ interface CustomersGeneratedResource {
4658
6410
  createCustomer(data: CreateCustomerDto): Promise<CustomerDto>;
4659
6411
  }
4660
6412
 
4661
- export { AGENT_ROLES, AUTOPAY_UNAVAILABLE_REASONS, type ActionContext, type ActionHandler, type ActionRequest, type ActionResult, type ActivityDto, ActivityResource, AgentApp, type AgentHandler, type AgentRole, ApiResource, type AttachExternalDocumentDto, type AttachPdfSettingDto, AuthenticationError, AuthorizationError, type AuthorizeOptions, type AutopayUnavailableReason, BILLING_ADJUSTMENT_STATUSES, BILLING_ADJUSTMENT_TARGETS, BILLING_AUTOPAY_STATUSES, BILLING_BACKFILL_MODES, BILLING_CADENCES, BILLING_COLLECTION_MODES, BILLING_DELIVERY_MODES, BILLING_DELIVERY_STATUSES, BILLING_INTERVALS, BILLING_PERIOD_STATUSES, BILLING_PREVIEW_PERIOD_STATUSES, BILLING_SCHEDULE_STATUSES, BILLING_STATUSES, BILL_TIMINGS, BaseResource, type BillTiming, type BillingAdjustment, type BillingAdjustmentListParams, type BillingAdjustmentListResponse, type BillingAdjustmentStatus, type BillingAdjustmentTarget, type BillingAutopayStatus, type BillingAutopaySummary, type BillingAutopaySummaryResponse, type BillingBackfillMode, type BillingCadence, type BillingCollectionMode, type BillingDeliveryMode, type BillingDeliveryStatus, type BillingInterval, type BillingInvoiceStatus, type BillingInvoiceTerms, type BillingNeedsReviewItem, type BillingNeedsReviewParams, type BillingNeedsReviewResponse, type BillingPeriodStatus, type BillingPreviewAdjustment, type BillingPreviewPeriodStatus, type BillingSchedule, type BillingScheduleDetail, type BillingScheduleLine, type BillingScheduleLineInput, type BillingScheduleLineVersion, type BillingScheduleLineVersionListResponse, type BillingScheduleListItem, type BillingScheduleListParams, type BillingScheduleListResponse, type BillingSchedulePeriod, type BillingSchedulePeriodListParams, type BillingSchedulePeriodListResponse, type BillingSchedulePreview, type BillingSchedulePreviewParams, type BillingSchedulePreviewPeriod, BillingScheduleResource, type BillingScheduleStatus, type BillingStatus, type BillingUpcomingPeriod, CONTACT_LIST_INCLUDES, CONTACT_SORT_KEYS, CUSTOMER_SORT_KEYS, type CalendarEventLocationType, type CalendarEventParticipantDto, CalendarEventResource, type CalendarEventStatus, type CalendarEventType, type CallOutcome, type ClientCredentialsOptions, type CommunicationAttachmentDto, type CommunicationChannel, type CommunicationDto, type CommunicationEntityType, type CommunicationSummaryDto, type CommunicationTarget, type CommunicationsListResponse, CommunicationsResource, type CompleteCalendarEventDto, type CompleteCalendarEventResponse, type CompletedTaskDto, type CompletionTriggerReason, type CompletionTriggerStage, type CompletionTriggerStatus, type CompletionWorkflowTrigger, type ConflictPreviewParticipant, type ConflictPreviewRequest, type ConflictPreviewResponse, type ConflictPreviewSchedule, type ConflictPreviewWindow, type ConsentLastChangeDto, type ConsentStateDto, type ContactChannelDto, ContactChannelResource, type ContactDto, type ContactEnrollmentDto, type ContactEnrollmentListItemDto, type ContactLinkDto, type ContactLinkTargetType, type ContactListInclude, type ContactListItemDto, type ContactListParams, type ContactMergeResult, ContactResource, type ContactSequenceDto, type ContactSequenceListResponse, ContactSequencesResource, type ContactSortKey, ContractResource, type Conversation, type ConversationActionItemDto, type ConversationAttendeeDto, type ConversationKind, type ConversationLink, type ConversationLinkEntityType, type ConversationListItem, type ConversationListResponse, type ConversationMatchCandidate, type ConversationMatchStatus, type ConversationParticipant, type ConversationSyncErrorClass, type ConversationSyncRosterItem, type ConversationSyncStatus, type ConversationSyncStatusMine, type ConversationTranscript, ConversationsResource, type CreateActivityDto, type CreateBillingAdjustmentDto, type CreateBillingScheduleDto, type CreateContactChannelDto, type CreateContactDto, type CreateCustomerDto, type CreateEstimateDto, type CreateInventoryItemDto, type CreateJobDto, type CreateOpportunityDto, type CreateOrttoMappingDto, type CreateOrttoPullMappingDto, type CreateOrttoPushMappingDto, type CreatePropertyDto, type CreateTagDto, type CreateTaskDto, type CreateWorkflowEventRuleInput, type CreateWorkflowTransitionInput, type CrewOverlapConflictDto, type CustomFieldDefinitionDto, type CustomFieldEntityType, type CustomFieldType, type CustomFieldValidationRules, CustomFieldsResource, type CustomerAddressInput, type CustomerDto, type CustomerListParams, type CustomerMergeResult, type CustomerPaymentMethodInvalidatedEvent, type CustomerPaymentMethodInvalidatedSnapshot, CustomerResource, type CustomerSortKey, type CustomersGeneratedResource, DEFAULT_BASE_URL, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, DEFAULT_TOKEN_REFRESH_SKEW_MS, type DeleteWorkflowEventRuleResult, type DisconnectSourceConnectionDto, type DocumentDto, type DocumentEntityType, type DocumentKind, type DocumentsListResponse, DocumentsResource, ESTIMATE_STATUSES, type EnrollmentStatus, type EnrollmentTrigger, EnrollmentsResource, type EntityEvent, type EntityEventType, type EntityTagDto, type EntityType, type EstimateListParams, EstimateResource, type EstimateStatus, type EstimateSummaryDto, type ExchangeCodeOptions, FEATURE_KEYS, type FeatureKey, type FieldError, type GenerateNowResult, GmailResource, type GrantEffect, type GrantTier, type HandlerMap, type IntegrationConnectionDeactivatedEvent, type IntegrationConnectionDeactivatedSnapshot, type InternalDomainsDto, type InternalDomainsResult, type InventoryItemListParams, InventoryResource, type InventoryUnitOfMeasure, type InvoiceAutopayFailedEvent, type InvoiceAutopayFailedSnapshot, type InvoiceAutopaySucceededEvent, type InvoiceAutopaySucceededSnapshot, type InvoiceDetailDto, type InvoiceLineItemDto, type InvoiceListItemDto, type InvoiceListParams, type InvoiceOverdueEvent, type InvoiceOverdueSnapshot, type InvoiceOverdueSummaryDto, type InvoicePayLinkDto, type InvoicePayLinkStatusDto, type InvoicePaymentDto, type InvoiceReminderAppliesTo, type InvoiceReminderPreviewDto, type InvoiceReminderPreviewParams, type InvoiceReminderRuleDto, type InvoiceReminderRuleInputDto, type InvoiceReminderSettingsDto, InvoiceRemindersResource, InvoiceResource, InvoiceSettingsResource, type InvoiceSourceType, type InvoiceStatus, JOB_SORT_KEYS, type JobListParams, JobResource, type JobSortKey, type JobStatus, type JobTradeCoverageItemDto, type JobTradeCoverageResponse, type LinkCommunicationDto, type LinkConversationDto, type ListCalendarEventsParams, type ListCommunicationsParams, type ListConversationsParams, type ListCustomFieldDefinitionsParams, type ListEnrollmentsParams, type ListOrttoAudiencesParams, type ListParams, type ListTasksParams, type ListTransitionSummariesParams, type LogCallCommunicationDto, type LogCommunicationDto, type LogCommunicationResult, type LogConversationDto, type LogConversationResult, type LogEmailCommunicationDto, MODULE_KEYS, type MeAbilitiesResponse, MeResource, MemoryTokenStorage, type ModuleKey, ModulesResource, NotFoundError, OAuthError, OPPORTUNITY_SORT_KEYS, OPPORTUNITY_STATES, type OfflineInstructionsDto, type OpportunitiesGeneratedResource, type OpportunityDto, type OpportunityListParams, OpportunityResource, type OpportunitySortKey, type OpportunityState, type OrttoAudienceDto, type OrttoMappingDirection, type OrttoMappingDto, type OrttoMappingLastResult, OrttoResource, type OrttoSyncLastRun, type OrttoSyncRequestResult, type OrttoSyncStatusDto, type OrttoSyncTotals, type OverdueInvoiceDto, type OverdueInvoiceListParams, type OverdueOffsetsDto, PLAN_KEYS, PLAN_SOURCES, type PackedAbilityRule, type PaginatedCustomerResponse, type PaginatedOpportunityResponse, type PaginatedResponse, type PaginationMeta, type PatchConversationDto, type PaymentStatus, type PermissionLevel, type PlanKey, PlanResource, type PlanSource, Planes, PlanesClient, type PlanesConfig, PlanesError, type PropertyListParams, PropertyResource, type PullConversationsDto, type PullConversationsResult, type PullStatus, type PullStatusCounts, type PullStatusState, RECORD_VIEW_ENTITY_TYPES, RateLimitError, type RecentRecordView, type RecentRecordViewsParams, type RecordViewEntityType, type RecordViewInput, RecordViewsResource, type RecurrenceEditMode, type RefreshOptions, type RegeneratePeriodResult, type RegisterOptions, type RequestOrttoSyncDto, type ResolveConversationMatchDto, type RoleCellDto, type RoleDetailDto, type RoleGrantChange, type RoleHistoryEntryDto, type RoleHistoryPage, type RoleHistoryParams, type RoleKey, type RoleListResponse, type RoleRowDto, type RoleSummaryDto, RolesResource, type SavedPaymentMethodSummary, type SendGmailDto, type SendGmailResult, ServerError, ServiceSchedulesResource, type SetEntityTagsDto, type SkipBillingPeriodDto, type SourceConnectionResult, type SourceConnectionStatus, type StoredTokens, type SyncNowResult, type TagDto, type TagEntityDto, TagResource, type TaskAssigneeDto, type TaskAssigneeInput, type TaskAssigneeType, type TaskDto, type TaskEntityType, type TaskPriority, TaskResource, type TaskStatus, type TenantModuleStatusDto, type TenantPlanDto, type TokenResponse, type TokenStorage, type TranscriptAccess, type TranscriptAccessMode, type TranscriptSegment, type TransitionSummariesResponse, type TransitionSummaryDto, type TriggerType, type TunableRole, type UpdateBillingScheduleDto, type UpdateCalendarEventDto, type UpdateCalendarEventOptions, type UpdateContactChannelDto, type UpdateContactDto, type UpdateCustomerDto, type UpdateEstimateDto, type UpdateInventoryItemDto, type UpdateJobDto, type UpdateOpportunityDto$1 as UpdateOpportunityDto, type UpdateOrttoMappingDto, type UpdatePropertyDto, type UpdateRoleGrantsBody, type UpdateTagDto, type UpdateTaskDto, type UpdateWorkflowEventRuleInput, type UpdateWorkflowTransitionInput, ValidationError, WEBHOOK_EVENT_TYPES, WORKFLOW_EVENT_RULE_EVENT_TYPES, WORKFLOW_EVENT_RULE_MATCH_ALL_EVENT_TYPES, type WebhookDelivery, type WebhookHandler, type WebhookProcessInput, WebhookRouter, WebhookVerificationError, type WorkflowEndOutcome, type WorkflowEntityType, type WorkflowEventRuleDto, type WorkflowEventRuleEventType, type WorkflowEventRuleWhen, WorkflowEventRulesResource, type WorkflowTransitionDto, type WorkflowTransitionRef, type WorkflowVersionStageDto, type WorkflowVersionStagesResponse, WorkflowsResource, type WorkingHoursConflictDto, buildAuthorizeUrl, clientCredentialsGrant, createAgentApp, exchangeCode, parseWebhookEvent, refreshAccessToken, verifyWebhookSignature };
6413
+ export { AGENT_ROLES, AUTOPAY_UNAVAILABLE_REASONS, type ActionContext, type ActionHandler, type ActionRequest, type ActionResult, type ActivityDto, ActivityResource, type AddCalendarParticipantDto, type AddEntityTagDto, type AddEntityTagRef, AgentApp, type AgentHandler, type AgentRole, ApiResource, type AttachExternalDocumentDto, type AttachPdfSettingDto, AuthenticationError, AuthorizationError, type AuthorizeOptions, type AutopayUnavailableReason, BILLING_ADJUSTMENT_STATUSES, BILLING_ADJUSTMENT_TARGETS, BILLING_AUTOPAY_STATUSES, BILLING_BACKFILL_MODES, BILLING_CADENCES, BILLING_COLLECTION_MODES, BILLING_DELIVERY_MODES, BILLING_DELIVERY_STATUSES, BILLING_INTERVALS, BILLING_PERIOD_STATUSES, BILLING_PREVIEW_PERIOD_STATUSES, BILLING_SCHEDULE_STATUSES, BILLING_STATUSES, BILL_TIMINGS, BaseResource, type BillTiming, type BillingAdjustment, type BillingAdjustmentListParams, type BillingAdjustmentListResponse, type BillingAdjustmentStatus, type BillingAdjustmentTarget, type BillingAutopayStatus, type BillingAutopaySummary, type BillingAutopaySummaryResponse, type BillingBackfillMode, type BillingCadence, type BillingCollectionMode, type BillingDeliveryMode, type BillingDeliveryStatus, type BillingInterval, type BillingInvoiceStatus, type BillingInvoiceTerms, type BillingNeedsReviewItem, type BillingNeedsReviewParams, type BillingNeedsReviewResponse, type BillingPeriodStatus, type BillingPreviewAdjustment, type BillingPreviewPeriodStatus, type BillingSchedule, type BillingScheduleDetail, type BillingScheduleLine, type BillingScheduleLineInput, type BillingScheduleLineVersion, type BillingScheduleLineVersionListResponse, type BillingScheduleListItem, type BillingScheduleListParams, type BillingScheduleListResponse, type BillingSchedulePeriod, type BillingSchedulePeriodListParams, type BillingSchedulePeriodListResponse, type BillingSchedulePreview, type BillingSchedulePreviewParams, type BillingSchedulePreviewPeriod, BillingScheduleResource, type BillingScheduleStatus, type BillingStatus, type BillingUpcomingPeriod, CONTACT_LIST_INCLUDES, CONTACT_SORT_KEYS, CUSTOMER_SORT_KEYS, type CalendarEventLocationType, type CalendarEventParticipantDto, CalendarEventResource, type CalendarEventStatus, type CalendarEventType, type CalendarParticipantStatus, type CallOutcome, type ClientCredentialsOptions, type CommunicationAttachmentDto, type CommunicationChannel, type CommunicationDto, type CommunicationEntityType, type CommunicationSummaryDto, type CommunicationTarget, type CommunicationsListResponse, CommunicationsResource, type CompleteCalendarEventDto, type CompleteCalendarEventResponse, type CompletedTaskDto, type CompletionTriggerReason, type CompletionTriggerStage, type CompletionTriggerStatus, type CompletionWorkflowTrigger, type ConflictPreviewParticipant, type ConflictPreviewRequest, type ConflictPreviewResponse, type ConflictPreviewSchedule, type ConflictPreviewWindow, type ConsentLastChangeDto, type ConsentStateDto, type ContactChannelDto, ContactChannelResource, type ContactDto, type ContactEnrollmentDto, type ContactEnrollmentListItemDto, type ContactLinkDto, type ContactLinkTargetType, type ContactListInclude, type ContactListItemDto, type ContactListParams, type ContactMergeResult, ContactResource, type ContactSequenceDto, type ContactSequenceListResponse, ContactSequencesResource, type ContactSortKey, type ContactWorkflowDto, type ContactWorkflowHistoryDto, ContractResource, type Conversation, type ConversationActionItemDto, type ConversationAttendeeDto, type ConversationKind, type ConversationLink, type ConversationLinkEntityType, type ConversationListItem, type ConversationListResponse, type ConversationMatchCandidate, type ConversationMatchStatus, type ConversationParticipant, type ConversationSyncErrorClass, type ConversationSyncRosterItem, type ConversationSyncStatus, type ConversationSyncStatusMine, type ConversationTranscript, ConversationsResource, type ConvertCustomerToCompanyDto, type CreateActivityDto, type CreateBillingAdjustmentDto, type CreateBillingScheduleDto, type CreateChangeOrderDto, type CreateContactChannelDto, type CreateContactDto, type CreateContactLinkDto, type CreateContractForSubjectDto, type CreateCustomFieldDefinitionDto, type CreateCustomerDto, type CreateEstimateDto, type CreateEstimateLineItemDto, type CreateEventAutomationInput, type CreateFlatContractDto, type CreateInventoryItemDto, type CreateJobDto, type CreateLeadSourceDto, type CreateListDto, type CreateOpportunityDto, type CreateOrttoMappingDto, type CreateOrttoPullMappingDto, type CreateOrttoPushMappingDto, type CreatePropertyDto, type CreateServiceScheduleInput, type CreateTagDto, type CreateTaskDto, type CreateWebFormInput, type CreateWebhookSubscriptionDto, type CreateWorkflowEventRuleInput, type CreateWorkflowTransitionInput, type CreatedWebhookSubscription, type CrewHomeAddressResult, type CrewOverlapConflictDto, type CrewRolesDto, type CustomFieldDefinitionDto, type CustomFieldEntityType, type CustomFieldType, type CustomFieldValidationRules, type CustomFieldValidationRulesInput, CustomFieldsResource, type CustomerAddressInput, type CustomerDto, type CustomerListParams, type CustomerMergeResult, type CustomerPaymentMethodInvalidatedEvent, type CustomerPaymentMethodInvalidatedSnapshot, CustomerResource, type CustomerSortKey, type CustomersGeneratedResource, DEFAULT_BASE_URL, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, DEFAULT_TOKEN_REFRESH_SKEW_MS, type DeleteEventAutomationResult, type DeleteWorkflowEventRuleResult, type DisconnectSourceConnectionDto, type DispatchCrewDto, type DocumentDto, type DocumentEntityType, type DocumentKind, type DocumentsListResponse, DocumentsResource, ESTIMATE_STATUSES, type EnrollmentStatus, type EnrollmentTrigger, EnrollmentsResource, type EntityEvent, type EntityEventType, type EntityTagDto, type EntityType, type EstimateLineItemType, type EstimateListParams, EstimateResource, type EstimateStatus, type EstimateSummaryDto, type EventAutomationActionInput, type EventAutomationDto, type EventAutomationWhen, EventAutomationsResource, type ExchangeCodeOptions, FEATURE_KEYS, type FeatureKey, type FieldError, type GenerateNowResult, GmailResource, type GrantEffect, type GrantTier, type HandlerMap, type IntegrationConnectionDeactivatedEvent, type IntegrationConnectionDeactivatedSnapshot, type InternalDomainsDto, type InternalDomainsResult, type InventoryItemListParams, InventoryResource, type InventoryUnitOfMeasure, type InvoiceAutopayFailedEvent, type InvoiceAutopayFailedSnapshot, type InvoiceAutopaySucceededEvent, type InvoiceAutopaySucceededSnapshot, type InvoiceDetailDto, type InvoiceLineItemDto, type InvoiceListItemDto, type InvoiceListParams, type InvoiceOverdueEvent, type InvoiceOverdueSnapshot, type InvoiceOverdueSummaryDto, type InvoicePayLinkDto, type InvoicePayLinkStatusDto, type InvoicePaymentDto, type InvoiceReminderAppliesTo, type InvoiceReminderPreviewDto, type InvoiceReminderPreviewParams, type InvoiceReminderRuleDto, type InvoiceReminderRuleInputDto, type InvoiceReminderSettingsDto, InvoiceRemindersResource, InvoiceResource, InvoiceSettingsResource, type InvoiceSourceType, type InvoiceStatus, JOB_SORT_KEYS, type JobConsumptionHistoryDto, type JobConsumptionItemDto, type JobConsumptionListParams, type JobConsumptionMovementDto, type JobListParams, JobResource, type JobSortKey, type JobStatus, type JobTradeCoverageItemDto, type JobTradeCoverageResponse, type LeadSourceDto, LeadSourcesResource, type LinkCommunicationDto, type LinkConversationDto, type ListCalendarEventsParams, type ListCommunicationsParams, type ListConversationsParams, type ListCustomFieldDefinitionsParams, type ListDefinitionError, type ListDto, type ListEnrollmentsParams, type ListEntityType, type ListEventAutomationsParams, type ListExportHandle, type ListFilterField, type ListFilterFieldsDto, type ListKind, type ListMemberEntityType, type ListMemberRef, type ListOrttoAudiencesParams, type ListParams, type ListRecipientDto, type ListRecipientsPage, type ListRecipientsParams, type ListTasksParams, type ListTransitionSummariesParams, type ListUsersParams, type ListWebFormSubmissionsParams, type ListWebhookDeliveriesParams, type ListWebhookSubscriptionsParams, ListsResource, type LogCallCommunicationDto, type LogCommunicationDto, type LogCommunicationResult, type LogConversationDto, type LogConversationResult, type LogEmailCommunicationDto, MODULE_KEYS, type MeAbilitiesResponse, MeResource, MemoryTokenStorage, type ModuleKey, ModulesResource, NotFoundError, OAuthError, OPPORTUNITY_SORT_KEYS, OPPORTUNITY_STATES, type OfflineInstructionsDto, type OpportunitiesGeneratedResource, type OpportunityDto, type OpportunityListParams, OpportunityResource, type OpportunitySortKey, type OpportunityState, type OpportunityTrade, type OrttoAudienceDto, type OrttoMappingDirection, type OrttoMappingDto, type OrttoMappingLastResult, OrttoResource, type OrttoSyncLastRun, type OrttoSyncRequestResult, type OrttoSyncStatusDto, type OrttoSyncTotals, type OverdueInvoiceDto, type OverdueInvoiceListParams, type OverdueOffsetsDto, PLAN_KEYS, PLAN_SOURCES, type PackedAbilityRule, type PaginatedCustomerResponse, type PaginatedOpportunityResponse, type PaginatedResponse, type PaginationMeta, type PatchConversationDto, type PaymentStatus, type PermissionLevel, type PlanKey, PlanResource, type PlanSource, Planes, PlanesClient, type PlanesConfig, PlanesError, type PropertyListParams, PropertyResource, type ProtectedReason, type PullConversationsDto, type PullConversationsResult, type PullStatus, type PullStatusCounts, type PullStatusState, RECORD_VIEW_ENTITY_TYPES, RateLimitError, type RecentRecordView, type RecentRecordViewsParams, type RecordJobConsumptionDto, type RecordViewEntityType, type RecordViewInput, RecordViewsResource, type RecurrenceEditMode, type RefreshOptions, type RegeneratePeriodResult, type RegisterOptions, type ReorderEstimateLineItemsDto, type RequestOrttoSyncDto, type ResolveConversationMatchDto, type ReturnFromJobDto, type RoleCellDto, type RoleDetailDto, type RoleGrantChange, type RoleHistoryEntryDto, type RoleHistoryPage, type RoleHistoryParams, type RoleKey, type RoleListResponse, type RoleRowDto, type RoleSummaryDto, RolesResource, type RouteSubmissionResult, type SavedPaymentMethodSummary, type ScheduleUpdateResult, type SendContractDto, type SendGmailDto, type SendGmailResult, ServerError, type ServiceScheduleDto, type ServiceScheduleParticipant, type ServiceScheduleStatus, type ServiceScheduleSubjectType, type ServiceScheduleUpdateResult, ServiceSchedulesResource, type SetEntityTagsDto, type SkipBillingPeriodDto, type SmartFilter, type SmartFilterOp, type SmartListDefinition, type SourceConnectionResult, type SourceConnectionStatus, type StoredTokens, type SyncNowResult, TASK_SORT_KEYS, type TagDto, type TagEntityDto, type TagMergeResult, TagResource, type TaskAssigneeDto, type TaskAssigneeInput, type TaskAssigneeType, type TaskDto, type TaskEntityType, type TaskPriority, TaskResource, type TaskSortKey, type TaskStatus, type TeamDto, type TeamMemberDto, type TeamMemberRole, TeamsResource, type TenantModuleStatusDto, type TenantPlanDto, type TokenResponse, type TokenStorage, type TranscriptAccess, type TranscriptAccessMode, type TranscriptSegment, type TransitionSummariesResponse, type TransitionSummaryDto, type TriggerType, type TunableRole, type UpdateBillingScheduleDto, type UpdateCalendarEventDto, type UpdateCalendarEventOptions, type UpdateContactChannelDto, type UpdateContactDto, type UpdateContactLinkDto, type UpdateCustomFieldDefinitionDto, type UpdateCustomerDto, type UpdateEstimateDto, type UpdateEstimateLineItemDto, type UpdateEstimateStatusDto, type UpdateEventAutomationInput, type UpdateInventoryItemDto, type UpdateJobDto, type UpdateLeadSourceDto, type UpdateListDto, type UpdateOpportunityDto$1 as UpdateOpportunityDto, type UpdateOrttoMappingDto, type UpdatePropertyDto, type UpdateRoleGrantsBody, type UpdateServiceScheduleInput, type UpdateTagDto, type UpdateTaskDto, type UpdateWebFormInput, type UpdateWebhookSubscriptionDto, type UpdateWorkflowEventRuleInput, type UpdateWorkflowTransitionInput, type UserDirectoryEntry, type UserDirectoryParams, type UserDto, type UserPage, type UserRole, type UserStatus, type UserWorkingHours, UsersResource, ValidationError, WEBHOOK_EVENT_TYPES, WORKFLOW_EVENT_RULE_CATCH_UP_EVENT_TYPES, WORKFLOW_EVENT_RULE_EVENT_TYPES, WORKFLOW_EVENT_RULE_MATCH_ALL_EVENT_TYPES, type WebFormAnswer, type WebFormConfirmation, type WebFormCoreKey, type WebFormDefinition, type WebFormDto, type WebFormHoldReason, type WebFormQuestion, type WebFormQuestionType, type WebFormRecordLink, type WebFormRoutingState, type WebFormRoutingStepDto, type WebFormSubmissionDetailDto, type WebFormSubmissionDto, type WebFormSubmissionsCursor, type WebFormSubmissionsPage, WebFormSubmissionsResource, type WebFormTradeOption, type WebFormTriageStatus, WebFormsResource, type WebhookDelivery, type WebhookDeliveryLogDto, type WebhookDeliveryLogPage, type WebhookDeliveryStatus, type WebhookHandler, type WebhookProcessInput, type WebhookRetryResult, WebhookRouter, type WebhookSubscriptionDto, type WebhookSubscriptionEntityType, type WebhookSubscriptionList, type WebhookSubscriptionStatus, WebhookSubscriptionsResource, type WebhookTestResult, WebhookVerificationError, type WorkflowEndOutcome, type WorkflowEntityType, type WorkflowEventRuleDto, type WorkflowEventRuleEventType, type WorkflowEventRuleWhen, WorkflowEventRulesResource, type WorkflowTransitionDto, type WorkflowTransitionRef, type WorkflowVersionStageDto, type WorkflowVersionStagesResponse, WorkflowsResource, type WorkingHoursConflictDto, type WorkingHoursEntry, buildAuthorizeUrl, clientCredentialsGrant, createAgentApp, exchangeCode, parseWebhookEvent, refreshAccessToken, verifyWebhookSignature };