@planescrm/sdk 0.4.0 → 0.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +423 -12
- package/dist/index.d.mts +3669 -183
- package/dist/index.d.ts +3669 -183
- package/dist/index.js +1737 -44
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1685 -44
- package/dist/index.mjs.map +1 -1
- package/package.json +17 -13
package/dist/index.d.mts
CHANGED
|
@@ -89,6 +89,8 @@ interface HttpRequestOptions {
|
|
|
89
89
|
body?: unknown;
|
|
90
90
|
params?: Record<string, unknown>;
|
|
91
91
|
headers?: Record<string, string>;
|
|
92
|
+
/** 'arrayBuffer' returns the raw response body (binary downloads); default 'json'. */
|
|
93
|
+
responseType?: 'json' | 'arrayBuffer';
|
|
92
94
|
}
|
|
93
95
|
/**
|
|
94
96
|
* Internal HTTP client wrapper using native fetch.
|
|
@@ -151,20 +153,31 @@ interface ListParams {
|
|
|
151
153
|
}
|
|
152
154
|
|
|
153
155
|
/**
|
|
154
|
-
*
|
|
156
|
+
* Minimal base: the http client and the resource's base path, no methods.
|
|
157
|
+
* Resources whose API routes aren't flat CRUD on `basePath` (nested under a
|
|
158
|
+
* parent like `customers/:customerId/properties`, or missing an operation like
|
|
159
|
+
* tasks without delete) extend this and declare only the methods the API
|
|
160
|
+
* serves, so a method the API doesn't have is a compile error, not a 404.
|
|
161
|
+
*/
|
|
162
|
+
declare abstract class ApiResource {
|
|
163
|
+
protected readonly http: HttpClient;
|
|
164
|
+
protected readonly basePath: string;
|
|
165
|
+
constructor(http: HttpClient, basePath: string);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Flat CRUD on `basePath`: `GET /`, `POST /`, `GET /:id`, `PATCH /:id`,
|
|
169
|
+
* `DELETE /:id`. Extend it only when the API serves all five (override a verb
|
|
170
|
+
* where it differs); otherwise extend `ApiResource`.
|
|
155
171
|
* Generic parameters:
|
|
156
172
|
* - TEntity: the entity response type
|
|
157
173
|
* - TCreate: the create request body type
|
|
158
174
|
* - TUpdate: the update request body type
|
|
159
175
|
*/
|
|
160
|
-
declare abstract class BaseResource<TEntity = Record<string, unknown>, TCreate = Record<string, unknown>, TUpdate = Record<string, unknown>> {
|
|
161
|
-
protected readonly http: HttpClient;
|
|
162
|
-
protected readonly basePath: string;
|
|
163
|
-
constructor(http: HttpClient, basePath: string);
|
|
176
|
+
declare abstract class BaseResource<TEntity = Record<string, unknown>, TCreate = Record<string, unknown>, TUpdate = Record<string, unknown>, TList = PaginatedResponse<TEntity>> extends ApiResource {
|
|
164
177
|
/**
|
|
165
178
|
* List entities with optional filters and pagination.
|
|
166
179
|
*/
|
|
167
|
-
list(params?: ListParams): Promise<
|
|
180
|
+
list(params?: ListParams): Promise<TList>;
|
|
168
181
|
/**
|
|
169
182
|
* Get a single entity by ID.
|
|
170
183
|
*/
|
|
@@ -183,24 +196,413 @@ declare abstract class BaseResource<TEntity = Record<string, unknown>, TCreate =
|
|
|
183
196
|
delete(id: string): Promise<void>;
|
|
184
197
|
}
|
|
185
198
|
|
|
186
|
-
/**
|
|
199
|
+
/**
|
|
200
|
+
* Query params for `GET /opportunities` — mirrors `opportunityFilterSchema` in
|
|
201
|
+
* `@blueprint/shared`. `tag_ids` is ANY-of: an opportunity tagged with at least
|
|
202
|
+
* one of the given tags matches (max 20). It is sent as one comma-separated value.
|
|
203
|
+
* Extends the generic `ListParams` so it stays assignable to `BaseResource.list`.
|
|
204
|
+
*/
|
|
205
|
+
/** 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"];
|
|
207
|
+
type OpportunitySortKey = (typeof OPPORTUNITY_SORT_KEYS)[number];
|
|
208
|
+
/**
|
|
209
|
+
* Lifecycle states on `GET /opportunities` (kept in lockstep with the server's
|
|
210
|
+
* `OPPORTUNITY_STATES` by the SDK's wire-contract spec).
|
|
211
|
+
*/
|
|
212
|
+
declare const OPPORTUNITY_STATES: readonly ["open", "closed", "won", "lost"];
|
|
213
|
+
type OpportunityState = (typeof OPPORTUNITY_STATES)[number];
|
|
214
|
+
interface OpportunityListParams extends ListParams {
|
|
215
|
+
search?: string;
|
|
216
|
+
/** Stage name (matched case-insensitively against the published pipeline). */
|
|
217
|
+
stage?: string;
|
|
218
|
+
/**
|
|
219
|
+
* Open / closed / won / lost, read from the record's current stage — works
|
|
220
|
+
* across pipeline versions (stage names can differ between versions).
|
|
221
|
+
* Records with no pipeline match no state. ANDs with `stage`.
|
|
222
|
+
*/
|
|
223
|
+
state?: OpportunityState;
|
|
224
|
+
agent_id?: string;
|
|
225
|
+
customer_id?: string;
|
|
226
|
+
priority?: 'low' | 'normal' | 'high' | 'urgent';
|
|
227
|
+
source?: string;
|
|
228
|
+
tag_ids?: string[];
|
|
229
|
+
/**
|
|
230
|
+
* Mirrors `OPPORTUNITY_SORT_KEYS`. `customer_name` orders by the customer's
|
|
231
|
+
* display name, `stage` by pipeline position (stage-less rows last),
|
|
232
|
+
* `priority` low → normal → high → urgent. `recent` orders by the calling
|
|
233
|
+
* user's last view (newest first, never-viewed last) and ignores `sort_order`.
|
|
234
|
+
*/
|
|
235
|
+
sort_by?: OpportunitySortKey;
|
|
236
|
+
sort_order?: 'asc' | 'desc';
|
|
237
|
+
page?: number;
|
|
238
|
+
limit?: number;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* `PUT /opportunities/{id}` body — mirrors `updateOpportunitySchema` in
|
|
242
|
+
* `@blueprint/shared` (every field optional; `null` clears a nullable one).
|
|
243
|
+
* `source` is validated against the tenant's lead sources; `customFields`
|
|
244
|
+
* against the tenant's opportunity field definitions. Stage moves go through
|
|
245
|
+
* the workflow transition routes, not this body.
|
|
246
|
+
*/
|
|
247
|
+
interface UpdateOpportunityDto$1 {
|
|
248
|
+
title?: string | undefined;
|
|
249
|
+
customerId?: string | undefined;
|
|
250
|
+
agentId?: string | null | undefined;
|
|
251
|
+
source?: string | null | undefined;
|
|
252
|
+
priority?: 'low' | 'normal' | 'high' | 'urgent' | undefined;
|
|
253
|
+
total?: number | undefined;
|
|
254
|
+
notes?: string | null | undefined;
|
|
255
|
+
/** ISO 8601 datetime. */
|
|
256
|
+
closedAt?: string | null | undefined;
|
|
257
|
+
closedReason?: string | null | undefined;
|
|
258
|
+
primaryContactId?: string | null | undefined;
|
|
259
|
+
customFields?: Record<string, unknown> | null | undefined;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** Opportunity resource — CRUD operations on /opportunities (updates are PUT). */
|
|
187
263
|
declare class OpportunityResource extends BaseResource {
|
|
188
264
|
constructor(http: ConstructorParameters<typeof BaseResource>[0]);
|
|
265
|
+
/**
|
|
266
|
+
* List opportunities. `tag_ids` is ANY-of and travels as one comma-separated
|
|
267
|
+
* query value (`?tag_ids=a,b`), which is what the API's filter schema parses.
|
|
268
|
+
*/
|
|
269
|
+
list(params?: OpportunityListParams): Promise<PaginatedResponse<Record<string, unknown>>>;
|
|
270
|
+
/** PUT /opportunities/{id} — partial update; stage moves go through workflow transitions. */
|
|
271
|
+
update(id: string, data: UpdateOpportunityDto$1): Promise<Record<string, unknown>>;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Company merge result (E38-F10-S1) — the body of
|
|
276
|
+
* `POST /customers/{winnerId}/merge/{loserId}`.
|
|
277
|
+
*
|
|
278
|
+
* Derived from `CustomerMergeResult` on the API service rather than hand-written
|
|
279
|
+
* from the docs: `counts` is keyed by table / repoint-handler name and grows as
|
|
280
|
+
* features register handlers, so it is deliberately an open record rather than a
|
|
281
|
+
* closed shape that would go stale the first time a module is added.
|
|
282
|
+
*/
|
|
283
|
+
interface CustomerMergeResult {
|
|
284
|
+
/** The survivor. */
|
|
285
|
+
winnerId: string;
|
|
286
|
+
/** The duplicate, now soft-deleted; its id still resolves to the winner. */
|
|
287
|
+
loserId: string;
|
|
288
|
+
/** Rows moved per table / handler, e.g. `{ opportunity: 2, invoice: 1 }`. */
|
|
289
|
+
counts: Record<string, number>;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Optional service address embeddable on customer create/update. Mirrors
|
|
293
|
+
* `createAddressInputSchema` in `packages/shared/src/validation/property.ts`:
|
|
294
|
+
* all-or-nothing — once present, line1/city/state/zip are required.
|
|
295
|
+
*/
|
|
296
|
+
interface CustomerAddressInput {
|
|
297
|
+
addressLine1: string;
|
|
298
|
+
addressLine2?: string;
|
|
299
|
+
city: string;
|
|
300
|
+
/** Two-letter state code. */
|
|
301
|
+
state: string;
|
|
302
|
+
/** 5-digit or ZIP+4. */
|
|
303
|
+
zip: string;
|
|
304
|
+
/** Two-letter country code; defaults to `US`. */
|
|
305
|
+
country?: string;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* `PUT /customers/{id}` body. Mirrors `updateCustomerSchema` in
|
|
309
|
+
* `packages/shared/src/validation/customer.ts`. Every field is optional; the
|
|
310
|
+
* kind ↔ name rules only apply when `kind` is sent.
|
|
311
|
+
*
|
|
312
|
+
* `address` is an upsert, never a delete: a match on an existing property is a
|
|
313
|
+
* no-op, the customer's only property is updated in place, otherwise a new
|
|
314
|
+
* property is added. Omit it to leave properties untouched.
|
|
315
|
+
*/
|
|
316
|
+
interface UpdateCustomerDto {
|
|
317
|
+
kind?: 'person' | 'company';
|
|
318
|
+
firstName?: string;
|
|
319
|
+
lastName?: string;
|
|
320
|
+
companyName?: string | null;
|
|
321
|
+
email?: string | null;
|
|
322
|
+
phone?: string | null;
|
|
323
|
+
phoneDnc?: boolean | null;
|
|
324
|
+
marketingOptOut?: boolean | null;
|
|
325
|
+
notes?: string | null;
|
|
326
|
+
source?: string | null;
|
|
327
|
+
address?: CustomerAddressInput;
|
|
328
|
+
customFields?: Record<string, unknown> | null;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Query params for `GET /customers` — mirrors `customerFilterSchema` in
|
|
332
|
+
* `@blueprint/shared`. `tag_ids` is ANY-of: a customer tagged with at least one
|
|
333
|
+
* of the given tags matches (max 20). It is sent as one comma-separated value.
|
|
334
|
+
* Extends the generic `ListParams` so it stays assignable to `BaseResource.list`.
|
|
335
|
+
*/
|
|
336
|
+
/** 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"];
|
|
338
|
+
type CustomerSortKey = (typeof CUSTOMER_SORT_KEYS)[number];
|
|
339
|
+
interface CustomerListParams extends ListParams {
|
|
340
|
+
/** Person or company name; every word must match, so a full name works in either order. */
|
|
341
|
+
search?: string;
|
|
342
|
+
notes_contains?: string;
|
|
343
|
+
source?: string;
|
|
344
|
+
kind?: 'person' | 'company';
|
|
345
|
+
tag_ids?: string[];
|
|
346
|
+
/**
|
|
347
|
+
* Mirrors `CUSTOMER_SORT_KEYS`. `last_name` sorts companies by company name.
|
|
348
|
+
* email / phone / source are nullable and sort NULLs last in both directions.
|
|
349
|
+
* `recent` orders by the calling user's last view (newest first, never-viewed
|
|
350
|
+
* last) and ignores `sort_order`.
|
|
351
|
+
*/
|
|
352
|
+
sort_by?: CustomerSortKey;
|
|
353
|
+
sort_order?: 'asc' | 'desc';
|
|
354
|
+
page?: number;
|
|
355
|
+
limit?: number;
|
|
189
356
|
}
|
|
190
357
|
|
|
191
358
|
/** Customer resource — CRUD operations on /customers. */
|
|
192
359
|
declare class CustomerResource extends BaseResource {
|
|
193
360
|
constructor(http: ConstructorParameters<typeof BaseResource>[0]);
|
|
361
|
+
/**
|
|
362
|
+
* Update a customer. The API route is `PUT /customers/{id}` (not PATCH like
|
|
363
|
+
* the other resources), so this overrides the base verb; the body is still a
|
|
364
|
+
* partial — send only the fields to change. See `UpdateCustomerDto.address`
|
|
365
|
+
* for how a service address resolves to a property.
|
|
366
|
+
*/
|
|
367
|
+
update(id: string, data: UpdateCustomerDto): Promise<Record<string, unknown>>;
|
|
368
|
+
/**
|
|
369
|
+
* List customers. `tag_ids` is ANY-of and travels as one comma-separated
|
|
370
|
+
* query value (`?tag_ids=a,b`), which is what the API's filter schema parses.
|
|
371
|
+
*/
|
|
372
|
+
list(params?: CustomerListParams): Promise<PaginatedResponse<Record<string, unknown>>>;
|
|
373
|
+
/**
|
|
374
|
+
* Fold a duplicate company (`loserId`) into a survivor (`winnerId`).
|
|
375
|
+
*
|
|
376
|
+
* Everything hanging off the loser moves to the winner, the winner's empty
|
|
377
|
+
* fields are filled from the loser, and the loser is soft-deleted with a
|
|
378
|
+
* resolvable pointer — `GET /customers/{loserId}` afterwards returns the
|
|
379
|
+
* winner's detail with a `mergedFrom` pointer, so a stored loser id keeps
|
|
380
|
+
* working. Irreversible; requires admin scope.
|
|
381
|
+
*/
|
|
382
|
+
merge(winnerId: string, loserId: string): Promise<CustomerMergeResult>;
|
|
194
383
|
}
|
|
195
384
|
|
|
196
|
-
/**
|
|
197
|
-
|
|
198
|
-
|
|
385
|
+
/**
|
|
386
|
+
* Wire shapes for properties (`/customers/{customerId}/properties`, plus the
|
|
387
|
+
* direct `GET /properties/{id}`). Mirror `createPropertySchema` /
|
|
388
|
+
* `updatePropertySchema` / `propertyFilterSchema` in
|
|
389
|
+
* `packages/shared/src/validation/property.ts`, redefined here so the
|
|
390
|
+
* published package carries no dependency on `@blueprint/shared`;
|
|
391
|
+
* `crud-route-types.parity.ts` fails the build when the two drift.
|
|
392
|
+
*/
|
|
393
|
+
/** `POST /customers/{customerId}/properties` body — the customer comes from the path. */
|
|
394
|
+
interface CreatePropertyDto {
|
|
395
|
+
addressLine1: string;
|
|
396
|
+
addressLine2?: string | null | undefined;
|
|
397
|
+
city: string;
|
|
398
|
+
/** Two-letter state code. */
|
|
399
|
+
state: string;
|
|
400
|
+
zip: string;
|
|
401
|
+
/** Defaults to `US`. */
|
|
402
|
+
country?: string | undefined;
|
|
403
|
+
metadata?: Record<string, unknown> | undefined;
|
|
404
|
+
}
|
|
405
|
+
/** `PUT /customers/{customerId}/properties/{id}` body — every field optional. */
|
|
406
|
+
interface UpdatePropertyDto {
|
|
407
|
+
addressLine1?: string | undefined;
|
|
408
|
+
addressLine2?: string | null | undefined;
|
|
409
|
+
city?: string | undefined;
|
|
410
|
+
state?: string | undefined;
|
|
411
|
+
zip?: string | undefined;
|
|
412
|
+
country?: string | undefined;
|
|
413
|
+
metadata?: Record<string, unknown> | null | undefined;
|
|
414
|
+
}
|
|
415
|
+
/** Query for `GET /customers/{customerId}/properties` (`page` ≥ 1, `limit` 1–100, default 25). */
|
|
416
|
+
type PropertyListParams = {
|
|
417
|
+
search?: string | undefined;
|
|
418
|
+
page?: number | undefined;
|
|
419
|
+
limit?: number | undefined;
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Properties. Every write and the list are nested under the owning customer
|
|
424
|
+
* (`/customers/{customerId}/properties`); only the single-property read has a
|
|
425
|
+
* direct route (`GET /properties/{id}`).
|
|
426
|
+
*/
|
|
427
|
+
declare class PropertyResource extends ApiResource {
|
|
428
|
+
constructor(http: ConstructorParameters<typeof ApiResource>[0]);
|
|
429
|
+
/** GET /customers/{customerId}/properties — paginated (`page`, `limit` ≤ 100). */
|
|
430
|
+
list(customerId: string, params?: PropertyListParams): Promise<PaginatedResponse<Record<string, unknown>>>;
|
|
431
|
+
/** GET /properties/{id} — one property, without naming its customer. */
|
|
432
|
+
get(id: string): Promise<Record<string, unknown>>;
|
|
433
|
+
/** POST /customers/{customerId}/properties — the property inherits the customer's org path. */
|
|
434
|
+
create(customerId: string, data: CreatePropertyDto): Promise<Record<string, unknown>>;
|
|
435
|
+
/** PUT /customers/{customerId}/properties/{id} — partial update. */
|
|
436
|
+
update(customerId: string, id: string, data: UpdatePropertyDto): Promise<Record<string, unknown>>;
|
|
437
|
+
/** DELETE /customers/{customerId}/properties/{id} — soft delete (204). */
|
|
438
|
+
delete(customerId: string, id: string): Promise<void>;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Wire shapes for `POST /events/:id/complete` (E46-F6-S2) and
|
|
443
|
+
* `PATCH /events/:id` (body E46-F6-S6, edit mode E46-F6-S11).
|
|
444
|
+
*
|
|
445
|
+
* Mirrors `completionWorkflowTriggerSchema` / `COMPLETION_TRIGGER_REASONS` in
|
|
446
|
+
* `packages/shared/src/validation/calendar-event.ts` and the shape
|
|
447
|
+
* `CalendarService.completeEvent` returns. Types are redefined here (not
|
|
448
|
+
* imported) so the published package carries no dependency on
|
|
449
|
+
* `@blueprint/shared`; `calendar-events.spec.ts` parses the response with the
|
|
450
|
+
* REAL shared schema.
|
|
451
|
+
*/
|
|
452
|
+
/** Whether the event's "on complete" transition ran. */
|
|
453
|
+
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';
|
|
455
|
+
/** A pipeline stage, named as the record's pipeline version names it (0.55.0). */
|
|
456
|
+
interface CompletionTriggerStage {
|
|
457
|
+
id: string;
|
|
458
|
+
name: string;
|
|
459
|
+
}
|
|
460
|
+
interface CompletionWorkflowTrigger {
|
|
461
|
+
status: CompletionTriggerStatus;
|
|
462
|
+
/** Present whenever `status` isn't `fired`. */
|
|
463
|
+
reason?: CompletionTriggerReason | undefined;
|
|
464
|
+
/** Human-readable explanation, safe to show to the person who completed the event. */
|
|
465
|
+
message?: string | undefined;
|
|
466
|
+
/**
|
|
467
|
+
* Present only when `status` is `fired`: the stage the completion's
|
|
468
|
+
* transition moved the record to (0.55.0). Actions on that transition run
|
|
469
|
+
* afterwards, so a chained transition may move the record again later.
|
|
470
|
+
*/
|
|
471
|
+
to_stage?: CompletionTriggerStage | undefined;
|
|
472
|
+
}
|
|
473
|
+
interface CompleteCalendarEventDto {
|
|
474
|
+
completion_notes?: string;
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* The completed event (snake_case, as every `/events` read returns it) plus
|
|
478
|
+
* `workflow_trigger`. Completing always completes the event; a trigger that
|
|
479
|
+
* fails is reported here and to the tenant's admins, never thrown.
|
|
480
|
+
*/
|
|
481
|
+
interface CompleteCalendarEventResponse extends Record<string, unknown> {
|
|
482
|
+
id: string;
|
|
483
|
+
status: 'completed';
|
|
484
|
+
completion_workflow_transition_id: string | null;
|
|
485
|
+
entity_type: string | null;
|
|
486
|
+
entity_id: string | null;
|
|
487
|
+
workflow_trigger: CompletionWorkflowTrigger;
|
|
488
|
+
}
|
|
489
|
+
type CalendarEventType = 'appointment' | 'site_visit' | 'call' | 'delivery' | 'pickup' | 'session' | 'custom';
|
|
490
|
+
type CalendarEventLocationType = 'physical' | 'virtual' | 'none';
|
|
491
|
+
type CalendarEventStatus = 'scheduled' | 'confirmed' | 'in_progress' | 'completed' | 'cancelled' | 'no_show';
|
|
492
|
+
interface CalendarEventParticipantDto {
|
|
493
|
+
type: 'user' | 'contact' | 'crew' | 'agent';
|
|
494
|
+
id: string;
|
|
495
|
+
/** Defaults to `invited`. */
|
|
496
|
+
status?: 'invited' | 'accepted' | 'declined' | 'tentative' | undefined;
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Body of `PATCH /events/:id`. Mirrors `updateCalendarEventSchema`
|
|
500
|
+
* (`calendar-event-types.parity.ts` fails the build if they drift). Every
|
|
501
|
+
* field is optional; an omitted field is left unchanged.
|
|
502
|
+
*/
|
|
503
|
+
interface UpdateCalendarEventDto {
|
|
504
|
+
title?: string | undefined;
|
|
505
|
+
description?: string | undefined;
|
|
506
|
+
event_type?: CalendarEventType | undefined;
|
|
507
|
+
/** Wall-clock time in `timezone`, e.g. `2026-11-02T14:00:00`. */
|
|
508
|
+
starts_at?: string | undefined;
|
|
509
|
+
ends_at?: string | undefined;
|
|
510
|
+
all_day?: boolean | undefined;
|
|
511
|
+
timezone?: string | undefined;
|
|
512
|
+
/** RRULE; blank means "does not repeat". */
|
|
513
|
+
recurrence_rule?: string | undefined;
|
|
514
|
+
location_type?: CalendarEventLocationType | undefined;
|
|
515
|
+
address_line1?: string | undefined;
|
|
516
|
+
address_line2?: string | undefined;
|
|
517
|
+
city?: string | undefined;
|
|
518
|
+
state?: string | undefined;
|
|
519
|
+
zip?: string | undefined;
|
|
520
|
+
/** A bare host like `zoom.us/j/123` is stored as `https://zoom.us/j/123`; blank clears it. */
|
|
521
|
+
virtual_url?: string | undefined;
|
|
522
|
+
property_id?: string | undefined;
|
|
523
|
+
entity_type?: string | undefined;
|
|
524
|
+
entity_id?: string | undefined;
|
|
525
|
+
status?: CalendarEventStatus | undefined;
|
|
526
|
+
/**
|
|
527
|
+
* The workflow transition to run when the event is completed. Must belong to
|
|
528
|
+
* the linked record's pipeline (else 422 COMPLETION_TRANSITION_WRONG_PIPELINE).
|
|
529
|
+
* `null` removes the completion step; omit it to leave the step unchanged.
|
|
530
|
+
*/
|
|
531
|
+
completion_workflow_transition_id?: string | null | undefined;
|
|
532
|
+
/** Replaces the event's participants with exactly this list. */
|
|
533
|
+
participants?: CalendarEventParticipantDto[] | undefined;
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Which occurrences of a recurring event an update applies to. Mirrors the
|
|
537
|
+
* shared `RECURRENCE_EDIT_MODES`; sent as the `recurrence_edit_mode` query
|
|
538
|
+
* parameter. Ignored for one-time events.
|
|
539
|
+
* - `this` — this occurrence only (the default). Not allowed on a series master.
|
|
540
|
+
* - `this_and_future` — splits the series here; this and later occurrences change.
|
|
541
|
+
* - `all` — the whole series.
|
|
542
|
+
*/
|
|
543
|
+
type RecurrenceEditMode = 'this' | 'this_and_future' | 'all';
|
|
544
|
+
/** Options for `calendarEvents.update()` (E46-F6-S11). */
|
|
545
|
+
interface UpdateCalendarEventOptions {
|
|
546
|
+
/** Defaults to `this` on the server when omitted. */
|
|
547
|
+
editMode?: RecurrenceEditMode | undefined;
|
|
199
548
|
}
|
|
200
549
|
|
|
201
|
-
/**
|
|
202
|
-
|
|
550
|
+
/**
|
|
551
|
+
* Query filters for `GET /events`. Mirrors the API's
|
|
552
|
+
* `listCalendarEventsQuerySchema` (`@blueprint/shared`) — keep in sync.
|
|
553
|
+
* Deliberately NOT `ListParams`: this endpoint paginates by `limit`/`offset`
|
|
554
|
+
* only and has no `page`, `sort`, `order` or `search` (Zod would strip them
|
|
555
|
+
* silently and the caller would loop on page 1 forever).
|
|
556
|
+
*/
|
|
557
|
+
interface ListCalendarEventsParams {
|
|
558
|
+
/** ISO timestamp — events starting at or after this instant. */
|
|
559
|
+
starts_after?: string;
|
|
560
|
+
/** ISO timestamp — events starting at or before this instant. */
|
|
561
|
+
starts_before?: string;
|
|
562
|
+
/** Must be paired with `entity_id`. */
|
|
563
|
+
entity_type?: string;
|
|
564
|
+
entity_id?: string;
|
|
565
|
+
/** Agent id of the event's creator. */
|
|
566
|
+
created_by?: string;
|
|
567
|
+
/**
|
|
568
|
+
* Events this agent is ON: a staff participant (canonical `{id}` or legacy
|
|
569
|
+
* `{agent_id}` shape), or the creator only when the event has no staff
|
|
570
|
+
* participants (self-booked / Google-synced) — the same rule availability
|
|
571
|
+
* uses to count busy time. An event booked for someone else is not on the
|
|
572
|
+
* creator's schedule.
|
|
573
|
+
*/
|
|
574
|
+
agent_id?: string;
|
|
575
|
+
status?: string;
|
|
576
|
+
event_type?: string;
|
|
577
|
+
/** Only recurrence masters / one-time events (no generated instances). */
|
|
578
|
+
masters_only?: boolean;
|
|
579
|
+
limit?: number;
|
|
580
|
+
offset?: number;
|
|
581
|
+
}
|
|
582
|
+
/** What `GET /events` actually returns: offset pagination, no `meta` envelope. */
|
|
583
|
+
interface CalendarEventListResponse<T = Record<string, unknown>> {
|
|
584
|
+
data: T[];
|
|
585
|
+
total: number;
|
|
586
|
+
limit: number;
|
|
587
|
+
offset: number;
|
|
588
|
+
}
|
|
589
|
+
/** Calendar event resource — CRUD operations on /events. */
|
|
590
|
+
declare class CalendarEventResource extends BaseResource<Record<string, unknown>, Record<string, unknown>, UpdateCalendarEventDto, CalendarEventListResponse> {
|
|
203
591
|
constructor(http: ConstructorParameters<typeof BaseResource>[0]);
|
|
592
|
+
list(params?: ListCalendarEventsParams): Promise<CalendarEventListResponse>;
|
|
593
|
+
/**
|
|
594
|
+
* PATCH /events/:id. For an occurrence of a recurring event, `editMode`
|
|
595
|
+
* picks which occurrences change (`this` when omitted — the server's
|
|
596
|
+
* default); it is ignored for one-time events.
|
|
597
|
+
*/
|
|
598
|
+
update(id: string, data: UpdateCalendarEventDto, options?: UpdateCalendarEventOptions): Promise<Record<string, unknown>>;
|
|
599
|
+
/**
|
|
600
|
+
* POST /events/:id/complete — marks the event completed and runs its "on
|
|
601
|
+
* complete" transition, best-effort. The event is completed even when the
|
|
602
|
+
* transition can't run; `workflow_trigger` says whether it fired, was
|
|
603
|
+
* skipped (none set) or failed (with a reason).
|
|
604
|
+
*/
|
|
605
|
+
complete(id: string, body?: CompleteCalendarEventDto): Promise<CompleteCalendarEventResponse>;
|
|
204
606
|
}
|
|
205
607
|
|
|
206
608
|
/** Contract resource — CRUD operations on /contracts. */
|
|
@@ -208,24 +610,453 @@ declare class ContractResource extends BaseResource {
|
|
|
208
610
|
constructor(http: ConstructorParameters<typeof BaseResource>[0]);
|
|
209
611
|
}
|
|
210
612
|
|
|
211
|
-
/**
|
|
212
|
-
|
|
213
|
-
|
|
613
|
+
/**
|
|
614
|
+
* Query params for `GET /opportunities/{opportunityId}/jobs` — mirrors
|
|
615
|
+
* `jobFilterSchema` in `packages/shared/src/validation/job.ts`. Extends the
|
|
616
|
+
* generic `ListParams` so it stays assignable to `BaseResource.list`.
|
|
617
|
+
*/
|
|
618
|
+
/** Sort keys on the per-opportunity jobs list (kept in lockstep with the server enum by the SDK's wire-contract spec). */
|
|
619
|
+
declare const JOB_SORT_KEYS: readonly ["created_at", "recent"];
|
|
620
|
+
type JobSortKey = (typeof JOB_SORT_KEYS)[number];
|
|
621
|
+
type JobStatus = 'active' | 'on_hold' | 'completed' | 'cancelled';
|
|
622
|
+
interface JobListParams extends ListParams {
|
|
623
|
+
tradeId?: string;
|
|
624
|
+
status?: JobStatus;
|
|
625
|
+
/**
|
|
626
|
+
* Mirrors `JOB_SORT_KEYS`. Default `created_at` desc. `recent` orders by the
|
|
627
|
+
* calling user's last view (newest first, never-viewed last) and ignores
|
|
628
|
+
* `sort_order`.
|
|
629
|
+
*/
|
|
630
|
+
sort_by?: JobSortKey;
|
|
631
|
+
sort_order?: 'asc' | 'desc';
|
|
632
|
+
page?: number;
|
|
633
|
+
limit?: number;
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* One active trade and whether a job can be created under it
|
|
637
|
+
* (`GET /api/v1/jobs/trade-coverage`). Mirrors `jobTradeCoverageItemSchema` in
|
|
638
|
+
* `packages/shared` — redefined here so the published package carries no
|
|
639
|
+
* dependency on `@blueprint/shared`; `jobs.spec.ts` parses the response with
|
|
640
|
+
* the REAL shared schema. `hasWorkflow: false` means creating a job with this
|
|
641
|
+
* trade returns 422 WORKFLOW_NOT_CONFIGURED.
|
|
642
|
+
*/
|
|
643
|
+
interface JobTradeCoverageItemDto {
|
|
644
|
+
tradeId: string;
|
|
645
|
+
name: string;
|
|
646
|
+
hasWorkflow: boolean;
|
|
647
|
+
}
|
|
648
|
+
/** Every active trade of the tenant, ordered by name, with job-workflow coverage. */
|
|
649
|
+
interface JobTradeCoverageResponse {
|
|
650
|
+
trades: JobTradeCoverageItemDto[];
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* `POST /opportunities/{opportunityId}/jobs` body — mirrors `createJobSchema`
|
|
654
|
+
* minus `opportunityId` (it comes from the path). A trade with no published
|
|
655
|
+
* job workflow returns 422 WORKFLOW_NOT_CONFIGURED; see `getTradeCoverage()`.
|
|
656
|
+
*/
|
|
657
|
+
interface CreateJobDto {
|
|
658
|
+
tradeId: string;
|
|
659
|
+
propertyId?: string | undefined;
|
|
660
|
+
notes?: string | undefined;
|
|
661
|
+
}
|
|
662
|
+
/** `PUT /opportunities/{opportunityId}/jobs/{id}` body — mirrors `updateJobSchema`. */
|
|
663
|
+
interface UpdateJobDto {
|
|
664
|
+
status?: JobStatus | undefined;
|
|
665
|
+
notes?: string | null | undefined;
|
|
214
666
|
}
|
|
215
667
|
|
|
216
|
-
/**
|
|
217
|
-
|
|
218
|
-
|
|
668
|
+
/**
|
|
669
|
+
* Jobs. CRUD is nested under the parent opportunity
|
|
670
|
+
* (`/opportunities/{opportunityId}/jobs`); there is no flat `/jobs` list or
|
|
671
|
+
* `/jobs/{id}` read. `getTradeCoverage()` is the one top-level route.
|
|
672
|
+
*/
|
|
673
|
+
declare class JobResource extends ApiResource {
|
|
674
|
+
constructor(http: ConstructorParameters<typeof ApiResource>[0]);
|
|
675
|
+
/** The jobs under one opportunity — the same route as `listForOpportunity()`. */
|
|
676
|
+
list(opportunityId: string, params?: JobListParams): Promise<PaginatedResponse<Record<string, unknown>>>;
|
|
677
|
+
/**
|
|
678
|
+
* List the jobs under one opportunity — `GET /opportunities/{opportunityId}/jobs`,
|
|
679
|
+
* the API's job list route. Default order is `created_at` desc;
|
|
680
|
+
* `sort_by: 'recent'` puts the calling user's most recently opened jobs first.
|
|
681
|
+
*/
|
|
682
|
+
listForOpportunity(opportunityId: string, params?: JobListParams): Promise<PaginatedResponse<Record<string, unknown>>>;
|
|
683
|
+
/** GET /opportunities/{opportunityId}/jobs/{id} */
|
|
684
|
+
get(opportunityId: string, id: string): Promise<Record<string, unknown>>;
|
|
685
|
+
/**
|
|
686
|
+
* POST /opportunities/{opportunityId}/jobs — 422 WORKFLOW_NOT_CONFIGURED when
|
|
687
|
+
* the trade has no published job workflow (check `getTradeCoverage()` first).
|
|
688
|
+
*/
|
|
689
|
+
create(opportunityId: string, data: CreateJobDto): Promise<Record<string, unknown>>;
|
|
690
|
+
/** PUT /opportunities/{opportunityId}/jobs/{id} — partial update (status, notes). */
|
|
691
|
+
update(opportunityId: string, id: string, data: UpdateJobDto): Promise<Record<string, unknown>>;
|
|
692
|
+
/** DELETE /opportunities/{opportunityId}/jobs/{id} — soft delete (204). */
|
|
693
|
+
delete(opportunityId: string, id: string): Promise<void>;
|
|
694
|
+
/**
|
|
695
|
+
* GET /jobs/trade-coverage — every active trade with whether a job can be
|
|
696
|
+
* created under it (a published job workflow resolves: the trade's own or the
|
|
697
|
+
* generic one). Check before creating a job to avoid a 422
|
|
698
|
+
* WORKFLOW_NOT_CONFIGURED. Readable by any role that can create jobs (403
|
|
699
|
+
* otherwise); carries no workflow details.
|
|
700
|
+
*/
|
|
701
|
+
getTradeCoverage(): Promise<JobTradeCoverageResponse>;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
/** Estimate statuses — mirrors `ESTIMATE_STATUSES` in `packages/shared/src/validation/estimate.ts` (runtime parity spec). */
|
|
705
|
+
declare const ESTIMATE_STATUSES: readonly ["draft", "sent", "approved", "rejected"];
|
|
706
|
+
type EstimateStatus = (typeof ESTIMATE_STATUSES)[number];
|
|
707
|
+
/**
|
|
708
|
+
* Query params for the estimate lists — mirrors `estimateFilterSchema`
|
|
709
|
+
* (`page` ≥ 1, `limit` 1–100, default 25).
|
|
710
|
+
*/
|
|
711
|
+
interface EstimateListParams extends ListParams {
|
|
712
|
+
status?: EstimateStatus;
|
|
713
|
+
page?: number;
|
|
714
|
+
limit?: number;
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* One estimate list row (no line items) — transcribed from
|
|
718
|
+
* `EstimatesService.findAllForOpportunity`, the same shape as the per-job list.
|
|
719
|
+
* Money/rate columns are Postgres numerics, so they arrive as strings.
|
|
720
|
+
*/
|
|
721
|
+
interface EstimateSummaryDto {
|
|
722
|
+
id: string;
|
|
723
|
+
tenantId: string;
|
|
724
|
+
jobId: string;
|
|
725
|
+
estimateTemplateId: string | null;
|
|
726
|
+
status: EstimateStatus;
|
|
727
|
+
notes: string | null;
|
|
728
|
+
subtotal: string;
|
|
729
|
+
discountType: string | null;
|
|
730
|
+
discountValue: string | null;
|
|
731
|
+
taxRate: string | null;
|
|
732
|
+
taxAmount: string | null;
|
|
733
|
+
total: string;
|
|
734
|
+
createdBy: string;
|
|
735
|
+
createdAt: string;
|
|
736
|
+
updatedAt: string;
|
|
737
|
+
lineItemCount: number;
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* `POST /jobs/{jobId}/estimates` body — mirrors `createEstimateSchema` minus
|
|
741
|
+
* `jobId` (it comes from the path).
|
|
742
|
+
*/
|
|
743
|
+
interface CreateEstimateDto {
|
|
744
|
+
estimateTemplateId?: string | undefined;
|
|
745
|
+
/** Defaults to `{}`. */
|
|
746
|
+
measurements?: Record<string, unknown> | undefined;
|
|
747
|
+
notes?: string | undefined;
|
|
748
|
+
}
|
|
749
|
+
/** `PUT /jobs/{jobId}/estimates/{id}` body — mirrors `updateEstimateSchema`. `taxRate` is a fraction (0–1). */
|
|
750
|
+
interface UpdateEstimateDto {
|
|
751
|
+
measurements?: Record<string, unknown> | undefined;
|
|
752
|
+
notes?: string | null | undefined;
|
|
753
|
+
discountType?: 'percent' | 'flat' | null | undefined;
|
|
754
|
+
discountValue?: number | null | undefined;
|
|
755
|
+
taxRate?: number | null | undefined;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* Estimates. CRUD is nested under the parent job (`/jobs/{jobId}/estimates`);
|
|
760
|
+
* `listForOpportunity()` reads every estimate across an opportunity's jobs.
|
|
761
|
+
* There is no flat `/estimates` list or `/estimates/{id}` read.
|
|
762
|
+
*/
|
|
763
|
+
declare class EstimateResource extends ApiResource {
|
|
764
|
+
constructor(http: ConstructorParameters<typeof ApiResource>[0]);
|
|
765
|
+
/** GET /jobs/{jobId}/estimates — newest first, paginated (`page`, `limit` ≤ 100). */
|
|
766
|
+
list(jobId: string, params?: EstimateListParams): Promise<PaginatedResponse<EstimateSummaryDto>>;
|
|
767
|
+
/**
|
|
768
|
+
* Every estimate across all of one opportunity's jobs, in one request —
|
|
769
|
+
* `GET /opportunities/{opportunityId}/estimates`. Newest first; each row
|
|
770
|
+
* carries its `jobId`. Paginated with `page` / `limit` (max 100).
|
|
771
|
+
*/
|
|
772
|
+
listForOpportunity(opportunityId: string, params?: EstimateListParams): Promise<PaginatedResponse<EstimateSummaryDto>>;
|
|
773
|
+
/** GET /jobs/{jobId}/estimates/{id} — the estimate with its line items. */
|
|
774
|
+
get(jobId: string, id: string): Promise<Record<string, unknown>>;
|
|
775
|
+
/** POST /jobs/{jobId}/estimates — optionally cloned from an estimate template. */
|
|
776
|
+
create(jobId: string, data: CreateEstimateDto): Promise<Record<string, unknown>>;
|
|
777
|
+
/** PUT /jobs/{jobId}/estimates/{id} — partial update (measurements, notes, discount, tax). */
|
|
778
|
+
update(jobId: string, id: string, data: UpdateEstimateDto): Promise<Record<string, unknown>>;
|
|
779
|
+
/** DELETE /jobs/{jobId}/estimates/{id} — soft delete (204). */
|
|
780
|
+
delete(jobId: string, id: string): Promise<void>;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
/**
|
|
784
|
+
* Wire shapes for `GET /admin/invoices` — mirrors `invoiceFilterSchema` in
|
|
785
|
+
* `@blueprint/shared` and the row `InvoiceService.findAll` actually returns
|
|
786
|
+
* (camelCase Drizzle columns, Date columns serialised as ISO strings, money as
|
|
787
|
+
* numeric(12,2) dollar strings). Redefined here (not imported) so the published
|
|
788
|
+
* package carries no dependency on `@blueprint/shared`; `invoices.spec.ts`
|
|
789
|
+
* parses the query the SDK sends with the REAL shared filter schema.
|
|
790
|
+
*/
|
|
791
|
+
type InvoiceStatus = 'draft' | 'sent' | 'partially_paid' | 'paid' | 'void' | 'uncollectible';
|
|
792
|
+
type InvoiceSourceType = 'job' | 'contract' | 'estimate' | 'manual' | 'billing_schedule';
|
|
793
|
+
/**
|
|
794
|
+
* Status of a payment row. `needs_review` (E56-F5-S2) is a processor payment
|
|
795
|
+
* that landed on a void invoice: recorded so the money is never lost, but it
|
|
796
|
+
* does not count toward the invoice's totals until someone resolves it.
|
|
797
|
+
*/
|
|
798
|
+
type PaymentStatus = 'pending' | 'succeeded' | 'failed' | 'refunded' | 'needs_review';
|
|
799
|
+
/**
|
|
800
|
+
* `payLink` on `GET /admin/invoices/:id` (E56-F5-S2) — mirrors
|
|
801
|
+
* `invoicePayLinkStatusSchema`. Whether a live pay link exists and when one was
|
|
802
|
+
* last issued. The URL itself is never returned: only its hash is stored. Call
|
|
803
|
+
* `invoices.createPayLink(id)` to get a new one.
|
|
804
|
+
*/
|
|
805
|
+
interface InvoicePayLinkStatusDto {
|
|
806
|
+
active: boolean;
|
|
807
|
+
lastSentAt: string | null;
|
|
808
|
+
}
|
|
809
|
+
/** Response of `POST /admin/invoices/:id/pay-link` — mirrors `invoicePayLinkSchema`. */
|
|
810
|
+
interface InvoicePayLinkDto {
|
|
811
|
+
url: string;
|
|
812
|
+
}
|
|
813
|
+
interface InvoiceListParams extends ListParams {
|
|
814
|
+
status?: InvoiceStatus;
|
|
815
|
+
customerId?: string;
|
|
816
|
+
sourceType?: InvoiceSourceType;
|
|
817
|
+
sourceId?: string;
|
|
818
|
+
page?: number;
|
|
819
|
+
limit?: number;
|
|
820
|
+
}
|
|
821
|
+
/** One row of `GET /admin/invoices`. */
|
|
822
|
+
interface InvoiceListItemDto {
|
|
823
|
+
id: string;
|
|
824
|
+
tenantId: string;
|
|
825
|
+
invoiceNumber: string;
|
|
826
|
+
sourceType: InvoiceSourceType;
|
|
827
|
+
sourceId: string | null;
|
|
828
|
+
customerId: string;
|
|
829
|
+
/**
|
|
830
|
+
* The billed customer's display name — company name for a company, "First
|
|
831
|
+
* Last" for a person. Still set when the customer has since been deleted
|
|
832
|
+
* (historical invoice); `null` only if the customer row is missing.
|
|
833
|
+
*/
|
|
834
|
+
customerName: string | null;
|
|
835
|
+
orgPath: string;
|
|
836
|
+
status: InvoiceStatus;
|
|
837
|
+
currency: string;
|
|
838
|
+
subtotal: string;
|
|
839
|
+
taxAmount: string;
|
|
840
|
+
total: string;
|
|
841
|
+
amountPaid: string;
|
|
842
|
+
balance: string;
|
|
843
|
+
issuedAt: string | null;
|
|
844
|
+
dueAt: string | null;
|
|
845
|
+
paidAt: string | null;
|
|
846
|
+
memo: string | null;
|
|
847
|
+
terms: string | null;
|
|
848
|
+
/** Provider → external id, e.g. `{ quickbooks: '130', stripe: 'in_…' }`. */
|
|
849
|
+
externalRef: Record<string, string>;
|
|
850
|
+
/**
|
|
851
|
+
* Storage key of the PDF copy stored when the invoice was sent (E56-F6-S1);
|
|
852
|
+
* `null` for drafts and for sends that stored no copy. Download the bytes
|
|
853
|
+
* with `invoices.downloadPdf(id)`.
|
|
854
|
+
*/
|
|
855
|
+
pdfStorageKey: string | null;
|
|
856
|
+
pdfGeneratedAt: string | null;
|
|
857
|
+
createdAt: string;
|
|
858
|
+
updatedAt: string;
|
|
859
|
+
deletedAt: string | null;
|
|
860
|
+
}
|
|
861
|
+
/** One line of `GET /admin/invoices/:id`. */
|
|
862
|
+
type InvoiceLineItemDto = {
|
|
863
|
+
id: string;
|
|
864
|
+
tenantId: string;
|
|
865
|
+
invoiceId: string;
|
|
866
|
+
description: string;
|
|
867
|
+
quantity: string;
|
|
868
|
+
unitPrice: string;
|
|
869
|
+
lineTotal: string;
|
|
870
|
+
sourceLineId: string | null;
|
|
871
|
+
sortOrder: number;
|
|
872
|
+
createdAt: string;
|
|
873
|
+
updatedAt: string;
|
|
874
|
+
};
|
|
875
|
+
/**
|
|
876
|
+
* One payment of `GET /admin/invoices/:id`. A `needs_review` row (money that
|
|
877
|
+
* arrived after the invoice was voided) is listed here but is not counted in
|
|
878
|
+
* the invoice's `amountPaid`/`balance`.
|
|
879
|
+
*/
|
|
880
|
+
type InvoicePaymentDto = {
|
|
881
|
+
id: string;
|
|
882
|
+
tenantId: string;
|
|
883
|
+
invoiceId: string;
|
|
884
|
+
amount: string;
|
|
885
|
+
currency: string;
|
|
886
|
+
method: string;
|
|
887
|
+
processor: string;
|
|
888
|
+
status: PaymentStatus;
|
|
889
|
+
externalRef: Record<string, string>;
|
|
890
|
+
receivedAt: string;
|
|
891
|
+
memo: string | null;
|
|
892
|
+
/** Set on a refund row: the payment it refunds. */
|
|
893
|
+
refundsPaymentId: string | null;
|
|
894
|
+
createdAt: string;
|
|
895
|
+
updatedAt: string;
|
|
896
|
+
deletedAt: string | null;
|
|
897
|
+
};
|
|
898
|
+
/** `GET /admin/invoices/:id` — the invoice row plus its lines, payments and pay-link state. */
|
|
899
|
+
type InvoiceDetailDto = Omit<InvoiceListItemDto, 'customerName'> & {
|
|
900
|
+
lineItems: InvoiceLineItemDto[];
|
|
901
|
+
payments: InvoicePaymentDto[];
|
|
902
|
+
payLink: InvoicePayLinkStatusDto;
|
|
903
|
+
};
|
|
904
|
+
/**
|
|
905
|
+
* Query of `GET /admin/invoices/overdue` (E56-F8-S2) — mirrors
|
|
906
|
+
* `overdueInvoiceQuerySchema` in `@blueprint/shared`.
|
|
907
|
+
*/
|
|
908
|
+
interface OverdueInvoiceListParams {
|
|
909
|
+
/** Only invoices at least this many whole days past due (1–3650). */
|
|
910
|
+
minDays?: number;
|
|
911
|
+
customerId?: string;
|
|
912
|
+
page?: number;
|
|
913
|
+
limit?: number;
|
|
914
|
+
}
|
|
915
|
+
/**
|
|
916
|
+
* One row of `GET /admin/invoices/overdue` — mirrors `overdueInvoiceSchema`:
|
|
917
|
+
* a sent or partially paid invoice with a balance, past its due date.
|
|
918
|
+
*/
|
|
919
|
+
interface OverdueInvoiceDto {
|
|
920
|
+
id: string;
|
|
921
|
+
invoiceNumber: string;
|
|
922
|
+
customerId: string;
|
|
923
|
+
customerName: string | null;
|
|
924
|
+
status: 'sent' | 'partially_paid';
|
|
925
|
+
currency: string;
|
|
926
|
+
total: string;
|
|
927
|
+
balance: string;
|
|
928
|
+
issuedAt: string | null;
|
|
929
|
+
dueAt: string;
|
|
930
|
+
/** Whole days since the due date (0 = past due today). */
|
|
931
|
+
daysOverdue: number;
|
|
932
|
+
/** The highest overdue offset (days) Planes has recorded for it, or null if none yet. */
|
|
933
|
+
lastOffsetReached: number | null;
|
|
934
|
+
sourceType: InvoiceSourceType;
|
|
935
|
+
sourceId: string | null;
|
|
936
|
+
}
|
|
937
|
+
/** Response of `GET /admin/invoices/overdue/summary` — mirrors `invoiceOverdueSummarySchema`. */
|
|
938
|
+
interface InvoiceOverdueSummaryDto {
|
|
939
|
+
count: number;
|
|
940
|
+
/** Sum of the overdue balances, dollars as a decimal string. */
|
|
941
|
+
total: string;
|
|
219
942
|
}
|
|
220
943
|
|
|
221
|
-
/** Invoice resource — CRUD operations on /invoices. */
|
|
222
|
-
declare class InvoiceResource extends BaseResource {
|
|
944
|
+
/** Invoice resource — CRUD operations on /admin/invoices (the API's invoices controller route). */
|
|
945
|
+
declare class InvoiceResource extends BaseResource<Record<string, unknown>, Record<string, unknown>, Record<string, unknown>, PaginatedResponse<InvoiceListItemDto>> {
|
|
223
946
|
constructor(http: ConstructorParameters<typeof BaseResource>[0]);
|
|
947
|
+
/** List invoices, newest first. Each row carries the customer's `customerName`. */
|
|
948
|
+
list(params?: InvoiceListParams): Promise<PaginatedResponse<InvoiceListItemDto>>;
|
|
949
|
+
/**
|
|
950
|
+
* GET /admin/invoices/:id — the invoice with its line items, payments
|
|
951
|
+
* (including any `needs_review` payment) and `payLink` state.
|
|
952
|
+
*/
|
|
953
|
+
get(id: string): Promise<InvoiceDetailDto>;
|
|
954
|
+
/**
|
|
955
|
+
* POST /admin/invoices/:id/pay-link — issue a fresh durable pay link for a
|
|
956
|
+
* `sent` or `partially_paid` invoice (Send Invoice grant) and return its URL,
|
|
957
|
+
* e.g. to share by text. Rotates: the previously emailed link stops working.
|
|
958
|
+
* Any other status → 409 `INVOICE_NOT_PAYABLE`.
|
|
959
|
+
*/
|
|
960
|
+
createPayLink(id: string): Promise<InvoicePayLinkDto>;
|
|
961
|
+
/**
|
|
962
|
+
* GET /admin/invoices/:id/pdf — the invoice PDF bytes (Read Invoice grant).
|
|
963
|
+
* A sent invoice returns the copy stored when it was sent; a draft renders on
|
|
964
|
+
* demand with a DRAFT watermark.
|
|
965
|
+
*/
|
|
966
|
+
downloadPdf(id: string): Promise<ArrayBuffer>;
|
|
967
|
+
/**
|
|
968
|
+
* GET /admin/invoices/overdue — sent / partially paid invoices with a balance
|
|
969
|
+
* past their due date, most overdue first, each with `daysOverdue` and the
|
|
970
|
+
* last overdue offset reached (E56-F8-S2). Read Invoice.
|
|
971
|
+
*/
|
|
972
|
+
listOverdue(params?: OverdueInvoiceListParams): Promise<PaginatedResponse<OverdueInvoiceDto>>;
|
|
973
|
+
/** GET /admin/invoices/overdue/summary — `{ count, total }` of every overdue invoice. Read Invoice. */
|
|
974
|
+
overdueSummary(): Promise<InvoiceOverdueSummaryDto>;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
/**
|
|
978
|
+
* Wire shapes for inventory items (`/admin/inventory/items`). Mirror
|
|
979
|
+
* `createInventoryItemSchema` / `updateInventoryItemSchema` /
|
|
980
|
+
* `inventoryItemFilterSchema` in `packages/shared/src/validation/inventory.ts`,
|
|
981
|
+
* redefined here so the published package carries no dependency on
|
|
982
|
+
* `@blueprint/shared`; `crud-route-types.parity.ts` fails the build when the
|
|
983
|
+
* two drift.
|
|
984
|
+
*/
|
|
985
|
+
/** Units an inventory item is counted in — mirrors `UNITS_OF_MEASURE`. */
|
|
986
|
+
type InventoryUnitOfMeasure = 'ea' | 'sq' | 'lf' | 'bundle' | 'box' | 'roll' | 'jug' | 'spool';
|
|
987
|
+
/** `POST /admin/inventory/items` body. Money and quantities are decimal strings (`"82.50"`). */
|
|
988
|
+
interface CreateInventoryItemDto {
|
|
989
|
+
name: string;
|
|
990
|
+
tradeId: string;
|
|
991
|
+
unitOfMeasure: InventoryUnitOfMeasure;
|
|
992
|
+
materialCatalogId?: string | null | undefined;
|
|
993
|
+
metadata?: Record<string, unknown> | null | undefined;
|
|
994
|
+
sku?: string | null | undefined;
|
|
995
|
+
productGroup?: string | null | undefined;
|
|
996
|
+
description?: string | null | undefined;
|
|
997
|
+
costDefault?: string | null | undefined;
|
|
998
|
+
/** Defaults to `true`. */
|
|
999
|
+
trackStock?: boolean | undefined;
|
|
1000
|
+
reorderPoint?: string | null | undefined;
|
|
1001
|
+
category?: string | null | undefined;
|
|
1002
|
+
manufacturer?: string | null | undefined;
|
|
224
1003
|
}
|
|
1004
|
+
/** `PUT /admin/inventory/items/{id}` body — any subset of the create fields. */
|
|
1005
|
+
type UpdateInventoryItemDto = {
|
|
1006
|
+
[K in keyof CreateInventoryItemDto]?: CreateInventoryItemDto[K] | undefined;
|
|
1007
|
+
};
|
|
1008
|
+
/** Query for `GET /admin/inventory/items`. Booleans travel as `'true'` / `'false'`. */
|
|
1009
|
+
type InventoryItemListParams = {
|
|
1010
|
+
tradeId?: string | undefined;
|
|
1011
|
+
category?: string | undefined;
|
|
1012
|
+
productGroup?: string | undefined;
|
|
1013
|
+
active?: 'true' | 'false' | undefined;
|
|
1014
|
+
trackStock?: 'true' | 'false' | undefined;
|
|
1015
|
+
search?: string | undefined;
|
|
1016
|
+
page?: number | undefined;
|
|
1017
|
+
limit?: number | undefined;
|
|
1018
|
+
};
|
|
225
1019
|
|
|
226
|
-
/** Inventory
|
|
227
|
-
declare class InventoryResource extends BaseResource {
|
|
1020
|
+
/** Inventory items — CRUD on /admin/inventory/items (updates are PUT). */
|
|
1021
|
+
declare class InventoryResource extends BaseResource<Record<string, unknown>, CreateInventoryItemDto, UpdateInventoryItemDto> {
|
|
228
1022
|
constructor(http: ConstructorParameters<typeof BaseResource>[0]);
|
|
1023
|
+
list(params?: InventoryItemListParams): Promise<PaginatedResponse<Record<string, unknown>>>;
|
|
1024
|
+
/** PUT /admin/inventory/items/{id} — partial update. */
|
|
1025
|
+
update(id: string, data: UpdateInventoryItemDto): Promise<Record<string, unknown>>;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
/**
|
|
1029
|
+
* The `consent` object on contact-channel and customer reads (E53-F5-S1) —
|
|
1030
|
+
* mirrors `ConsentStateDto` in @blueprint/shared (parity-checked in
|
|
1031
|
+
* `consent-types.parity.ts`).
|
|
1032
|
+
*
|
|
1033
|
+
* Consent is per ADDRESS (a phone number or email), not per record. The
|
|
1034
|
+
* record's own flags say what was set on THIS record; `effective_opted_out`
|
|
1035
|
+
* is the verdict every send honours, which can be true while the record's own
|
|
1036
|
+
* flag is false because another record bearing the same address holds it.
|
|
1037
|
+
*/
|
|
1038
|
+
/** The newest recorded consent change for the record's address(es). */
|
|
1039
|
+
interface ConsentLastChangeDto {
|
|
1040
|
+
outcome: 'revoked' | 'granted';
|
|
1041
|
+
/** `manual`, `stop_reply`, `unsubscribe_link`, `import`, or `integration:<slug>`. */
|
|
1042
|
+
source: string;
|
|
1043
|
+
/** ISO timestamp. */
|
|
1044
|
+
at: string;
|
|
1045
|
+
/** `value`: applied to every record with the address. `row`: a manual un-opt-out of one record. */
|
|
1046
|
+
scope: 'row' | 'value';
|
|
1047
|
+
}
|
|
1048
|
+
interface ConsentStateDto {
|
|
1049
|
+
/** This record's own marketing opt-out flag. */
|
|
1050
|
+
marketing_opt_out: boolean;
|
|
1051
|
+
/** This record's own do-not-call flag (`dnc` on a channel, `phoneDnc` on a customer). */
|
|
1052
|
+
dnc: boolean;
|
|
1053
|
+
/** By-address verdict across every contact channel and customer bearing the address. */
|
|
1054
|
+
effective_opted_out: {
|
|
1055
|
+
marketing_email: boolean;
|
|
1056
|
+
sms: boolean;
|
|
1057
|
+
call: boolean;
|
|
1058
|
+
};
|
|
1059
|
+
last_change: ConsentLastChangeDto | null;
|
|
229
1060
|
}
|
|
230
1061
|
|
|
231
1062
|
/**
|
|
@@ -240,225 +1071,2690 @@ declare class InventoryResource extends BaseResource {
|
|
|
240
1071
|
* (tenantId, deletedAt, createdBy, …) are intentionally omitted — see
|
|
241
1072
|
* `CustomerDto` for the house style.
|
|
242
1073
|
*/
|
|
1074
|
+
|
|
243
1075
|
type ContactSource = 'manual' | 'import' | 'convert_from_customer';
|
|
1076
|
+
/**
|
|
1077
|
+
* Query params for `GET /contacts` — mirrors `contactFilterSchema` in
|
|
1078
|
+
* `@blueprint/shared`. `customer_id` / `property_id` return only contacts with
|
|
1079
|
+
* an ACTIVE link to that record; `q` matches a name or a channel value, word
|
|
1080
|
+
* by word (every word must match), so a full name works in either order.
|
|
1081
|
+
* `sort_by: 'name'` is case-insensitive first name then last name; the default
|
|
1082
|
+
* is `created_at` desc. Extends the generic `ListParams` so it stays assignable
|
|
1083
|
+
* to `BaseResource.list`.
|
|
1084
|
+
*/
|
|
1085
|
+
/** 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"];
|
|
1087
|
+
type ContactSortKey = (typeof CONTACT_SORT_KEYS)[number];
|
|
1088
|
+
/**
|
|
1089
|
+
* Related collections `GET /contacts?include=` eager-loads onto each row
|
|
1090
|
+
* (kept in lockstep with the server's `CONTACT_LIST_INCLUDES` by the SDK's
|
|
1091
|
+
* wire-contract spec). `channels` = all channels; `links` = ACTIVE links only.
|
|
1092
|
+
*/
|
|
1093
|
+
declare const CONTACT_LIST_INCLUDES: readonly ["channels", "links"];
|
|
1094
|
+
type ContactListInclude = (typeof CONTACT_LIST_INCLUDES)[number];
|
|
1095
|
+
interface ContactListParams extends ListParams {
|
|
1096
|
+
customer_id?: string;
|
|
1097
|
+
property_id?: string;
|
|
1098
|
+
q?: string;
|
|
1099
|
+
/** Mirrors `CONTACT_SORT_KEYS`. `recent` = the calling user's last view, newest first; ignores `sort_order`. */
|
|
1100
|
+
sort_by?: ContactSortKey;
|
|
1101
|
+
sort_order?: 'asc' | 'desc';
|
|
1102
|
+
page?: number;
|
|
1103
|
+
limit?: number;
|
|
1104
|
+
/**
|
|
1105
|
+
* Eager-load related collections onto each row in one request — sent as one
|
|
1106
|
+
* comma-separated value (`include=channels,links`). Use this instead of a
|
|
1107
|
+
* `get()` per row.
|
|
1108
|
+
*/
|
|
1109
|
+
include?: ContactListInclude[];
|
|
1110
|
+
}
|
|
244
1111
|
interface ContactDto {
|
|
245
1112
|
id: string;
|
|
246
|
-
firstName: string;
|
|
247
|
-
lastName: string | null;
|
|
248
|
-
notes: string | null;
|
|
249
|
-
customFields: Record<string, unknown> | null;
|
|
250
|
-
source: ContactSource | null;
|
|
251
|
-
createdAt: string;
|
|
252
|
-
updatedAt: string;
|
|
1113
|
+
firstName: string;
|
|
1114
|
+
lastName: string | null;
|
|
1115
|
+
notes: string | null;
|
|
1116
|
+
customFields: Record<string, unknown> | null;
|
|
1117
|
+
source: ContactSource | null;
|
|
1118
|
+
createdAt: string;
|
|
1119
|
+
updatedAt: string;
|
|
1120
|
+
}
|
|
1121
|
+
interface CreateContactDto {
|
|
1122
|
+
firstName: string;
|
|
1123
|
+
lastName?: string | null;
|
|
1124
|
+
notes?: string | null;
|
|
1125
|
+
customFields?: Record<string, unknown> | null;
|
|
1126
|
+
source?: ContactSource | null;
|
|
1127
|
+
}
|
|
1128
|
+
interface UpdateContactDto {
|
|
1129
|
+
firstName?: string;
|
|
1130
|
+
lastName?: string | null;
|
|
1131
|
+
notes?: string | null;
|
|
1132
|
+
customFields?: Record<string, unknown> | null;
|
|
1133
|
+
source?: ContactSource | null;
|
|
1134
|
+
}
|
|
1135
|
+
type ContactChannelType = 'email' | 'phone' | 'url';
|
|
1136
|
+
type ContactChannelPhoneType = 'mobile' | 'landline' | 'voip' | 'unknown';
|
|
1137
|
+
interface ContactChannelDto {
|
|
1138
|
+
id: string;
|
|
1139
|
+
contactId: string;
|
|
1140
|
+
channelType: ContactChannelType;
|
|
1141
|
+
label: string | null;
|
|
1142
|
+
value: string;
|
|
1143
|
+
isPrimary: boolean;
|
|
1144
|
+
phoneType: ContactChannelPhoneType | null;
|
|
1145
|
+
smsCapable: boolean | null;
|
|
1146
|
+
dnc: boolean | null;
|
|
1147
|
+
marketingOptOut: boolean | null;
|
|
1148
|
+
createdAt: string;
|
|
1149
|
+
updatedAt: string;
|
|
1150
|
+
/**
|
|
1151
|
+
* Consent for this channel's address (E53-F5-S1): own flags, the
|
|
1152
|
+
* by-address verdict and the newest change. Present on every channel the
|
|
1153
|
+
* API returns (`GET /contacts/:id`, `include=channels`, channel create/update).
|
|
1154
|
+
*/
|
|
1155
|
+
consent: ConsentStateDto;
|
|
1156
|
+
}
|
|
1157
|
+
type ContactLinkTargetType = 'customer' | 'property';
|
|
1158
|
+
/** A contact's link to a customer or property (`endedAt` null = active). */
|
|
1159
|
+
interface ContactLinkDto {
|
|
1160
|
+
id: string;
|
|
1161
|
+
contactId: string;
|
|
1162
|
+
targetType: ContactLinkTargetType;
|
|
1163
|
+
targetId: string;
|
|
1164
|
+
role: string | null;
|
|
1165
|
+
isPrimary: boolean;
|
|
1166
|
+
endedAt: string | null;
|
|
1167
|
+
createdAt: string;
|
|
1168
|
+
updatedAt: string;
|
|
1169
|
+
}
|
|
1170
|
+
/**
|
|
1171
|
+
* A `GET /contacts` row. `channels` / `links` are present only when requested
|
|
1172
|
+
* via `include` — the same shapes `GET /contacts/:id` returns (links: active only).
|
|
1173
|
+
*/
|
|
1174
|
+
interface ContactListItemDto extends ContactDto {
|
|
1175
|
+
channels?: ContactChannelDto[];
|
|
1176
|
+
links?: ContactLinkDto[];
|
|
1177
|
+
}
|
|
1178
|
+
interface CreateContactChannelDto {
|
|
1179
|
+
channelType: ContactChannelType;
|
|
1180
|
+
label?: string | null;
|
|
1181
|
+
value: string;
|
|
1182
|
+
isPrimary?: boolean;
|
|
1183
|
+
dnc?: boolean | null;
|
|
1184
|
+
marketingOptOut?: boolean | null;
|
|
1185
|
+
}
|
|
1186
|
+
interface UpdateContactChannelDto {
|
|
1187
|
+
label?: string | null;
|
|
1188
|
+
value?: string;
|
|
1189
|
+
isPrimary?: boolean;
|
|
1190
|
+
dnc?: boolean | null;
|
|
1191
|
+
marketingOptOut?: boolean | null;
|
|
1192
|
+
}
|
|
1193
|
+
/** A channel elsewhere in the tenant with the same normalized value. */
|
|
1194
|
+
interface ContactChannelDuplicateMatch {
|
|
1195
|
+
contactId: string;
|
|
1196
|
+
channelId: string;
|
|
1197
|
+
value: string;
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* `POST /contacts/:id/channels` return shape — `ContactChannelsService.addChannel()`
|
|
1201
|
+
* always returns this wrapper, never a flat channel. `duplicateOf` is the
|
|
1202
|
+
* dedup signal (empty array when there's no match) — the point of this API
|
|
1203
|
+
* for connectors doing identity resolution (e.g. Messenger).
|
|
1204
|
+
*/
|
|
1205
|
+
interface AddContactChannelResult {
|
|
1206
|
+
channel: ContactChannelDto;
|
|
1207
|
+
duplicateOf: ContactChannelDuplicateMatch[];
|
|
1208
|
+
}
|
|
1209
|
+
interface ContactMergeResult {
|
|
1210
|
+
winnerId: string;
|
|
1211
|
+
loserId: string;
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
/**
|
|
1215
|
+
* `/contacts/:id/channels` — POST/PATCH/DELETE only. There is no list/get
|
|
1216
|
+
* route: reads come embedded in the contact detail response (`GET
|
|
1217
|
+
* /contacts/:id` returns `{ ...contact, channels, links, mergedInto }`), so
|
|
1218
|
+
* this does NOT extend `BaseResource`.
|
|
1219
|
+
*/
|
|
1220
|
+
declare class ContactChannelResource {
|
|
1221
|
+
private readonly http;
|
|
1222
|
+
private readonly basePath;
|
|
1223
|
+
constructor(http: HttpClient, contactId: string);
|
|
1224
|
+
/** Returns `{ channel, duplicateOf }` — `duplicateOf` is the dedup signal. */
|
|
1225
|
+
create(data: CreateContactChannelDto): Promise<AddContactChannelResult>;
|
|
1226
|
+
update(channelId: string, data: UpdateContactChannelDto): Promise<ContactChannelDto>;
|
|
1227
|
+
delete(channelId: string): Promise<void>;
|
|
1228
|
+
}
|
|
1229
|
+
declare class ContactResource extends BaseResource<ContactDto, CreateContactDto, UpdateContactDto> {
|
|
1230
|
+
constructor(http: ConstructorParameters<typeof BaseResource>[0]);
|
|
1231
|
+
/**
|
|
1232
|
+
* List contacts. Typed against the real filter schema (customer_id /
|
|
1233
|
+
* property_id / q / sort_by / sort_order / page / limit / include) — the base
|
|
1234
|
+
* `list` would accept any key and let a typo reach the server as a 400.
|
|
1235
|
+
* `include: ['channels', 'links']` attaches each row's channels and active
|
|
1236
|
+
* links in the same response.
|
|
1237
|
+
*/
|
|
1238
|
+
list(params?: ContactListParams): Promise<PaginatedResponse<ContactListItemDto>>;
|
|
1239
|
+
merge(winnerId: string, loserId: string): Promise<ContactMergeResult>;
|
|
1240
|
+
channels(contactId: string): ContactChannelResource;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
/**
|
|
1244
|
+
* Wire shapes for the generic activity/timeline API (E31-F1).
|
|
1245
|
+
*
|
|
1246
|
+
* Mirrors `recordActivitySchema` (write) and `ActivityRecord` (read) in
|
|
1247
|
+
* `packages/shared/src/validation/activity.ts` — both snake_case on the wire.
|
|
1248
|
+
* Types are redefined here (not imported) so the published package carries no
|
|
1249
|
+
* runtime or type dependency on `@blueprint/shared`.
|
|
1250
|
+
*/
|
|
1251
|
+
interface CreateActivityDto {
|
|
1252
|
+
entity_type: string;
|
|
1253
|
+
entity_id?: string | null;
|
|
1254
|
+
/** The contact a channel-targeted send was addressed to, if any. */
|
|
1255
|
+
contact_id?: string | null;
|
|
1256
|
+
source: string;
|
|
1257
|
+
type: string;
|
|
1258
|
+
occurred_at?: string;
|
|
1259
|
+
actor?: string | null;
|
|
1260
|
+
/** Required — a short human-readable description of the event. */
|
|
1261
|
+
summary: string;
|
|
1262
|
+
external_ref?: string | null;
|
|
1263
|
+
match_key?: string | null;
|
|
1264
|
+
payload?: Record<string, unknown>;
|
|
1265
|
+
payload_version?: number;
|
|
1266
|
+
}
|
|
1267
|
+
interface ActivityDto {
|
|
1268
|
+
id: string;
|
|
1269
|
+
type: string;
|
|
1270
|
+
source: string;
|
|
1271
|
+
occurred_at: string;
|
|
1272
|
+
actor: string | null;
|
|
1273
|
+
summary: string;
|
|
1274
|
+
entity_type: string;
|
|
1275
|
+
entity_id: string | null;
|
|
1276
|
+
contact_id: string | null;
|
|
1277
|
+
payload: Record<string, unknown>;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
declare class ActivityResource {
|
|
1281
|
+
private readonly http;
|
|
1282
|
+
constructor(http: HttpClient);
|
|
1283
|
+
create(data: CreateActivityDto): Promise<ActivityDto>;
|
|
1284
|
+
list(params?: ListParams): Promise<PaginatedResponse<ActivityDto>>;
|
|
1285
|
+
listForEntity(entityType: string, entityId: string, params?: ListParams): Promise<PaginatedResponse<ActivityDto>>;
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
/**
|
|
1289
|
+
* Wire shapes for the communications log API (E48-F1).
|
|
1290
|
+
*
|
|
1291
|
+
* Mirrors the schemas in `packages/shared/src/validation/communications.ts`
|
|
1292
|
+
* (logCommunicationSchema, listCommunicationsQuerySchema, linkCommunicationSchema,
|
|
1293
|
+
* CommunicationSummaryDto, CommunicationDto) — all snake_case on the wire.
|
|
1294
|
+
* Types are redefined here (not imported) so the published package carries no
|
|
1295
|
+
* runtime or type dependency on `@blueprint/shared`.
|
|
1296
|
+
*/
|
|
1297
|
+
interface CommunicationAttachmentDto {
|
|
1298
|
+
name: string;
|
|
1299
|
+
mimeType: string;
|
|
1300
|
+
}
|
|
1301
|
+
/** `email` (default) or `call`. */
|
|
1302
|
+
type CommunicationChannel = 'email' | 'call';
|
|
1303
|
+
/** The record levels a communication can be logged against / linked to. */
|
|
1304
|
+
type CommunicationEntityType = 'customer' | 'contact' | 'property' | 'opportunity' | 'job';
|
|
1305
|
+
/** How a logged call ended. */
|
|
1306
|
+
type CallOutcome = 'connected' | 'voicemail' | 'no_answer' | 'busy' | 'left_message';
|
|
1307
|
+
/** A record target: both fields together. */
|
|
1308
|
+
interface CommunicationTarget {
|
|
1309
|
+
entity_type: CommunicationEntityType;
|
|
1310
|
+
entity_id: string;
|
|
1311
|
+
}
|
|
1312
|
+
interface LogCommunicationBase {
|
|
1313
|
+
direction: 'inbound' | 'outbound';
|
|
1314
|
+
summary: string;
|
|
1315
|
+
/** Email body, or call notes. Max 64KB. */
|
|
1316
|
+
body?: string;
|
|
1317
|
+
occurred_at: string;
|
|
1318
|
+
via?: 'agent' | 'bcc' | 'gmail' | 'dropbox' | 'manual';
|
|
1319
|
+
/**
|
|
1320
|
+
* The PRIMARY record to log against (any level). Omit for the legacy
|
|
1321
|
+
* behavior: a customer row via `customer_id` / server-side matching.
|
|
1322
|
+
*/
|
|
1323
|
+
entity_type?: CommunicationEntityType;
|
|
1324
|
+
entity_id?: string;
|
|
1325
|
+
/** Legacy explicit customer link; must agree with `entity_*` when both given. */
|
|
1326
|
+
customer_id?: string;
|
|
1327
|
+
/** The contact this was with (secondary attribution, any target). */
|
|
1328
|
+
contact_id?: string;
|
|
1329
|
+
}
|
|
1330
|
+
/** Log an email: `from` and a non-empty `to` are required. */
|
|
1331
|
+
interface LogEmailCommunicationDto extends LogCommunicationBase {
|
|
1332
|
+
channel?: 'email';
|
|
1333
|
+
from: string;
|
|
1334
|
+
to: string[];
|
|
1335
|
+
cc?: string[];
|
|
1336
|
+
subject?: string;
|
|
1337
|
+
attachments?: CommunicationAttachmentDto[];
|
|
1338
|
+
/** RFC 5322 Message-ID — the dedupe key. Optional (an outbound API send has none). */
|
|
1339
|
+
provider_message_id?: string | null;
|
|
1340
|
+
thread_id?: string;
|
|
1341
|
+
}
|
|
1342
|
+
/** Log a call: no addresses; optional number, duration and outcome. */
|
|
1343
|
+
interface LogCallCommunicationDto extends LogCommunicationBase {
|
|
1344
|
+
channel: 'call';
|
|
1345
|
+
phone_number?: string;
|
|
1346
|
+
/** 0–1440. */
|
|
1347
|
+
duration_minutes?: number;
|
|
1348
|
+
outcome?: CallOutcome;
|
|
1349
|
+
}
|
|
1350
|
+
/**
|
|
1351
|
+
* Input for logging a communication: an email (default channel) or a call.
|
|
1352
|
+
* Mirrors `logCommunicationSchema`.
|
|
1353
|
+
*/
|
|
1354
|
+
type LogCommunicationDto = LogEmailCommunicationDto | LogCallCommunicationDto;
|
|
1355
|
+
/**
|
|
1356
|
+
* Result of logging a communication.
|
|
1357
|
+
* Includes the activity ID, link status, and dedup status.
|
|
1358
|
+
*/
|
|
1359
|
+
interface LogCommunicationResult {
|
|
1360
|
+
activity_id: string;
|
|
1361
|
+
linked: boolean;
|
|
1362
|
+
deduped: boolean;
|
|
1363
|
+
}
|
|
1364
|
+
/**
|
|
1365
|
+
* Query parameters for listing communications with filters and pagination.
|
|
1366
|
+
* Supports filtering by customer, contact, participant email, direction, date range, and link status.
|
|
1367
|
+
*/
|
|
1368
|
+
interface ListCommunicationsParams {
|
|
1369
|
+
channel?: CommunicationChannel;
|
|
1370
|
+
/** Filter by the primary record (any level). */
|
|
1371
|
+
entity_type?: CommunicationEntityType;
|
|
1372
|
+
entity_id?: string;
|
|
1373
|
+
/** Legacy: rows whose primary record is this customer. */
|
|
1374
|
+
customer_id?: string;
|
|
1375
|
+
contact_id?: string;
|
|
1376
|
+
participant?: string;
|
|
1377
|
+
direction?: 'inbound' | 'outbound';
|
|
1378
|
+
linked?: boolean | string;
|
|
1379
|
+
from_date?: string;
|
|
1380
|
+
to_date?: string;
|
|
1381
|
+
cursor?: string;
|
|
1382
|
+
limit?: number;
|
|
1383
|
+
}
|
|
1384
|
+
/**
|
|
1385
|
+
* Keyset-paginated response from list() endpoint.
|
|
1386
|
+
* Uses cursor-based pagination (not offset/limit).
|
|
1387
|
+
*/
|
|
1388
|
+
interface CommunicationsListResponse {
|
|
1389
|
+
data: CommunicationSummaryDto[];
|
|
1390
|
+
cursor: string | null;
|
|
1391
|
+
has_more: boolean;
|
|
1392
|
+
}
|
|
1393
|
+
/**
|
|
1394
|
+
* Summary DTO for a communication (list view).
|
|
1395
|
+
* Includes metadata and excerpt, but not the full body or attachments.
|
|
1396
|
+
*/
|
|
1397
|
+
interface CommunicationSummaryDto {
|
|
1398
|
+
id: string;
|
|
1399
|
+
channel: CommunicationChannel;
|
|
1400
|
+
/** The primary record this row is logged against. */
|
|
1401
|
+
entity_type: string;
|
|
1402
|
+
entity_id: string | null;
|
|
1403
|
+
/** Legacy view: `entity_id` when `entity_type === 'customer'`, else null. */
|
|
1404
|
+
customer_id: string | null;
|
|
1405
|
+
contact_id: string | null;
|
|
1406
|
+
/** True when attached to any record (`entity_id` or `contact_id` set). */
|
|
1407
|
+
linked: boolean;
|
|
1408
|
+
direction: 'inbound' | 'outbound';
|
|
1409
|
+
/** Email only — `''` for a call. */
|
|
1410
|
+
from: string;
|
|
1411
|
+
to: string[];
|
|
1412
|
+
cc: string[];
|
|
1413
|
+
subject: string;
|
|
1414
|
+
summary: string;
|
|
1415
|
+
phone_number: string | null;
|
|
1416
|
+
duration_minutes: number | null;
|
|
1417
|
+
outcome: CallOutcome | null;
|
|
1418
|
+
occurred_at: string;
|
|
1419
|
+
thread_id: string | null;
|
|
1420
|
+
has_attachments: boolean;
|
|
1421
|
+
via: string;
|
|
1422
|
+
/**
|
|
1423
|
+
* The RFC 5322 Message-ID this row was logged/deduped under
|
|
1424
|
+
* (`activity.external_ref`). `CommunicationsService.toSummaryDto` maps a
|
|
1425
|
+
* missing `external_ref` to `''`, never `null` — the field is always a
|
|
1426
|
+
* string on the wire (Gmail Send Phase 1, Task 5 carried parity item).
|
|
1427
|
+
*/
|
|
1428
|
+
provider_message_id: string;
|
|
1429
|
+
}
|
|
1430
|
+
/**
|
|
1431
|
+
* Full DTO for a communication (detail view).
|
|
1432
|
+
* Extends CommunicationSummaryDto with body and attachments.
|
|
1433
|
+
*/
|
|
1434
|
+
interface CommunicationDto extends CommunicationSummaryDto {
|
|
1435
|
+
body: string;
|
|
1436
|
+
attachments: CommunicationAttachmentDto[];
|
|
1437
|
+
}
|
|
1438
|
+
/**
|
|
1439
|
+
* Link (or re-link) a communication to a record. Mirrors
|
|
1440
|
+
* `linkCommunicationSchema`: an `entity_type` + `entity_id` target at any
|
|
1441
|
+
* level, or the legacy `customer_id` / `contact_id`; at least one required.
|
|
1442
|
+
*/
|
|
1443
|
+
interface LinkCommunicationDto {
|
|
1444
|
+
entity_type?: CommunicationEntityType;
|
|
1445
|
+
entity_id?: string;
|
|
1446
|
+
customer_id?: string;
|
|
1447
|
+
contact_id?: string;
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
declare class CommunicationsResource {
|
|
1451
|
+
private readonly http;
|
|
1452
|
+
constructor(http: HttpClient);
|
|
1453
|
+
log(data: LogCommunicationDto): Promise<LogCommunicationResult>;
|
|
1454
|
+
list(params?: ListCommunicationsParams): Promise<CommunicationsListResponse>;
|
|
1455
|
+
get(id: string): Promise<CommunicationDto>;
|
|
1456
|
+
link(id: string, data: LinkCommunicationDto): Promise<CommunicationDto>;
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
/**
|
|
1460
|
+
* E55 — Conversations SDK types. Redefined here (not imported) so the published
|
|
1461
|
+
* package carries no dependency on @blueprint/shared; conversations.spec.ts
|
|
1462
|
+
* asserts parity with the real Zod schemas.
|
|
1463
|
+
*/
|
|
1464
|
+
type ConversationKind = 'meeting';
|
|
1465
|
+
type ConversationMatchStatus = 'matched' | 'needs_review' | 'ignored';
|
|
1466
|
+
type ConversationLinkEntityType = 'customer' | 'opportunity' | 'job';
|
|
1467
|
+
interface ConversationAttendeeDto {
|
|
1468
|
+
name?: string | null;
|
|
1469
|
+
email: string;
|
|
1470
|
+
}
|
|
1471
|
+
interface ConversationActionItemDto {
|
|
1472
|
+
title: string;
|
|
1473
|
+
description?: string | null;
|
|
1474
|
+
assignee_email?: string | null;
|
|
1475
|
+
status?: 'pending' | 'done';
|
|
1476
|
+
}
|
|
1477
|
+
interface LogConversationDto {
|
|
1478
|
+
kind?: ConversationKind;
|
|
1479
|
+
title: string;
|
|
1480
|
+
occurred_at: string;
|
|
1481
|
+
duration_s?: number;
|
|
1482
|
+
summary_md?: string;
|
|
1483
|
+
attendees?: ConversationAttendeeDto[];
|
|
1484
|
+
action_items?: ConversationActionItemDto[];
|
|
1485
|
+
customer_id?: string;
|
|
1486
|
+
calendar_event_id?: string;
|
|
1487
|
+
}
|
|
1488
|
+
interface PatchConversationDto {
|
|
1489
|
+
title?: string;
|
|
1490
|
+
summary_md?: string;
|
|
1491
|
+
action_items?: ConversationActionItemDto[];
|
|
1492
|
+
}
|
|
1493
|
+
interface LinkConversationDto {
|
|
1494
|
+
entity_type: ConversationLinkEntityType;
|
|
1495
|
+
entity_id: string;
|
|
1496
|
+
}
|
|
1497
|
+
type ResolveConversationMatchDto = {
|
|
1498
|
+
action: 'match';
|
|
1499
|
+
customer_id: string;
|
|
1500
|
+
} | {
|
|
1501
|
+
action: 'ignore';
|
|
1502
|
+
};
|
|
1503
|
+
interface InternalDomainsDto {
|
|
1504
|
+
domains: string[];
|
|
1505
|
+
}
|
|
1506
|
+
interface ListConversationsParams {
|
|
1507
|
+
entity_type?: ConversationLinkEntityType;
|
|
1508
|
+
entity_id?: string;
|
|
1509
|
+
match_status?: ConversationMatchStatus;
|
|
1510
|
+
limit?: number;
|
|
1511
|
+
offset?: number;
|
|
1512
|
+
}
|
|
1513
|
+
interface ConversationParticipant {
|
|
1514
|
+
id: string;
|
|
1515
|
+
kind: 'contact' | 'user' | 'unmatched';
|
|
1516
|
+
contact_id: string | null;
|
|
1517
|
+
agent_id: string | null;
|
|
1518
|
+
/**
|
|
1519
|
+
* null either when masked (internal users' emails need Read on Agent) or,
|
|
1520
|
+
* since E57-F2-S1, genuinely null at rest for a name-only attendee.
|
|
1521
|
+
*/
|
|
1522
|
+
name: string | null;
|
|
1523
|
+
email: string | null;
|
|
1524
|
+
role: string | null;
|
|
1525
|
+
}
|
|
1526
|
+
interface ConversationLink {
|
|
1527
|
+
id: string;
|
|
1528
|
+
entity_type: ConversationLinkEntityType;
|
|
1529
|
+
entity_id: string;
|
|
1530
|
+
}
|
|
1531
|
+
/**
|
|
1532
|
+
* E55-F1-S8 — a company that tied when the conversation landed in the review
|
|
1533
|
+
* queue. `name` is null when the caller can't see that candidate (out of
|
|
1534
|
+
* their RLS scope); the id is still listed.
|
|
1535
|
+
*/
|
|
1536
|
+
interface ConversationMatchCandidate {
|
|
1537
|
+
customer_id: string;
|
|
1538
|
+
name: string | null;
|
|
1539
|
+
votes: number;
|
|
1540
|
+
via: 'attendee' | 'domain';
|
|
1541
|
+
}
|
|
1542
|
+
interface Conversation {
|
|
1543
|
+
id: string;
|
|
1544
|
+
kind: ConversationKind;
|
|
1545
|
+
source: string;
|
|
1546
|
+
external_id: string | null;
|
|
1547
|
+
title: string;
|
|
1548
|
+
occurred_at: string;
|
|
1549
|
+
duration_s: number | null;
|
|
1550
|
+
summary_md: string;
|
|
1551
|
+
action_items: ConversationActionItemDto[];
|
|
1552
|
+
provider_insights: Record<string, unknown> | null;
|
|
1553
|
+
has_transcript: boolean;
|
|
1554
|
+
calendar_event_id: string | null;
|
|
1555
|
+
/** E57-F2-S1 — the source provider's meeting URL (e.g. Circleback's `url`). */
|
|
1556
|
+
meeting_url: string | null;
|
|
1557
|
+
match_status: ConversationMatchStatus;
|
|
1558
|
+
match_candidates: ConversationMatchCandidate[];
|
|
1559
|
+
created_at: string;
|
|
1560
|
+
updated_at: string;
|
|
1561
|
+
participants: ConversationParticipant[];
|
|
1562
|
+
links: ConversationLink[];
|
|
1563
|
+
}
|
|
1564
|
+
interface ConversationListItem {
|
|
1565
|
+
id: string;
|
|
1566
|
+
kind: ConversationKind;
|
|
1567
|
+
source: string;
|
|
1568
|
+
title: string;
|
|
1569
|
+
occurred_at: string;
|
|
1570
|
+
duration_s: number | null;
|
|
1571
|
+
meeting_url: string | null;
|
|
1572
|
+
match_status: ConversationMatchStatus;
|
|
1573
|
+
match_candidates: ConversationMatchCandidate[];
|
|
1574
|
+
participant_count: number;
|
|
1575
|
+
links: ConversationLink[];
|
|
1576
|
+
}
|
|
1577
|
+
interface ConversationListResponse {
|
|
1578
|
+
data: ConversationListItem[];
|
|
1579
|
+
total: number;
|
|
1580
|
+
limit: number;
|
|
1581
|
+
offset: number;
|
|
1582
|
+
}
|
|
1583
|
+
interface LogConversationResult {
|
|
1584
|
+
conversation: Conversation;
|
|
1585
|
+
created: boolean;
|
|
1586
|
+
}
|
|
1587
|
+
interface InternalDomainsResult {
|
|
1588
|
+
domains: string[];
|
|
1589
|
+
inferred: boolean;
|
|
1590
|
+
}
|
|
1591
|
+
/**
|
|
1592
|
+
* E57-F2-S4 — the caller's own source connection. Only `disconnect` is
|
|
1593
|
+
* SDK-exposed: `connect` + `callback` are the interactive browser OAuth leg
|
|
1594
|
+
* (authorize redirect → web callback page → POST with the rep's session),
|
|
1595
|
+
* deliberately not an SDK surface.
|
|
1596
|
+
*/
|
|
1597
|
+
type SourceConnectionStatus = 'connected' | 'disconnected' | 'error';
|
|
1598
|
+
interface DisconnectSourceConnectionDto {
|
|
1599
|
+
connectionId: string;
|
|
1600
|
+
}
|
|
1601
|
+
interface SourceConnectionResult {
|
|
1602
|
+
connectionId: string;
|
|
1603
|
+
status: SourceConnectionStatus;
|
|
1604
|
+
}
|
|
1605
|
+
/**
|
|
1606
|
+
* E57-F2-S8 — on-demand sync. `pull` backfills one company from every
|
|
1607
|
+
* active teammate's connected source; `syncNow` runs the caller's own
|
|
1608
|
+
* connection; `syncStatus` reports it (plus a restricted roster for admins).
|
|
1609
|
+
*/
|
|
1610
|
+
interface PullConversationsDto {
|
|
1611
|
+
customer_id: string;
|
|
1612
|
+
}
|
|
1613
|
+
/** `job_ids` (E57-F2-S9): one per connection — pass them to `getPullStatus`. `job_id` is `job_ids[0]`. */
|
|
1614
|
+
interface PullConversationsResult {
|
|
1615
|
+
job_id: string;
|
|
1616
|
+
job_ids: string[];
|
|
1617
|
+
connections: number;
|
|
1618
|
+
}
|
|
1619
|
+
/**
|
|
1620
|
+
* E57-F2-S9 — whether a Pull has finished. `state` aggregates the jobs:
|
|
1621
|
+
* pending if any is pending; else completed if any completed; else skipped if
|
|
1622
|
+
* any skipped; else failed. `missing` counts expired / unknown ids.
|
|
1623
|
+
*/
|
|
1624
|
+
type PullStatusState = 'pending' | 'completed' | 'failed' | 'skipped';
|
|
1625
|
+
interface PullStatusCounts {
|
|
1626
|
+
listed: number;
|
|
1627
|
+
read: number;
|
|
1628
|
+
ingested: number;
|
|
1629
|
+
duplicate: number;
|
|
1630
|
+
skipped_no_match: number;
|
|
1631
|
+
skipped_internal: number;
|
|
1632
|
+
malformed: number;
|
|
1633
|
+
}
|
|
1634
|
+
interface PullStatus {
|
|
1635
|
+
state: PullStatusState;
|
|
1636
|
+
jobs: {
|
|
1637
|
+
pending: number;
|
|
1638
|
+
completed: number;
|
|
1639
|
+
failed: number;
|
|
1640
|
+
skipped: number;
|
|
1641
|
+
missing: number;
|
|
1642
|
+
};
|
|
1643
|
+
/** Summed over the finished runs; absent until one reports counts. */
|
|
1644
|
+
counts?: PullStatusCounts;
|
|
1645
|
+
}
|
|
1646
|
+
interface SyncNowResult {
|
|
1647
|
+
job_id: string;
|
|
1648
|
+
connection_id: string;
|
|
1649
|
+
}
|
|
1650
|
+
type ConversationSyncErrorClass = 'owner_deactivated' | 'auth_expired' | 'rate_limited' | 'upstream_error' | 'outbound_disabled' | 'malformed_item' | 'internal_error';
|
|
1651
|
+
interface ConversationSyncStatusMine {
|
|
1652
|
+
connection_id: string;
|
|
1653
|
+
status: SourceConnectionStatus;
|
|
1654
|
+
last_run_at: string | null;
|
|
1655
|
+
last_success_at: string | null;
|
|
1656
|
+
last_error_class: ConversationSyncErrorClass | null;
|
|
1657
|
+
last_counts: Record<string, number>;
|
|
1658
|
+
backoff_until: string | null;
|
|
1659
|
+
}
|
|
1660
|
+
/** Admin roster row: exactly these four fields — never an account id or email. */
|
|
1661
|
+
interface ConversationSyncRosterItem {
|
|
1662
|
+
agent_id: string;
|
|
1663
|
+
name: string | null;
|
|
1664
|
+
status: SourceConnectionStatus;
|
|
1665
|
+
last_success_at: string | null;
|
|
1666
|
+
}
|
|
1667
|
+
interface ConversationSyncStatus {
|
|
1668
|
+
mine: ConversationSyncStatusMine | null;
|
|
1669
|
+
has_sources: boolean;
|
|
1670
|
+
/** Present only for a caller who can Update Tenant (an admin). */
|
|
1671
|
+
roster?: ConversationSyncRosterItem[];
|
|
1672
|
+
}
|
|
1673
|
+
/**
|
|
1674
|
+
* E57-F4-S1 — a synced meeting's transcript, fetched LIVE from the meeting
|
|
1675
|
+
* recorder through the connection that synced it; Planes never stores it.
|
|
1676
|
+
* `timestamp` is the segment start in seconds. `segments: []` means the
|
|
1677
|
+
* recorder has no transcript for the meeting yet (not an error).
|
|
1678
|
+
*/
|
|
1679
|
+
interface TranscriptSegment {
|
|
1680
|
+
speaker: string | null;
|
|
1681
|
+
text: string;
|
|
1682
|
+
timestamp: number | null;
|
|
1683
|
+
}
|
|
1684
|
+
interface ConversationTranscript {
|
|
1685
|
+
segments: TranscriptSegment[];
|
|
1686
|
+
}
|
|
1687
|
+
/** `owner` (default): only the rep whose recorder synced the meeting. `viewers`: anyone who can see the conversation. */
|
|
1688
|
+
type TranscriptAccessMode = 'owner' | 'viewers';
|
|
1689
|
+
interface TranscriptAccess {
|
|
1690
|
+
transcript_access: TranscriptAccessMode;
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
/** E55 — client conversations (meetings): log, list, link, review-queue resolve. */
|
|
1694
|
+
declare class ConversationsResource {
|
|
1695
|
+
private readonly http;
|
|
1696
|
+
constructor(http: HttpClient);
|
|
1697
|
+
log(data: LogConversationDto): Promise<LogConversationResult>;
|
|
1698
|
+
list(params?: ListConversationsParams): Promise<ConversationListResponse>;
|
|
1699
|
+
/** The review queue: `list()` pinned to `match_status: 'needs_review'`. */
|
|
1700
|
+
reviewQueue(params?: Omit<ListConversationsParams, 'match_status'>): Promise<ConversationListResponse>;
|
|
1701
|
+
get(id: string): Promise<Conversation>;
|
|
1702
|
+
update(id: string, data: PatchConversationDto): Promise<Conversation>;
|
|
1703
|
+
delete(id: string): Promise<void>;
|
|
1704
|
+
link(id: string, data: LinkConversationDto): Promise<Conversation>;
|
|
1705
|
+
unlink(id: string, linkId: string): Promise<Conversation>;
|
|
1706
|
+
resolve(id: string, data: ResolveConversationMatchDto): Promise<Conversation>;
|
|
1707
|
+
getInternalDomains(): Promise<InternalDomainsResult>;
|
|
1708
|
+
/** Requires an admin: the server checks `Update` on `Subject.Tenant` (tenant-wide matching config), not `Subject.Conversation`. */
|
|
1709
|
+
setInternalDomains(data: InternalDomainsDto): Promise<InternalDomainsResult>;
|
|
1710
|
+
/**
|
|
1711
|
+
* E57-F2-S4 — disconnect the CALLER's own Circleback connection (Update
|
|
1712
|
+
* Conversation). Another user's connection id is a 404. Connecting is the
|
|
1713
|
+
* interactive browser OAuth flow (Settings → Conversations), not an SDK call.
|
|
1714
|
+
*/
|
|
1715
|
+
disconnectCircleback(data: DisconnectSourceConnectionDto): Promise<SourceConnectionResult>;
|
|
1716
|
+
/**
|
|
1717
|
+
* E57-F2-S8 — pull one company's meetings from every active teammate's
|
|
1718
|
+
* connected source (Update Conversation). 202, runs in the background.
|
|
1719
|
+
* 404 for a company you can't see; 409 `NO_SOURCES` when nobody has one.
|
|
1720
|
+
*/
|
|
1721
|
+
pull(data: PullConversationsDto): Promise<PullConversationsResult>;
|
|
1722
|
+
/**
|
|
1723
|
+
* E57-F2-S9 — whether a Pull has finished: pass the `job_ids` `pull()`
|
|
1724
|
+
* returned (1–50). Update Conversation, like `pull()`. 404
|
|
1725
|
+
* `PULL_NOT_FOUND` when none of them is readable (expired after ~2h,
|
|
1726
|
+
* unknown) — treat that as settled.
|
|
1727
|
+
*/
|
|
1728
|
+
getPullStatus(jobIds: readonly string[]): Promise<PullStatus>;
|
|
1729
|
+
/** E57-F2-S8 — sync the caller's OWN Circleback connection now (deduplicated). 409 `NO_CONNECTION` when they have none. */
|
|
1730
|
+
syncNow(): Promise<SyncNowResult>;
|
|
1731
|
+
/** E57-F2-S8 — the caller's own connection, `has_sources`, and (admins only) the roster. */
|
|
1732
|
+
syncStatus(): Promise<ConversationSyncStatus>;
|
|
1733
|
+
/**
|
|
1734
|
+
* E57-F4-S1 — a synced meeting's transcript, fetched live from the meeting
|
|
1735
|
+
* recorder (never stored by Planes; the response is `Cache-Control:
|
|
1736
|
+
* no-store`). Read Conversation, plus the tenant's transcript-access rule:
|
|
1737
|
+
* 403 `TRANSCRIPT_OWNER_ONLY` under `owner` for a non-owner; 409
|
|
1738
|
+
* `TRANSCRIPT_SOURCE_UNAVAILABLE` (`owner_name` says who must reconnect) or
|
|
1739
|
+
* `TRANSCRIPT_NOT_AVAILABLE` (not a synced meeting); 404 when you can't see
|
|
1740
|
+
* the conversation. `segments: []` = no transcript yet.
|
|
1741
|
+
*/
|
|
1742
|
+
getTranscript(id: string): Promise<ConversationTranscript>;
|
|
1743
|
+
/** E57-F4-S1 — who can view transcripts: `owner` (default) or `viewers`. Read Conversation. */
|
|
1744
|
+
getTranscriptAccess(): Promise<TranscriptAccess>;
|
|
1745
|
+
/** E57-F4-S1 — requires an admin: the server checks `Update` on `Subject.Tenant`. */
|
|
1746
|
+
setTranscriptAccess(value: TranscriptAccessMode): Promise<TranscriptAccess>;
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
/**
|
|
1750
|
+
* Wire shapes for the Gmail send API (Gmail Send Phase 1, Task 4/5).
|
|
1751
|
+
*
|
|
1752
|
+
* Mirrors `sendGmailSchema` / `SendGmailResultDto` in
|
|
1753
|
+
* `packages/shared/src/validation/gmail-send.ts` and the actual return of
|
|
1754
|
+
* `GmailSendService.send()` (`apps/api/src/modules/integrations/google/surfaces/gmail/gmail-send.service.ts`,
|
|
1755
|
+
* `GmailSendResult`). Types are redefined here (not imported) so the
|
|
1756
|
+
* published package carries no runtime or type dependency on
|
|
1757
|
+
* `@blueprint/shared`.
|
|
1758
|
+
*/
|
|
1759
|
+
/**
|
|
1760
|
+
* Input for sending an email from the connected user's real Gmail address.
|
|
1761
|
+
* `to`/`cc` accept at most 10 combined recipients (enforced server-side);
|
|
1762
|
+
* `reply_to_communication_id` threads the send off a prior communication
|
|
1763
|
+
* (`In-Reply-To`/`References`) via `GmailSendService`'s reply-mode.
|
|
1764
|
+
*/
|
|
1765
|
+
interface SendGmailDto {
|
|
1766
|
+
to: string[];
|
|
1767
|
+
cc?: string[];
|
|
1768
|
+
subject: string;
|
|
1769
|
+
body: string;
|
|
1770
|
+
reply_to_communication_id?: string;
|
|
1771
|
+
/**
|
|
1772
|
+
* Optional: which of the caller's connected Gmail accounts to send from
|
|
1773
|
+
* (its account email address). Absent sends from the caller's primary
|
|
1774
|
+
* gmail-enabled connection (unchanged prior behavior).
|
|
1775
|
+
*/
|
|
1776
|
+
from?: string;
|
|
1777
|
+
}
|
|
1778
|
+
/**
|
|
1779
|
+
* Result of a successful Gmail send: the logged communication's activity id and
|
|
1780
|
+
* Gmail's own thread id.
|
|
1781
|
+
*
|
|
1782
|
+
* `provider_message_id` is `null` for outbound sends — Gmail asserts its OWN
|
|
1783
|
+
* RFC 5322 Message-ID and discards the one we put in the MIME, and we cannot
|
|
1784
|
+
* read the real one back under the `gmail.send` scope, so there is no real id
|
|
1785
|
+
* to return (and we NEVER return our `<uuid>@planescrm.com` correlation id).
|
|
1786
|
+
* `thread_id` is Gmail's conversation id — the authoritative threading key
|
|
1787
|
+
* (reply grouping keys on it, not on a Message-ID).
|
|
1788
|
+
*/
|
|
1789
|
+
interface SendGmailResult {
|
|
1790
|
+
communication_id: string;
|
|
1791
|
+
provider_message_id: string | null;
|
|
1792
|
+
thread_id: string;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
declare class GmailResource {
|
|
1796
|
+
private readonly http;
|
|
1797
|
+
constructor(http: HttpClient);
|
|
1798
|
+
/**
|
|
1799
|
+
* Send an email RIGHT NOW from the connected user's real Gmail address.
|
|
1800
|
+
* Hits `POST /admin/integrations/google/gmail/send` — final per Task 4
|
|
1801
|
+
* (`apps/api/src/modules/integrations/google/google-connection.controller.ts`).
|
|
1802
|
+
*/
|
|
1803
|
+
send(data: SendGmailDto): Promise<SendGmailResult>;
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
/**
|
|
1807
|
+
* Wire shapes for the documents API (Drive Rung 0 — external references).
|
|
1808
|
+
*
|
|
1809
|
+
* Input mirrors `attachExternalDocumentSchema` in
|
|
1810
|
+
* `packages/shared/src/validation/document.ts` (snake_case on the wire).
|
|
1811
|
+
* Responses are the documents API's existing `DocumentDto` (camelCase — it
|
|
1812
|
+
* predates the snake_case convention; transcribed from
|
|
1813
|
+
* DocumentsService.toDto), extended with externalUrl/externalProvider.
|
|
1814
|
+
* Types are redefined here so the published package carries no dependency
|
|
1815
|
+
* on `@blueprint/shared`.
|
|
1816
|
+
*/
|
|
1817
|
+
type DocumentEntityType = 'opportunity' | 'customer' | 'job' | 'estimate';
|
|
1818
|
+
type DocumentKind = 'image' | 'document';
|
|
1819
|
+
/** Body for POST /documents/external. */
|
|
1820
|
+
interface AttachExternalDocumentDto {
|
|
1821
|
+
entity_type: DocumentEntityType;
|
|
1822
|
+
entity_id: string;
|
|
1823
|
+
/** Becomes the document's fileName (max 255). */
|
|
1824
|
+
title: string;
|
|
1825
|
+
/** Absolute https:// link, max 2048 chars. Stored as data; never fetched by the server. */
|
|
1826
|
+
url: string;
|
|
1827
|
+
/** Lowercase snake_case provider tag. Default 'google_drive'. */
|
|
1828
|
+
provider?: string;
|
|
1829
|
+
/** Default 'text/uri-list'. */
|
|
1830
|
+
mime_type?: string;
|
|
1831
|
+
/** Default 'document'. */
|
|
1832
|
+
kind?: DocumentKind;
|
|
1833
|
+
}
|
|
1834
|
+
/** A document row — uploaded blob OR external link (exactly one). */
|
|
1835
|
+
interface DocumentDto {
|
|
1836
|
+
id: string;
|
|
1837
|
+
entityType: string;
|
|
1838
|
+
entityId: string;
|
|
1839
|
+
customerId: string | null;
|
|
1840
|
+
fileName: string;
|
|
1841
|
+
mimeType: string;
|
|
1842
|
+
sizeBytes: number;
|
|
1843
|
+
kind: DocumentKind;
|
|
1844
|
+
uploadedBy: string | null;
|
|
1845
|
+
createdAt: string;
|
|
1846
|
+
/** Set for external rows; open it directly — there is no download URL for these. */
|
|
1847
|
+
externalUrl: string | null;
|
|
1848
|
+
externalProvider: string | null;
|
|
1849
|
+
}
|
|
1850
|
+
/** GET /:entityType/:entityId/documents — plain list, not keyset-paginated. */
|
|
1851
|
+
interface DocumentsListResponse {
|
|
1852
|
+
data: DocumentDto[];
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
declare class DocumentsResource {
|
|
1856
|
+
private readonly http;
|
|
1857
|
+
constructor(http: HttpClient);
|
|
1858
|
+
/** Attach an external (link-only) document — e.g. a Google Drive link — to a record. */
|
|
1859
|
+
attachExternal(data: AttachExternalDocumentDto): Promise<DocumentDto>;
|
|
1860
|
+
/** Documents filed directly on one record (uploaded + external), newest first. */
|
|
1861
|
+
listForEntity(entityType: DocumentEntityType, entityId: string): Promise<DocumentsListResponse>;
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
/**
|
|
1865
|
+
* Wire shapes for the Tags & entity-tagging API.
|
|
1866
|
+
*
|
|
1867
|
+
* Mirrors `createTagSchema`/`updateTagSchema`/`setEntityTagsSchema` in
|
|
1868
|
+
* `packages/shared/src/validation/tags.ts`, plus `TagsService`'s actual
|
|
1869
|
+
* response shapes — snake_case, per `toDto()`/`list()`. Types are redefined
|
|
1870
|
+
* here (not imported) so the published package carries no runtime or type
|
|
1871
|
+
* dependency on `@blueprint/shared`.
|
|
1872
|
+
*/
|
|
1873
|
+
interface TagDto {
|
|
1874
|
+
id: string;
|
|
1875
|
+
name: string;
|
|
1876
|
+
color: string | null;
|
|
1877
|
+
created_at: string;
|
|
1878
|
+
updated_at: string;
|
|
1879
|
+
/** Only present on `list()` — `create()`/`update()` omit it. */
|
|
1880
|
+
usage_count?: number;
|
|
1881
|
+
}
|
|
1882
|
+
interface CreateTagDto {
|
|
1883
|
+
name: string;
|
|
1884
|
+
color?: string | null;
|
|
1885
|
+
}
|
|
1886
|
+
interface UpdateTagDto {
|
|
1887
|
+
name?: string;
|
|
1888
|
+
color?: string | null;
|
|
1889
|
+
}
|
|
1890
|
+
/**
|
|
1891
|
+
* Declarative set-tags input. Provide `tag_ids` and/or `tag_names` — at least
|
|
1892
|
+
* one must be present (the server rejects neither); an empty array clears
|
|
1893
|
+
* that side of the set.
|
|
1894
|
+
*/
|
|
1895
|
+
interface SetEntityTagsDto {
|
|
1896
|
+
tag_ids?: string[];
|
|
1897
|
+
tag_names?: string[];
|
|
1898
|
+
}
|
|
1899
|
+
interface EntityTagDto {
|
|
1900
|
+
id: string;
|
|
1901
|
+
name: string;
|
|
1902
|
+
color: string | null;
|
|
1903
|
+
}
|
|
1904
|
+
interface TagEntityDto {
|
|
1905
|
+
entity_type: string;
|
|
1906
|
+
entity_id: string;
|
|
1907
|
+
}
|
|
1908
|
+
interface TagEntitiesPage {
|
|
1909
|
+
data: TagEntityDto[];
|
|
1910
|
+
page: number;
|
|
1911
|
+
limit: number;
|
|
1912
|
+
total: number;
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
/**
|
|
1916
|
+
* Tags. There is no single-tag read: `list()` returns every tag (with usage
|
|
1917
|
+
* counts), and `getEntities()` pages through the records carrying one.
|
|
1918
|
+
*/
|
|
1919
|
+
declare class TagResource extends ApiResource {
|
|
1920
|
+
constructor(http: ConstructorParameters<typeof ApiResource>[0]);
|
|
1921
|
+
/** GET /tags */
|
|
1922
|
+
list(params?: ListParams): Promise<PaginatedResponse<TagDto>>;
|
|
1923
|
+
/** POST /tags — 409 on a case-insensitive duplicate name. */
|
|
1924
|
+
create(data: CreateTagDto): Promise<TagDto>;
|
|
1925
|
+
/** PATCH /tags/:id — rename / recolor; 409 on a case-insensitive duplicate name. */
|
|
1926
|
+
update(id: string, data: UpdateTagDto): Promise<TagDto>;
|
|
1927
|
+
/** DELETE /tags/:id — cascades the tag off every record. */
|
|
1928
|
+
delete(id: string): Promise<void>;
|
|
1929
|
+
/** `TagsService.setEntityTags()` returns the final tag set wrapped in `{ tags }`. */
|
|
1930
|
+
setEntityTags(entityType: string, entityId: string, data: SetEntityTagsDto): Promise<{
|
|
1931
|
+
tags: TagDto[];
|
|
1932
|
+
}>;
|
|
1933
|
+
getEntityTags(entityType: string, entityId: string): Promise<EntityTagDto[]>;
|
|
1934
|
+
getEntities(tagId: string, params?: Record<string, unknown>): Promise<TagEntitiesPage>;
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
/**
|
|
1938
|
+
* Wire shapes for the Tasks API (`/api/v1/tasks`, E41-F3).
|
|
1939
|
+
*
|
|
1940
|
+
* Mirrors `createTaskSchema` / `patchTaskSchema` / `listTasksQuerySchema` in
|
|
1941
|
+
* `packages/shared/src/validation/tasks.ts` plus `TasksService.TaskDto`'s
|
|
1942
|
+
* actual response shape — snake_case, Date columns serialised as ISO strings.
|
|
1943
|
+
* Types are redefined here (not imported) so the published package carries no
|
|
1944
|
+
* runtime or type dependency on `@blueprint/shared`; `tasks.spec.ts` asserts
|
|
1945
|
+
* every request body against the REAL shared zod schema.
|
|
1946
|
+
*/
|
|
1947
|
+
|
|
1948
|
+
type TaskStatus = 'open' | 'in_progress' | 'completed' | 'cancelled';
|
|
1949
|
+
type TaskPriority = 'low' | 'normal' | 'high' | 'urgent';
|
|
1950
|
+
/** Records a task can hang off (polymorphic link). */
|
|
1951
|
+
type TaskEntityType = 'customer' | 'opportunity' | 'job' | 'contract' | 'calendar_event';
|
|
1952
|
+
type TaskAssigneeType = 'agent' | 'team';
|
|
1953
|
+
/** One assignee to put on a task (an agent or a whole team). */
|
|
1954
|
+
interface TaskAssigneeInput {
|
|
1955
|
+
assignee_type: TaskAssigneeType;
|
|
1956
|
+
assignee_id: string;
|
|
1957
|
+
role_label?: string | null;
|
|
1958
|
+
}
|
|
1959
|
+
/** One assignee as read back — with the agent's display name / team's name. */
|
|
1960
|
+
interface TaskAssigneeDto {
|
|
1961
|
+
assignee_type: TaskAssigneeType;
|
|
1962
|
+
assignee_id: string;
|
|
1963
|
+
role_label: string | null;
|
|
1964
|
+
display_name: string | null;
|
|
1965
|
+
}
|
|
1966
|
+
interface TaskDto {
|
|
1967
|
+
id: string;
|
|
1968
|
+
org_path: string;
|
|
1969
|
+
title: string;
|
|
1970
|
+
description: string | null;
|
|
1971
|
+
status: TaskStatus;
|
|
1972
|
+
priority: TaskPriority;
|
|
1973
|
+
due_at: string | null;
|
|
1974
|
+
entity_type: string | null;
|
|
1975
|
+
entity_id: string | null;
|
|
1976
|
+
/** Parent opportunity id for a job/contract-linked task (nested detail route). */
|
|
1977
|
+
entity_parent_id: string | null;
|
|
1978
|
+
completion_transition_id: string | null;
|
|
1979
|
+
source: string;
|
|
1980
|
+
created_by: string | null;
|
|
1981
|
+
completed_by: string | null;
|
|
1982
|
+
completed_at: string | null;
|
|
1983
|
+
created_at: string;
|
|
1984
|
+
updated_at: string;
|
|
1985
|
+
/** Always present — empty when unassigned. */
|
|
1986
|
+
assignees: TaskAssigneeDto[];
|
|
1987
|
+
}
|
|
1988
|
+
/**
|
|
1989
|
+
* `POST /tasks/:id/complete` (E46-F6-S8): the completed task plus whether its
|
|
1990
|
+
* "on complete" transition ran. The task completes whatever the outcome; a
|
|
1991
|
+
* `failed` trigger also notifies the tenant's admins. Same shape as the
|
|
1992
|
+
* calendar event completion's `workflow_trigger`.
|
|
1993
|
+
*/
|
|
1994
|
+
interface CompletedTaskDto extends TaskDto {
|
|
1995
|
+
workflow_trigger: CompletionWorkflowTrigger;
|
|
1996
|
+
}
|
|
1997
|
+
interface CreateTaskDto {
|
|
1998
|
+
title: string;
|
|
1999
|
+
description?: string | null;
|
|
2000
|
+
/** Defaults to 'normal'. */
|
|
2001
|
+
priority?: TaskPriority;
|
|
2002
|
+
/** ISO 8601. */
|
|
2003
|
+
due_at?: string | null;
|
|
2004
|
+
/** Provide entity_type and entity_id together. */
|
|
2005
|
+
entity_type?: TaskEntityType | null;
|
|
2006
|
+
entity_id?: string | null;
|
|
2007
|
+
/**
|
|
2008
|
+
* Transition to run when the task is completed. Needs a linked record and
|
|
2009
|
+
* must belong to its pipeline (else 422 COMPLETION_TRANSITION_WRONG_PIPELINE).
|
|
2010
|
+
*/
|
|
2011
|
+
completion_transition_id?: string | null;
|
|
2012
|
+
/** Up to 50. */
|
|
2013
|
+
assignees?: TaskAssigneeInput[];
|
|
2014
|
+
}
|
|
2015
|
+
/**
|
|
2016
|
+
* PATCH edits an active task. `status` may only nudge between the two
|
|
2017
|
+
* non-terminal states — completion/cancellation/reopen are explicit actions
|
|
2018
|
+
* (`complete()`, `cancel()`, `reopen()`). `assignees`, when present, is the
|
|
2019
|
+
* FULL desired set (replace-set); `[]` clears every assignee; omit to leave
|
|
2020
|
+
* assignees untouched.
|
|
2021
|
+
*/
|
|
2022
|
+
interface UpdateTaskDto {
|
|
2023
|
+
title?: string;
|
|
2024
|
+
description?: string | null;
|
|
2025
|
+
priority?: TaskPriority;
|
|
2026
|
+
/** ISO 8601. */
|
|
2027
|
+
due_at?: string | null;
|
|
2028
|
+
status?: 'open' | 'in_progress';
|
|
2029
|
+
assignees?: TaskAssigneeInput[];
|
|
2030
|
+
/**
|
|
2031
|
+
* Transition to run when the task is completed (E46-F6-S8). Must belong to
|
|
2032
|
+
* the linked record's pipeline (else 422 COMPLETION_TRANSITION_WRONG_PIPELINE).
|
|
2033
|
+
* `null` clears it; omit to leave it unchanged.
|
|
2034
|
+
*/
|
|
2035
|
+
completion_transition_id?: string | null;
|
|
2036
|
+
}
|
|
2037
|
+
interface ListTasksParams {
|
|
2038
|
+
status?: TaskStatus;
|
|
2039
|
+
priority?: TaskPriority;
|
|
2040
|
+
/** `'me'` unions tasks assigned directly + via a team the caller belongs to. */
|
|
2041
|
+
assignee?: 'me';
|
|
2042
|
+
/** One specific agent or team — provide together with `assignee_type`. */
|
|
2043
|
+
assignee_id?: string;
|
|
2044
|
+
assignee_type?: TaskAssigneeType;
|
|
2045
|
+
/** `true` → only tasks with no assignee. */
|
|
2046
|
+
unassigned?: boolean;
|
|
2047
|
+
entity_type?: TaskEntityType;
|
|
2048
|
+
entity_id?: string;
|
|
2049
|
+
/** ISO 8601. */
|
|
2050
|
+
due_before?: string;
|
|
2051
|
+
/** ISO 8601. */
|
|
2052
|
+
due_after?: string;
|
|
2053
|
+
overdue?: boolean;
|
|
2054
|
+
/** 1–500, default 100. */
|
|
2055
|
+
limit?: number;
|
|
2056
|
+
offset?: number;
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
/**
|
|
2060
|
+
* Tasks — the free-core to-do module (`/api/v1/tasks`). `list()` returns a
|
|
2061
|
+
* BARE array (the controller does not wrap in `{ data, meta }`); paginate with
|
|
2062
|
+
* `limit`/`offset`. Terminal status changes go through the explicit action
|
|
2063
|
+
* methods, never `update()`. There is no delete: a task is cancelled
|
|
2064
|
+
* (`cancel()`), and `reopen()` brings it back.
|
|
2065
|
+
*/
|
|
2066
|
+
declare class TaskResource extends ApiResource {
|
|
2067
|
+
constructor(http: ConstructorParameters<typeof ApiResource>[0]);
|
|
2068
|
+
list(params?: ListTasksParams): Promise<TaskDto[]>;
|
|
2069
|
+
/** GET /tasks/:id */
|
|
2070
|
+
get(id: string): Promise<TaskDto>;
|
|
2071
|
+
/** POST /tasks */
|
|
2072
|
+
create(data: CreateTaskDto): Promise<TaskDto>;
|
|
2073
|
+
/** PATCH /tasks/:id — non-terminal fields only; terminal status changes use the action methods. */
|
|
2074
|
+
update(id: string, data: UpdateTaskDto): Promise<TaskDto>;
|
|
2075
|
+
/**
|
|
2076
|
+
* POST /tasks/:id/complete — fires the linked workflow transition (best-effort).
|
|
2077
|
+
* The task always completes; `workflow_trigger` says whether the next step ran.
|
|
2078
|
+
*/
|
|
2079
|
+
complete(id: string): Promise<CompletedTaskDto>;
|
|
2080
|
+
/** POST /tasks/:id/cancel */
|
|
2081
|
+
cancel(id: string): Promise<TaskDto>;
|
|
2082
|
+
/** POST /tasks/:id/reopen — the sanctioned resurrect of a completed/cancelled task. */
|
|
2083
|
+
reopen(id: string): Promise<TaskDto>;
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
/**
|
|
2087
|
+
* Wire shapes for record views (`/api/v1/record-views`, E41-F7) — the
|
|
2088
|
+
* per-user "recently viewed" primitive behind `sort_by: 'recent'` on the
|
|
2089
|
+
* customer / contact / opportunity / job lists.
|
|
2090
|
+
*
|
|
2091
|
+
* Mirrors `recordViewSchema` / `recentRecordViewsQuerySchema` in
|
|
2092
|
+
* `packages/shared/src/validation/record-view.ts`. Redefined here (not
|
|
2093
|
+
* imported) so the published package carries no dependency on
|
|
2094
|
+
* `@blueprint/shared`; `record-views.spec.ts` asserts every request against the
|
|
2095
|
+
* REAL shared schema.
|
|
2096
|
+
*/
|
|
2097
|
+
/** Root records whose detail views are counted (kept in lockstep with the server by the wire spec). */
|
|
2098
|
+
declare const RECORD_VIEW_ENTITY_TYPES: readonly ["customer", "contact", "opportunity", "job"];
|
|
2099
|
+
type RecordViewEntityType = (typeof RECORD_VIEW_ENTITY_TYPES)[number];
|
|
2100
|
+
/** Body of `POST /record-views`. The viewer is always the authenticated user. */
|
|
2101
|
+
interface RecordViewInput {
|
|
2102
|
+
entity_type: RecordViewEntityType;
|
|
2103
|
+
entity_id: string;
|
|
2104
|
+
}
|
|
2105
|
+
/** Query of `GET /record-views/recent`. `limit` defaults to 10 on the server, max 50. */
|
|
2106
|
+
interface RecentRecordViewsParams {
|
|
2107
|
+
entity_type?: RecordViewEntityType;
|
|
2108
|
+
limit?: number;
|
|
2109
|
+
}
|
|
2110
|
+
/** One row of `GET /record-views/recent`, newest first. */
|
|
2111
|
+
interface RecentRecordView {
|
|
2112
|
+
entity_type: RecordViewEntityType;
|
|
2113
|
+
entity_id: string;
|
|
2114
|
+
/** ISO timestamp of the caller's most recent view. */
|
|
2115
|
+
viewed_at: string;
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
/**
|
|
2119
|
+
* Record views (`/api/v1/record-views`, E41-F7) — "recently viewed". Not a
|
|
2120
|
+
* CRUD resource (no id, no get/update/delete), so it does NOT extend
|
|
2121
|
+
* `BaseResource`.
|
|
2122
|
+
*
|
|
2123
|
+
* `touch()` is the idempotent beacon a UI sends when a record opens; the server
|
|
2124
|
+
* keeps one row per user × record and answers 204 even for an id that no
|
|
2125
|
+
* longer exists. `recent()` is the caller's newest views. Views feed
|
|
2126
|
+
* `sort_by: 'recent'` on `customers.list` / `contacts.list` /
|
|
2127
|
+
* `opportunities.list` / `jobs.listForOpportunity`.
|
|
2128
|
+
*/
|
|
2129
|
+
declare class RecordViewsResource {
|
|
2130
|
+
private readonly http;
|
|
2131
|
+
private readonly basePath;
|
|
2132
|
+
constructor(http: HttpClient);
|
|
2133
|
+
/** POST /record-views — record that the calling user opened this record. Resolves on 204. */
|
|
2134
|
+
touch(input: RecordViewInput): Promise<void>;
|
|
2135
|
+
/** GET /record-views/recent — the calling user's most recently viewed records, newest first. */
|
|
2136
|
+
recent(params?: RecentRecordViewsParams): Promise<RecentRecordView[]>;
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2139
|
+
/**
|
|
2140
|
+
* Wire shapes for tenant module status (`GET /api/v1/modules`, E51-F1-S1).
|
|
2141
|
+
*
|
|
2142
|
+
* Mirrors `tenantModuleStatusSchema` / `MODULE_KEYS` in `packages/shared`.
|
|
2143
|
+
* Redefined here (not imported) so the published package carries no dependency
|
|
2144
|
+
* on `@blueprint/shared`; `modules.spec.ts` asserts key parity and parses the
|
|
2145
|
+
* response with the REAL shared schema.
|
|
2146
|
+
*/
|
|
2147
|
+
/** 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"];
|
|
2149
|
+
type ModuleKey = (typeof MODULE_KEYS)[number];
|
|
2150
|
+
/** One entry of `GET /modules` — whether a module is on for the caller's tenant. */
|
|
2151
|
+
interface TenantModuleStatusDto {
|
|
2152
|
+
moduleKey: ModuleKey;
|
|
2153
|
+
/** `false` both for an explicitly deactivated module and one never activated. */
|
|
2154
|
+
isActive: boolean;
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
/**
|
|
2158
|
+
* Module status (`/api/v1/modules`, E51-F1-S1) — which modules are active for
|
|
2159
|
+
* the caller's tenant. Readable by every role; read-only (activating a module
|
|
2160
|
+
* is an admin action on `/admin/modules`, deliberately not exposed here). Not a
|
|
2161
|
+
* CRUD resource, so it does NOT extend `BaseResource`.
|
|
2162
|
+
*/
|
|
2163
|
+
declare class ModulesResource {
|
|
2164
|
+
private readonly http;
|
|
2165
|
+
private readonly basePath;
|
|
2166
|
+
constructor(http: HttpClient);
|
|
2167
|
+
/** GET /modules — one entry per registered module key, in canonical order. */
|
|
2168
|
+
list(): Promise<TenantModuleStatusDto[]>;
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
/**
|
|
2172
|
+
* Wire shapes for the tenant's plan (`GET /api/v1/plan`, E54-F1-S2).
|
|
2173
|
+
*
|
|
2174
|
+
* Mirrors `tenantPlanSchema` and the plan enums in `packages/shared`
|
|
2175
|
+
* (`features/plans.ts`, `features/feature-keys.ts`). Redefined here (not
|
|
2176
|
+
* imported) so the published package carries no dependency on
|
|
2177
|
+
* `@blueprint/shared`; `plan.spec.ts` asserts enum parity and parses the
|
|
2178
|
+
* response with the REAL shared schema.
|
|
2179
|
+
*/
|
|
2180
|
+
|
|
2181
|
+
declare const PLAN_KEYS: readonly ["solo", "sales", "business", "operations", "legacy", "internal"];
|
|
2182
|
+
type PlanKey = (typeof PLAN_KEYS)[number];
|
|
2183
|
+
declare const BILLING_STATUSES: readonly ["trialing", "active", "past_due", "unpaid", "paused", "canceled", "comped"];
|
|
2184
|
+
type BillingStatus = (typeof BILLING_STATUSES)[number];
|
|
2185
|
+
declare const PLAN_SOURCES: readonly ["stripe", "manual"];
|
|
2186
|
+
type PlanSource = (typeof PLAN_SOURCES)[number];
|
|
2187
|
+
declare const BILLING_INTERVALS: readonly ["month", "year"];
|
|
2188
|
+
type BillingInterval = (typeof BILLING_INTERVALS)[number];
|
|
2189
|
+
/** Every feature-flag key a plan ceiling can include, in the server's order. */
|
|
2190
|
+
declare const FEATURE_KEYS: readonly ["calendar", "estimates", "contracts", "service_dispatch", "production_scheduling", "sub_management", "reports", "open_api", "workflow_builder", "integrations.quickbooks", "integrations.stripe", "integrations.hover", "integrations.ortto", "communications.marketing", "ai.scheduling", "ai.content_assist", "ai.documents", "ai.search", "inventory_management", "workflow_execution", "marketplace"];
|
|
2191
|
+
type FeatureKey = (typeof FEATURE_KEYS)[number];
|
|
2192
|
+
/** `GET /plan` — the caller tenant's plan, billing state and plan ceiling. */
|
|
2193
|
+
interface TenantPlanDto {
|
|
2194
|
+
planKey: PlanKey;
|
|
2195
|
+
/** Display name, e.g. "Business". */
|
|
2196
|
+
label: string;
|
|
2197
|
+
billingStatus: BillingStatus;
|
|
2198
|
+
/** Who last set the plan: `stripe` (subscription webhook) or `manual` (Planes staff). */
|
|
2199
|
+
planSource: PlanSource;
|
|
2200
|
+
/** ISO-8601, or null when not trialing. */
|
|
2201
|
+
trialEndsAt: string | null;
|
|
2202
|
+
billingInterval: BillingInterval | null;
|
|
2203
|
+
/** ISO-8601 end of a price lock (Founding Fleet), or null. */
|
|
2204
|
+
priceLockedUntil: string | null;
|
|
2205
|
+
/** Module keys the plan may enable (a ceiling, not what is switched on). */
|
|
2206
|
+
modules: ModuleKey[];
|
|
2207
|
+
/** Feature keys the plan may enable. */
|
|
2208
|
+
features: FeatureKey[];
|
|
2209
|
+
includedFullSeats: number;
|
|
2210
|
+
crewSeatsAllowed: boolean;
|
|
2211
|
+
monthlyAiCredits: number;
|
|
2212
|
+
storageGb: number;
|
|
2213
|
+
}
|
|
2214
|
+
|
|
2215
|
+
/**
|
|
2216
|
+
* The caller tenant's plan (`/api/v1/plan`, E54-F1-S2). Readable by every role;
|
|
2217
|
+
* read-only — plans change through Stripe-hosted billing in Settings → Billing,
|
|
2218
|
+
* deliberately not through the API. Not a CRUD resource, so it does NOT extend
|
|
2219
|
+
* `BaseResource`.
|
|
2220
|
+
*/
|
|
2221
|
+
declare class PlanResource {
|
|
2222
|
+
private readonly http;
|
|
2223
|
+
private readonly basePath;
|
|
2224
|
+
constructor(http: HttpClient);
|
|
2225
|
+
/** GET /plan — plan, billing status and the plan's ceiling. */
|
|
2226
|
+
get(): Promise<TenantPlanDto>;
|
|
2227
|
+
}
|
|
2228
|
+
|
|
2229
|
+
/**
|
|
2230
|
+
* Wire shapes for `GET /api/v1/me/abilities` (E52-F1-S3).
|
|
2231
|
+
*
|
|
2232
|
+
* Mirrors `meAbilitiesResponseSchema` / `AGENT_ROLES` in `packages/shared`.
|
|
2233
|
+
* Redefined here (not imported) so the published package carries no dependency
|
|
2234
|
+
* on `@blueprint/shared`; `me.spec.ts` asserts role parity and parses the
|
|
2235
|
+
* response with the REAL shared schema.
|
|
2236
|
+
*/
|
|
2237
|
+
/** Every built-in role, in the server's canonical order. */
|
|
2238
|
+
declare const AGENT_ROLES: readonly ["admin", "sales", "service", "production", "sub", "readonly", "system_agent"];
|
|
2239
|
+
type AgentRole = (typeof AGENT_ROLES)[number];
|
|
2240
|
+
/**
|
|
2241
|
+
* One CASL packed rule (`packRules` from `@casl/ability/extra`):
|
|
2242
|
+
* `[action, subject, conditions|0, inverted 1|0, fields|0, reason]`, trailing
|
|
2243
|
+
* empty slots trimmed. Rebuild the ability with
|
|
2244
|
+
* `createMongoAbility(unpackRules(rules))`.
|
|
2245
|
+
*/
|
|
2246
|
+
type PackedAbilityRule = [string, string] | [string, string, Record<string, unknown>] | [string, string, Record<string, unknown> | 0, 1] | [string, string, Record<string, unknown> | 0, 1 | 0, string] | [string, string, Record<string, unknown> | 0, 1 | 0, string | 0, string];
|
|
2247
|
+
/** `GET /me/abilities` — the caller's effective ability. */
|
|
2248
|
+
interface MeAbilitiesResponse {
|
|
2249
|
+
/** Live role (session), key role (API key) or token role (service token). */
|
|
2250
|
+
role: AgentRole;
|
|
2251
|
+
/** API keys only: the acting agent's live role; `rules` are the intersection. */
|
|
2252
|
+
actingRole?: AgentRole;
|
|
2253
|
+
/** Same value as the `X-Planes-Abilities-Version` response header. Opaque — compare, don't parse. */
|
|
2254
|
+
version: string;
|
|
2255
|
+
/** The exact rules the server enforces for this caller, CASL-packed. */
|
|
2256
|
+
rules: PackedAbilityRule[];
|
|
2257
|
+
}
|
|
2258
|
+
|
|
2259
|
+
/**
|
|
2260
|
+
* The authenticated caller (`/api/v1/me/*`, E52-F1-S3). Any principal may read
|
|
2261
|
+
* its own abilities; not a CRUD resource, so it does NOT extend `BaseResource`.
|
|
2262
|
+
*/
|
|
2263
|
+
declare class MeResource {
|
|
2264
|
+
private readonly http;
|
|
2265
|
+
private readonly basePath;
|
|
2266
|
+
constructor(http: HttpClient);
|
|
2267
|
+
/**
|
|
2268
|
+
* GET /me/abilities — the caller's effective ability: for an API key, the key
|
|
2269
|
+
* role intersected with its acting agent's live role (`actingRole`).
|
|
2270
|
+
*/
|
|
2271
|
+
abilities(): Promise<MeAbilitiesResponse>;
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
/**
|
|
2275
|
+
* Wire shapes for Settings → Roles (`/api/v1/roles`, E52-F2-S3/S4/S5).
|
|
2276
|
+
*
|
|
2277
|
+
* Mirrors `roleSummarySchema`, `roleDetailSchema`, `updateRoleGrantsRequestSchema`
|
|
2278
|
+
* and `roleHistoryPageSchema` in `packages/shared/src/auth/roles-api.ts`.
|
|
2279
|
+
* Redefined here (not imported) so the published package carries no dependency
|
|
2280
|
+
* on `@blueprint/shared`; `roles.spec.ts` parses every request body with the
|
|
2281
|
+
* REAL shared request schema and every response fixture with the REAL
|
|
2282
|
+
* response schemas, so drift fails there rather than as a production 400.
|
|
2283
|
+
*/
|
|
2284
|
+
|
|
2285
|
+
/** Every role Settings → Roles shows (all built-in roles but `system_agent`). */
|
|
2286
|
+
type RoleKey = Exclude<AgentRole, 'system_agent'>;
|
|
2287
|
+
/** The roles whose grants can be changed (`admin` never is). */
|
|
2288
|
+
type TunableRole = Exclude<RoleKey, 'admin'>;
|
|
2289
|
+
/** A cell's stored state: `default` = no change from the Planes default. */
|
|
2290
|
+
type GrantEffect = 'allow' | 'deny' | 'default';
|
|
2291
|
+
/** `shell` and `company` cells are locked; `financial` needs confirmation to grant. */
|
|
2292
|
+
type GrantTier = 'shell' | 'record' | 'financial' | 'company';
|
|
2293
|
+
/** `GET /roles` row. */
|
|
2294
|
+
interface RoleSummaryDto {
|
|
2295
|
+
key: RoleKey;
|
|
2296
|
+
label: string;
|
|
2297
|
+
tunable: boolean;
|
|
2298
|
+
/** Active users with this role. */
|
|
2299
|
+
userCount: number;
|
|
2300
|
+
/** Cells changed from the Planes default. */
|
|
2301
|
+
changeCount: number;
|
|
2302
|
+
}
|
|
2303
|
+
interface RoleListResponse {
|
|
2304
|
+
data: RoleSummaryDto[];
|
|
2305
|
+
}
|
|
2306
|
+
/** One (action × subject) cell of the matrix. */
|
|
2307
|
+
interface RoleCellDto {
|
|
2308
|
+
/** e.g. `read`, `create`, `update`, `delete`, `approve`, `mark_paid`. */
|
|
2309
|
+
action: string;
|
|
2310
|
+
/** e.g. `Customer`, `Invoice`, `Paysheet`. */
|
|
2311
|
+
subject: string;
|
|
2312
|
+
/** The role holds it now. */
|
|
2313
|
+
value: boolean;
|
|
2314
|
+
/** The Planes built-in value. */
|
|
2315
|
+
default: boolean;
|
|
2316
|
+
tier: GrantTier;
|
|
2317
|
+
/** Can't be toggled (shell/company tier, a long-standing default, or admin). */
|
|
2318
|
+
locked: boolean;
|
|
2319
|
+
}
|
|
2320
|
+
interface RoleRowDto {
|
|
2321
|
+
/** The subject-catalog row id, e.g. `customers`. */
|
|
2322
|
+
rowId: string;
|
|
2323
|
+
cells: RoleCellDto[];
|
|
2324
|
+
}
|
|
2325
|
+
/** `GET /roles/:key`, and the response of every write. */
|
|
2326
|
+
interface RoleDetailDto {
|
|
2327
|
+
key: RoleKey;
|
|
2328
|
+
label: string;
|
|
2329
|
+
tunable: boolean;
|
|
2330
|
+
/** One sentence, e.g. "Can create and edit Customers …; can't delete Customers." */
|
|
2331
|
+
summary: string;
|
|
2332
|
+
/** The tenant's grant version — send it back as `baseVersion` to detect concurrent edits. */
|
|
2333
|
+
version: string;
|
|
2334
|
+
rows: RoleRowDto[];
|
|
2335
|
+
}
|
|
2336
|
+
/** One sparse change in `PUT /roles/:key/grants`. */
|
|
2337
|
+
interface RoleGrantChange {
|
|
2338
|
+
action: string;
|
|
2339
|
+
subject: string;
|
|
2340
|
+
effect: GrantEffect;
|
|
2341
|
+
}
|
|
2342
|
+
/** `PUT /roles/:key/grants` body. */
|
|
2343
|
+
interface UpdateRoleGrantsBody {
|
|
2344
|
+
/** 1–200 changes, at most one per (action, subject). */
|
|
2345
|
+
changes: RoleGrantChange[];
|
|
2346
|
+
/** Required (`true`) with `reason` when a change grants a money action. */
|
|
2347
|
+
confirm?: boolean;
|
|
2348
|
+
/** Required with `confirm` when a change grants a money action (≤ 500 chars). */
|
|
2349
|
+
reason?: string;
|
|
2350
|
+
/** The `version` the edit was based on; a newer server version is a 409. */
|
|
2351
|
+
baseVersion?: string;
|
|
2352
|
+
}
|
|
2353
|
+
/** `GET /roles/history` query. */
|
|
2354
|
+
interface RoleHistoryParams {
|
|
2355
|
+
role?: TunableRole;
|
|
2356
|
+
/** The previous page's `cursor`. */
|
|
2357
|
+
cursor?: string;
|
|
2358
|
+
/** 1–100 (server default 50). */
|
|
2359
|
+
limit?: number;
|
|
2360
|
+
}
|
|
2361
|
+
interface RoleHistoryEntryDto {
|
|
2362
|
+
id: string;
|
|
2363
|
+
/** Null when the platform made the change. */
|
|
2364
|
+
actorAgentId: string | null;
|
|
2365
|
+
actorName: string | null;
|
|
2366
|
+
roleKey: TunableRole;
|
|
2367
|
+
action: string;
|
|
2368
|
+
subject: string;
|
|
2369
|
+
before: GrantEffect;
|
|
2370
|
+
after: GrantEffect;
|
|
2371
|
+
reason: string | null;
|
|
2372
|
+
createdAt: string;
|
|
2373
|
+
}
|
|
2374
|
+
/** Cursor page, newest first. */
|
|
2375
|
+
interface RoleHistoryPage {
|
|
2376
|
+
data: RoleHistoryEntryDto[];
|
|
2377
|
+
cursor: string | null;
|
|
2378
|
+
has_more: boolean;
|
|
2379
|
+
}
|
|
2380
|
+
|
|
2381
|
+
/**
|
|
2382
|
+
* Settings → Roles (`/api/v1/roles`, E52-F2). Admin only: reads need Read
|
|
2383
|
+
* RolePermission and writes Update RolePermission, which only admins hold —
|
|
2384
|
+
* any other caller gets a 403 `FORBIDDEN_BY_ROLE`. Not a CRUD resource, so it
|
|
2385
|
+
* does NOT extend `BaseResource`.
|
|
2386
|
+
*/
|
|
2387
|
+
declare class RolesResource {
|
|
2388
|
+
private readonly http;
|
|
2389
|
+
private readonly basePath;
|
|
2390
|
+
constructor(http: HttpClient);
|
|
2391
|
+
/** GET /roles — every role (not `system_agent`) with user and change counts. */
|
|
2392
|
+
list(): Promise<RoleListResponse>;
|
|
2393
|
+
/** GET /roles/:key — one role's permission matrix, summary and grant version. */
|
|
2394
|
+
get(key: RoleKey): Promise<RoleDetailDto>;
|
|
2395
|
+
/**
|
|
2396
|
+
* PUT /roles/:key/grants — sparse per-cell changes, all validated before any
|
|
2397
|
+
* is written. 422 `GRANT_REQUIRED` / `GRANT_NOT_DELEGABLE` for locked cells,
|
|
2398
|
+
* `CONFIRMATION_REQUIRED` when a money action is granted without
|
|
2399
|
+
* `confirm: true` + `reason`, `ROLE_NOT_TUNABLE` for admin; 409
|
|
2400
|
+
* `ROLE_VERSION_CONFLICT` on a stale `baseVersion`. Returns the updated role.
|
|
2401
|
+
*/
|
|
2402
|
+
updateGrants(key: TunableRole, body: UpdateRoleGrantsBody): Promise<RoleDetailDto>;
|
|
2403
|
+
/** DELETE /roles/:key/grants — back to the Planes defaults. Returns the reset role. */
|
|
2404
|
+
reset(key: TunableRole): Promise<RoleDetailDto>;
|
|
2405
|
+
/** GET /roles/history — the change log, newest first; page with `cursor`. */
|
|
2406
|
+
history(params?: RoleHistoryParams): Promise<RoleHistoryPage>;
|
|
2407
|
+
}
|
|
2408
|
+
|
|
2409
|
+
/** Body and response of `admin/invoice-settings/offline-instructions`. */
|
|
2410
|
+
interface OfflineInstructionsDto {
|
|
2411
|
+
instructions: string | null;
|
|
2412
|
+
}
|
|
2413
|
+
/** Body and response of `admin/invoice-settings/overdue-offsets` (E56-F8-S2). */
|
|
2414
|
+
interface OverdueOffsetsDto {
|
|
2415
|
+
/** Days after the due date at which `invoice.overdue` fires, ascending. */
|
|
2416
|
+
offsets: number[];
|
|
2417
|
+
}
|
|
2418
|
+
/** Body and response of `admin/invoice-settings/attach-pdf` (E56-F6-S2). */
|
|
2419
|
+
interface AttachPdfSettingDto {
|
|
2420
|
+
enabled: boolean;
|
|
2421
|
+
}
|
|
2422
|
+
/**
|
|
2423
|
+
* Per-tenant invoice settings (`/api/v1/admin/invoice-settings`, E56-F5-S4).
|
|
2424
|
+
* Reads need Read Invoice; writes need Update Tenant (admin only) — any other
|
|
2425
|
+
* caller gets a 403 `FORBIDDEN_BY_ROLE`. Not a CRUD resource, so it does NOT
|
|
2426
|
+
* extend `BaseResource`.
|
|
2427
|
+
*/
|
|
2428
|
+
declare class InvoiceSettingsResource {
|
|
2429
|
+
private readonly http;
|
|
2430
|
+
private readonly basePath;
|
|
2431
|
+
constructor(http: HttpClient);
|
|
2432
|
+
/**
|
|
2433
|
+
* GET /admin/invoice-settings/offline-instructions — the plain-text
|
|
2434
|
+
* instructions shown on the pay page when online payment is unavailable,
|
|
2435
|
+
* or null when none are set.
|
|
2436
|
+
*/
|
|
2437
|
+
getOfflineInstructions(): Promise<string | null>;
|
|
2438
|
+
/**
|
|
2439
|
+
* PUT /admin/invoice-settings/offline-instructions — store plain text
|
|
2440
|
+
* (trimmed, at most 2,000 characters); null or blank clears it. Returns the
|
|
2441
|
+
* stored value.
|
|
2442
|
+
*/
|
|
2443
|
+
setOfflineInstructions(text: string | null): Promise<string | null>;
|
|
2444
|
+
/**
|
|
2445
|
+
* GET /admin/invoice-settings/overdue-offsets — the days after the due date
|
|
2446
|
+
* at which `invoice.overdue` fires, ascending (default `[3, 7, 14]`).
|
|
2447
|
+
*/
|
|
2448
|
+
getOverdueOffsets(): Promise<number[]>;
|
|
2449
|
+
/**
|
|
2450
|
+
* PUT /admin/invoice-settings/overdue-offsets — replace the offsets: 1 to 5
|
|
2451
|
+
* unique whole days, each 1–90. Returns them sorted ascending. Admin only.
|
|
2452
|
+
*/
|
|
2453
|
+
setOverdueOffsets(offsets: number[]): Promise<number[]>;
|
|
2454
|
+
/**
|
|
2455
|
+
* GET /admin/invoice-settings/attach-pdf — whether invoice emails carry the
|
|
2456
|
+
* invoice PDF (on unless an admin turned it off).
|
|
2457
|
+
*/
|
|
2458
|
+
getAttachPdf(): Promise<boolean>;
|
|
2459
|
+
/**
|
|
2460
|
+
* PUT /admin/invoice-settings/attach-pdf — turn the PDF attachment on
|
|
2461
|
+
* invoice emails on or off. Returns the stored value.
|
|
2462
|
+
*/
|
|
2463
|
+
setAttachPdf(enabled: boolean): Promise<boolean>;
|
|
2464
|
+
}
|
|
2465
|
+
|
|
2466
|
+
/** Who a reminder rule emails about: every overdue invoice, or recurring ones only. */
|
|
2467
|
+
type InvoiceReminderAppliesTo = 'all' | 'recurring_only';
|
|
2468
|
+
/**
|
|
2469
|
+
* One rule as sent to `invoiceReminders.update()` (mirrors the shared
|
|
2470
|
+
* `invoiceReminderRuleSchema` input; the spec parses the captured body with it).
|
|
2471
|
+
*/
|
|
2472
|
+
interface InvoiceReminderRuleInputDto {
|
|
2473
|
+
/** Days past due the reminder sends at, 1–90, unique across the set. */
|
|
2474
|
+
offsetDays: number;
|
|
2475
|
+
enabled: boolean;
|
|
2476
|
+
/** Plain text, ≤ 200 chars. Placeholders: see `update()`. */
|
|
2477
|
+
subject: string;
|
|
2478
|
+
/** Plain text, ≤ 5,000 chars. */
|
|
2479
|
+
body: string;
|
|
2480
|
+
/** Defaults to `'all'`. */
|
|
2481
|
+
appliesTo?: InvoiceReminderAppliesTo;
|
|
2482
|
+
}
|
|
2483
|
+
/** A stored rule (mirrors `invoiceReminderRuleResponseSchema`). */
|
|
2484
|
+
interface InvoiceReminderRuleDto {
|
|
2485
|
+
offsetDays: number;
|
|
2486
|
+
enabled: boolean;
|
|
2487
|
+
subject: string;
|
|
2488
|
+
body: string;
|
|
2489
|
+
appliesTo: InvoiceReminderAppliesTo;
|
|
2490
|
+
/** The offset is not in the overdue offsets, so this rule never sends. */
|
|
2491
|
+
willNeverFire: boolean;
|
|
2492
|
+
}
|
|
2493
|
+
/** GET / PUT `admin/invoice-reminders` (mirrors `invoiceReminderSettingsSchema`). */
|
|
2494
|
+
interface InvoiceReminderSettingsDto {
|
|
2495
|
+
rules: InvoiceReminderRuleDto[];
|
|
2496
|
+
/** The days past due the overdue sweep fires at (`invoiceSettings.getOverdueOffsets()`). */
|
|
2497
|
+
overdueOffsets: number[];
|
|
2498
|
+
}
|
|
2499
|
+
/** Body of `invoiceReminders.preview()` (mirrors `invoiceReminderPreviewSchema`). */
|
|
2500
|
+
interface InvoiceReminderPreviewParams {
|
|
2501
|
+
subject: string;
|
|
2502
|
+
body: string;
|
|
2503
|
+
/** Render against this invoice; omit for a sample invoice. */
|
|
2504
|
+
invoiceId?: string;
|
|
2505
|
+
}
|
|
2506
|
+
/** What a reminder would send (mirrors `invoiceReminderPreviewResultSchema`). */
|
|
2507
|
+
interface InvoiceReminderPreviewDto {
|
|
2508
|
+
subject: string;
|
|
2509
|
+
body: string;
|
|
2510
|
+
/** True when rendered against the sample invoice. */
|
|
2511
|
+
sample: boolean;
|
|
2512
|
+
}
|
|
2513
|
+
/**
|
|
2514
|
+
* Payment reminder settings (`/api/v1/admin/invoice-reminders`, E56-F8-S6).
|
|
2515
|
+
* Admin only (Update Tenant) — reads included; anyone else gets a 403
|
|
2516
|
+
* `FORBIDDEN_BY_ROLE`. Not a CRUD resource, so it does NOT extend `BaseResource`.
|
|
2517
|
+
*/
|
|
2518
|
+
declare class InvoiceRemindersResource {
|
|
2519
|
+
private readonly http;
|
|
2520
|
+
private readonly basePath;
|
|
2521
|
+
constructor(http: HttpClient);
|
|
2522
|
+
/** GET /admin/invoice-reminders — the rules, ascending by offset, and the overdue offsets. */
|
|
2523
|
+
list(): Promise<InvoiceReminderSettingsDto>;
|
|
2524
|
+
/**
|
|
2525
|
+
* PUT /admin/invoice-reminders — replace the WHOLE rule set (a rule left out
|
|
2526
|
+
* is deleted): up to 5 rules at unique offsets. Templates may use only
|
|
2527
|
+
* `{{customerName}}`, `{{invoiceNumber}}`, `{{amountDue}}`, `{{total}}`,
|
|
2528
|
+
* `{{dueDate}}`, `{{daysOverdue}}` and `{{companyName}}`; any other is a 422
|
|
2529
|
+
* `REMINDER_TEMPLATE_INVALID` listing each one. Returns the stored set.
|
|
2530
|
+
*/
|
|
2531
|
+
update(rules: InvoiceReminderRuleInputDto[]): Promise<InvoiceReminderSettingsDto>;
|
|
2532
|
+
/**
|
|
2533
|
+
* POST /admin/invoice-reminders/preview — render a subject and body exactly
|
|
2534
|
+
* as the reminder email would, against an invoice or a sample. Sends nothing.
|
|
2535
|
+
*/
|
|
2536
|
+
preview(params: InvoiceReminderPreviewParams): Promise<InvoiceReminderPreviewDto>;
|
|
2537
|
+
}
|
|
2538
|
+
|
|
2539
|
+
/**
|
|
2540
|
+
* Wire shapes for enrollable sequences (`GET /api/v1/contact-sequences`,
|
|
2541
|
+
* E51-F2-S6).
|
|
2542
|
+
*
|
|
2543
|
+
* Mirrors `contactSequenceSchema` / `contactSequenceListResponseSchema` in
|
|
2544
|
+
* `packages/shared`. Redefined here (not imported) so the published package
|
|
2545
|
+
* carries no dependency on `@blueprint/shared`; `contact-sequences.spec.ts`
|
|
2546
|
+
* parses the response with the REAL shared schema.
|
|
2547
|
+
*/
|
|
2548
|
+
/** A published sequence a contact can be enrolled in. */
|
|
2549
|
+
interface ContactSequenceDto {
|
|
2550
|
+
/** Lineage root id — pass as `workflow_id` when enrolling a contact. */
|
|
2551
|
+
id: string;
|
|
2552
|
+
name: string;
|
|
2553
|
+
description: string | null;
|
|
2554
|
+
}
|
|
2555
|
+
/** `GET /contact-sequences` envelope — name-sorted, at most 100 rows. */
|
|
2556
|
+
interface ContactSequenceListResponse {
|
|
2557
|
+
data: ContactSequenceDto[];
|
|
2558
|
+
meta: {
|
|
2559
|
+
total: number;
|
|
2560
|
+
};
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
/**
|
|
2564
|
+
* Enrollable sequences (`/api/v1/contact-sequences`, E51-F2-S6) — the published
|
|
2565
|
+
* contact sequences in the caller's tenant, readable by any role that can enroll
|
|
2566
|
+
* a contact. Read-only (authoring sequences stays on the admin workflow API). Not
|
|
2567
|
+
* a CRUD resource, so it does NOT extend `BaseResource`.
|
|
2568
|
+
*/
|
|
2569
|
+
declare class ContactSequencesResource {
|
|
2570
|
+
private readonly http;
|
|
2571
|
+
private readonly basePath;
|
|
2572
|
+
constructor(http: HttpClient);
|
|
2573
|
+
/** GET /contact-sequences — `{ data, meta: { total } }`, name-sorted, max 100. */
|
|
2574
|
+
list(): Promise<ContactSequenceListResponse>;
|
|
2575
|
+
}
|
|
2576
|
+
|
|
2577
|
+
/**
|
|
2578
|
+
* Wire shapes for contact sequence enrollments (E51-F2-S8):
|
|
2579
|
+
* `POST /contacts/:id/enrollments`, `GET /contacts/:id/enrollments`,
|
|
2580
|
+
* `POST /enrollments/:id/exit`.
|
|
2581
|
+
*
|
|
2582
|
+
* Mirrors `enrollContactBodySchema` / `enrollmentStatusQuerySchema` /
|
|
2583
|
+
* `contactEnrollmentSchema` / `contactEnrollmentListItemSchema` in
|
|
2584
|
+
* `packages/shared` (which the API pins to the real ContactEnrollmentsService
|
|
2585
|
+
* return shapes). Redefined here (not imported) so the published package carries
|
|
2586
|
+
* no dependency on `@blueprint/shared`; `enrollments.spec.ts` validates requests
|
|
2587
|
+
* and fixtures with the REAL shared schemas.
|
|
2588
|
+
*/
|
|
2589
|
+
type EnrollmentStatus = 'active' | 'completed' | 'exited';
|
|
2590
|
+
/** Enrollment provenance — `{ type: 'manual' | 'tag_added' | 'list_joined', tag_id?, list_id? }`. */
|
|
2591
|
+
interface EnrollmentTrigger {
|
|
2592
|
+
type: string;
|
|
2593
|
+
[key: string]: unknown;
|
|
2594
|
+
}
|
|
2595
|
+
/** An enrollment row — returned by `enroll()` and `exit()`. */
|
|
2596
|
+
interface ContactEnrollmentDto {
|
|
2597
|
+
id: string;
|
|
2598
|
+
tenantId: string;
|
|
2599
|
+
contactId: string;
|
|
2600
|
+
/** Sequence lineage root — the `workflow_id` it was enrolled with. */
|
|
2601
|
+
workflowParentId: string;
|
|
2602
|
+
trigger: EnrollmentTrigger;
|
|
2603
|
+
status: EnrollmentStatus;
|
|
2604
|
+
/** Set when exited (`'manual'`, `'opted_out'`, `'goal_met'`, ...). */
|
|
2605
|
+
exitReason: string | null;
|
|
2606
|
+
createdAt: string;
|
|
2607
|
+
endedAt: string | null;
|
|
2608
|
+
}
|
|
2609
|
+
/** One row of `list()` — the enrollment plus its sequence name and current stage. */
|
|
2610
|
+
interface ContactEnrollmentListItemDto {
|
|
2611
|
+
id: string;
|
|
2612
|
+
contactId: string;
|
|
2613
|
+
workflowParentId: string;
|
|
2614
|
+
trigger: EnrollmentTrigger;
|
|
2615
|
+
status: EnrollmentStatus;
|
|
2616
|
+
exitReason: string | null;
|
|
2617
|
+
createdAt: string;
|
|
2618
|
+
endedAt: string | null;
|
|
2619
|
+
currentStageId: string | null;
|
|
2620
|
+
currentStageName: string | null;
|
|
2621
|
+
sequenceName: string | null;
|
|
2622
|
+
}
|
|
2623
|
+
interface ListEnrollmentsParams {
|
|
2624
|
+
status?: EnrollmentStatus;
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2627
|
+
/**
|
|
2628
|
+
* Contact sequence enrollments (E51-F2-S8) — enroll a contact in a sequence, list
|
|
2629
|
+
* its enrollments, and manually exit one. Pick the sequence with
|
|
2630
|
+
* `client.contactSequences.list()`; its `id` is the `workflowId` here. Not a CRUD
|
|
2631
|
+
* resource, so it does NOT extend `BaseResource`.
|
|
2632
|
+
*/
|
|
2633
|
+
declare class EnrollmentsResource {
|
|
2634
|
+
private readonly http;
|
|
2635
|
+
constructor(http: HttpClient);
|
|
2636
|
+
/**
|
|
2637
|
+
* POST /contacts/:id/enrollments — `{ workflow_id }`. 409 if the contact is
|
|
2638
|
+
* already active in the sequence; 422 if the sequence has no published version.
|
|
2639
|
+
*/
|
|
2640
|
+
enroll(contactId: string, workflowId: string): Promise<ContactEnrollmentDto>;
|
|
2641
|
+
/** GET /contacts/:id/enrollments — a bare array, newest first; optional `status` filter. */
|
|
2642
|
+
list(contactId: string, params?: ListEnrollmentsParams): Promise<ContactEnrollmentListItemDto[]>;
|
|
2643
|
+
/**
|
|
2644
|
+
* POST /enrollments/:id/exit — no body; the exit reason is recorded as
|
|
2645
|
+
* `'manual'`. Idempotent: an already-ended enrollment is returned unchanged.
|
|
2646
|
+
*/
|
|
2647
|
+
exit(enrollmentId: string): Promise<ContactEnrollmentDto>;
|
|
2648
|
+
}
|
|
2649
|
+
|
|
2650
|
+
/**
|
|
2651
|
+
* Wire shapes for a workflow's event rules on the admin workflow API
|
|
2652
|
+
* (`/api/v1/admin/workflows/:workflowId/event-rules`) — "advance this record
|
|
2653
|
+
* automatically when a related contract / invoice / calendar event changes".
|
|
2654
|
+
*
|
|
2655
|
+
* Mirrors `workflow-event-rule.ts` in `packages/shared`. Redefined here (not
|
|
2656
|
+
* imported) so the published package carries no dependency on
|
|
2657
|
+
* `@blueprint/shared`; `workflow-event-rule-types.parity.ts` fails the build
|
|
2658
|
+
* when the two drift, and `workflow-event-rules.spec.ts` parses every sent body
|
|
2659
|
+
* with the REAL shared schemas.
|
|
2660
|
+
*/
|
|
2661
|
+
/**
|
|
2662
|
+
* Event types a rule can route on. Must equal the shared
|
|
2663
|
+
* `WORKFLOW_EVENT_RULE_EVENT_TYPES`, in order — the parity check and the spec
|
|
2664
|
+
* both pin it.
|
|
2665
|
+
*/
|
|
2666
|
+
declare const WORKFLOW_EVENT_RULE_EVENT_TYPES: readonly ["contract.status_changed", "invoice.status_changed", "calendar_event.status_changed", "calendar_event.created"];
|
|
2667
|
+
type WorkflowEventRuleEventType = (typeof WORKFLOW_EVENT_RULE_EVENT_TYPES)[number];
|
|
2668
|
+
/**
|
|
2669
|
+
* Event types whose event carries no `changes` (a creation), so the only
|
|
2670
|
+
* matcher that can match is `when: {}`.
|
|
2671
|
+
*/
|
|
2672
|
+
declare const WORKFLOW_EVENT_RULE_MATCH_ALL_EVENT_TYPES: readonly WorkflowEventRuleEventType[];
|
|
2673
|
+
/**
|
|
2674
|
+
* Equality matcher over the event's `changes` map:
|
|
2675
|
+
* `{ status: { new: 'sent' } }` matches an event whose
|
|
2676
|
+
* `changes.status.new === 'sent'`. Each entry must name `old`, `new` or both
|
|
2677
|
+
* (an entry naming neither is a 400); `{}` matches every event of the type.
|
|
2678
|
+
*/
|
|
2679
|
+
type WorkflowEventRuleWhen = Record<string, {
|
|
2680
|
+
old?: unknown;
|
|
2681
|
+
new?: unknown;
|
|
2682
|
+
}>;
|
|
2683
|
+
/**
|
|
2684
|
+
* The transition to fire, by stage NAME, resolved against whichever workflow
|
|
2685
|
+
* version the record is pinned to — so a rule survives a version publish.
|
|
2686
|
+
*/
|
|
2687
|
+
interface WorkflowTransitionRef {
|
|
2688
|
+
from_stage_name: string;
|
|
2689
|
+
to_stage_name: string;
|
|
2690
|
+
}
|
|
2691
|
+
/** Body of `POST /admin/workflows/:workflowId/event-rules`. */
|
|
2692
|
+
interface CreateWorkflowEventRuleInput {
|
|
2693
|
+
eventType: WorkflowEventRuleEventType;
|
|
2694
|
+
/** Defaults to `{}` (every event of the type). */
|
|
2695
|
+
when?: WorkflowEventRuleWhen | undefined;
|
|
2696
|
+
transitionRef: WorkflowTransitionRef;
|
|
2697
|
+
/** Defaults to true. */
|
|
2698
|
+
enabled?: boolean | undefined;
|
|
2699
|
+
}
|
|
2700
|
+
/** Body of `PATCH /admin/workflows/:workflowId/event-rules/:id` — at least one field; only the fields sent change. */
|
|
2701
|
+
interface UpdateWorkflowEventRuleInput {
|
|
2702
|
+
eventType?: WorkflowEventRuleEventType | undefined;
|
|
2703
|
+
when?: WorkflowEventRuleWhen | undefined;
|
|
2704
|
+
transitionRef?: WorkflowTransitionRef | undefined;
|
|
2705
|
+
enabled?: boolean | undefined;
|
|
2706
|
+
}
|
|
2707
|
+
/**
|
|
2708
|
+
* An event rule as the admin API returns it (list, create, update) — exactly
|
|
2709
|
+
* the shared `WorkflowEventRuleDto`. 0.53.0 dropped `tenantId`, `createdBy` and
|
|
2710
|
+
* `deletedAt`, which the server no longer sends.
|
|
2711
|
+
*/
|
|
2712
|
+
interface WorkflowEventRuleDto {
|
|
2713
|
+
id: string;
|
|
2714
|
+
/** The workflow's LINEAGE ROOT id — the same for every version of one pipeline. */
|
|
2715
|
+
workflowId: string;
|
|
2716
|
+
/** TEXT on the server, so a rule stored with a newer type still reads back. */
|
|
2717
|
+
eventType: string;
|
|
2718
|
+
when: WorkflowEventRuleWhen;
|
|
2719
|
+
transitionRef: WorkflowTransitionRef;
|
|
2720
|
+
enabled: boolean;
|
|
2721
|
+
createdAt: string;
|
|
2722
|
+
updatedAt: string;
|
|
2723
|
+
}
|
|
2724
|
+
/** Response of `DELETE /admin/workflows/:workflowId/event-rules/:id` (200; the delete is soft). */
|
|
2725
|
+
interface DeleteWorkflowEventRuleResult {
|
|
2726
|
+
id: string;
|
|
2727
|
+
}
|
|
2728
|
+
|
|
2729
|
+
/**
|
|
2730
|
+
* One workflow's event rules on the admin workflow API
|
|
2731
|
+
* (`/api/v1/admin/workflows/:workflowId/event-rules`; manage Workflow + the
|
|
2732
|
+
* `workflow_builder` feature). Get one with `client.workflows.eventRules(id)`;
|
|
2733
|
+
* `workflowId` may be any version's id — the server keys rules by the lineage
|
|
2734
|
+
* root, so they survive a publish. Not flat CRUD (no single-rule read), so it
|
|
2735
|
+
* does NOT extend `BaseResource`.
|
|
2736
|
+
*/
|
|
2737
|
+
declare class WorkflowEventRulesResource {
|
|
2738
|
+
private readonly http;
|
|
2739
|
+
readonly workflowId: string;
|
|
2740
|
+
constructor(http: HttpClient, workflowId: string);
|
|
2741
|
+
/** GET — a bare array of the workflow's live rules, newest first. 404 `WORKFLOW_NOT_FOUND`. */
|
|
2742
|
+
list(): Promise<WorkflowEventRuleDto[]>;
|
|
2743
|
+
/**
|
|
2744
|
+
* POST — add a rule (201). `when` defaults to `{}` and `enabled` to true; use
|
|
2745
|
+
* `when: {}` for the creation types in `WORKFLOW_EVENT_RULE_MATCH_ALL_EVENT_TYPES`.
|
|
2746
|
+
* 400 `VALIDATION_FAILED` for a bad body; 404 `WORKFLOW_NOT_FOUND`.
|
|
2747
|
+
*/
|
|
2748
|
+
create(input: CreateWorkflowEventRuleInput): Promise<WorkflowEventRuleDto>;
|
|
2749
|
+
/** PATCH /:id — only the fields sent change (at least one). 404 `EVENT_RULE_NOT_FOUND`. */
|
|
2750
|
+
update(ruleId: string, input: UpdateWorkflowEventRuleInput): Promise<WorkflowEventRuleDto>;
|
|
2751
|
+
/** DELETE /:id — soft delete; returns `{ id }` (200). 404 `EVENT_RULE_NOT_FOUND`. */
|
|
2752
|
+
delete(ruleId: string): Promise<DeleteWorkflowEventRuleResult>;
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
/**
|
|
2756
|
+
* Wire shapes for one workflow version's stages (`GET /api/v1/workflows/:id/stages`).
|
|
2757
|
+
*
|
|
2758
|
+
* Mirrors `workflowVersionStageSchema` / `workflowVersionStagesResponseSchema`
|
|
2759
|
+
* in `packages/shared`. Redefined here (not imported) so the published package
|
|
2760
|
+
* carries no dependency on `@blueprint/shared`; `workflows.spec.ts` parses the
|
|
2761
|
+
* response with the REAL shared schema.
|
|
2762
|
+
*/
|
|
2763
|
+
type WorkflowEntityType = 'opportunity' | 'job' | 'purchase_order' | 'estimate' | 'contact' | 'contact_enrollment';
|
|
2764
|
+
/** How an end stage finished — set on every terminal stage (E2-F7-S6). */
|
|
2765
|
+
type WorkflowEndOutcome = 'won' | 'lost' | 'other';
|
|
2766
|
+
/** One stage of a workflow version — only what a stage progress bar draws. */
|
|
2767
|
+
interface WorkflowVersionStageDto {
|
|
2768
|
+
id: string;
|
|
2769
|
+
name: string;
|
|
2770
|
+
color: string | null;
|
|
2771
|
+
icon: string | null;
|
|
2772
|
+
sortOrder: number;
|
|
2773
|
+
isInitial: boolean;
|
|
2774
|
+
isTerminal: boolean;
|
|
2775
|
+
/** Won / lost / other on a terminal stage; null on every other stage. */
|
|
2776
|
+
endOutcome: WorkflowEndOutcome | null;
|
|
2777
|
+
}
|
|
2778
|
+
/**
|
|
2779
|
+
* The ordered stages (sortOrder ascending) of ONE workflow version — the version
|
|
2780
|
+
* a record's workflow instance is pinned to, which may be an archived version
|
|
2781
|
+
* still holding records.
|
|
2782
|
+
*/
|
|
2783
|
+
interface WorkflowVersionStagesResponse {
|
|
2784
|
+
id: string;
|
|
2785
|
+
name: string;
|
|
2786
|
+
entityType: WorkflowEntityType;
|
|
2787
|
+
version: number;
|
|
2788
|
+
status: 'published' | 'archived';
|
|
2789
|
+
stages: WorkflowVersionStageDto[];
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2792
|
+
/**
|
|
2793
|
+
* Wire shapes for authoring a workflow transition on the admin workflow API
|
|
2794
|
+
* (`POST /api/v1/admin/workflows/:wid/transitions`,
|
|
2795
|
+
* `PUT /api/v1/admin/workflows/:wid/transitions/:tid`).
|
|
2796
|
+
*
|
|
2797
|
+
* Mirrors `createTransitionSchema` / `updateTransitionSchema` and
|
|
2798
|
+
* `WorkflowTransitionDto` in `packages/shared`. Redefined here (not imported) so
|
|
2799
|
+
* the published package carries no dependency on `@blueprint/shared`;
|
|
2800
|
+
* `workflows.spec.ts` parses every sent body with the REAL shared schemas.
|
|
2801
|
+
*/
|
|
2802
|
+
/** Body of `POST /admin/workflows/:wid/transitions` (the workflow must be a draft). */
|
|
2803
|
+
interface CreateWorkflowTransitionInput {
|
|
2804
|
+
fromStageId: string;
|
|
2805
|
+
toStageId: string;
|
|
2806
|
+
name: string;
|
|
2807
|
+
description?: string | null;
|
|
2808
|
+
requiredRoles?: string[] | null;
|
|
2809
|
+
requiredFields?: string[] | null;
|
|
2810
|
+
/**
|
|
2811
|
+
* Fired only by automation (event rules, workflow actions, stage timers,
|
|
2812
|
+
* completion links); never offered as a manual move, and a manual execute is
|
|
2813
|
+
* a 422 `TRANSITION_AUTOMATIC_ONLY`. Defaults to false.
|
|
2814
|
+
*/
|
|
2815
|
+
automaticOnly?: boolean;
|
|
2816
|
+
sortOrder?: number;
|
|
2817
|
+
}
|
|
2818
|
+
/** Body of `PUT /admin/workflows/:wid/transitions/:tid` — only the fields sent change. */
|
|
2819
|
+
interface UpdateWorkflowTransitionInput {
|
|
2820
|
+
name?: string;
|
|
2821
|
+
description?: string | null;
|
|
2822
|
+
requiredRoles?: string[] | null;
|
|
2823
|
+
requiredFields?: string[] | null;
|
|
2824
|
+
automaticOnly?: boolean;
|
|
2825
|
+
sortOrder?: number;
|
|
2826
|
+
}
|
|
2827
|
+
/** A workflow transition row as the admin API returns it. */
|
|
2828
|
+
interface WorkflowTransitionDto {
|
|
2829
|
+
id: string;
|
|
2830
|
+
workflowId: string;
|
|
2831
|
+
fromStageId: string;
|
|
2832
|
+
toStageId: string;
|
|
2833
|
+
name: string;
|
|
2834
|
+
description: string | null;
|
|
2835
|
+
requiredRoles: string[] | null;
|
|
2836
|
+
requiredFields: string[] | null;
|
|
2837
|
+
automaticOnly: boolean;
|
|
2838
|
+
sortOrder: number;
|
|
2839
|
+
createdAt: string;
|
|
2840
|
+
updatedAt: string;
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2843
|
+
/**
|
|
2844
|
+
* Wire shapes for `GET /api/v1/workflows/transitions` — transition summaries
|
|
2845
|
+
* across the tenant's published workflows, or one workflow version's.
|
|
2846
|
+
*
|
|
2847
|
+
* Mirrors `transitionSummarySchema` / `transitionSummariesResponseSchema` /
|
|
2848
|
+
* `transitionSummariesQuerySchema` in `packages/shared`. Redefined here (not
|
|
2849
|
+
* imported) so the published package carries no dependency on
|
|
2850
|
+
* `@blueprint/shared`; `workflows.spec.ts` parses the response and the sent
|
|
2851
|
+
* query with the REAL shared schemas.
|
|
2852
|
+
*/
|
|
2853
|
+
|
|
2854
|
+
/** One transition of a workflow version. snake_case, as the server sends it. */
|
|
2855
|
+
interface TransitionSummaryDto {
|
|
2856
|
+
id: string;
|
|
2857
|
+
name: string;
|
|
2858
|
+
from_stage_name: string;
|
|
2859
|
+
to_stage_name: string;
|
|
2860
|
+
workflow_name: string;
|
|
2861
|
+
entity_type: WorkflowEntityType;
|
|
2862
|
+
/** The workflow version row this transition belongs to. */
|
|
2863
|
+
workflow_id: string;
|
|
2864
|
+
workflow_version: number;
|
|
2865
|
+
/** Lineage root (`COALESCE(parent_id, id)`) — the same for every version of one pipeline. */
|
|
2866
|
+
lineage_workflow_id: string;
|
|
2867
|
+
/** Fired only by automation; never offered as a manual move (E2-F10). */
|
|
2868
|
+
automatic_only: boolean;
|
|
2869
|
+
}
|
|
2870
|
+
interface TransitionSummariesResponse {
|
|
2871
|
+
transitions: TransitionSummaryDto[];
|
|
2872
|
+
}
|
|
2873
|
+
interface ListTransitionSummariesParams {
|
|
2874
|
+
/** Only these workflow entity types (sent comma-separated as `entity_types`). */
|
|
2875
|
+
entityTypes?: WorkflowEntityType[];
|
|
2876
|
+
/**
|
|
2877
|
+
* ONE workflow version's transitions, published or archived — pass a record's
|
|
2878
|
+
* instance `workflowId` (the version it is pinned to). Sent as `workflow_id`.
|
|
2879
|
+
* Without it only published versions are listed. Combined with
|
|
2880
|
+
* `entityTypes` it is an AND.
|
|
2881
|
+
*/
|
|
2882
|
+
workflowId?: string;
|
|
2883
|
+
}
|
|
2884
|
+
|
|
2885
|
+
/**
|
|
2886
|
+
* Tenant-readable workflow reads (`/api/v1/workflows`), plus transition
|
|
2887
|
+
* authoring on the admin workflow API (`/api/v1/admin/workflows`, which needs
|
|
2888
|
+
* the `workflow_builder` feature and a draft workflow), and a workflow's event
|
|
2889
|
+
* rules via `eventRules(workflowId)`. Not a CRUD resource, so it does NOT
|
|
2890
|
+
* extend `BaseResource`.
|
|
2891
|
+
*/
|
|
2892
|
+
declare class WorkflowsResource {
|
|
2893
|
+
private readonly http;
|
|
2894
|
+
private readonly basePath;
|
|
2895
|
+
private readonly adminPath;
|
|
2896
|
+
constructor(http: HttpClient);
|
|
2897
|
+
/**
|
|
2898
|
+
* GET /workflows/:id/stages — the ordered stages of one workflow version. Pass
|
|
2899
|
+
* a record's instance `workflowId` (e.g. from `GET /opportunities/:id/workflow`)
|
|
2900
|
+
* to get the stages of the version that record is pinned to, even an archived
|
|
2901
|
+
* one. 404 for an unknown or draft id; 403 if the caller cannot read the
|
|
2902
|
+
* workflow's record type.
|
|
2903
|
+
*/
|
|
2904
|
+
getStages(workflowId: string): Promise<WorkflowVersionStagesResponse>;
|
|
2905
|
+
/**
|
|
2906
|
+
* GET /workflows/transitions — transition summaries of every published
|
|
2907
|
+
* workflow, or with `workflowId` of that one version (published or archived;
|
|
2908
|
+
* an unknown, draft or other-tenant id returns an empty list). Each summary
|
|
2909
|
+
* carries `workflow_id`, `workflow_version`, `lineage_workflow_id` and
|
|
2910
|
+
* `automatic_only`. Only pipelines whose record type the caller can read
|
|
2911
|
+
* are listed; an unreadable `workflowId` returns an empty list, not 403.
|
|
2912
|
+
*/
|
|
2913
|
+
listTransitions(params?: ListTransitionSummariesParams): Promise<TransitionSummariesResponse>;
|
|
2914
|
+
/**
|
|
2915
|
+
* POST /admin/workflows/:wid/transitions — add a transition to a draft
|
|
2916
|
+
* workflow. Pass `automaticOnly: true` for an edge only automation should
|
|
2917
|
+
* fire (e.g. an event rule advancing on "contract sent").
|
|
2918
|
+
*/
|
|
2919
|
+
createTransition(workflowId: string, input: CreateWorkflowTransitionInput): Promise<WorkflowTransitionDto>;
|
|
2920
|
+
/**
|
|
2921
|
+
* The event rules of one workflow (`/admin/workflows/:wid/event-rules`) —
|
|
2922
|
+
* "advance automatically when…". Any version's id works; rules are keyed by
|
|
2923
|
+
* the lineage root.
|
|
2924
|
+
*/
|
|
2925
|
+
eventRules(workflowId: string): WorkflowEventRulesResource;
|
|
2926
|
+
/** PUT /admin/workflows/:wid/transitions/:tid — update a draft workflow's transition. */
|
|
2927
|
+
updateTransition(workflowId: string, transitionId: string, input: UpdateWorkflowTransitionInput): Promise<WorkflowTransitionDto>;
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2930
|
+
/**
|
|
2931
|
+
* Crew conflict preview (`POST /api/v1/service-schedules/conflicts/preview`).
|
|
2932
|
+
*
|
|
2933
|
+
* Mirrors `conflictPreviewSchema` / `conflictPreviewResponseSchema` in
|
|
2934
|
+
* `packages/shared` — redefined here so the published package carries no
|
|
2935
|
+
* dependency on `@blueprint/shared`; `service-schedules.spec.ts` parses the
|
|
2936
|
+
* request the SDK sends and a real-shaped response with the REAL shared
|
|
2937
|
+
* schemas, and pins these types to the shared inferred ones.
|
|
2938
|
+
*/
|
|
2939
|
+
/** A person to check. Matched by `id`; `type` is accepted for parity with event participants. */
|
|
2940
|
+
interface ConflictPreviewParticipant {
|
|
2941
|
+
id: string;
|
|
2942
|
+
type?: string | undefined;
|
|
2943
|
+
}
|
|
2944
|
+
/** A proposed booking window (ISO 8601 instants, `ends_at` after `starts_at`). */
|
|
2945
|
+
interface ConflictPreviewWindow {
|
|
2946
|
+
starts_at: string;
|
|
2947
|
+
ends_at: string;
|
|
2948
|
+
/** All-day booking: the working-hours check only asks whether each day covered is a working day. */
|
|
2949
|
+
all_day?: boolean | undefined;
|
|
2950
|
+
}
|
|
2951
|
+
/** Recurring mode: a schedule cadence, expanded over `horizon_weeks` (default 8, max 104) from `dtstart`. */
|
|
2952
|
+
interface ConflictPreviewSchedule {
|
|
2953
|
+
dtstart: string;
|
|
2954
|
+
recurrence_rule: string;
|
|
2955
|
+
/** YYYY-MM-DD dates to skip. */
|
|
2956
|
+
recurrence_exceptions?: string[] | undefined;
|
|
2957
|
+
/** IANA zone, e.g. `America/Chicago`. */
|
|
2958
|
+
timezone: string;
|
|
2959
|
+
default_duration_min: number;
|
|
2960
|
+
horizon_weeks?: number | undefined;
|
|
2961
|
+
}
|
|
2962
|
+
/** Give exactly one of `windows` or `schedule`. */
|
|
2963
|
+
interface ConflictPreviewRequest {
|
|
2964
|
+
participants: ConflictPreviewParticipant[];
|
|
2965
|
+
windows?: ConflictPreviewWindow[] | undefined;
|
|
2966
|
+
schedule?: ConflictPreviewSchedule | undefined;
|
|
2967
|
+
/** Editing an event: ignore itself. */
|
|
2968
|
+
exclude_event_id?: string | undefined;
|
|
2969
|
+
/** Editing a schedule: ignore its own generated visits. */
|
|
2970
|
+
exclude_schedule_id?: string | undefined;
|
|
2971
|
+
}
|
|
2972
|
+
interface ConflictWindowFields {
|
|
2973
|
+
/** Index into the request's `windows`, or the occurrence ordinal in recurring mode. */
|
|
2974
|
+
window_index: number;
|
|
2975
|
+
/** Recurring mode only: the occurrence's local YYYY-MM-DD. */
|
|
2976
|
+
occurrence_date?: string | undefined;
|
|
2977
|
+
starts_at: string;
|
|
2978
|
+
ends_at: string;
|
|
2979
|
+
agent_id: string;
|
|
2980
|
+
agent_display_name: string | null;
|
|
2981
|
+
}
|
|
2982
|
+
/** The person is already on another live event (any type, or time off) during the window. */
|
|
2983
|
+
interface CrewOverlapConflictDto extends ConflictWindowFields {
|
|
2984
|
+
kind: 'overlap';
|
|
2985
|
+
event_id: string;
|
|
2986
|
+
event_title: string;
|
|
2987
|
+
event_starts_at: string;
|
|
2988
|
+
event_ends_at: string;
|
|
2989
|
+
event_type: string;
|
|
2990
|
+
}
|
|
2991
|
+
/**
|
|
2992
|
+
* The window is outside the person's working hours (their own, else the
|
|
2993
|
+
* company default, in their timezone). People with no hours configured are
|
|
2994
|
+
* never reported.
|
|
2995
|
+
*/
|
|
2996
|
+
interface WorkingHoursConflictDto extends ConflictWindowFields {
|
|
2997
|
+
kind: 'outside_working_hours';
|
|
2998
|
+
/** `not_working_day`: they don't work that weekday. `outside_hours`: they do, but not then. */
|
|
2999
|
+
reason: 'not_working_day' | 'outside_hours';
|
|
3000
|
+
/** Their local date the verdict is about (YYYY-MM-DD). */
|
|
3001
|
+
local_date: string;
|
|
3002
|
+
/** 0=Sunday..6=Saturday. */
|
|
3003
|
+
day_of_week: number;
|
|
3004
|
+
/** That day's hours ('HH:mm') for `outside_hours`; null for `not_working_day`. */
|
|
3005
|
+
working_start: string | null;
|
|
3006
|
+
working_end: string | null;
|
|
3007
|
+
/** IANA zone the hours are in. */
|
|
3008
|
+
timezone: string;
|
|
3009
|
+
}
|
|
3010
|
+
interface ConflictPreviewResponse {
|
|
3011
|
+
conflicts: CrewOverlapConflictDto[];
|
|
3012
|
+
working_hours: WorkingHoursConflictDto[];
|
|
3013
|
+
/** How many windows were expanded and checked (0 conflicts ≠ 0 windows). */
|
|
3014
|
+
windows_checked: number;
|
|
3015
|
+
}
|
|
3016
|
+
|
|
3017
|
+
/**
|
|
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`.
|
|
3021
|
+
*/
|
|
3022
|
+
declare class ServiceSchedulesResource {
|
|
3023
|
+
private readonly http;
|
|
3024
|
+
private readonly basePath;
|
|
3025
|
+
constructor(http: HttpClient);
|
|
3026
|
+
/**
|
|
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).
|
|
3033
|
+
*/
|
|
3034
|
+
previewConflicts(request: ConflictPreviewRequest): Promise<ConflictPreviewResponse>;
|
|
3035
|
+
}
|
|
3036
|
+
|
|
3037
|
+
/**
|
|
3038
|
+
* Wire shapes for recurring billing schedules (`/admin/billing-schedules`,
|
|
3039
|
+
* E56-F3-S1/S2). snake_case on the wire, money and quantities as 2dp decimal
|
|
3040
|
+
* strings, dates as `YYYY-MM-DD` and timestamps as ISO strings.
|
|
3041
|
+
*
|
|
3042
|
+
* Mirrors the schemas in `packages/shared/src/validation/billing-schedule.ts`
|
|
3043
|
+
* (request bodies are their `z.input`, responses their `z.infer`, which are the
|
|
3044
|
+
* services' declared return types). Redefined here (not imported) so the
|
|
3045
|
+
* published package carries no dependency on `@blueprint/shared`;
|
|
3046
|
+
* `billing-schedule-types.parity.ts` fails `tsc` if a shape drifts, and
|
|
3047
|
+
* `billing-schedules.spec.ts` parses every request body the SDK sends with the
|
|
3048
|
+
* REAL shared schema.
|
|
3049
|
+
*/
|
|
3050
|
+
declare const BILLING_CADENCES: readonly ["weekly", "every_n_weeks", "monthly", "quarterly", "annually"];
|
|
3051
|
+
type BillingCadence = (typeof BILLING_CADENCES)[number];
|
|
3052
|
+
declare const BILLING_SCHEDULE_STATUSES: readonly ["active", "paused", "ended"];
|
|
3053
|
+
type BillingScheduleStatus = (typeof BILLING_SCHEDULE_STATUSES)[number];
|
|
3054
|
+
declare const BILL_TIMINGS: readonly ["in_advance", "in_arrears"];
|
|
3055
|
+
type BillTiming = (typeof BILL_TIMINGS)[number];
|
|
3056
|
+
declare const BILLING_DELIVERY_MODES: readonly ["auto_send", "draft_for_review"];
|
|
3057
|
+
type BillingDeliveryMode = (typeof BILLING_DELIVERY_MODES)[number];
|
|
3058
|
+
/**
|
|
3059
|
+
* `autopay` charges the customer's saved default card after each invoice is
|
|
3060
|
+
* sent (E56-F7-S4). It needs a platform-managed Stripe connection and a saved
|
|
3061
|
+
* default card on it — otherwise 422 `AUTOPAY_UNAVAILABLE` with a `reason`.
|
|
3062
|
+
*/
|
|
3063
|
+
declare const BILLING_COLLECTION_MODES: readonly ["send_link", "autopay"];
|
|
3064
|
+
type BillingCollectionMode = (typeof BILLING_COLLECTION_MODES)[number];
|
|
3065
|
+
/** Why autopay cannot be turned on (`AUTOPAY_UNAVAILABLE`'s `reason`). */
|
|
3066
|
+
declare const AUTOPAY_UNAVAILABLE_REASONS: readonly ["no_connect", "no_saved_method"];
|
|
3067
|
+
type AutopayUnavailableReason = (typeof AUTOPAY_UNAVAILABLE_REASONS)[number];
|
|
3068
|
+
/**
|
|
3069
|
+
* Autopay state of one ledger row (E56-F7-S4). `scheduled` / `retry_scheduled`
|
|
3070
|
+
* charge at `autopay_next_attempt_at`; `submitted` waits for Stripe's webhook;
|
|
3071
|
+
* `auth_required` emailed the customer the pay link and is never retried;
|
|
3072
|
+
* `abandoned` makes no more automatic tries. `failed` is reserved.
|
|
3073
|
+
*/
|
|
3074
|
+
declare const BILLING_AUTOPAY_STATUSES: readonly ["not_applicable", "scheduled", "submitted", "succeeded", "failed", "auth_required", "retry_scheduled", "abandoned"];
|
|
3075
|
+
type BillingAutopayStatus = (typeof BILLING_AUTOPAY_STATUSES)[number];
|
|
3076
|
+
/** A backdated create must choose: skip the past periods, or draft an invoice for each. */
|
|
3077
|
+
declare const BILLING_BACKFILL_MODES: readonly ["skip", "draft"];
|
|
3078
|
+
type BillingBackfillMode = (typeof BILLING_BACKFILL_MODES)[number];
|
|
3079
|
+
declare const BILLING_PERIOD_STATUSES: readonly ["generated", "skipped", "needs_review", "failed", "voided"];
|
|
3080
|
+
type BillingPeriodStatus = (typeof BILLING_PERIOD_STATUSES)[number];
|
|
3081
|
+
/** A preview row's state: its ledger status, or `upcoming` with no ledger row yet. */
|
|
3082
|
+
declare const BILLING_PREVIEW_PERIOD_STATUSES: readonly ["generated", "skipped", "needs_review", "failed", "voided", "upcoming"];
|
|
3083
|
+
type BillingPreviewPeriodStatus = (typeof BILLING_PREVIEW_PERIOD_STATUSES)[number];
|
|
3084
|
+
declare const BILLING_DELIVERY_STATUSES: readonly ["pending", "sent", "failed", "not_applicable"];
|
|
3085
|
+
type BillingDeliveryStatus = (typeof BILLING_DELIVERY_STATUSES)[number];
|
|
3086
|
+
/** One-off adjustment state (E56-F8-S5): `pending` until an invoice carries it. */
|
|
3087
|
+
declare const BILLING_ADJUSTMENT_STATUSES: readonly ["pending", "consumed", "cancelled"];
|
|
3088
|
+
type BillingAdjustmentStatus = (typeof BILLING_ADJUSTMENT_STATUSES)[number];
|
|
3089
|
+
/** Where an adjustment lands: only the schedule's next generated invoice for now. */
|
|
3090
|
+
declare const BILLING_ADJUSTMENT_TARGETS: readonly ["next_invoice"];
|
|
3091
|
+
type BillingAdjustmentTarget = (typeof BILLING_ADJUSTMENT_TARGETS)[number];
|
|
3092
|
+
type BillingInvoiceTerms = 'due_on_receipt' | 'net_15' | 'net_30' | 'net_60';
|
|
3093
|
+
type BillingInvoiceStatus = 'draft' | 'sent' | 'partially_paid' | 'paid' | 'void' | 'uncollectible';
|
|
3094
|
+
interface BillingScheduleLineInput {
|
|
3095
|
+
description: string;
|
|
3096
|
+
/** Decimal string greater than zero, up to 2 decimals. */
|
|
3097
|
+
quantity: string;
|
|
3098
|
+
/** Decimal string, up to 2 decimals. */
|
|
3099
|
+
unit_price: string;
|
|
3100
|
+
}
|
|
3101
|
+
/**
|
|
3102
|
+
* `POST /admin/billing-schedules`. `timezone` defaults to the tenant's. When
|
|
3103
|
+
* `start_date` is before today in that zone, `backfill` is required (else 400
|
|
3104
|
+
* `BACKFILL_REQUIRED` with the past-period count).
|
|
3105
|
+
*/
|
|
3106
|
+
interface CreateBillingScheduleDto {
|
|
3107
|
+
customer_id: string;
|
|
3108
|
+
property_id?: string | null | undefined;
|
|
3109
|
+
contract_id?: string | null | undefined;
|
|
3110
|
+
name: string;
|
|
3111
|
+
cadence: BillingCadence;
|
|
3112
|
+
interval_count?: number | undefined;
|
|
3113
|
+
/** Monthly schedules only (1–31; short months bill on their last day). */
|
|
3114
|
+
anchor_day?: number | null | undefined;
|
|
3115
|
+
timezone?: string | undefined;
|
|
3116
|
+
start_date: string;
|
|
3117
|
+
end_date?: string | null | undefined;
|
|
3118
|
+
end_after_count?: number | null | undefined;
|
|
3119
|
+
bill_timing?: BillTiming | undefined;
|
|
3120
|
+
lead_days?: number | undefined;
|
|
3121
|
+
terms?: BillingInvoiceTerms | undefined;
|
|
3122
|
+
tax_amount?: string | undefined;
|
|
3123
|
+
currency?: string | undefined;
|
|
3124
|
+
delivery?: BillingDeliveryMode | undefined;
|
|
3125
|
+
collection?: BillingCollectionMode | undefined;
|
|
3126
|
+
memo?: string | null | undefined;
|
|
3127
|
+
lines: BillingScheduleLineInput[];
|
|
3128
|
+
backfill?: BillingBackfillMode | undefined;
|
|
3129
|
+
}
|
|
3130
|
+
/**
|
|
3131
|
+
* `PATCH /admin/billing-schedules/:id` — partial; `customer_id` can't change,
|
|
3132
|
+
* null clears an optional field and `lines` replaces every line from
|
|
3133
|
+
* `effective_from` (a new line version). Changing the cadence after the first
|
|
3134
|
+
* invoice is 409 `CADENCE_LOCKED`.
|
|
3135
|
+
*/
|
|
3136
|
+
interface UpdateBillingScheduleDto {
|
|
3137
|
+
property_id?: string | null | undefined;
|
|
3138
|
+
contract_id?: string | null | undefined;
|
|
3139
|
+
name?: string | undefined;
|
|
3140
|
+
cadence?: BillingCadence | undefined;
|
|
3141
|
+
interval_count?: number | undefined;
|
|
3142
|
+
anchor_day?: number | null | undefined;
|
|
3143
|
+
timezone?: string | undefined;
|
|
3144
|
+
start_date?: string | undefined;
|
|
3145
|
+
end_date?: string | null | undefined;
|
|
3146
|
+
end_after_count?: number | null | undefined;
|
|
3147
|
+
bill_timing?: BillTiming | undefined;
|
|
3148
|
+
lead_days?: number | undefined;
|
|
3149
|
+
terms?: BillingInvoiceTerms | undefined;
|
|
3150
|
+
tax_amount?: string | undefined;
|
|
3151
|
+
currency?: string | undefined;
|
|
3152
|
+
delivery?: BillingDeliveryMode | undefined;
|
|
3153
|
+
collection?: BillingCollectionMode | undefined;
|
|
3154
|
+
memo?: string | null | undefined;
|
|
3155
|
+
lines?: BillingScheduleLineInput[] | undefined;
|
|
3156
|
+
/**
|
|
3157
|
+
* `YYYY-MM-DD` the sent `lines` take effect: periods starting on or after it
|
|
3158
|
+
* bill them. Needs `lines`. Omitted = the next period not yet invoiced; a
|
|
3159
|
+
* date inside an invoiced period is 422 `EFFECTIVE_DATE_IN_GENERATED_PERIOD`.
|
|
3160
|
+
*/
|
|
3161
|
+
effective_from?: string | undefined;
|
|
3162
|
+
}
|
|
3163
|
+
/** `GET /admin/billing-schedules` query. */
|
|
3164
|
+
interface BillingScheduleListParams {
|
|
3165
|
+
customer_id?: string | undefined;
|
|
3166
|
+
status?: BillingScheduleStatus | undefined;
|
|
3167
|
+
page?: number | undefined;
|
|
3168
|
+
limit?: number | undefined;
|
|
3169
|
+
}
|
|
3170
|
+
/** `GET /admin/billing-schedules/:id/preview` query: `count` 1–24, default 6. */
|
|
3171
|
+
interface BillingSchedulePreviewParams {
|
|
3172
|
+
count?: number | undefined;
|
|
3173
|
+
}
|
|
3174
|
+
/** `GET /admin/billing-schedules/:id/periods` query. */
|
|
3175
|
+
interface BillingSchedulePeriodListParams {
|
|
3176
|
+
status?: BillingPeriodStatus | undefined;
|
|
3177
|
+
page?: number | undefined;
|
|
3178
|
+
limit?: number | undefined;
|
|
3179
|
+
}
|
|
3180
|
+
/** `GET /admin/billing-schedules/periods/needs-review` query. */
|
|
3181
|
+
interface BillingNeedsReviewParams {
|
|
3182
|
+
page?: number | undefined;
|
|
3183
|
+
limit?: number | undefined;
|
|
3184
|
+
}
|
|
3185
|
+
/** `POST /admin/billing-schedules/:id/periods/:periodStart/skip` body. */
|
|
3186
|
+
interface SkipBillingPeriodDto {
|
|
3187
|
+
reason?: string | undefined;
|
|
3188
|
+
}
|
|
3189
|
+
/**
|
|
3190
|
+
* `POST /admin/billing-schedules/:id/adjustments` (E56-F8-S5). `amount` is a
|
|
3191
|
+
* signed 2dp decimal string: negative for a credit. Zero, or a credit larger
|
|
3192
|
+
* than the next invoice, is 422 `ADJUSTMENT_INVALID`.
|
|
3193
|
+
*/
|
|
3194
|
+
interface CreateBillingAdjustmentDto {
|
|
3195
|
+
description: string;
|
|
3196
|
+
amount: string;
|
|
3197
|
+
/** Defaults to `next_invoice`. */
|
|
3198
|
+
apply_to?: BillingAdjustmentTarget | undefined;
|
|
3199
|
+
}
|
|
3200
|
+
/** `GET /admin/billing-schedules/:id/adjustments` query. Omitted status: pending and consumed. */
|
|
3201
|
+
interface BillingAdjustmentListParams {
|
|
3202
|
+
status?: BillingAdjustmentStatus | undefined;
|
|
3203
|
+
}
|
|
3204
|
+
/** One upcoming period: when it generates and when the invoice is due. */
|
|
3205
|
+
interface BillingUpcomingPeriod {
|
|
3206
|
+
index: number;
|
|
3207
|
+
start: string;
|
|
3208
|
+
end: string;
|
|
3209
|
+
generate_at: string;
|
|
3210
|
+
due_date: string;
|
|
3211
|
+
}
|
|
3212
|
+
interface BillingScheduleLine {
|
|
3213
|
+
id: string;
|
|
3214
|
+
description: string;
|
|
3215
|
+
quantity: string;
|
|
3216
|
+
unit_price: string;
|
|
3217
|
+
sort_order: number;
|
|
3218
|
+
}
|
|
3219
|
+
/**
|
|
3220
|
+
* One version of a schedule's lines: periods starting on or after
|
|
3221
|
+
* `effective_from` (until the next version's date) bill them.
|
|
3222
|
+
*/
|
|
3223
|
+
interface BillingScheduleLineVersion {
|
|
3224
|
+
id: string;
|
|
3225
|
+
schedule_id: string;
|
|
3226
|
+
effective_from: string;
|
|
3227
|
+
note: string | null;
|
|
3228
|
+
created_by: string | null;
|
|
3229
|
+
created_at: string;
|
|
3230
|
+
lines: BillingScheduleLine[];
|
|
3231
|
+
}
|
|
3232
|
+
/** `GET /admin/billing-schedules/:id/versions`: newest effective date first. */
|
|
3233
|
+
interface BillingScheduleLineVersionListResponse {
|
|
3234
|
+
data: BillingScheduleLineVersion[];
|
|
3235
|
+
}
|
|
3236
|
+
/**
|
|
3237
|
+
* Returned by create, update, pause, resume and end. `lines` are what the next
|
|
3238
|
+
* invoice bills (the line version in effect at `next_period`).
|
|
3239
|
+
*/
|
|
3240
|
+
interface BillingSchedule {
|
|
3241
|
+
id: string;
|
|
3242
|
+
customer_id: string;
|
|
3243
|
+
property_id: string | null;
|
|
3244
|
+
contract_id: string | null;
|
|
3245
|
+
name: string;
|
|
3246
|
+
status: BillingScheduleStatus;
|
|
3247
|
+
currency: string;
|
|
3248
|
+
cadence: BillingCadence;
|
|
3249
|
+
interval_count: number;
|
|
3250
|
+
anchor_day: number | null;
|
|
3251
|
+
timezone: string;
|
|
3252
|
+
start_date: string;
|
|
3253
|
+
end_date: string | null;
|
|
3254
|
+
end_after_count: number | null;
|
|
3255
|
+
bill_timing: BillTiming;
|
|
3256
|
+
lead_days: number;
|
|
3257
|
+
terms: BillingInvoiceTerms;
|
|
3258
|
+
tax_amount: string;
|
|
3259
|
+
delivery: BillingDeliveryMode;
|
|
3260
|
+
collection: BillingCollectionMode;
|
|
3261
|
+
memo: string | null;
|
|
3262
|
+
lines: BillingScheduleLine[];
|
|
3263
|
+
next_generate_at: string | null;
|
|
3264
|
+
/** The next unbilled period, or null once the schedule has ended. */
|
|
3265
|
+
next_period: BillingUpcomingPeriod | null;
|
|
3266
|
+
created_at: string;
|
|
3267
|
+
updated_at: string;
|
|
3268
|
+
}
|
|
3269
|
+
/** The customer's saved default card, as shown before turning autopay on. */
|
|
3270
|
+
interface SavedPaymentMethodSummary {
|
|
3271
|
+
brand: string;
|
|
3272
|
+
last4: string;
|
|
3273
|
+
exp_month: number;
|
|
3274
|
+
exp_year: number;
|
|
3275
|
+
}
|
|
3276
|
+
/**
|
|
3277
|
+
* `GET /admin/billing-schedules/:id`: the schedule plus its next 3 periods, and
|
|
3278
|
+
* whether autopay can be turned on (the same check as `AUTOPAY_UNAVAILABLE`).
|
|
3279
|
+
*/
|
|
3280
|
+
interface BillingScheduleDetail extends BillingSchedule {
|
|
3281
|
+
upcoming_periods: BillingUpcomingPeriod[];
|
|
3282
|
+
/** The customer's active default card, or null. */
|
|
3283
|
+
saved_method: SavedPaymentMethodSummary | null;
|
|
3284
|
+
autopay_available: boolean;
|
|
3285
|
+
autopay_unavailable_reason: AutopayUnavailableReason | null;
|
|
3286
|
+
}
|
|
3287
|
+
/** One list row: no lines, but their count and the next invoice's total (lines + tax). */
|
|
3288
|
+
interface BillingScheduleListItem extends Omit<BillingSchedule, 'lines'> {
|
|
3289
|
+
next_amount: string;
|
|
3290
|
+
line_count: number;
|
|
3291
|
+
/** Display name of the schedule's customer; null if the customer row is gone. */
|
|
3292
|
+
customer_name: string | null;
|
|
3293
|
+
}
|
|
3294
|
+
/** A one-off adjustment line a preview period includes. */
|
|
3295
|
+
interface BillingPreviewAdjustment {
|
|
3296
|
+
id: string;
|
|
3297
|
+
description: string;
|
|
3298
|
+
amount: string;
|
|
253
3299
|
}
|
|
254
|
-
interface
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
3300
|
+
interface BillingSchedulePreviewPeriod extends BillingUpcomingPeriod {
|
|
3301
|
+
subtotal: string;
|
|
3302
|
+
tax: string;
|
|
3303
|
+
total: string;
|
|
3304
|
+
status: BillingPreviewPeriodStatus;
|
|
3305
|
+
/**
|
|
3306
|
+
* One-off adjustments included in the amounts: pending ones on the next
|
|
3307
|
+
* unbilled period, consumed ones on the period that billed them. Absent when none.
|
|
3308
|
+
*/
|
|
3309
|
+
adjustments?: BillingPreviewAdjustment[] | undefined;
|
|
260
3310
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
source?: ContactSource | null;
|
|
3311
|
+
/** `GET /admin/billing-schedules/:id/preview`. */
|
|
3312
|
+
interface BillingSchedulePreview {
|
|
3313
|
+
schedule_id: string | null;
|
|
3314
|
+
currency: string;
|
|
3315
|
+
periods: BillingSchedulePreviewPeriod[];
|
|
267
3316
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
3317
|
+
/**
|
|
3318
|
+
* One period-ledger row with its invoice and delivery state.
|
|
3319
|
+
* `schedule_snapshot` (what the period would bill) is present only on rows
|
|
3320
|
+
* with no invoice.
|
|
3321
|
+
*/
|
|
3322
|
+
interface BillingSchedulePeriod {
|
|
271
3323
|
id: string;
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
3324
|
+
schedule_id: string;
|
|
3325
|
+
period_start: string;
|
|
3326
|
+
period_end: string;
|
|
3327
|
+
invoice_id: string | null;
|
|
3328
|
+
superseded_invoice_id: string | null;
|
|
3329
|
+
status: BillingPeriodStatus;
|
|
3330
|
+
delivery_status: BillingDeliveryStatus;
|
|
3331
|
+
delivery_attempts: number;
|
|
3332
|
+
last_error: string | null;
|
|
3333
|
+
reason: string | null;
|
|
3334
|
+
generated_at: string | null;
|
|
3335
|
+
/** Autopay state (E56-F7-S4); `not_applicable` on send_link schedules. */
|
|
3336
|
+
autopay_status: BillingAutopayStatus;
|
|
3337
|
+
/** The current charge attempt (1 or 2). */
|
|
3338
|
+
autopay_attempt: number | null;
|
|
3339
|
+
/** What the current attempt charges, in cents. */
|
|
3340
|
+
autopay_amount_cents: number | null;
|
|
3341
|
+
/** Unknown-outcome re-drives of the current attempt (max 5). */
|
|
3342
|
+
autopay_error_tries: number;
|
|
3343
|
+
autopay_next_attempt_at: string | null;
|
|
3344
|
+
autopay_last_error: string | null;
|
|
3345
|
+
autopay_payment_intent_id: string | null;
|
|
3346
|
+
created_at: string;
|
|
3347
|
+
updated_at: string;
|
|
3348
|
+
invoice_number: string | null;
|
|
3349
|
+
invoice_status: BillingInvoiceStatus | null;
|
|
3350
|
+
/** Number of the voided invoice a regenerate replaced (null when none). */
|
|
3351
|
+
superseded_invoice_number: string | null;
|
|
3352
|
+
schedule_snapshot?: Record<string, unknown> | undefined;
|
|
283
3353
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
dnc?: boolean | null;
|
|
290
|
-
marketingOptOut?: boolean | null;
|
|
3354
|
+
/** A tenant-wide Needs review row: the ledger row plus its schedule and customer. */
|
|
3355
|
+
interface BillingNeedsReviewItem extends BillingSchedulePeriod {
|
|
3356
|
+
schedule_name: string;
|
|
3357
|
+
customer_id: string;
|
|
3358
|
+
customer_name: string | null;
|
|
291
3359
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
3360
|
+
type BillingScheduleListResponse = PaginatedResponse<BillingScheduleListItem>;
|
|
3361
|
+
type BillingSchedulePeriodListResponse = PaginatedResponse<BillingSchedulePeriod>;
|
|
3362
|
+
type BillingNeedsReviewResponse = PaginatedResponse<BillingNeedsReviewItem>;
|
|
3363
|
+
/**
|
|
3364
|
+
* `GET /admin/billing-schedules/autopay-summary` — what disconnecting Stripe
|
|
3365
|
+
* would touch: live autopay schedules, the distinct customers on them, and
|
|
3366
|
+
* active saved cards on the tenant's current Stripe connection.
|
|
3367
|
+
*/
|
|
3368
|
+
interface BillingAutopaySummary {
|
|
3369
|
+
autopaySchedules: number;
|
|
3370
|
+
customers: number;
|
|
3371
|
+
savedCards: number;
|
|
298
3372
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
contactId: string;
|
|
302
|
-
channelId: string;
|
|
303
|
-
value: string;
|
|
3373
|
+
interface BillingAutopaySummaryResponse {
|
|
3374
|
+
data: BillingAutopaySummary;
|
|
304
3375
|
}
|
|
305
3376
|
/**
|
|
306
|
-
* `POST /
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
* for connectors doing identity resolution (e.g. Messenger).
|
|
3377
|
+
* `POST /admin/billing-schedules/:id/generate-now`. `delivery: 'queued'` means
|
|
3378
|
+
* the auto_send delivery job was enqueued after commit; read its outcome from
|
|
3379
|
+
* the period ledger.
|
|
310
3380
|
*/
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
3381
|
+
type GenerateNowResult = {
|
|
3382
|
+
status: 'generated';
|
|
3383
|
+
invoice_id: string;
|
|
3384
|
+
period_start: string;
|
|
3385
|
+
delivery: 'queued' | 'not_applicable';
|
|
3386
|
+
} | {
|
|
3387
|
+
status: 'already_generated';
|
|
3388
|
+
invoice_id: string;
|
|
3389
|
+
period_start: string;
|
|
3390
|
+
};
|
|
3391
|
+
/** `POST /admin/billing-schedules/:id/periods/:periodStart/regenerate`. */
|
|
3392
|
+
interface RegeneratePeriodResult {
|
|
3393
|
+
invoice_id: string;
|
|
3394
|
+
superseded_invoice_id: string;
|
|
3395
|
+
delivery: 'queued' | 'not_applicable';
|
|
314
3396
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
3397
|
+
/** A one-off adjustment on a schedule's next invoice (E56-F8-S5). */
|
|
3398
|
+
interface BillingAdjustment {
|
|
3399
|
+
id: string;
|
|
3400
|
+
schedule_id: string;
|
|
3401
|
+
description: string;
|
|
3402
|
+
amount: string;
|
|
3403
|
+
apply_to: BillingAdjustmentTarget;
|
|
3404
|
+
status: BillingAdjustmentStatus;
|
|
3405
|
+
/** The invoice that carried it (set once consumed). */
|
|
3406
|
+
consumed_invoice_id: string | null;
|
|
3407
|
+
consumed_period_start: string | null;
|
|
3408
|
+
created_by: string | null;
|
|
3409
|
+
created_at: string;
|
|
3410
|
+
updated_at: string;
|
|
3411
|
+
}
|
|
3412
|
+
/** `GET /admin/billing-schedules/:id/adjustments`: oldest first. */
|
|
3413
|
+
interface BillingAdjustmentListResponse {
|
|
3414
|
+
data: BillingAdjustment[];
|
|
318
3415
|
}
|
|
319
3416
|
|
|
320
3417
|
/**
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
*
|
|
3418
|
+
* Recurring billing schedules (`/admin/billing-schedules`, E56-F3-S1/S2):
|
|
3419
|
+
* CRUD, pause / resume / end, preview, the period ledger, the tenant-wide
|
|
3420
|
+
* Needs review queue, generate-now, per-period skip / regenerate, and one-off
|
|
3421
|
+
* adjustments on the next invoice (E56-F8-S5). Needs the
|
|
3422
|
+
* invoicing module; reads need Read and writes Update on BillingSchedule.
|
|
325
3423
|
*/
|
|
326
|
-
declare class
|
|
327
|
-
private readonly http;
|
|
328
|
-
private readonly basePath;
|
|
329
|
-
constructor(http: HttpClient, contactId: string);
|
|
330
|
-
/** Returns `{ channel, duplicateOf }` — `duplicateOf` is the dedup signal. */
|
|
331
|
-
create(data: CreateContactChannelDto): Promise<AddContactChannelResult>;
|
|
332
|
-
update(channelId: string, data: UpdateContactChannelDto): Promise<ContactChannelDto>;
|
|
333
|
-
delete(channelId: string): Promise<void>;
|
|
334
|
-
}
|
|
335
|
-
declare class ContactResource extends BaseResource<ContactDto, CreateContactDto, UpdateContactDto> {
|
|
3424
|
+
declare class BillingScheduleResource extends BaseResource<BillingSchedule, CreateBillingScheduleDto, UpdateBillingScheduleDto, BillingScheduleListResponse> {
|
|
336
3425
|
constructor(http: ConstructorParameters<typeof BaseResource>[0]);
|
|
337
|
-
|
|
338
|
-
|
|
3426
|
+
/** GET /admin/billing-schedules — list rows (no lines; `line_count` and `next_amount` instead). */
|
|
3427
|
+
list(params?: BillingScheduleListParams): Promise<BillingScheduleListResponse>;
|
|
3428
|
+
/** GET /admin/billing-schedules/:id — the schedule with its lines and next 3 periods. */
|
|
3429
|
+
get(id: string): Promise<BillingScheduleDetail>;
|
|
3430
|
+
/**
|
|
3431
|
+
* POST /admin/billing-schedules. `timezone` defaults to the tenant's. A
|
|
3432
|
+
* backdated `start_date` needs `backfill` ('skip' | 'draft'), else 400
|
|
3433
|
+
* `BACKFILL_REQUIRED`; `collection: 'autopay'` without a platform-managed
|
|
3434
|
+
* Stripe connection and a saved default card is 422 `AUTOPAY_UNAVAILABLE`
|
|
3435
|
+
* (`reason` `no_connect` | `no_saved_method`).
|
|
3436
|
+
*/
|
|
3437
|
+
create(data: CreateBillingScheduleDto): Promise<BillingSchedule>;
|
|
3438
|
+
/**
|
|
3439
|
+
* PATCH /admin/billing-schedules/:id — partial. `lines` replaces every line
|
|
3440
|
+
* from `effective_from` (default: the next period not yet invoiced) as a new
|
|
3441
|
+
* line version. 409 `CADENCE_LOCKED`; 422 `EFFECTIVE_DATE_IN_GENERATED_PERIOD`
|
|
3442
|
+
* for a date inside an invoiced period.
|
|
3443
|
+
*/
|
|
3444
|
+
update(id: string, data: UpdateBillingScheduleDto): Promise<BillingSchedule>;
|
|
3445
|
+
/** DELETE /admin/billing-schedules/:id — only a schedule that never invoiced (else 409 `SCHEDULE_HAS_INVOICES`). */
|
|
3446
|
+
delete(id: string): Promise<void>;
|
|
3447
|
+
/** GET /admin/billing-schedules/:id/versions — line version history, newest effective date first. */
|
|
3448
|
+
listVersions(id: string): Promise<BillingScheduleLineVersionListResponse>;
|
|
3449
|
+
/**
|
|
3450
|
+
* POST /admin/billing-schedules/:id/adjustments — add a one-off amount
|
|
3451
|
+
* (signed; negative is a credit) to the schedule's next generated invoice.
|
|
3452
|
+
* Billed exactly once; no automatic proration. 422 `ADJUSTMENT_INVALID`
|
|
3453
|
+
* (zero, or the next invoice would go below zero) or `SCHEDULE_NOT_ACTIVE`.
|
|
3454
|
+
*/
|
|
3455
|
+
addAdjustment(id: string, data: CreateBillingAdjustmentDto): Promise<BillingAdjustment>;
|
|
3456
|
+
/** GET /admin/billing-schedules/:id/adjustments — oldest first; default pending and consumed. */
|
|
3457
|
+
listAdjustments(id: string, params?: BillingAdjustmentListParams): Promise<BillingAdjustmentListResponse>;
|
|
3458
|
+
/**
|
|
3459
|
+
* DELETE /admin/billing-schedules/:id/adjustments/:adjustmentId — cancel a
|
|
3460
|
+
* pending adjustment (it never bills). Returns it; 409
|
|
3461
|
+
* `ADJUSTMENT_ALREADY_CONSUMED` once an invoice carries it.
|
|
3462
|
+
*/
|
|
3463
|
+
cancelAdjustment(id: string, adjustmentId: string): Promise<BillingAdjustment>;
|
|
3464
|
+
/** POST /admin/billing-schedules/:id/pause — 409 `INVALID_STATUS_TRANSITION` unless active. */
|
|
3465
|
+
pause(id: string): Promise<BillingSchedule>;
|
|
3466
|
+
/** POST /admin/billing-schedules/:id/resume — periods that fell due while paused are skipped. */
|
|
3467
|
+
resume(id: string): Promise<BillingSchedule>;
|
|
3468
|
+
/** POST /admin/billing-schedules/:id/end — no further periods generate. */
|
|
3469
|
+
end(id: string): Promise<BillingSchedule>;
|
|
3470
|
+
/** GET /admin/billing-schedules/:id/preview — the next `count` (1–24, default 6) periods from the first unbilled one. */
|
|
3471
|
+
preview(id: string, params?: BillingSchedulePreviewParams): Promise<BillingSchedulePreview>;
|
|
3472
|
+
/** GET /admin/billing-schedules/:id/periods — the period ledger, newest first. */
|
|
3473
|
+
periods(id: string, params?: BillingSchedulePeriodListParams): Promise<BillingSchedulePeriodListResponse>;
|
|
3474
|
+
/**
|
|
3475
|
+
* GET /admin/billing-schedules/periods/needs-review — tenant-wide: needs_review
|
|
3476
|
+
* rows plus failed and stuck (pending over 2h) deliveries.
|
|
3477
|
+
*/
|
|
3478
|
+
needsReview(params?: BillingNeedsReviewParams): Promise<BillingNeedsReviewResponse>;
|
|
3479
|
+
/**
|
|
3480
|
+
* GET /admin/billing-schedules/autopay-summary — what disconnecting Stripe
|
|
3481
|
+
* would touch: live autopay schedules, the distinct customers on them, and
|
|
3482
|
+
* active saved cards on the current Stripe connection. On disconnect, autopay
|
|
3483
|
+
* schedules that can no longer charge switch to emailed pay links.
|
|
3484
|
+
*/
|
|
3485
|
+
autopaySummary(): Promise<BillingAutopaySummaryResponse>;
|
|
3486
|
+
/**
|
|
3487
|
+
* POST /admin/billing-schedules/:id/generate-now — bill the current due
|
|
3488
|
+
* period now. Idempotent (`already_generated`); 409 `NOTHING_DUE` or
|
|
3489
|
+
* `SCHEDULE_NOT_ACTIVE`.
|
|
3490
|
+
*/
|
|
3491
|
+
generateNow(id: string): Promise<GenerateNowResult>;
|
|
3492
|
+
/**
|
|
3493
|
+
* POST /admin/billing-schedules/:id/periods/:periodStart/skip — skip one
|
|
3494
|
+
* period (`periodStart` is `YYYY-MM-DD`). Returns the skipped ledger row;
|
|
3495
|
+
* 400 `NOT_A_PERIOD`, 409 `PERIOD_ALREADY_INVOICED`.
|
|
3496
|
+
*/
|
|
3497
|
+
skipPeriod(id: string, periodStart: string, data?: SkipBillingPeriodDto): Promise<BillingSchedulePeriod>;
|
|
3498
|
+
/**
|
|
3499
|
+
* POST /admin/billing-schedules/:id/periods/:periodStart/regenerate — re-bill
|
|
3500
|
+
* a period whose invoice was voided (new draft on the same ledger row).
|
|
3501
|
+
* 409 `INVOICE_NOT_VOID` or `CHECKOUT_IN_FLIGHT`.
|
|
3502
|
+
*/
|
|
3503
|
+
regeneratePeriod(id: string, periodStart: string): Promise<RegeneratePeriodResult>;
|
|
339
3504
|
}
|
|
340
3505
|
|
|
341
3506
|
/**
|
|
342
|
-
*
|
|
3507
|
+
* Value types for `GET /custom-fields` definitions (E38-F9).
|
|
343
3508
|
*
|
|
344
|
-
* Mirrors `
|
|
345
|
-
* `packages/shared/src/
|
|
3509
|
+
* Mirrors `CustomFieldEntityType` / `CustomFieldType` /
|
|
3510
|
+
* `CustomFieldValidationRules` in `packages/shared/src/custom-fields/types.ts`.
|
|
346
3511
|
* Types are redefined here (not imported) so the published package carries no
|
|
347
|
-
*
|
|
3512
|
+
* dependency on `@blueprint/shared`; `custom-field-types.parity.ts` fails the
|
|
3513
|
+
* build when either side drifts.
|
|
348
3514
|
*/
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
|
|
360
|
-
external_ref?: string | null;
|
|
361
|
-
match_key?: string | null;
|
|
362
|
-
payload?: Record<string, unknown>;
|
|
363
|
-
payload_version?: number;
|
|
3515
|
+
/** Entity types that may carry tenant-defined custom fields. */
|
|
3516
|
+
type CustomFieldEntityType = 'contact' | 'customer' | 'opportunity' | 'job' | 'vendor' | 'agent';
|
|
3517
|
+
/** The supported input/value types. */
|
|
3518
|
+
type CustomFieldType = 'text' | 'number' | 'select' | 'multi_select' | 'date' | 'boolean' | 'url' | 'email' | 'phone';
|
|
3519
|
+
interface CustomFieldValidationRules {
|
|
3520
|
+
required?: boolean;
|
|
3521
|
+
/** number: value bound · text: length · multi_select: array length */
|
|
3522
|
+
min?: number;
|
|
3523
|
+
max?: number;
|
|
3524
|
+
/** text/regex pattern */
|
|
3525
|
+
pattern?: string;
|
|
364
3526
|
}
|
|
365
|
-
|
|
3527
|
+
|
|
3528
|
+
/** A custom-field definition as returned by `GET /custom-fields`. */
|
|
3529
|
+
interface CustomFieldDefinitionDto {
|
|
366
3530
|
id: string;
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
3531
|
+
tenantId: string;
|
|
3532
|
+
entityType: CustomFieldEntityType;
|
|
3533
|
+
fieldKey: string;
|
|
3534
|
+
label: string;
|
|
3535
|
+
fieldType: CustomFieldType;
|
|
3536
|
+
options: string[];
|
|
3537
|
+
validationRules: CustomFieldValidationRules;
|
|
3538
|
+
defaultValue: unknown;
|
|
3539
|
+
displayOrder: number;
|
|
3540
|
+
section: string | null;
|
|
3541
|
+
searchable: boolean;
|
|
3542
|
+
showInList: boolean;
|
|
3543
|
+
showInReports: boolean;
|
|
3544
|
+
active: boolean;
|
|
3545
|
+
createdAt: string;
|
|
3546
|
+
updatedAt: string;
|
|
376
3547
|
}
|
|
377
|
-
|
|
378
|
-
|
|
3548
|
+
interface ListCustomFieldDefinitionsParams {
|
|
3549
|
+
entity_type?: CustomFieldEntityType;
|
|
3550
|
+
/** Include deactivated definitions. Their stored values remain valid on records. */
|
|
3551
|
+
include_inactive?: boolean;
|
|
3552
|
+
}
|
|
3553
|
+
/**
|
|
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.
|
|
3557
|
+
*
|
|
3558
|
+
* Read-only by design: configuring definitions is an admin action on
|
|
3559
|
+
* `/admin/custom-fields` and is deliberately not exposed here.
|
|
3560
|
+
*/
|
|
3561
|
+
declare class CustomFieldsResource {
|
|
379
3562
|
private readonly http;
|
|
380
3563
|
constructor(http: HttpClient);
|
|
381
|
-
|
|
382
|
-
list(params?:
|
|
383
|
-
listForEntity(entityType: string, entityId: string, params?: ListParams): Promise<PaginatedResponse<ActivityDto>>;
|
|
3564
|
+
/** List definitions, optionally narrowed to one entity type. */
|
|
3565
|
+
list(params?: ListCustomFieldDefinitionsParams): Promise<CustomFieldDefinitionDto[]>;
|
|
384
3566
|
}
|
|
385
3567
|
|
|
386
3568
|
/**
|
|
387
|
-
* Wire shapes for the
|
|
3569
|
+
* Wire shapes for the Ortto connector admin API (E53, `/admin/integrations/ortto/*`).
|
|
388
3570
|
*
|
|
389
|
-
* Mirrors `
|
|
390
|
-
* `
|
|
391
|
-
*
|
|
392
|
-
*
|
|
393
|
-
*
|
|
3571
|
+
* Mirrors `createOrttoMappingSchema` / `updateOrttoMappingSchema` /
|
|
3572
|
+
* `orttoAudiencesQuerySchema` / `orttoSyncRequestSchema` and the response
|
|
3573
|
+
* interfaces (`OrttoMappingDto`, `OrttoAudienceDto`, `OrttoSyncStatusDto`,
|
|
3574
|
+
* `OrttoSyncRequestResultDto`, ...) in `packages/shared/src/validation/ortto.ts`. Types are
|
|
3575
|
+
* redefined here (not imported) so the published package carries no runtime or
|
|
3576
|
+
* type dependency on `@blueprint/shared`; `ortto.spec.ts` parses every request
|
|
3577
|
+
* body with the REAL shared zod schema and asserts type parity with the shared
|
|
3578
|
+
* inferred types.
|
|
394
3579
|
*/
|
|
395
|
-
|
|
3580
|
+
type OrttoMappingDirection = 'push' | 'pull';
|
|
3581
|
+
/**
|
|
3582
|
+
* Push a Planes list's membership to Ortto as a tag. `ortto_tag` defaults to
|
|
3583
|
+
* `planes:<list name>` server-side.
|
|
3584
|
+
*/
|
|
3585
|
+
interface CreateOrttoPushMappingDto {
|
|
3586
|
+
direction: 'push';
|
|
3587
|
+
list_id: string;
|
|
3588
|
+
ortto_tag?: string;
|
|
3589
|
+
}
|
|
3590
|
+
/**
|
|
3591
|
+
* Mirror an Ortto audience into a read-only static Planes list — either an
|
|
3592
|
+
* existing empty static list (`list_id`) or a new one (`new_list_name`), never
|
|
3593
|
+
* both.
|
|
3594
|
+
*/
|
|
3595
|
+
type CreateOrttoPullMappingDto = {
|
|
3596
|
+
direction: 'pull';
|
|
3597
|
+
ortto_audience_id: string;
|
|
3598
|
+
create_unmatched?: boolean;
|
|
3599
|
+
} & ({
|
|
3600
|
+
list_id: string;
|
|
3601
|
+
new_list_name?: never;
|
|
3602
|
+
} | {
|
|
3603
|
+
new_list_name: string;
|
|
3604
|
+
list_id?: never;
|
|
3605
|
+
});
|
|
3606
|
+
type CreateOrttoMappingDto = CreateOrttoPushMappingDto | CreateOrttoPullMappingDto;
|
|
3607
|
+
/** Direction and list are immutable — delete and recreate instead. At least one field is required. */
|
|
3608
|
+
interface UpdateOrttoMappingDto {
|
|
3609
|
+
ortto_tag?: string;
|
|
3610
|
+
create_unmatched?: boolean;
|
|
3611
|
+
}
|
|
3612
|
+
interface ListOrttoAudiencesParams {
|
|
3613
|
+
search?: string;
|
|
3614
|
+
}
|
|
3615
|
+
interface OrttoAudienceDto {
|
|
396
3616
|
id: string;
|
|
397
3617
|
name: string;
|
|
398
|
-
|
|
3618
|
+
/** Member count, when Ortto reports one. */
|
|
3619
|
+
members?: number;
|
|
3620
|
+
}
|
|
3621
|
+
interface OrttoMappingDto {
|
|
3622
|
+
id: string;
|
|
3623
|
+
connection_id: string;
|
|
3624
|
+
list_id: string;
|
|
3625
|
+
/** Null when the list has since been deleted. */
|
|
3626
|
+
list_name: string | null;
|
|
3627
|
+
list_kind: 'static' | 'smart' | null;
|
|
3628
|
+
direction: OrttoMappingDirection;
|
|
3629
|
+
ortto_tag: string | null;
|
|
3630
|
+
ortto_audience_id: string | null;
|
|
3631
|
+
ortto_audience_name: string | null;
|
|
3632
|
+
create_unmatched: boolean;
|
|
3633
|
+
last_synced_at: string | null;
|
|
3634
|
+
/** The last successful run's counts for this mapping; null before one. */
|
|
3635
|
+
last_result?: OrttoMappingLastResult | null;
|
|
3636
|
+
last_error: string | null;
|
|
399
3637
|
created_at: string;
|
|
400
3638
|
updated_at: string;
|
|
401
|
-
/** Only present on `list()` — `create()`/`update()` omit it. */
|
|
402
|
-
usage_count?: number;
|
|
403
|
-
}
|
|
404
|
-
interface CreateTagDto {
|
|
405
|
-
name: string;
|
|
406
|
-
color?: string | null;
|
|
407
3639
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
3640
|
+
/** Counts summed over one sync run (every step, every mapping it covered). */
|
|
3641
|
+
interface OrttoSyncTotals {
|
|
3642
|
+
added: number;
|
|
3643
|
+
removed: number;
|
|
3644
|
+
unsubscribed: number;
|
|
3645
|
+
resubscribed: number;
|
|
3646
|
+
created: number;
|
|
3647
|
+
errors: number;
|
|
3648
|
+
/** Ortto opt-outs for emails no Planes person has — skipped. */
|
|
3649
|
+
unsubscribed_unknown: number;
|
|
411
3650
|
}
|
|
412
3651
|
/**
|
|
413
|
-
*
|
|
414
|
-
*
|
|
415
|
-
* that side of the set.
|
|
3652
|
+
* A mapping's last SUCCESSFUL run. A run that succeeded with a caveat carries
|
|
3653
|
+
* it in `warning`; `last_error` is set only when a run FAILED.
|
|
416
3654
|
*/
|
|
417
|
-
interface
|
|
418
|
-
|
|
419
|
-
|
|
3655
|
+
interface OrttoMappingLastResult extends OrttoSyncTotals {
|
|
3656
|
+
/** Pull: Ortto people without a usable email. */
|
|
3657
|
+
skipped_no_email?: number;
|
|
3658
|
+
/** Pull: unmatched people not created because `create_unmatched` is off. */
|
|
3659
|
+
skipped_unmatched?: number;
|
|
3660
|
+
/** Succeeded, but with this caveat. */
|
|
3661
|
+
warning?: string;
|
|
3662
|
+
trigger: string;
|
|
3663
|
+
finished_at: string;
|
|
420
3664
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
3665
|
+
/** The connection's most recent finished run, with connection-level counts. */
|
|
3666
|
+
interface OrttoSyncLastRun {
|
|
3667
|
+
finished_at: string;
|
|
3668
|
+
trigger: string;
|
|
3669
|
+
/** `completed`, `auth_failed` (key rejected) or `aborted` (a connection step failed). */
|
|
3670
|
+
status: string;
|
|
3671
|
+
/** Set when the run synced one mapping only. */
|
|
3672
|
+
mapping_id: string | null;
|
|
3673
|
+
totals: OrttoSyncTotals;
|
|
425
3674
|
}
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
3675
|
+
/** Omit `mapping_id` to sync every mapping on the connection. */
|
|
3676
|
+
interface RequestOrttoSyncDto {
|
|
3677
|
+
mapping_id?: string;
|
|
429
3678
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
total: number;
|
|
3679
|
+
/** `deduped` is true when a sync for the same target was already queued or running. */
|
|
3680
|
+
interface OrttoSyncRequestResult {
|
|
3681
|
+
job_id: string;
|
|
3682
|
+
deduped: boolean;
|
|
435
3683
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
3684
|
+
interface OrttoSyncStatusDto {
|
|
3685
|
+
connection: {
|
|
3686
|
+
id: string;
|
|
3687
|
+
status: string;
|
|
3688
|
+
error_message: string | null;
|
|
3689
|
+
last_sync_at: string | null;
|
|
3690
|
+
/** Null before the first finished run. */
|
|
3691
|
+
last_run: OrttoSyncLastRun | null;
|
|
3692
|
+
};
|
|
3693
|
+
/** True while any sync on the connection is queued or running. */
|
|
3694
|
+
running: boolean;
|
|
3695
|
+
mappings: Array<{
|
|
3696
|
+
id: string;
|
|
3697
|
+
list_id: string;
|
|
3698
|
+
direction: OrttoMappingDirection;
|
|
3699
|
+
last_synced_at: string | null;
|
|
3700
|
+
last_result: OrttoMappingLastResult | null;
|
|
3701
|
+
/** Set only when the mapping's last run FAILED (a warning is in last_result). */
|
|
3702
|
+
last_error: string | null;
|
|
3703
|
+
running: boolean;
|
|
442
3704
|
}>;
|
|
443
|
-
getEntityTags(entityType: string, entityId: string): Promise<EntityTagDto[]>;
|
|
444
|
-
getEntities(tagId: string, params?: Record<string, unknown>): Promise<TagEntitiesPage>;
|
|
445
3705
|
}
|
|
446
3706
|
|
|
447
3707
|
/**
|
|
448
|
-
*
|
|
3708
|
+
* Ortto connector (E53) — list mappings, the connected account's audiences,
|
|
3709
|
+
* manual sync and sync status under `/admin/integrations/ortto`. Admin-only
|
|
3710
|
+
* (Manage IntegrationConnection) and gated by the `marketplace` feature.
|
|
3711
|
+
* Connecting the Ortto API key is out of scope. Every route wraps its payload
|
|
3712
|
+
* in `{ data }`; the methods unwrap it. Not a CRUD resource (no get-by-id), so
|
|
3713
|
+
* it does NOT extend `BaseResource`.
|
|
3714
|
+
*/
|
|
3715
|
+
declare class OrttoResource {
|
|
3716
|
+
private readonly http;
|
|
3717
|
+
private readonly basePath;
|
|
3718
|
+
constructor(http: HttpClient);
|
|
3719
|
+
/** GET /admin/integrations/ortto/mappings — live mappings with their list names. */
|
|
3720
|
+
listMappings(): Promise<OrttoMappingDto[]>;
|
|
3721
|
+
/** GET /admin/integrations/ortto/audiences — the connected account's audiences (cached 60 s). */
|
|
3722
|
+
listAudiences(params?: ListOrttoAudiencesParams): Promise<OrttoAudienceDto[]>;
|
|
3723
|
+
/** POST /admin/integrations/ortto/mappings — 409 when the list already has a mapping. */
|
|
3724
|
+
createMapping(data: CreateOrttoMappingDto): Promise<OrttoMappingDto>;
|
|
3725
|
+
/** PATCH /admin/integrations/ortto/mappings/:id — `ortto_tag` and/or `create_unmatched`. */
|
|
3726
|
+
updateMapping(id: string, data: UpdateOrttoMappingDto): Promise<OrttoMappingDto>;
|
|
3727
|
+
/**
|
|
3728
|
+
* DELETE /admin/integrations/ortto/mappings/:id (204). A pull list becomes
|
|
3729
|
+
* editable again and keeps its members; a push tag is NOT removed from Ortto.
|
|
3730
|
+
*/
|
|
3731
|
+
deleteMapping(id: string): Promise<void>;
|
|
3732
|
+
/**
|
|
3733
|
+
* POST /admin/integrations/ortto/sync (202) — queue a sync for one mapping or
|
|
3734
|
+
* the whole connection. Never calls Ortto in-request.
|
|
3735
|
+
*/
|
|
3736
|
+
sync(data?: RequestOrttoSyncDto): Promise<OrttoSyncRequestResult>;
|
|
3737
|
+
/** GET /admin/integrations/ortto/sync-status — 404 when Ortto is not connected. */
|
|
3738
|
+
syncStatus(): Promise<OrttoSyncStatusDto>;
|
|
3739
|
+
}
|
|
3740
|
+
|
|
3741
|
+
/**
|
|
3742
|
+
* Every subscribable webhook event type, in the server's canonical order.
|
|
449
3743
|
*
|
|
450
|
-
* Mirrored (self-contained, NOT imported) from
|
|
451
|
-
* `packages/shared
|
|
452
|
-
*
|
|
3744
|
+
* Mirrored (self-contained, NOT imported) from `WEBHOOK_EVENT_TYPES` in
|
|
3745
|
+
* `packages/shared` — the SDK must not depend on `@blueprint/shared`.
|
|
3746
|
+
* `webhooks.spec.ts` asserts runtime parity, so drift fails there.
|
|
453
3747
|
*/
|
|
454
|
-
|
|
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"];
|
|
3749
|
+
/** The kinds of change a webhook event can describe. */
|
|
3750
|
+
type EntityEventType = (typeof WEBHOOK_EVENT_TYPES)[number];
|
|
455
3751
|
/**
|
|
456
3752
|
* The entity kinds a webhook event can target.
|
|
457
3753
|
*
|
|
458
3754
|
* Mirrored (self-contained, NOT imported) from
|
|
459
3755
|
* `packages/shared/src/types/entity-events.ts`. Keep byte-identical.
|
|
460
3756
|
*/
|
|
461
|
-
type EntityType = 'customer' | 'opportunity' | 'job' | 'estimate' | 'contract' | 'property' | 'inventory_item' | 'agent_execution' | 'calendar_event' | 'invoice' | 'payment';
|
|
3757
|
+
type EntityType = 'customer' | 'opportunity' | 'job' | 'estimate' | 'contract' | 'property' | 'inventory_item' | 'agent_execution' | 'calendar_event' | 'invoice' | 'payment' | 'billing_schedule' | 'integration_connection';
|
|
462
3758
|
/**
|
|
463
3759
|
* A single entity-change event as emitted onto the Planes event bus and
|
|
464
3760
|
* delivered inside a {@link WebhookDelivery}.
|
|
@@ -487,6 +3783,142 @@ interface EntityEvent {
|
|
|
487
3783
|
/** Correlation ID linking related events/actions. */
|
|
488
3784
|
correlation_id: string;
|
|
489
3785
|
}
|
|
3786
|
+
/**
|
|
3787
|
+
* `event.snapshot` of an `invoice.overdue` event (E56-F8-S2). Planes' daily
|
|
3788
|
+
* overdue sweep emits it once per invoice at each of the company's overdue
|
|
3789
|
+
* offsets (default 3, 7 and 14 days after the due date) while the invoice is
|
|
3790
|
+
* sent and not fully paid. After downtime only the highest offset reached is
|
|
3791
|
+
* emitted. Mirrored from `InvoiceOverdueSnapshot` in `packages/shared`.
|
|
3792
|
+
*/
|
|
3793
|
+
interface InvoiceOverdueSnapshot {
|
|
3794
|
+
invoiceId: string;
|
|
3795
|
+
invoiceNumber: string;
|
|
3796
|
+
customerId: string;
|
|
3797
|
+
/** The configured offset this event is for (days after the due date). */
|
|
3798
|
+
offsetDays: number;
|
|
3799
|
+
/** Whole days since the due date when the sweep ran (at least `offsetDays`). */
|
|
3800
|
+
daysOverdue: number;
|
|
3801
|
+
/** Dollars still owed, as a decimal string, e.g. `'1250.00'`. */
|
|
3802
|
+
balance: string;
|
|
3803
|
+
currency: string;
|
|
3804
|
+
/** ISO 8601. */
|
|
3805
|
+
dueAt: string;
|
|
3806
|
+
/** Where the invoice came from, e.g. `'billing_schedule'`. */
|
|
3807
|
+
sourceType: string;
|
|
3808
|
+
/** The billing schedule, when the invoice came from one. */
|
|
3809
|
+
scheduleId?: string;
|
|
3810
|
+
}
|
|
3811
|
+
/**
|
|
3812
|
+
* An `invoice.overdue` event: the standard {@link EntityEvent} envelope
|
|
3813
|
+
* (`entity_type` `'invoice'`, `entity_id` the invoice, `changes` `{}`) with a
|
|
3814
|
+
* typed snapshot. Narrow a delivery with `event.event_type === 'invoice.overdue'`.
|
|
3815
|
+
*/
|
|
3816
|
+
interface InvoiceOverdueEvent extends Omit<EntityEvent, 'event_type' | 'entity_type' | 'snapshot'> {
|
|
3817
|
+
event_type: 'invoice.overdue';
|
|
3818
|
+
entity_type: 'invoice';
|
|
3819
|
+
snapshot: InvoiceOverdueSnapshot & Record<string, unknown>;
|
|
3820
|
+
}
|
|
3821
|
+
/**
|
|
3822
|
+
* `event.snapshot` of an `integration_connection.deactivated` event
|
|
3823
|
+
* (E56-F7-S2): one of the company's integration connections was disconnected,
|
|
3824
|
+
* or replaced by a new connection for the same provider. Mirrored from
|
|
3825
|
+
* `IntegrationConnectionDeactivatedSnapshot` in `packages/shared`.
|
|
3826
|
+
*/
|
|
3827
|
+
interface IntegrationConnectionDeactivatedSnapshot {
|
|
3828
|
+
connectionId: string;
|
|
3829
|
+
/** The provider, e.g. `'stripe'`. */
|
|
3830
|
+
providerSlug: string;
|
|
3831
|
+
reason: 'disconnected' | 'replaced';
|
|
3832
|
+
/** The new connection, for `replaced`; otherwise null. */
|
|
3833
|
+
replacedByConnectionId: string | null;
|
|
3834
|
+
}
|
|
3835
|
+
/**
|
|
3836
|
+
* An `integration_connection.deactivated` event: the standard
|
|
3837
|
+
* {@link EntityEvent} envelope (`entity_type` `'integration_connection'`,
|
|
3838
|
+
* `entity_id` the connection, `changes` `{}`) with a typed snapshot.
|
|
3839
|
+
*/
|
|
3840
|
+
interface IntegrationConnectionDeactivatedEvent extends Omit<EntityEvent, 'event_type' | 'entity_type' | 'snapshot'> {
|
|
3841
|
+
event_type: 'integration_connection.deactivated';
|
|
3842
|
+
entity_type: 'integration_connection';
|
|
3843
|
+
snapshot: IntegrationConnectionDeactivatedSnapshot & Record<string, unknown>;
|
|
3844
|
+
}
|
|
3845
|
+
/**
|
|
3846
|
+
* `event.snapshot` of a `customer_payment_method.invalidated` event
|
|
3847
|
+
* (E56-F7-S2): a customer's saved card can no longer be charged because the
|
|
3848
|
+
* Stripe connection it was saved on went away. One event per card. Mirrored
|
|
3849
|
+
* from `CustomerPaymentMethodInvalidatedSnapshot` in `packages/shared`.
|
|
3850
|
+
*/
|
|
3851
|
+
interface CustomerPaymentMethodInvalidatedSnapshot {
|
|
3852
|
+
customerId: string;
|
|
3853
|
+
/** The saved payment method's id. */
|
|
3854
|
+
paymentMethodId: string;
|
|
3855
|
+
/** The connection the card lived on. */
|
|
3856
|
+
connectionId: string;
|
|
3857
|
+
/** Why, e.g. `'connection_changed'`. */
|
|
3858
|
+
reason: string;
|
|
3859
|
+
}
|
|
3860
|
+
/**
|
|
3861
|
+
* A `customer_payment_method.invalidated` event: the standard
|
|
3862
|
+
* {@link EntityEvent} envelope (`entity_type` `'customer'`, `entity_id` the
|
|
3863
|
+
* customer, `changes` `{}`) with a typed snapshot.
|
|
3864
|
+
*/
|
|
3865
|
+
interface CustomerPaymentMethodInvalidatedEvent extends Omit<EntityEvent, 'event_type' | 'entity_type' | 'snapshot'> {
|
|
3866
|
+
event_type: 'customer_payment_method.invalidated';
|
|
3867
|
+
entity_type: 'customer';
|
|
3868
|
+
snapshot: CustomerPaymentMethodInvalidatedSnapshot & Record<string, unknown>;
|
|
3869
|
+
}
|
|
3870
|
+
/**
|
|
3871
|
+
* `event.snapshot` of an `invoice.autopay_succeeded` event (E56-F7-S4): a
|
|
3872
|
+
* billing schedule's autopay charge on the customer's saved card was paid.
|
|
3873
|
+
* Mirrored from `InvoiceAutopaySucceededSnapshot` in `packages/shared`.
|
|
3874
|
+
*/
|
|
3875
|
+
interface InvoiceAutopaySucceededSnapshot {
|
|
3876
|
+
invoiceId: string;
|
|
3877
|
+
scheduleId: string;
|
|
3878
|
+
periodId: string;
|
|
3879
|
+
/** The charge attempt that succeeded (1, or 2 after a decline). */
|
|
3880
|
+
attempt: number;
|
|
3881
|
+
paymentIntentId: string;
|
|
3882
|
+
}
|
|
3883
|
+
/**
|
|
3884
|
+
* An `invoice.autopay_succeeded` event: the standard {@link EntityEvent}
|
|
3885
|
+
* envelope (`entity_type` `'invoice'`, `entity_id` the invoice, `changes` `{}`)
|
|
3886
|
+
* with a typed snapshot.
|
|
3887
|
+
*/
|
|
3888
|
+
interface InvoiceAutopaySucceededEvent extends Omit<EntityEvent, 'event_type' | 'entity_type' | 'snapshot'> {
|
|
3889
|
+
event_type: 'invoice.autopay_succeeded';
|
|
3890
|
+
entity_type: 'invoice';
|
|
3891
|
+
snapshot: InvoiceAutopaySucceededSnapshot & Record<string, unknown>;
|
|
3892
|
+
}
|
|
3893
|
+
/**
|
|
3894
|
+
* `event.snapshot` of an `invoice.autopay_failed` event (E56-F7-S4): one
|
|
3895
|
+
* autopay attempt ended without a payment — exactly one event per failed
|
|
3896
|
+
* attempt. `reason` is `'authentication_required'` (the customer was emailed
|
|
3897
|
+
* the pay link; never retried), the card's decline code (e.g.
|
|
3898
|
+
* `'insufficient_funds'`), or why autopay gave up (e.g. `'no_saved_method'`).
|
|
3899
|
+
* Mirrored from `InvoiceAutopayFailedSnapshot` in `packages/shared`.
|
|
3900
|
+
*/
|
|
3901
|
+
interface InvoiceAutopayFailedSnapshot {
|
|
3902
|
+
invoiceId: string;
|
|
3903
|
+
scheduleId: string;
|
|
3904
|
+
periodId: string;
|
|
3905
|
+
attempt: number;
|
|
3906
|
+
reason: string;
|
|
3907
|
+
/** True when a second attempt is scheduled (after a first decline). */
|
|
3908
|
+
willRetry: boolean;
|
|
3909
|
+
/** ISO 8601, present when `willRetry`. */
|
|
3910
|
+
nextAttemptAt?: string;
|
|
3911
|
+
}
|
|
3912
|
+
/**
|
|
3913
|
+
* An `invoice.autopay_failed` event: the standard {@link EntityEvent}
|
|
3914
|
+
* envelope (`entity_type` `'invoice'`, `entity_id` the invoice, `changes` `{}`)
|
|
3915
|
+
* with a typed snapshot.
|
|
3916
|
+
*/
|
|
3917
|
+
interface InvoiceAutopayFailedEvent extends Omit<EntityEvent, 'event_type' | 'entity_type' | 'snapshot'> {
|
|
3918
|
+
event_type: 'invoice.autopay_failed';
|
|
3919
|
+
entity_type: 'invoice';
|
|
3920
|
+
snapshot: InvoiceAutopayFailedSnapshot & Record<string, unknown>;
|
|
3921
|
+
}
|
|
490
3922
|
/**
|
|
491
3923
|
* The webhook delivery envelope Planes POSTs to a subscriber's URL.
|
|
492
3924
|
*
|
|
@@ -632,7 +4064,26 @@ declare class PlanesClient {
|
|
|
632
4064
|
private _inventory?;
|
|
633
4065
|
private _contacts?;
|
|
634
4066
|
private _activities?;
|
|
4067
|
+
private _communications?;
|
|
4068
|
+
private _conversations?;
|
|
4069
|
+
private _gmail?;
|
|
4070
|
+
private _documents?;
|
|
635
4071
|
private _tags?;
|
|
4072
|
+
private _tasks?;
|
|
4073
|
+
private _recordViews?;
|
|
4074
|
+
private _modules?;
|
|
4075
|
+
private _plan?;
|
|
4076
|
+
private _me?;
|
|
4077
|
+
private _roles?;
|
|
4078
|
+
private _invoiceSettings?;
|
|
4079
|
+
private _invoiceReminders?;
|
|
4080
|
+
private _contactSequences?;
|
|
4081
|
+
private _enrollments?;
|
|
4082
|
+
private _workflows?;
|
|
4083
|
+
private _serviceSchedules?;
|
|
4084
|
+
private _billingSchedules?;
|
|
4085
|
+
private _customFields?;
|
|
4086
|
+
private _ortto?;
|
|
636
4087
|
private _webhooks?;
|
|
637
4088
|
constructor(config: PlanesConfig);
|
|
638
4089
|
get opportunities(): OpportunityResource;
|
|
@@ -646,7 +4097,42 @@ declare class PlanesClient {
|
|
|
646
4097
|
get inventory(): InventoryResource;
|
|
647
4098
|
get contacts(): ContactResource;
|
|
648
4099
|
get activities(): ActivityResource;
|
|
4100
|
+
get communications(): CommunicationsResource;
|
|
4101
|
+
/** Logged meetings — manual + provider-synced, with company matching (E55). */
|
|
4102
|
+
get conversations(): ConversationsResource;
|
|
4103
|
+
get gmail(): GmailResource;
|
|
4104
|
+
get documents(): DocumentsResource;
|
|
649
4105
|
get tags(): TagResource;
|
|
4106
|
+
get tasks(): TaskResource;
|
|
4107
|
+
/** Record views — the "recently viewed" beacon + read (E41-F7). */
|
|
4108
|
+
get recordViews(): RecordViewsResource;
|
|
4109
|
+
/** Module status — which modules are active for the caller's tenant (E51-F1-S1). */
|
|
4110
|
+
get modules(): ModulesResource;
|
|
4111
|
+
/** The tenant's plan, billing status and plan ceiling — `plan.get()` (E54-F1-S2). */
|
|
4112
|
+
get plan(): PlanResource;
|
|
4113
|
+
/** The authenticated caller — `me.abilities()` (E52-F1-S3). */
|
|
4114
|
+
get me(): MeResource;
|
|
4115
|
+
/** Settings → Roles, admin only — `roles.list/get/updateGrants/reset/history` (E52-F2-S5). */
|
|
4116
|
+
get roles(): RolesResource;
|
|
4117
|
+
/** Invoice settings — `invoiceSettings.getOfflineInstructions/setOfflineInstructions` (E56-F5-S4). */
|
|
4118
|
+
get invoiceSettings(): InvoiceSettingsResource;
|
|
4119
|
+
/** Payment reminder settings, admin only — `invoiceReminders.list/update/preview` (E56-F8-S6). */
|
|
4120
|
+
get invoiceReminders(): InvoiceRemindersResource;
|
|
4121
|
+
/** Published sequences a contact can be enrolled in (E51-F2-S6). */
|
|
4122
|
+
get contactSequences(): ContactSequencesResource;
|
|
4123
|
+
/** Enroll a contact in a sequence, list its enrollments, exit one (E51-F2-S8). */
|
|
4124
|
+
get enrollments(): EnrollmentsResource;
|
|
4125
|
+
/** Tenant-readable workflow reads — a workflow version's ordered stages. */
|
|
4126
|
+
get workflows(): WorkflowsResource;
|
|
4127
|
+
get serviceSchedules(): ServiceSchedulesResource;
|
|
4128
|
+
/**
|
|
4129
|
+
* Recurring billing schedules (E56-F3) — CRUD, pause/resume/end, preview,
|
|
4130
|
+
* the period ledger, Needs review, generate-now, skip and regenerate.
|
|
4131
|
+
*/
|
|
4132
|
+
get billingSchedules(): BillingScheduleResource;
|
|
4133
|
+
get customFields(): CustomFieldsResource;
|
|
4134
|
+
/** Ortto connector — list mappings, audiences, manual sync, sync status (E53). Admin-only. */
|
|
4135
|
+
get ortto(): OrttoResource;
|
|
650
4136
|
/**
|
|
651
4137
|
* Ergonomic webhook event router — `client.webhooks.on(pattern, handler)`
|
|
652
4138
|
* plus `client.webhooks.process({ body, signature, secret })`. Auth-independent
|
|
@@ -1172,4 +4658,4 @@ interface CustomersGeneratedResource {
|
|
|
1172
4658
|
createCustomer(data: CreateCustomerDto): Promise<CustomerDto>;
|
|
1173
4659
|
}
|
|
1174
4660
|
|
|
1175
|
-
export { type ActionContext, type ActionHandler, type ActionRequest, type ActionResult, type ActivityDto, ActivityResource, AgentApp, type AgentHandler, AuthenticationError, AuthorizationError, type AuthorizeOptions, BaseResource, CalendarEventResource, type ClientCredentialsOptions, type ContactChannelDto, ContactChannelResource, type ContactDto, type ContactMergeResult, ContactResource, ContractResource, type CreateActivityDto, type CreateContactChannelDto, type CreateContactDto, type CreateCustomerDto, type CreateOpportunityDto, type CreateTagDto, type CustomerDto, CustomerResource, type CustomersGeneratedResource, DEFAULT_BASE_URL, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, DEFAULT_TOKEN_REFRESH_SKEW_MS, type EntityEvent, type EntityEventType, type EntityTagDto, type EntityType, EstimateResource, type ExchangeCodeOptions, type FieldError, type HandlerMap, InventoryResource, InvoiceResource, JobResource, type ListParams, MemoryTokenStorage, NotFoundError, OAuthError, type OpportunitiesGeneratedResource, type OpportunityDto, OpportunityResource, type PaginatedCustomerResponse, type PaginatedOpportunityResponse, type PaginatedResponse, type PaginationMeta, type PermissionLevel, Planes, PlanesClient, type PlanesConfig, PlanesError, PropertyResource, RateLimitError, type RefreshOptions, type RegisterOptions, ServerError, type SetEntityTagsDto, type StoredTokens, type TagDto, type TagEntityDto, TagResource, type TokenResponse, type TokenStorage, type TriggerType, type UpdateContactChannelDto, type UpdateContactDto, type UpdateOpportunityDto, type UpdateTagDto, ValidationError, type WebhookDelivery, type WebhookHandler, type WebhookProcessInput, WebhookRouter, WebhookVerificationError, buildAuthorizeUrl, clientCredentialsGrant, createAgentApp, exchangeCode, parseWebhookEvent, refreshAccessToken, verifyWebhookSignature };
|
|
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 };
|