@dench.com/cli 3.5.6-staging.344 → 3.6.0-staging.356

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/app-sdk.d.ts CHANGED
@@ -12,6 +12,443 @@
12
12
  // ── Operation request/response types (from cli/lib/api-schemas.ts) ──────
13
13
 
14
14
  export interface ApiRequests {
15
+ /** Create an idempotent empty campaign draft with the caller's available sender pools. Does not launch or send. — `dench campaign draft` — POST /api/v1/campaigns/drafts */
16
+ "campaigns.drafts.create": {
17
+ /** Your stable id for this request, 8-64 characters. Retrying with the same id returns the same draft instead of creating another. */
18
+ clientRequestId: string;
19
+ name?: string;
20
+ /** IANA timezone, e.g. America/Los_Angeles. Sets a Mon-Fri 9-18 send window in it; without one the draft has no send window. */
21
+ timezone?: string;
22
+ };
23
+ /** Search people by filters without adding CRM records or campaign recipients. Search credits apply; this is not a free provider preview. — `dench campaign search` — POST /api/v1/campaigns/audience/search */
24
+ "campaigns.audience.search": {
25
+ sequenceId?: string;
26
+ filters: {
27
+ linkedinUrl?: string;
28
+ fullName?: string;
29
+ firstName?: string;
30
+ lastName?: string;
31
+ /** Current-title text only. For profile or work descriptions, use profileKeywords. Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
32
+ keywords?: string;
33
+ companyDomain?: string;
34
+ companyName?: string;
35
+ /** Current job titles (free text). Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
36
+ titles?: Array<string | {
37
+ value: string;
38
+ exclude?: boolean;
39
+ exactMatch?: boolean;
40
+ }>;
41
+ /** Past job titles (free text). */
42
+ pastTitles?: Array<string | {
43
+ value: string;
44
+ exclude?: boolean;
45
+ exactMatch?: boolean;
46
+ }>;
47
+ personNames?: Array<string | {
48
+ value: string;
49
+ exclude?: boolean;
50
+ exactMatch?: boolean;
51
+ }>;
52
+ /** Seniority in any past role, independent of pastCompanyNames/pastTitles. Current seniority vocabulary plus Founding Team. Founder includes Co-Founder; C-level and Founding Team do not imply founder. Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
53
+ pastSeniorities?: Array<string | {
54
+ value: string;
55
+ exclude?: boolean;
56
+ exactMatch?: boolean;
57
+ }>;
58
+ /** Text in headline/about or any current/past work description. OR includes, global exclusions. Always loose text matching; missing evidence does not match. */
59
+ profileKeywords?: Array<string | {
60
+ value: string;
61
+ exclude?: boolean;
62
+ exactMatch?: boolean;
63
+ }>;
64
+ /** Current employer business focus/model (e.g. SaaS, B2B, Cloud), from description/tagline/business tags; distinct from legal companyTypes. Same employer as other current-job filters. Always loose text matching. May need another filter to retrieve candidates. */
65
+ companyKeywords?: Array<string | {
66
+ value: string;
67
+ exclude?: boolean;
68
+ exactMatch?: boolean;
69
+ }>;
70
+ /** Exact enum: Owner, Founder, C-level, Partner, VP, Head, Director, Manager, Senior. */
71
+ seniorities?: Array<string | {
72
+ value: string;
73
+ exclude?: boolean;
74
+ exactMatch?: boolean;
75
+ }>;
76
+ /** Exact enum, e.g. Sales, Marketing, Software. Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
77
+ jobFunctions?: Array<string | {
78
+ value: string;
79
+ exclude?: boolean;
80
+ exactMatch?: boolean;
81
+ }>;
82
+ /** Exact enum, e.g. SDR/BDR, Demand Generation. Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
83
+ subFunctions?: Array<string | {
84
+ value: string;
85
+ exclude?: boolean;
86
+ exactMatch?: boolean;
87
+ }>;
88
+ /** Exact enum, e.g. Software Development. Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
89
+ industries?: Array<string | {
90
+ value: string;
91
+ exclude?: boolean;
92
+ exactMatch?: boolean;
93
+ }>;
94
+ /** Person locations — cities, states, countries, or metros (free text). Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
95
+ locations?: Array<string | {
96
+ value: string;
97
+ exclude?: boolean;
98
+ exactMatch?: boolean;
99
+ }>;
100
+ /** Exact buckets: 1-10, 11-50, 51-200, 201-500, 501-1000, 1001-5000, 5001-10000, 10001+. */
101
+ headcountRanges?: Array<string | {
102
+ value: string;
103
+ exclude?: boolean;
104
+ exactMatch?: boolean;
105
+ }>;
106
+ companyNames?: Array<string | {
107
+ value: string;
108
+ exclude?: boolean;
109
+ exactMatch?: boolean;
110
+ }>;
111
+ pastCompanyNames?: Array<string | {
112
+ value: string;
113
+ exclude?: boolean;
114
+ exactMatch?: boolean;
115
+ }>;
116
+ companyDomains?: Array<string | {
117
+ value: string;
118
+ exclude?: boolean;
119
+ exactMatch?: boolean;
120
+ }>;
121
+ /** Company HQ locations — cities, states, countries, or metros (free text). Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
122
+ companyHeadquarters?: Array<string | {
123
+ value: string;
124
+ exclude?: boolean;
125
+ exactMatch?: boolean;
126
+ }>;
127
+ /** Exact enum: Partnership, Nonprofit, Educational, Privately Held, Public Company, Self-Owned, Self-Employed, Government Agency. */
128
+ companyTypes?: Array<string | {
129
+ value: string;
130
+ exclude?: boolean;
131
+ exactMatch?: boolean;
132
+ }>;
133
+ /** Universities attended (free text). Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
134
+ universities?: Array<string | {
135
+ value: string;
136
+ exclude?: boolean;
137
+ exactMatch?: boolean;
138
+ }>;
139
+ /** Profile skills (free text). Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
140
+ skills?: Array<string | {
141
+ value: string;
142
+ exclude?: boolean;
143
+ exactMatch?: boolean;
144
+ }>;
145
+ /** Spoken languages, e.g. English, German. Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
146
+ languages?: Array<string | {
147
+ value: string;
148
+ exclude?: boolean;
149
+ exactMatch?: boolean;
150
+ }>;
151
+ yearsInRole?: {
152
+ min?: number;
153
+ max?: number;
154
+ };
155
+ yearsAtCompany?: {
156
+ min?: number;
157
+ max?: number;
158
+ };
159
+ daysSinceJobChange?: {
160
+ min?: number;
161
+ max?: number;
162
+ };
163
+ /** Company founded-year range, e.g. {min: 2015, max: 2024}. */
164
+ foundedYears?: {
165
+ min?: number;
166
+ max?: number;
167
+ };
168
+ /** Match free-text filters as whole strings. Default false: titles ['Founder'] also returns 'Co-Founder' and 'Founder & CEO'. Set true to narrow. Domains, LinkedIn URLs, enum filters and numeric ranges are always exact; keywords is always a loose text probe. */
169
+ exactMatch?: boolean;
170
+ preferCache?: boolean;
171
+ };
172
+ limit?: number;
173
+ pageToken?: string;
174
+ };
175
+ /** Search and add up to 50 people to an existing campaign. New identities become Leads. Search credits apply; use nextPageToken for another page. — `dench campaign add --search` — POST /api/v1/campaigns/{sequenceId}/people/search */
176
+ "campaigns.people.addFromSearch": {
177
+ sequenceId: string;
178
+ filters: {
179
+ linkedinUrl?: string;
180
+ fullName?: string;
181
+ firstName?: string;
182
+ lastName?: string;
183
+ /** Current-title text only. For profile or work descriptions, use profileKeywords. Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
184
+ keywords?: string;
185
+ companyDomain?: string;
186
+ companyName?: string;
187
+ /** Current job titles (free text). Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
188
+ titles?: Array<string | {
189
+ value: string;
190
+ exclude?: boolean;
191
+ exactMatch?: boolean;
192
+ }>;
193
+ /** Past job titles (free text). */
194
+ pastTitles?: Array<string | {
195
+ value: string;
196
+ exclude?: boolean;
197
+ exactMatch?: boolean;
198
+ }>;
199
+ personNames?: Array<string | {
200
+ value: string;
201
+ exclude?: boolean;
202
+ exactMatch?: boolean;
203
+ }>;
204
+ /** Seniority in any past role, independent of pastCompanyNames/pastTitles. Current seniority vocabulary plus Founding Team. Founder includes Co-Founder; C-level and Founding Team do not imply founder. Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
205
+ pastSeniorities?: Array<string | {
206
+ value: string;
207
+ exclude?: boolean;
208
+ exactMatch?: boolean;
209
+ }>;
210
+ /** Text in headline/about or any current/past work description. OR includes, global exclusions. Always loose text matching; missing evidence does not match. */
211
+ profileKeywords?: Array<string | {
212
+ value: string;
213
+ exclude?: boolean;
214
+ exactMatch?: boolean;
215
+ }>;
216
+ /** Current employer business focus/model (e.g. SaaS, B2B, Cloud), from description/tagline/business tags; distinct from legal companyTypes. Same employer as other current-job filters. Always loose text matching. May need another filter to retrieve candidates. */
217
+ companyKeywords?: Array<string | {
218
+ value: string;
219
+ exclude?: boolean;
220
+ exactMatch?: boolean;
221
+ }>;
222
+ /** Exact enum: Owner, Founder, C-level, Partner, VP, Head, Director, Manager, Senior. */
223
+ seniorities?: Array<string | {
224
+ value: string;
225
+ exclude?: boolean;
226
+ exactMatch?: boolean;
227
+ }>;
228
+ /** Exact enum, e.g. Sales, Marketing, Software. Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
229
+ jobFunctions?: Array<string | {
230
+ value: string;
231
+ exclude?: boolean;
232
+ exactMatch?: boolean;
233
+ }>;
234
+ /** Exact enum, e.g. SDR/BDR, Demand Generation. Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
235
+ subFunctions?: Array<string | {
236
+ value: string;
237
+ exclude?: boolean;
238
+ exactMatch?: boolean;
239
+ }>;
240
+ /** Exact enum, e.g. Software Development. Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
241
+ industries?: Array<string | {
242
+ value: string;
243
+ exclude?: boolean;
244
+ exactMatch?: boolean;
245
+ }>;
246
+ /** Person locations — cities, states, countries, or metros (free text). Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
247
+ locations?: Array<string | {
248
+ value: string;
249
+ exclude?: boolean;
250
+ exactMatch?: boolean;
251
+ }>;
252
+ /** Exact buckets: 1-10, 11-50, 51-200, 201-500, 501-1000, 1001-5000, 5001-10000, 10001+. */
253
+ headcountRanges?: Array<string | {
254
+ value: string;
255
+ exclude?: boolean;
256
+ exactMatch?: boolean;
257
+ }>;
258
+ companyNames?: Array<string | {
259
+ value: string;
260
+ exclude?: boolean;
261
+ exactMatch?: boolean;
262
+ }>;
263
+ pastCompanyNames?: Array<string | {
264
+ value: string;
265
+ exclude?: boolean;
266
+ exactMatch?: boolean;
267
+ }>;
268
+ companyDomains?: Array<string | {
269
+ value: string;
270
+ exclude?: boolean;
271
+ exactMatch?: boolean;
272
+ }>;
273
+ /** Company HQ locations — cities, states, countries, or metros (free text). Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
274
+ companyHeadquarters?: Array<string | {
275
+ value: string;
276
+ exclude?: boolean;
277
+ exactMatch?: boolean;
278
+ }>;
279
+ /** Exact enum: Partnership, Nonprofit, Educational, Privately Held, Public Company, Self-Owned, Self-Employed, Government Agency. */
280
+ companyTypes?: Array<string | {
281
+ value: string;
282
+ exclude?: boolean;
283
+ exactMatch?: boolean;
284
+ }>;
285
+ /** Universities attended (free text). Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
286
+ universities?: Array<string | {
287
+ value: string;
288
+ exclude?: boolean;
289
+ exactMatch?: boolean;
290
+ }>;
291
+ /** Profile skills (free text). Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
292
+ skills?: Array<string | {
293
+ value: string;
294
+ exclude?: boolean;
295
+ exactMatch?: boolean;
296
+ }>;
297
+ /** Spoken languages, e.g. English, German. Accepted values: see `dench leads filters` or https://dench.com/references/find-filter-options.json. */
298
+ languages?: Array<string | {
299
+ value: string;
300
+ exclude?: boolean;
301
+ exactMatch?: boolean;
302
+ }>;
303
+ yearsInRole?: {
304
+ min?: number;
305
+ max?: number;
306
+ };
307
+ yearsAtCompany?: {
308
+ min?: number;
309
+ max?: number;
310
+ };
311
+ daysSinceJobChange?: {
312
+ min?: number;
313
+ max?: number;
314
+ };
315
+ /** Company founded-year range, e.g. {min: 2015, max: 2024}. */
316
+ foundedYears?: {
317
+ min?: number;
318
+ max?: number;
319
+ };
320
+ /** Match free-text filters as whole strings. Default false: titles ['Founder'] also returns 'Co-Founder' and 'Founder & CEO'. Set true to narrow. Domains, LinkedIn URLs, enum filters and numeric ranges are always exact; keywords is always a loose text probe. */
321
+ exactMatch?: boolean;
322
+ preferCache?: boolean;
323
+ };
324
+ limit?: number;
325
+ pageToken?: string;
326
+ checkDuplicatesAcrossWorkspace?: boolean;
327
+ };
328
+ /** Add up to 50 selected recipients without another search. Deduplicates, applies suppression, and preserves the campaign's launch state. — `dench campaign add --people-file` — POST /api/v1/campaigns/{sequenceId}/people/batch */
329
+ "campaigns.people.addBatch": {
330
+ sequenceId: string;
331
+ recipients: {
332
+ email?: string;
333
+ linkedinProfileUrl?: string;
334
+ displayName?: string;
335
+ /** Merge values keyed by name, e.g. {"Company":"Acme"} for {{Company}}. */
336
+ personalization?: Record<string, unknown>;
337
+ }[];
338
+ newRecordsObject?: "lead" | "people";
339
+ checkDuplicatesAcrossWorkspace?: boolean;
340
+ };
341
+ /** Read a campaign's saved signal source, targeting and schedule. — `dench campaign sources get` — GET /api/v1/campaigns/{sequenceId}/sources */
342
+ "campaigns.sources.get": {
343
+ sequenceId: string;
344
+ };
345
+ /** Read signal choices, suggested terms and current source configuration. — `dench campaign sources signals` — GET /api/v1/campaigns/{sequenceId}/sources/signals */
346
+ "campaigns.sources.signals": {
347
+ sequenceId: string;
348
+ };
349
+ /** Update source cadence, pause/resume, targeting, signals or terms. Active sources may perform billable future work. — `dench campaign sources set` — PATCH /api/v1/campaigns/{sequenceId}/sources */
350
+ "campaigns.sources.update": {
351
+ sequenceId: string;
352
+ status?: "active" | "paused";
353
+ cadence?: "daily" | "weekly" | "monthly";
354
+ findMoreMatching?: boolean;
355
+ targeting?: {
356
+ titles: string[];
357
+ locations: string[];
358
+ companySizes: string[];
359
+ industries: string[];
360
+ excludes: string[];
361
+ companies?: string[];
362
+ };
363
+ signal?: {
364
+ signal: "post_engagement" | "keyword" | "hiring" | "funding" | "launch" | "new_leader";
365
+ enabled: boolean;
366
+ };
367
+ terms?: {
368
+ signal: "post_engagement" | "keyword" | "hiring";
369
+ values: string[];
370
+ };
371
+ };
372
+ /** Preview a signal source using its current audience. Provider credits may apply; does not enroll people. — `dench campaign sources preview` — POST /api/v1/campaigns/{sequenceId}/sources/preview */
373
+ "campaigns.sources.preview": {
374
+ sequenceId: string;
375
+ signal: "post_engagement" | "keyword" | "hiring" | "funding" | "launch" | "new_leader";
376
+ terms?: string[];
377
+ };
378
+ /** Read the company profile and suggested campaign audience. — `dench campaign builder profile` — GET /api/v1/campaigns/builder/profile */
379
+ "campaigns.builder.profile": Record<string, unknown>;
380
+ /** Save a signal campaign's audience, signals and terms idempotently. Does not start a build. — `dench campaign builder save` — POST /api/v1/campaigns/builder/drafts */
381
+ "campaigns.builder.save": {
382
+ /** Your stable id for this request, 8-64 characters. Retrying with the same id returns the same draft instead of creating another. */
383
+ clientRequestId: string;
384
+ targeting: {
385
+ titles: string[];
386
+ locations: string[];
387
+ companySizes: string[];
388
+ industries: string[];
389
+ excludes: string[];
390
+ companies?: string[];
391
+ };
392
+ signals: Array<"post_engagement" | "keyword" | "hiring" | "funding" | "launch" | "new_leader">;
393
+ signalTerms?: {
394
+ post_engagement?: string[];
395
+ keyword?: string[];
396
+ hiring?: string[];
397
+ };
398
+ };
399
+ /** Read signal build progress, preview people, messages and errors. — `dench campaign builder get` — GET /api/v1/campaigns/builder/drafts/{draftId} */
400
+ "campaigns.builder.get": {
401
+ draftId: string;
402
+ };
403
+ /** Start the same billable signal/audience/message build used by the UI; poll the draft for progress. — `dench campaign builder build` — POST /api/v1/campaigns/builder/drafts/{draftId}/build */
404
+ "campaigns.builder.build": {
405
+ draftId: string;
406
+ };
407
+ /** Create a campaign from a reviewed signal draft. Does not launch the campaign. — `dench campaign builder create` — POST /api/v1/campaigns/builder/drafts/{draftId}/create */
408
+ "campaigns.builder.create": {
409
+ draftId: string;
410
+ name?: string;
411
+ timezone?: string;
412
+ };
413
+ /** Edit or reset one preview person's opening line before creating the campaign. — `dench campaign builder opener` — PUT /api/v1/campaigns/builder/drafts/{draftId}/people/{leadId}/opener */
414
+ "campaigns.builder.opener": {
415
+ draftId: string;
416
+ leadId: string;
417
+ opener: string;
418
+ };
419
+ /** Turn an audience description into targeting filters. AI credits apply. — `dench campaign builder autofill` — POST /api/v1/campaigns/builder/autofill */
420
+ "campaigns.builder.autofill": {
421
+ description: string;
422
+ };
423
+ /** Suggest signal terms for the selected audience. AI credits apply. — `dench campaign builder terms` — POST /api/v1/campaigns/builder/terms */
424
+ "campaigns.builder.terms": {
425
+ targeting: {
426
+ titles: string[];
427
+ locations: string[];
428
+ companySizes: string[];
429
+ industries: string[];
430
+ excludes: string[];
431
+ companies?: string[];
432
+ };
433
+ };
434
+ /** Estimate audience or weekly signal volume using the UI's cached estimator. Provider credits may apply. — `dench campaign builder estimate` — POST /api/v1/campaigns/builder/estimate */
435
+ "campaigns.builder.estimate": {
436
+ kind: "people" | "week";
437
+ targeting: {
438
+ titles: string[];
439
+ locations: string[];
440
+ companySizes: string[];
441
+ industries: string[];
442
+ excludes: string[];
443
+ companies?: string[];
444
+ };
445
+ signals?: Array<"post_engagement" | "keyword" | "hiring" | "funding" | "launch" | "new_leader">;
446
+ signalTerms?: {
447
+ post_engagement?: string[];
448
+ keyword?: string[];
449
+ hiring?: string[];
450
+ };
451
+ };
15
452
  /** List all CLI/API operations and parity classifications. — `dench help` — GET /api/v1/commands */
16
453
  "commands.list": Record<string, unknown>;
17
454
  /** Create an agent sign-in request. — `dench signin` — POST /api/v1/auth/signin-requests */
@@ -104,9 +541,36 @@ export interface ApiRequests {
104
541
  /** Get one saved search / list by artifact id. — `dench lists show` — GET /api/v1/lists/{artifactId} */
105
542
  "lists.get": Record<string, unknown>;
106
543
  /** Save find results as a named list (rows + filters become a workspace artifact). — `dench lists save` — POST /api/v1/lists */
107
- "lists.save": Record<string, unknown>;
544
+ "lists.save": {
545
+ /** Use find_people, find_companies or find_jobs for a prospect list. */
546
+ createdFrom: "find_people" | "find_companies" | "find_jobs" | "mixed" | "watch_fire" | "generate_image";
547
+ /** Name of the new list. */
548
+ title: string;
549
+ /** True makes the list visible in Find. Omitted saves an unlisted draft that can still be read or added to a campaign by id. */
550
+ saved?: boolean;
551
+ /** Original search filters to retain with the list. Saving does not run a search. */
552
+ filters?: unknown;
553
+ /** Complete person records from a search, including existing contact details and custom fields. */
554
+ people?: Record<string, unknown>[];
555
+ /** Complete company records from a search. */
556
+ companies?: Record<string, unknown>[];
557
+ /** Complete job records from a search. */
558
+ jobs?: Record<string, unknown>[];
559
+ };
108
560
  /** Update a saved list in place (title, filters, and/or replacement rows). — `dench lists update` — PATCH /api/v1/lists/{artifactId} */
109
- "lists.update": Record<string, unknown>;
561
+ "lists.update": {
562
+ /** The existing list id. */
563
+ artifactId: string;
564
+ title?: string;
565
+ /** Replacement filter metadata; does not run a new search. */
566
+ filters?: unknown;
567
+ /** Replacement people. Omit to preserve existing rows; an empty array clears them. */
568
+ people?: Record<string, unknown>[];
569
+ /** Replacement companies. Omit to preserve existing rows. */
570
+ companies?: Record<string, unknown>[];
571
+ /** Replacement jobs. Omit to preserve existing rows. */
572
+ jobs?: Record<string, unknown>[];
573
+ };
110
574
  /** Rename a saved search / list. — `dench lists rename` — POST /api/v1/lists/{artifactId}/rename */
111
575
  "lists.rename": Record<string, unknown>;
112
576
  /** Delete a saved search / list, its exported CSV/JSONL files, and any linked watch. — `dench lists delete` — DELETE /api/v1/lists/{artifactId} */
@@ -1881,6 +2345,8 @@ export interface ApiRequests {
1881
2345
  "email.sequence.enrollment.stop": Record<string, unknown>;
1882
2346
  /** Discover LinkedIn sender ids, labels, availability and remaining capacity visible to the acting workspace member. Never returns provider credentials. — `dench campaign accounts` — GET /api/v1/campaigns/accounts/linkedin */
1883
2347
  "campaigns.accounts.linkedin": Record<string, unknown>;
2348
+ /** Discover the mailboxes the acting workspace member can send campaign email from: ids for emailMailboxAccountIds, status, warm-up state and when it is done, the daily cold-email cap and what is left today. Never returns provider credentials. — `dench campaign accounts` — GET /api/v1/campaigns/accounts/email */
2349
+ "campaigns.accounts.email": Record<string, unknown>;
1884
2350
  /** List outreach campaigns (archived ones on request). — `dench campaign list` — GET /api/v1/campaigns */
1885
2351
  "campaigns.list": {
1886
2352
  /** Include archived campaigns. */
@@ -1896,6 +2362,11 @@ export interface ApiRequests {
1896
2362
  /** IANA timezone for the default Mon-Fri 9-18 send window. */
1897
2363
  timezone?: string;
1898
2364
  };
2365
+ /** Copy a campaign into a new draft named "<name> copy": the same steps, schedule, sender pools and personalized lines, its lead source paused, and no people. To reach more than 300 people, duplicate and add the next page of the search to the copy. — `dench campaign duplicate` — POST /api/v1/campaigns/{sequenceId}/duplicate */
2366
+ "campaigns.duplicate": {
2367
+ /** The campaign to copy; any status, including archived. */
2368
+ sequenceId: string;
2369
+ };
1899
2370
  /** Read a campaign: settings, steps, people, their current step and hold, last touches, linked leads. — `dench campaign get` — GET /api/v1/campaigns/{sequenceId} */
1900
2371
  "campaigns.get": {
1901
2372
  sequenceId: string;
@@ -1908,6 +2379,10 @@ export interface ApiRequests {
1908
2379
  "campaigns.live": {
1909
2380
  sequenceId: string;
1910
2381
  };
2382
+ /** Where a campaign's people sit in the workspace's lead pipeline right now: each lead Status in order with how many enrolled leads are at it, and how many have no lead or a status outside the pipeline. — `dench campaign pipeline` — GET /api/v1/campaigns/{sequenceId}/pipeline */
2383
+ "campaigns.pipeline": {
2384
+ sequenceId: string;
2385
+ };
1911
2386
  /** Change a campaign's name, sender pools, send windows, daily email cap, stop-on-reply, start or end. Works until archived; existing conversations keep their assigned sender. — `dench campaign set` — PATCH /api/v1/campaigns/{sequenceId} */
1912
2387
  "campaigns.update": {
1913
2388
  sequenceId: string;
@@ -1945,33 +2420,154 @@ export interface ApiRequests {
1945
2420
  /** Cold emails per day, 1-100. */
1946
2421
  dailySendCap?: number;
1947
2422
  };
1948
- /** Replace every step of a draft campaign (email, wait, LinkedIn visit, connection request, message). Configure sender pools on the campaign; step sender ids are legacy-only. — `dench campaign steps set` — PUT /api/v1/campaigns/{sequenceId}/steps */
2423
+ /** Replace every step of a draft campaign (email, wait, LinkedIn visit, connection request, message, post reaction, InMail). Steps are checked first: a field the step type would drop, missing text or {TOKEN} single braces are rejected, not saved. Configure sender pools on the campaign; step sender ids are legacy-only. — `dench campaign steps set` — PUT /api/v1/campaigns/{sequenceId}/steps */
1949
2424
  "campaigns.steps.replace": {
1950
2425
  sequenceId: string;
2426
+ /** Every step, in send order. Rejected, not trimmed: a field the step type would drop (onlyIf off email/post-like steps, a body on a visit, reply-in-thread on the first email), a missing subject or required body, an overlength note/message/InMail subject, out-of-range wait/withdrawal/post-age values, and {TOKEN} single braces, which would be sent as typed. */
1951
2427
  steps: Array<{
1952
2428
  /** Step type. */
1953
- type: "email" | "wait" | "linkedin_visit" | "linkedin_connection" | "linkedin_message";
2429
+ type: "email" | "wait" | "linkedin_visit" | "linkedin_connection" | "linkedin_message" | "linkedin_like_post" | "linkedin_inmail";
1954
2430
  /** wait steps: hours to wait before the next step. */
1955
2431
  waitHours?: number;
1956
2432
  /** Legacy email step sender. Pool campaigns choose senders in emailMailboxAccountIds on the campaign, not on individual steps. */
1957
2433
  emailMailboxAccountId?: string;
1958
2434
  /** email steps: subject; {{Column}} merge tokens allowed. */
1959
2435
  emailSubject?: string;
2436
+ /** email steps: HTML body. Sent instead of emailTextBody when both are set, so when you edit the text, update or drop this too. */
1960
2437
  emailHtmlBody?: string;
2438
+ /** email steps: plain-text body; used as the email when there is no emailHtmlBody. */
1961
2439
  emailTextBody?: string;
1962
2440
  /** email steps: thread under the previous email step instead of a new subject. */
1963
2441
  emailReplyToPrevious?: boolean;
1964
- /** Run this step only when the person is / is not a LinkedIn connection. */
2442
+ /** email and linkedin_like_post only: always (default), connected or not_connected. InMail automatically skips connected people; do not set a condition on it. */
1965
2443
  onlyIf?: "always" | "connected" | "not_connected";
1966
2444
  /** Legacy LinkedIn step sender. Pool campaigns use the campaign's linkedinAccountIds instead. */
1967
2445
  linkedinAccountId?: string;
1968
- /** linkedin_connection: the invite note (optional, up to 300 chars; sent without it if LinkedIn refuses the note); linkedin_message: the message (up to 3000 chars). */
2446
+ /** linkedin_connection: the invite note (optional, up to 300 chars; sent without it if LinkedIn refuses the note); linkedin_message: the required message (up to 3000 chars); linkedin_inmail: the required message (up to 1900 chars). */
1969
2447
  linkedinMessageBody?: string;
1970
2448
  /** linkedin_message: what to do when the invite is still pending. */
1971
2449
  linkedinMessageMode?: "skip_if_not_connected" | "wait_until_connected";
1972
- /** linkedin_message with linkedinMessageMode=wait_until_connected: give up waiting for the accept after this many hours (default 720). */
2450
+ /** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720). After a connection step this mode is the default. */
1973
2451
  connectionTimeoutHours?: number;
2452
+ /** linkedin_like_post only: the reaction to leave (default like). */
2453
+ likeReaction?: "like" | "celebrate" | "support" | "love" | "insightful" | "funny";
2454
+ /** linkedin_like_post only: select the newest eligible original post from the last 1-365 days (default 30). */
2455
+ likeMaxPostAgeDays?: number;
2456
+ /** linkedin_like_post only: skip consecutive following wait steps whenever the reaction step is skipped (default true). False keeps those waits. */
2457
+ likeSkipNextWait?: boolean;
2458
+ /** linkedin_inmail only: optional subject, up to 200 characters; merge tokens allowed. Clear with an empty string. */
2459
+ inmailSubject?: string;
2460
+ /** linkedin_connection only: withdraw a still-pending invitation sent by this campaign after 168-2160 hours (7-90 days). Omitted means off on creation; null turns it off on edit. */
2461
+ withdrawAfterHours?: number | null;
1974
2462
  }>;
2463
+ /** Send {single braces} exactly as typed instead of rejecting them. Merge tokens always use {{double braces}}. */
2464
+ allowSingleBraces?: boolean;
2465
+ };
2466
+ /** Edit the text, waits and conditions of a launched (or paused) campaign's steps in place. Each step keeps its id, type and place; pass the stepId and the updatedAt you read, and only the fields you change. Messages already sent or being prepared keep their text; drafts use campaigns.steps.replace. — `dench campaign steps edit` — PATCH /api/v1/campaigns/{sequenceId}/steps */
2467
+ "campaigns.steps.update": {
2468
+ sequenceId: string;
2469
+ /** The steps to change. Rejected, not trimmed: a field the step type would drop, an overlength note/message/InMail subject, out-of-range wait/withdrawal/post-age values, and {TOKEN} single braces. */
2470
+ steps: Array<{
2471
+ /** The step's current type. A launched step's type can't change. */
2472
+ type: "email" | "wait" | "linkedin_visit" | "linkedin_connection" | "linkedin_message" | "linkedin_like_post" | "linkedin_inmail";
2473
+ /** wait steps: hours to wait before the next step. */
2474
+ waitHours?: number;
2475
+ /** Legacy email step sender. Pool campaigns choose senders in emailMailboxAccountIds on the campaign, not on individual steps. */
2476
+ emailMailboxAccountId?: string;
2477
+ /** email steps: subject; {{Column}} merge tokens allowed. */
2478
+ emailSubject?: string;
2479
+ /** email steps: HTML body. Sent instead of emailTextBody when both are set, so when you edit the text, update or drop this too. */
2480
+ emailHtmlBody?: string;
2481
+ /** email steps: plain-text body; used as the email when there is no emailHtmlBody. */
2482
+ emailTextBody?: string;
2483
+ /** email steps: thread under the previous email step instead of a new subject. */
2484
+ emailReplyToPrevious?: boolean;
2485
+ /** email and linkedin_like_post only: always (default), connected or not_connected. InMail automatically skips connected people; do not set a condition on it. */
2486
+ onlyIf?: "always" | "connected" | "not_connected";
2487
+ /** Legacy LinkedIn step sender. Pool campaigns use the campaign's linkedinAccountIds instead. */
2488
+ linkedinAccountId?: string;
2489
+ /** linkedin_connection: the invite note (optional, up to 300 chars; sent without it if LinkedIn refuses the note); linkedin_message: the required message (up to 3000 chars); linkedin_inmail: the required message (up to 1900 chars). */
2490
+ linkedinMessageBody?: string;
2491
+ /** linkedin_message: what to do when the invite is still pending. */
2492
+ linkedinMessageMode?: "skip_if_not_connected" | "wait_until_connected";
2493
+ /** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720). After a connection step this mode is the default. */
2494
+ connectionTimeoutHours?: number;
2495
+ /** linkedin_like_post only: the reaction to leave (default like). */
2496
+ likeReaction?: "like" | "celebrate" | "support" | "love" | "insightful" | "funny";
2497
+ /** linkedin_like_post only: select the newest eligible original post from the last 1-365 days (default 30). */
2498
+ likeMaxPostAgeDays?: number;
2499
+ /** linkedin_like_post only: skip consecutive following wait steps whenever the reaction step is skipped (default true). False keeps those waits. */
2500
+ likeSkipNextWait?: boolean;
2501
+ /** linkedin_inmail only: optional subject, up to 200 characters; merge tokens allowed. Clear with an empty string. */
2502
+ inmailSubject?: string;
2503
+ /** linkedin_connection only: withdraw a still-pending invitation sent by this campaign after 168-2160 hours (7-90 days). Omitted means off on creation; null turns it off on edit. */
2504
+ withdrawAfterHours?: number | null;
2505
+ /** The step's _id from campaigns.get steps[]. */
2506
+ stepId: string;
2507
+ /** The step's updatedAt when you read it. If someone saved it since, the edit is refused instead of overwriting theirs. */
2508
+ expectedUpdatedAt: number;
2509
+ }>;
2510
+ /** Send {single braces} exactly as typed instead of rejecting them. Merge tokens always use {{double braces}}. */
2511
+ allowSingleBraces?: boolean;
2512
+ };
2513
+ /** Read a campaign's personalized lines (written for each person): their {{keys}} for steps, instructions and fallbacks, how many people have them, and the cost per person. — `dench campaign personalize get` — GET /api/v1/campaigns/{sequenceId}/personalization */
2514
+ "campaigns.personalization.get": {
2515
+ sequenceId: string;
2516
+ };
2517
+ /** Define up to 5 personalized lines (each used as {{key}} in steps) and what you sell. Saving starts writing missing lines for up to 100 people, about 3 cents a person; for more it returns needsConfirm and writes nothing until campaigns.personalization.write is confirmed. — `dench campaign personalize set` — PUT /api/v1/campaigns/{sequenceId}/personalization */
2518
+ "campaigns.personalization.set": {
2519
+ sequenceId: string;
2520
+ /** The lines and context; null turns personalized lines off. */
2521
+ template: {
2522
+ variables: {
2523
+ /** The {{key}} used in steps: a letter, then letters, digits or _ (up to 40). Not a built-in field like firstName or company. */
2524
+ key: string;
2525
+ /** The line's name, up to 60 characters. */
2526
+ label: string;
2527
+ /** What the writer should say, up to 600 characters. */
2528
+ prompt: string;
2529
+ /** Sent when there is nothing specific to say; up to 300 characters, no {{variables}}. */
2530
+ fallback: string;
2531
+ /** A field to use before the fallback, e.g. Company. */
2532
+ fallbackFrom?: string;
2533
+ /** The longest line, default 200 characters. */
2534
+ maxChars?: number;
2535
+ }[];
2536
+ context: {
2537
+ /** What you sell, up to 1000 characters. */
2538
+ sells: string;
2539
+ /** The offer or call to action, up to 300 characters. */
2540
+ offer?: string;
2541
+ };
2542
+ } | null;
2543
+ };
2544
+ /** Turn off a campaign's personalized lines and cancel the ones not yet written. Refused while a step still uses one of the {{keys}}. — `dench campaign personalize clear` — DELETE /api/v1/campaigns/{sequenceId}/personalization */
2545
+ "campaigns.personalization.clear": {
2546
+ sequenceId: string;
2547
+ };
2548
+ /** Write personalized lines for the people missing them (mode missing) or rewrite everyone's (mode all). Rewriting everyone or more than 100 people returns needsConfirm and the estimate until called with confirmed: true. — `dench campaign personalize write` — POST /api/v1/campaigns/{sequenceId}/personalization/write */
2549
+ "campaigns.personalization.write": {
2550
+ sequenceId: string;
2551
+ /** missing (default): only people without lines. all: rewrite everyone's. */
2552
+ mode?: "missing" | "all";
2553
+ /** true after the user accepts the estimate from needsConfirm. */
2554
+ confirmed?: boolean;
2555
+ };
2556
+ /** Set one person's personalized line by hand; an empty value undoes the edit. Braces are removed and text past the line's length is cut. — `dench campaign personalize edit` — PUT /api/v1/campaigns/people/{enrollmentId}/personalization */
2557
+ "campaigns.personalization.edit": {
2558
+ /** From dench campaign people. */
2559
+ enrollmentId: string;
2560
+ /** The line's key, as in {{key}}. */
2561
+ key: string;
2562
+ /** The line to send; an empty string undoes the edit. */
2563
+ value: string;
2564
+ };
2565
+ /** Write a fresh personalized line for one person: one key, or all of their lines when key is left out. About 3 cents. — `dench campaign personalize rewrite` — POST /api/v1/campaigns/people/{enrollmentId}/personalization/rewrite */
2566
+ "campaigns.personalization.rewrite": {
2567
+ /** From dench campaign people. */
2568
+ enrollmentId: string;
2569
+ /** One line's key; leave out to rewrite all of their lines. */
2570
+ key?: string;
1975
2571
  };
1976
2572
  /** Add CRM records (up to 100 ids per call) to a campaign; returns how many were added and why others were skipped. — `dench campaign add` — POST /api/v1/campaigns/{sequenceId}/people */
1977
2573
  "campaigns.people.addFromCrm": {
@@ -2008,7 +2604,15 @@ export interface ApiRequests {
2008
2604
  personalization?: Record<string, unknown>;
2009
2605
  checkDuplicatesAcrossWorkspace?: boolean;
2010
2606
  };
2011
- /** Launch readiness: blockers grouped by problem, warnings, and the fingerprint `launch` requires. — `dench campaign launch` — GET /api/v1/campaigns/{sequenceId}/launch */
2607
+ /** Show the message one person gets at one email or LinkedIn step, with their fields and personalized lines filled in: subject, body, sender, recipient, merge fields still missing, warnings, and why the step would be skipped. Nothing is sent, prepared or charged. — `dench campaign preview` — GET /api/v1/campaigns/{sequenceId}/preview */
2608
+ "campaigns.preview": {
2609
+ sequenceId: string;
2610
+ /** The person to preview, from dench campaign people. */
2611
+ enrollmentId: string;
2612
+ /** An email or LinkedIn step, its _id from campaigns.get steps[]. A wait step sends nothing. */
2613
+ stepId: string;
2614
+ };
2615
+ /** Launch readiness without launching: blockers grouped by problem, warnings, and the fingerprint `launch` requires. — `dench campaign launch --check` — GET /api/v1/campaigns/{sequenceId}/launch */
2012
2616
  "campaigns.launch.preview": {
2013
2617
  sequenceId: string;
2014
2618
  };
@@ -2028,7 +2632,7 @@ export interface ApiRequests {
2028
2632
  "campaigns.resume": {
2029
2633
  sequenceId: string;
2030
2634
  };
2031
- /** Archive a campaign and stop everyone still in flight. — `dench campaign archive` — POST /api/v1/campaigns/{sequenceId}/archive */
2635
+ /** Archive a campaign and stop everyone still in flight. This is the app's Delete: campaigns are never erased, and their people, leads and activity stay. — `dench campaign archive` — POST /api/v1/campaigns/{sequenceId}/archive */
2032
2636
  "campaigns.archive": {
2033
2637
  sequenceId: string;
2034
2638
  };
@@ -2048,6 +2652,53 @@ export interface ApiRequests {
2048
2652
  "campaigns.people.resume": {
2049
2653
  enrollmentId: string;
2050
2654
  };
2655
+ /** Give a person in a draft campaign a new or corrected email address; their linked CRM record gets it too. Only before launch; another person in the campaign can't share it. — `dench campaign person set --email` — PUT /api/v1/campaigns/people/{enrollmentId}/email */
2656
+ "campaigns.people.setEmail": {
2657
+ /** From dench campaign people. */
2658
+ enrollmentId: string;
2659
+ /** The address email steps should use. */
2660
+ email: string;
2661
+ };
2662
+ /** Give a person in a draft campaign a new or corrected LinkedIn profile URL; their linked CRM record gets it too. Only before launch. — `dench campaign person set --linkedin-url` — PUT /api/v1/campaigns/people/{enrollmentId}/linkedin */
2663
+ "campaigns.people.setLinkedin": {
2664
+ /** From dench campaign people. */
2665
+ enrollmentId: string;
2666
+ /** A LinkedIn member profile URL, e.g. https://linkedin.com/in/ada. */
2667
+ linkedinProfileUrl: string;
2668
+ };
2669
+ /** Fill or fix one {{merge field}} for a person in a draft campaign, e.g. a missing Company that blocks launch; a matching column on their CRM record is updated too. Only before launch; written personalized lines are not merge fields and can't be set here. — `dench campaign person set --field` — PUT /api/v1/campaigns/people/{enrollmentId}/fields */
2670
+ "campaigns.people.setField": {
2671
+ /** From dench campaign people. */
2672
+ enrollmentId: string;
2673
+ /** The merge token name without braces, e.g. Company for {{Company}} or fund for {{fund}}. */
2674
+ key: string;
2675
+ /** Up to 2000 characters. */
2676
+ value: string;
2677
+ };
2678
+ /** Resume every paused person in an active campaign at once, e.g. after a sending account is reconnected. Returns how many were resumed. — `dench campaign resume-person --all` — POST /api/v1/campaigns/{sequenceId}/people/resume */
2679
+ "campaigns.people.resumeAll": {
2680
+ /** An active campaign. */
2681
+ sequenceId: string;
2682
+ };
2683
+ /** Fill each unfinished person's empty email, LinkedIn URL, name and merge fields from their linked CRM record, e.g. after enriching the records. Never overwrites a value the campaign already has; returns how many people changed. — `dench campaign sync` — POST /api/v1/campaigns/{sequenceId}/people/sync */
2684
+ "campaigns.people.sync": {
2685
+ sequenceId: string;
2686
+ };
2687
+ /** The campaigns a CRM record (a person or a lead) is in, newest first, with the person's status in each and the accounts that send to them. — `dench campaign where` — GET /api/v1/campaigns/by-record/{entryId} */
2688
+ "campaigns.people.forRecord": {
2689
+ /** A CRM record's _id: a person, or a lead created from one. */
2690
+ entryId: string;
2691
+ };
2692
+ /** Everything a campaign did for one person, step by step: what was sent (subject and text), whether it was opened or clicked, what was skipped and why, waits, failures and retries. — `dench campaign person show` — GET /api/v1/campaigns/people/{enrollmentId}/timeline */
2693
+ "campaigns.people.timeline": {
2694
+ /** From dench campaign people. */
2695
+ enrollmentId: string;
2696
+ };
2697
+ /** Remove a person who was never contacted from a draft campaign. Frees their place in the 300-person cap and keeps the draft launchable; stop anyone already contacted instead. — `dench campaign remove` — DELETE /api/v1/campaigns/people/{enrollmentId} */
2698
+ "campaigns.people.remove": {
2699
+ /** From dench campaign people; the person must never have been contacted. */
2700
+ enrollmentId: string;
2701
+ };
2051
2702
  /** List routines. — `dench cron list` — GET /api/v1/routines */
2052
2703
  "cron.list": {
2053
2704
  enabledOnly?: boolean;
@@ -2290,7 +2941,7 @@ export interface ApiRequests {
2290
2941
  /** Optional base64 mask image. */
2291
2942
  mask_base64?: string;
2292
2943
  };
2293
- /** List every connected integration — Composio apps plus the Gmail, Outlook, Calendar, LinkedIn and Slack connections Dench brokers itself (Slack rows report source: dench). — `dench integrations` — GET /api/v1/integrations */
2944
+ /** List every connected integration — connected apps plus the Gmail, Outlook, Calendar, LinkedIn and Slack connections Dench provides itself (Slack rows report source: dench). — `dench integrations` — GET /api/v1/integrations */
2294
2945
  "integrations.list": Record<string, unknown>;
2295
2946
  /** List installed App Store apps in the workspace. — `dench apps list` — GET /api/v1/apps */
2296
2947
  "apps.list": Record<string, unknown>;
@@ -2361,7 +3012,7 @@ export interface ApiRequests {
2361
3012
  };
2362
3013
  /** List connected tool accounts. — `dench tool status` — GET /api/v1/tools/status */
2363
3014
  "tool.status": Record<string, unknown>;
2364
- /** Create a tool OAuth connection link. Slack is in-house, never Composio: for toolkit slack the CLI prints the first-party install URL (/api/slack/install?slug=<workspace>, org admin) instead of calling this endpoint. — `dench tool connect` — POST /api/v1/tools/connections */
3015
+ /** Create a tool OAuth connection link. Slack is in-house, never a third-party connection: for toolkit slack the CLI prints the first-party install URL (/api/slack/install?slug=<workspace>, org admin) instead of calling this endpoint. — `dench tool connect` — POST /api/v1/tools/connections */
2365
3016
  "tool.connect": {
2366
3017
  /** Toolkit slug, e.g. github, gmail, stripe. */
2367
3018
  toolkit: string;
@@ -2382,12 +3033,12 @@ export interface ApiRequests {
2382
3033
  account?: string;
2383
3034
  model?: string;
2384
3035
  };
2385
- /** Run an external tool action. SLACK_* slugs (SLACK_SEND_MESSAGE with Block Kit blocks/buttons, SLACK_FETCH_HISTORY, SLACK_LIST_CHANNELS, …) run through Dench's in-house Slack app install — any channel in the connected workspace — and are always preferred over Composio Slack. — `dench tool run` — POST /api/v1/tools/run */
3036
+ /** Run an external tool action. SLACK_* slugs (SLACK_SEND_MESSAGE with Block Kit blocks/buttons, SLACK_FETCH_HISTORY, SLACK_LIST_CHANNELS, …) run through Dench's in-house Slack app install — any channel in the connected workspace — and are always preferred over any third-party Slack connection. — `dench tool run` — POST /api/v1/tools/run */
2386
3037
  "tool.run": {
2387
3038
  /** Execution ref from a prior search, OR pass session_id+tool_slug. */
2388
3039
  execution_ref?: string;
2389
3040
  session_id?: string;
2390
- /** Composio tool slug, e.g. GMAIL_FETCH_EMAILS. */
3041
+ /** Tool slug, e.g. GMAIL_FETCH_EMAILS. */
2391
3042
  tool_slug?: string;
2392
3043
  /** Tool arguments object. */
2393
3044
  arguments?: Record<string, unknown>;
@@ -2525,6 +3176,133 @@ export interface ApiRequests {
2525
3176
  }
2526
3177
 
2527
3178
  export interface ApiResponses {
3179
+ "campaigns.drafts.create": {
3180
+ sequenceId: string;
3181
+ };
3182
+ "campaigns.audience.search": {
3183
+ rows: Record<string, unknown>[];
3184
+ people: unknown[];
3185
+ recipients: {
3186
+ email?: string;
3187
+ linkedinProfileUrl?: string;
3188
+ displayName?: string;
3189
+ /** Merge values keyed by name, e.g. {"Company":"Acme"} for {{Company}}. */
3190
+ personalization?: Record<string, unknown>;
3191
+ }[];
3192
+ metadata: Record<string, unknown>;
3193
+ /** The search cost ceiling reported by Dench billing, in cents. Null means the receipt is unavailable. */
3194
+ estimatedCents: number | null;
3195
+ /** The actual search charge reported by Dench billing, in cents. Null means the receipt is unavailable; results remain valid. */
3196
+ chargedCents: number | null;
3197
+ };
3198
+ "campaigns.people.addFromSearch": {
3199
+ rows: Record<string, unknown>[];
3200
+ people: unknown[];
3201
+ recipients: {
3202
+ email?: string;
3203
+ linkedinProfileUrl?: string;
3204
+ displayName?: string;
3205
+ /** Merge values keyed by name, e.g. {"Company":"Acme"} for {{Company}}. */
3206
+ personalization?: Record<string, unknown>;
3207
+ }[];
3208
+ metadata: Record<string, unknown>;
3209
+ /** The search cost ceiling reported by Dench billing, in cents. Null means the receipt is unavailable. */
3210
+ estimatedCents: number | null;
3211
+ /** The actual search charge reported by Dench billing, in cents. Null means the receipt is unavailable; results remain valid. */
3212
+ chargedCents: number | null;
3213
+ added: number;
3214
+ requested: number;
3215
+ cappedAtLimit: number | null;
3216
+ duplicates: number;
3217
+ duplicatesElsewhere: number;
3218
+ suppressed: number;
3219
+ invalid: number;
3220
+ skippedNoIdentity: number;
3221
+ skippedMissingInfo: number;
3222
+ missingInfoSample?: unknown;
3223
+ found: number;
3224
+ skippedSearchProfiles: number;
3225
+ };
3226
+ "campaigns.people.addBatch": {
3227
+ added: number;
3228
+ requested: number;
3229
+ cappedAtLimit: number | null;
3230
+ duplicates: number;
3231
+ duplicatesElsewhere: number;
3232
+ suppressed: number;
3233
+ invalid: number;
3234
+ skippedNoIdentity: number;
3235
+ skippedMissingInfo: number;
3236
+ missingInfoSample?: unknown;
3237
+ };
3238
+ "campaigns.sources.get": Record<string, unknown> | null;
3239
+ "campaigns.sources.signals": Record<string, unknown> | null;
3240
+ "campaigns.sources.update": null;
3241
+ "campaigns.sources.preview": {
3242
+ ok: boolean;
3243
+ [key: string]: unknown;
3244
+ };
3245
+ "campaigns.builder.profile": {
3246
+ hasProfile: boolean;
3247
+ targeting: {
3248
+ titles: string[];
3249
+ locations: string[];
3250
+ companySizes: string[];
3251
+ industries: string[];
3252
+ excludes: string[];
3253
+ companies?: string[];
3254
+ };
3255
+ [key: string]: unknown;
3256
+ };
3257
+ "campaigns.builder.save": {
3258
+ draftId: string;
3259
+ };
3260
+ "campaigns.builder.get": {
3261
+ status: string;
3262
+ targeting: {
3263
+ titles: string[];
3264
+ locations: string[];
3265
+ companySizes: string[];
3266
+ industries: string[];
3267
+ excludes: string[];
3268
+ companies?: string[];
3269
+ };
3270
+ signals: Array<"post_engagement" | "keyword" | "hiring" | "funding" | "launch" | "new_leader">;
3271
+ people: Record<string, unknown>[];
3272
+ [key: string]: unknown;
3273
+ };
3274
+ "campaigns.builder.build": {
3275
+ ok: boolean;
3276
+ started: boolean;
3277
+ };
3278
+ "campaigns.builder.create": {
3279
+ sequenceId: string;
3280
+ enrolled: number;
3281
+ };
3282
+ "campaigns.builder.opener": null;
3283
+ "campaigns.builder.autofill": {
3284
+ targeting: {
3285
+ titles: string[];
3286
+ locations: string[];
3287
+ companySizes: string[];
3288
+ industries: string[];
3289
+ excludes: string[];
3290
+ companies?: string[];
3291
+ };
3292
+ [key: string]: unknown;
3293
+ };
3294
+ "campaigns.builder.terms": {
3295
+ signalTerms: {
3296
+ post_engagement?: string[];
3297
+ keyword?: string[];
3298
+ hiring?: string[];
3299
+ };
3300
+ [key: string]: unknown;
3301
+ };
3302
+ "campaigns.builder.estimate": {
3303
+ count: number | null;
3304
+ [key: string]: unknown;
3305
+ };
2528
3306
  "commands.list": {
2529
3307
  operations: Array<{
2530
3308
  id: string;
@@ -2534,7 +3312,7 @@ export interface ApiResponses {
2534
3312
  aliases: string[];
2535
3313
  method: string;
2536
3314
  path: string;
2537
- backend: "convex" | "gateway" | "custom" | "local";
3315
+ backend: "api" | "gateway" | "custom" | "local";
2538
3316
  deprecated: boolean;
2539
3317
  }>;
2540
3318
  };
@@ -2962,8 +3740,20 @@ export interface ApiResponses {
2962
3740
  "lists.rows": unknown;
2963
3741
  "lists.import": unknown;
2964
3742
  "lists.get": unknown;
2965
- "lists.save": unknown;
2966
- "lists.update": unknown;
3743
+ "lists.save": {
3744
+ artifactId: string;
3745
+ filePath: string;
3746
+ rowCount: number;
3747
+ previewRows: unknown[];
3748
+ title: string;
3749
+ createdFrom: string;
3750
+ };
3751
+ "lists.update": {
3752
+ artifactId: string;
3753
+ rowCount: number;
3754
+ previewRows: unknown[];
3755
+ title: string;
3756
+ };
2967
3757
  "lists.rename": unknown;
2968
3758
  "lists.delete": unknown;
2969
3759
  "lists.prospects.reviews": unknown;
@@ -4233,7 +5023,7 @@ export interface ApiResponses {
4233
5023
  };
4234
5024
  "crm.people.search": {
4235
5025
  source: "live" | "cache";
4236
- /** Provider results normalized to the CRM upsert shape. */
5026
+ /** Search results normalized to the CRM upsert shape. */
4237
5027
  people: {
4238
5028
  fullName?: string;
4239
5029
  firstName?: string;
@@ -4250,6 +5040,12 @@ export interface ApiResponses {
4250
5040
  }[];
4251
5041
  resolvedPersonIds: string[];
4252
5042
  creditsCharged: number;
5043
+ billing?: {
5044
+ /** Search cost ceiling authorized by Dench billing, in cents. */
5045
+ estimatedCents: number;
5046
+ /** Actual workspace search charge reported by Dench billing, in cents. */
5047
+ chargedCents: number;
5048
+ };
4253
5049
  metadata?: {
4254
5050
  /** Total matches for the search. Stable across pages; absent when only an estimate exists. */
4255
5051
  total?: number;
@@ -4264,7 +5060,7 @@ export interface ApiResponses {
4264
5060
  };
4265
5061
  "crm.companies.search": {
4266
5062
  source: "live" | "cache";
4267
- /** Provider results normalized to the CRM upsert shape. */
5063
+ /** Search results normalized to the CRM upsert shape. */
4268
5064
  companies: {
4269
5065
  name?: string;
4270
5066
  website?: string;
@@ -4278,6 +5074,12 @@ export interface ApiResponses {
4278
5074
  }[];
4279
5075
  resolvedCompanyIds: string[];
4280
5076
  creditsCharged: number;
5077
+ billing?: {
5078
+ /** Search cost ceiling authorized by Dench billing, in cents. */
5079
+ estimatedCents: number;
5080
+ /** Actual workspace search charge reported by Dench billing, in cents. */
5081
+ chargedCents: number;
5082
+ };
4281
5083
  metadata?: {
4282
5084
  /** Total matches for the search. Stable across pages; absent when only an estimate exists. */
4283
5085
  total?: number;
@@ -4788,6 +5590,26 @@ export interface ApiResponses {
4788
5590
  /** Account availability snapshot. Queued work, campaign limits and launch/dispatch checks still apply. */
4789
5591
  availability: "ready" | "paused" | "disconnected" | "errored" | "disabled" | "circuit_break" | "spacing" | "outside_window" | "daily_cap";
4790
5592
  }>;
5593
+ "campaigns.accounts.email": Array<{
5594
+ /** The emailMailboxAccountId to put in emailMailboxAccountIds. */
5595
+ _id: string;
5596
+ email: string;
5597
+ provider: "gmail" | "outlook";
5598
+ status: "running" | "disconnected" | "errored";
5599
+ statusReason?: string;
5600
+ /** ready or skipped: sends at its cap. warming: sends less until readyAt. pending_auth and error need the owner in the app. */
5601
+ warmupStatus: "skipped" | "pending_auth" | "warming" | "ready" | "error";
5602
+ /** When warm-up finished, or is expected to finish while warming (epoch ms). */
5603
+ readyAt?: number;
5604
+ /** The most cold emails a day; the mailbox owner sets it in the app. */
5605
+ dailyColdSendCap: number;
5606
+ /** Cold emails it can still send today. */
5607
+ remainingToday: number;
5608
+ ownerName: string;
5609
+ isOwner: boolean;
5610
+ visibility: "private" | "shared";
5611
+ [key: string]: unknown;
5612
+ }>;
4791
5613
  "campaigns.list": Array<{
4792
5614
  _id: string;
4793
5615
  name: string;
@@ -4832,6 +5654,10 @@ export interface ApiResponses {
4832
5654
  "campaigns.create": {
4833
5655
  sequenceId: string;
4834
5656
  };
5657
+ "campaigns.duplicate": {
5658
+ /** The new draft. Rename it with campaigns.update. */
5659
+ sequenceId: string;
5660
+ };
4835
5661
  "campaigns.get": {
4836
5662
  sequence: {
4837
5663
  _id: string;
@@ -4876,27 +5702,39 @@ export interface ApiResponses {
4876
5702
  };
4877
5703
  steps: Array<{
4878
5704
  /** Step type. */
4879
- type: "email" | "wait" | "linkedin_visit" | "linkedin_connection" | "linkedin_message";
5705
+ type: "email" | "wait" | "linkedin_visit" | "linkedin_connection" | "linkedin_message" | "linkedin_like_post" | "linkedin_inmail";
4880
5706
  /** wait steps: hours to wait before the next step. */
4881
5707
  waitHours?: number;
4882
5708
  /** Legacy email step sender. Pool campaigns choose senders in emailMailboxAccountIds on the campaign, not on individual steps. */
4883
5709
  emailMailboxAccountId?: string;
4884
5710
  /** email steps: subject; {{Column}} merge tokens allowed. */
4885
5711
  emailSubject?: string;
5712
+ /** email steps: HTML body. Sent instead of emailTextBody when both are set, so when you edit the text, update or drop this too. */
4886
5713
  emailHtmlBody?: string;
5714
+ /** email steps: plain-text body; used as the email when there is no emailHtmlBody. */
4887
5715
  emailTextBody?: string;
4888
5716
  /** email steps: thread under the previous email step instead of a new subject. */
4889
5717
  emailReplyToPrevious?: boolean;
4890
- /** Run this step only when the person is / is not a LinkedIn connection. */
5718
+ /** email and linkedin_like_post only: always (default), connected or not_connected. InMail automatically skips connected people; do not set a condition on it. */
4891
5719
  onlyIf?: "always" | "connected" | "not_connected";
4892
5720
  /** Legacy LinkedIn step sender. Pool campaigns use the campaign's linkedinAccountIds instead. */
4893
5721
  linkedinAccountId?: string;
4894
- /** linkedin_connection: the invite note (optional, up to 300 chars; sent without it if LinkedIn refuses the note); linkedin_message: the message (up to 3000 chars). */
5722
+ /** linkedin_connection: the invite note (optional, up to 300 chars; sent without it if LinkedIn refuses the note); linkedin_message: the required message (up to 3000 chars); linkedin_inmail: the required message (up to 1900 chars). */
4895
5723
  linkedinMessageBody?: string;
4896
5724
  /** linkedin_message: what to do when the invite is still pending. */
4897
5725
  linkedinMessageMode?: "skip_if_not_connected" | "wait_until_connected";
4898
- /** linkedin_message with linkedinMessageMode=wait_until_connected: give up waiting for the accept after this many hours (default 720). */
5726
+ /** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720). After a connection step this mode is the default. */
4899
5727
  connectionTimeoutHours?: number;
5728
+ /** linkedin_like_post only: the reaction to leave (default like). */
5729
+ likeReaction?: "like" | "celebrate" | "support" | "love" | "insightful" | "funny";
5730
+ /** linkedin_like_post only: select the newest eligible original post from the last 1-365 days (default 30). */
5731
+ likeMaxPostAgeDays?: number;
5732
+ /** linkedin_like_post only: skip consecutive following wait steps whenever the reaction step is skipped (default true). False keeps those waits. */
5733
+ likeSkipNextWait?: boolean;
5734
+ /** linkedin_inmail only: optional subject, up to 200 characters; merge tokens allowed. Clear with an empty string. */
5735
+ inmailSubject?: string;
5736
+ /** linkedin_connection only: withdraw a still-pending invitation sent by this campaign after 168-2160 hours (7-90 days). Omitted means off on creation; null turns it off on edit. */
5737
+ withdrawAfterHours?: number | null;
4900
5738
  [key: string]: unknown;
4901
5739
  }>;
4902
5740
  enrollments: Record<string, unknown>[];
@@ -4949,6 +5787,20 @@ export interface ApiResponses {
4949
5787
  senders: Record<string, unknown>[];
4950
5788
  [key: string]: unknown;
4951
5789
  };
5790
+ "campaigns.pipeline": {
5791
+ /** People in the campaign. */
5792
+ total: number;
5793
+ /** The workspace's lead Statuses, in pipeline order. */
5794
+ statuses: {
5795
+ /** A lead Status, as named in the CRM. */
5796
+ name: string;
5797
+ color: string;
5798
+ /** Enrolled leads at this Status. */
5799
+ count: number;
5800
+ }[];
5801
+ /** People with no lead, or a Status outside the pipeline. */
5802
+ other: number;
5803
+ } | null;
4952
5804
  "campaigns.update": {
4953
5805
  ok: boolean;
4954
5806
  };
@@ -4956,6 +5808,95 @@ export interface ApiResponses {
4956
5808
  ok: boolean;
4957
5809
  stepCount: number;
4958
5810
  };
5811
+ "campaigns.steps.update": {
5812
+ ok: boolean;
5813
+ /** How many steps were edited. */
5814
+ stepCount: number;
5815
+ };
5816
+ "campaigns.personalization.get": {
5817
+ template: {
5818
+ variables: {
5819
+ /** The {{key}} used in steps: a letter, then letters, digits or _ (up to 40). Not a built-in field like firstName or company. */
5820
+ key: string;
5821
+ /** The line's name, up to 60 characters. */
5822
+ label: string;
5823
+ /** What the writer should say, up to 600 characters. */
5824
+ prompt: string;
5825
+ /** Sent when there is nothing specific to say; up to 300 characters, no {{variables}}. */
5826
+ fallback: string;
5827
+ /** A field to use before the fallback, e.g. Company. */
5828
+ fallbackFrom?: string;
5829
+ /** The longest line, default 200 characters. */
5830
+ maxChars?: number;
5831
+ }[];
5832
+ context: {
5833
+ /** What you sell, up to 1000 characters. */
5834
+ sells: string;
5835
+ /** The offer or call to action, up to 300 characters. */
5836
+ offer?: string;
5837
+ };
5838
+ version: number;
5839
+ updatedAt: number;
5840
+ [key: string]: unknown;
5841
+ } | null;
5842
+ counts: {
5843
+ done: number;
5844
+ pending: number;
5845
+ failed: number;
5846
+ total: number;
5847
+ };
5848
+ paused: boolean;
5849
+ notice: {
5850
+ code: "insufficient_credits";
5851
+ at: number;
5852
+ } | null;
5853
+ suggestedContext: {
5854
+ sells?: string;
5855
+ };
5856
+ estimatedCentsPerPerson: number;
5857
+ eligible: number;
5858
+ [key: string]: unknown;
5859
+ };
5860
+ "campaigns.personalization.set": {
5861
+ version: number;
5862
+ /** People who would get a line. */
5863
+ eligible: number;
5864
+ /** About 3 cents a person. */
5865
+ estimatedCents: number;
5866
+ /** True when nothing was written: confirm with campaigns.personalization.write and confirmed: true. */
5867
+ needsConfirm: boolean;
5868
+ /** People whose lines are being written now. */
5869
+ queued: number;
5870
+ };
5871
+ "campaigns.personalization.clear": {
5872
+ version: number;
5873
+ /** People who would get a line. */
5874
+ eligible: number;
5875
+ /** About 3 cents a person. */
5876
+ estimatedCents: number;
5877
+ /** True when nothing was written: confirm with campaigns.personalization.write and confirmed: true. */
5878
+ needsConfirm: boolean;
5879
+ /** People whose lines are being written now. */
5880
+ queued: number;
5881
+ };
5882
+ "campaigns.personalization.write": {
5883
+ version: number;
5884
+ /** People who would get a line. */
5885
+ eligible: number;
5886
+ /** About 3 cents a person. */
5887
+ estimatedCents: number;
5888
+ /** True when nothing was written: confirm with campaigns.personalization.write and confirmed: true. */
5889
+ needsConfirm: boolean;
5890
+ /** People whose lines are being written now. */
5891
+ queued: number;
5892
+ };
5893
+ "campaigns.personalization.edit": {
5894
+ ok: boolean;
5895
+ };
5896
+ "campaigns.personalization.rewrite": {
5897
+ /** False when new lines are already being written. */
5898
+ queued: boolean;
5899
+ };
4959
5900
  "campaigns.people.addFromCrm": {
4960
5901
  added: number;
4961
5902
  requested: number;
@@ -4982,6 +5923,44 @@ export interface ApiResponses {
4982
5923
  "campaigns.people.add": {
4983
5924
  enrollmentId: string;
4984
5925
  };
5926
+ "campaigns.preview": {
5927
+ channel: "email" | "linkedin";
5928
+ /** Email steps. */
5929
+ subject?: string;
5930
+ /** Email steps: plain text. */
5931
+ textBody?: string;
5932
+ /** Email steps: HTML. */
5933
+ htmlBody?: string;
5934
+ /** LinkedIn steps: the note or message, or a line saying no note or message is sent. */
5935
+ messageBody?: string;
5936
+ /** The sending account. */
5937
+ fromName?: string;
5938
+ fromEmail?: string;
5939
+ toName: string;
5940
+ toEmail?: string;
5941
+ /** {{merge fields}} this person has no value for; fill them with campaigns.people.setField. */
5942
+ missingFields: string[];
5943
+ warnings: string[];
5944
+ /** Set when the person would skip this step, e.g. no email address. */
5945
+ skippedReason?: string;
5946
+ highlights?: string[];
5947
+ personalized?: Array<{
5948
+ /** The line's {{key}}. */
5949
+ key: string;
5950
+ label: string;
5951
+ /** What this person gets: the written line, or the fallback. */
5952
+ value: string;
5953
+ /** written or edited: the line is final. fallback: nothing specific was found, so the fallback is used. writing, paused and not_written: the fallback shows until the line is written. */
5954
+ state: "written" | "edited" | "writing" | "paused" | "fallback" | "not_written";
5955
+ /** What the line was written from. */
5956
+ source?: "company" | "news" | "signal" | "profile" | "fallback";
5957
+ maxChars: number;
5958
+ /** A new line is being written over the current one. */
5959
+ rewriting?: "writing" | "paused";
5960
+ [key: string]: unknown;
5961
+ }>;
5962
+ [key: string]: unknown;
5963
+ };
4985
5964
  "campaigns.launch.preview": {
4986
5965
  ready: boolean;
4987
5966
  /** Pass this to `launch`; it changes whenever the campaign changes. */
@@ -5033,6 +6012,120 @@ export interface ApiResponses {
5033
6012
  "campaigns.people.resume": {
5034
6013
  ok: boolean;
5035
6014
  };
6015
+ "campaigns.people.setEmail": {
6016
+ ok: boolean;
6017
+ };
6018
+ "campaigns.people.setLinkedin": {
6019
+ ok: boolean;
6020
+ };
6021
+ "campaigns.people.setField": {
6022
+ ok: boolean;
6023
+ };
6024
+ "campaigns.people.resumeAll": {
6025
+ /** How many paused people were resumed. */
6026
+ resumed: number;
6027
+ };
6028
+ "campaigns.people.sync": {
6029
+ /** How many people gained a detail from their CRM record. */
6030
+ updated: number;
6031
+ };
6032
+ "campaigns.people.forRecord": Array<{
6033
+ /** The person in that campaign: _id, sequenceId, status, currentStepIndex, repliedAt. */
6034
+ enrollment: Record<string, unknown>;
6035
+ sequenceName: string;
6036
+ isOwner: boolean;
6037
+ canManage: boolean;
6038
+ /** The accounts that send to this person. */
6039
+ senders: {
6040
+ email: {
6041
+ accountId: string;
6042
+ /** The mailbox address or LinkedIn name. */
6043
+ label: string;
6044
+ status: string;
6045
+ } | null;
6046
+ linkedin: {
6047
+ accountId: string;
6048
+ /** The mailbox address or LinkedIn name. */
6049
+ label: string;
6050
+ status: string;
6051
+ } | null;
6052
+ };
6053
+ [key: string]: unknown;
6054
+ }>;
6055
+ "campaigns.people.timeline": {
6056
+ /** The person in this campaign: status, lastError, repliedAt. */
6057
+ enrollment: Record<string, unknown>;
6058
+ sequence: Record<string, unknown> | null;
6059
+ /** The campaign's steps in order, each with its _id. */
6060
+ steps: Array<{
6061
+ /** Step type. */
6062
+ type: "email" | "wait" | "linkedin_visit" | "linkedin_connection" | "linkedin_message" | "linkedin_like_post" | "linkedin_inmail";
6063
+ /** wait steps: hours to wait before the next step. */
6064
+ waitHours?: number;
6065
+ /** Legacy email step sender. Pool campaigns choose senders in emailMailboxAccountIds on the campaign, not on individual steps. */
6066
+ emailMailboxAccountId?: string;
6067
+ /** email steps: subject; {{Column}} merge tokens allowed. */
6068
+ emailSubject?: string;
6069
+ /** email steps: HTML body. Sent instead of emailTextBody when both are set, so when you edit the text, update or drop this too. */
6070
+ emailHtmlBody?: string;
6071
+ /** email steps: plain-text body; used as the email when there is no emailHtmlBody. */
6072
+ emailTextBody?: string;
6073
+ /** email steps: thread under the previous email step instead of a new subject. */
6074
+ emailReplyToPrevious?: boolean;
6075
+ /** email and linkedin_like_post only: always (default), connected or not_connected. InMail automatically skips connected people; do not set a condition on it. */
6076
+ onlyIf?: "always" | "connected" | "not_connected";
6077
+ /** Legacy LinkedIn step sender. Pool campaigns use the campaign's linkedinAccountIds instead. */
6078
+ linkedinAccountId?: string;
6079
+ /** linkedin_connection: the invite note (optional, up to 300 chars; sent without it if LinkedIn refuses the note); linkedin_message: the required message (up to 3000 chars); linkedin_inmail: the required message (up to 1900 chars). */
6080
+ linkedinMessageBody?: string;
6081
+ /** linkedin_message: what to do when the invite is still pending. */
6082
+ linkedinMessageMode?: "skip_if_not_connected" | "wait_until_connected";
6083
+ /** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720). After a connection step this mode is the default. */
6084
+ connectionTimeoutHours?: number;
6085
+ /** linkedin_like_post only: the reaction to leave (default like). */
6086
+ likeReaction?: "like" | "celebrate" | "support" | "love" | "insightful" | "funny";
6087
+ /** linkedin_like_post only: select the newest eligible original post from the last 1-365 days (default 30). */
6088
+ likeMaxPostAgeDays?: number;
6089
+ /** linkedin_like_post only: skip consecutive following wait steps whenever the reaction step is skipped (default true). False keeps those waits. */
6090
+ likeSkipNextWait?: boolean;
6091
+ /** linkedin_inmail only: optional subject, up to 200 characters; merge tokens allowed. Clear with an empty string. */
6092
+ inmailSubject?: string;
6093
+ /** linkedin_connection only: withdraw a still-pending invitation sent by this campaign after 168-2160 hours (7-90 days). Omitted means off on creation; null turns it off on edit. */
6094
+ withdrawAfterHours?: number | null;
6095
+ [key: string]: unknown;
6096
+ }>;
6097
+ /** One run for each step the person has reached, in order. */
6098
+ runs: Array<{
6099
+ _id: string;
6100
+ /** The step's _id, as in steps[]. */
6101
+ stepId: string;
6102
+ /** The step's place, from 0. */
6103
+ stepIndex: number;
6104
+ /** Step type. */
6105
+ type: "email" | "wait" | "linkedin_visit" | "linkedin_connection" | "linkedin_message" | "linkedin_like_post" | "linkedin_inmail";
6106
+ /** sent: done (a wait that finished is sent too). skipped: see result.reason. retry: will be tried again at retryAt. unknown: needs a look. */
6107
+ status: "queued" | "running" | "waiting" | "retry" | "sent" | "skipped" | "failed" | "unknown";
6108
+ scheduledAt?: number;
6109
+ startedAt?: number;
6110
+ waitUntil?: number;
6111
+ retryAt?: number;
6112
+ completedAt?: number;
6113
+ /** The email this run sent, in emailMessages[]. */
6114
+ emailMessageId?: string;
6115
+ lastError?: string;
6116
+ /** For a skipped step, { reason } says why. */
6117
+ result?: unknown;
6118
+ [key: string]: unknown;
6119
+ }>;
6120
+ /** The emails those runs sent: subject, textBody, status, sentAt, firstOpenedAt, firstClickedAt. */
6121
+ emailMessages: Record<string, unknown>[];
6122
+ /** The LinkedIn messages those runs sent: text, sentAt, deliveredAt, readAt, outreachStepRunId. */
6123
+ linkedinMessages: Record<string, unknown>[];
6124
+ [key: string]: unknown;
6125
+ };
6126
+ "campaigns.people.remove": {
6127
+ ok: boolean;
6128
+ };
5036
6129
  "cron.list": {
5037
6130
  jobs: Array<{
5038
6131
  id: string;
@@ -5411,7 +6504,7 @@ export interface ApiResponses {
5411
6504
  reconnect?: Record<string, unknown>;
5412
6505
  [key: string]: unknown;
5413
6506
  }>;
5414
- /** Raw Composio payload. */
6507
+ /** Deprecated: the unprocessed provider response. Do not depend on it. */
5415
6508
  raw: unknown;
5416
6509
  [key: string]: unknown;
5417
6510
  };
@@ -5463,7 +6556,7 @@ export interface ApiResponses {
5463
6556
  reconnect?: Record<string, unknown>;
5464
6557
  [key: string]: unknown;
5465
6558
  }>;
5466
- /** Raw Composio payload. */
6559
+ /** Deprecated: the unprocessed provider response. Do not depend on it. */
5467
6560
  raw: unknown;
5468
6561
  [key: string]: unknown;
5469
6562
  };
@@ -6170,15 +7263,47 @@ export type DenchApiTree = {
6170
7263
  };
6171
7264
  campaigns: {
6172
7265
  accounts: {
7266
+ /** Discover the mailboxes the acting workspace member can send campaign email from: ids for emailMailboxAccountIds, status, warm-up state and when it is done, the daily cold-email cap and what is left today. Never returns provider credentials. (`dench campaign accounts`) */
7267
+ email(args?: Req<"campaigns.accounts.email">): Promise<Res<"campaigns.accounts.email">>;
6173
7268
  /** Discover LinkedIn sender ids, labels, availability and remaining capacity visible to the acting workspace member. Never returns provider credentials. (`dench campaign accounts`) */
6174
7269
  linkedin(args?: Req<"campaigns.accounts.linkedin">): Promise<Res<"campaigns.accounts.linkedin">>;
6175
7270
  };
6176
7271
  /** Campaign funnel: enrolled, contacted, invited, accepted, messaged, replied, opens and clicks. (`dench campaign get`) */
6177
7272
  analytics(args: Req<"campaigns.analytics">): Promise<Res<"campaigns.analytics">>;
6178
- /** Archive a campaign and stop everyone still in flight. (`dench campaign archive`) */
7273
+ /** Archive a campaign and stop everyone still in flight. This is the app's Delete: campaigns are never erased, and their people, leads and activity stay. (`dench campaign archive`) */
6179
7274
  archive(args: Req<"campaigns.archive">): Promise<Res<"campaigns.archive">>;
7275
+ audience: {
7276
+ /** Search people by filters without adding CRM records or campaign recipients. Search credits apply; this is not a free provider preview. (`dench campaign search`) */
7277
+ search(args: Req<"campaigns.audience.search">): Promise<Res<"campaigns.audience.search">>;
7278
+ };
7279
+ builder: {
7280
+ /** Turn an audience description into targeting filters. AI credits apply. (`dench campaign builder autofill`) */
7281
+ autofill(args: Req<"campaigns.builder.autofill">): Promise<Res<"campaigns.builder.autofill">>;
7282
+ /** Start the same billable signal/audience/message build used by the UI; poll the draft for progress. (`dench campaign builder build`) */
7283
+ build(args: Req<"campaigns.builder.build">): Promise<Res<"campaigns.builder.build">>;
7284
+ /** Create a campaign from a reviewed signal draft. Does not launch the campaign. (`dench campaign builder create`) */
7285
+ create(args: Req<"campaigns.builder.create">): Promise<Res<"campaigns.builder.create">>;
7286
+ /** Estimate audience or weekly signal volume using the UI's cached estimator. Provider credits may apply. (`dench campaign builder estimate`) */
7287
+ estimate(args: Req<"campaigns.builder.estimate">): Promise<Res<"campaigns.builder.estimate">>;
7288
+ /** Read signal build progress, preview people, messages and errors. (`dench campaign builder get`) */
7289
+ get(args: Req<"campaigns.builder.get">): Promise<Res<"campaigns.builder.get">>;
7290
+ /** Edit or reset one preview person's opening line before creating the campaign. (`dench campaign builder opener`) */
7291
+ opener(args: Req<"campaigns.builder.opener">): Promise<Res<"campaigns.builder.opener">>;
7292
+ /** Read the company profile and suggested campaign audience. (`dench campaign builder profile`) */
7293
+ profile(args?: Req<"campaigns.builder.profile">): Promise<Res<"campaigns.builder.profile">>;
7294
+ /** Save a signal campaign's audience, signals and terms idempotently. Does not start a build. (`dench campaign builder save`) */
7295
+ save(args: Req<"campaigns.builder.save">): Promise<Res<"campaigns.builder.save">>;
7296
+ /** Suggest signal terms for the selected audience. AI credits apply. (`dench campaign builder terms`) */
7297
+ terms(args: Req<"campaigns.builder.terms">): Promise<Res<"campaigns.builder.terms">>;
7298
+ };
6180
7299
  /** Create a draft outreach campaign with email and LinkedIn sender pools and a business-hours send window in the given timezone. (`dench campaign create`) */
6181
7300
  create(args: Req<"campaigns.create">): Promise<Res<"campaigns.create">>;
7301
+ drafts: {
7302
+ /** Create an idempotent empty campaign draft with the caller's available sender pools. Does not launch or send. (`dench campaign draft`) */
7303
+ create(args: Req<"campaigns.drafts.create">): Promise<Res<"campaigns.drafts.create">>;
7304
+ };
7305
+ /** Copy a campaign into a new draft named "<name> copy": the same steps, schedule, sender pools and personalized lines, its lead source paused, and no people. To reach more than 300 people, duplicate and add the next page of the search to the copy. (`dench campaign duplicate`) */
7306
+ duplicate(args: Req<"campaigns.duplicate">): Promise<Res<"campaigns.duplicate">>;
6182
7307
  /** The campaign's activity log, newest first (sent, accepted, replied, skipped, failed, paused, stopped). (`dench campaign events`) */
6183
7308
  events(args: Req<"campaigns.events">): Promise<Res<"campaigns.events">>;
6184
7309
  /** Read a campaign: settings, steps, people, their current step and hold, last touches, linked leads. (`dench campaign get`) */
@@ -6187,7 +7312,7 @@ export type DenchApiTree = {
6187
7312
  /** Launch a ready draft. Pass the fingerprint from the preview and acknowledge the LinkedIn notice when LinkedIn steps exist. (`dench campaign launch`) */
6188
7313
  (args: Req<"campaigns.launch">): Promise<Res<"campaigns.launch">>;
6189
7314
  $call(args: Req<"campaigns.launch">): Promise<Res<"campaigns.launch">>;
6190
- /** Launch readiness: blockers grouped by problem, warnings, and the fingerprint `launch` requires. (`dench campaign launch`) */
7315
+ /** Launch readiness without launching: blockers grouped by problem, warnings, and the fingerprint `launch` requires. (`dench campaign launch --check`) */
6191
7316
  preview(args: Req<"campaigns.launch.preview">): Promise<Res<"campaigns.launch.preview">>;
6192
7317
  };
6193
7318
  /** List outreach campaigns (archived ones on request). (`dench campaign list`) */
@@ -6199,18 +7324,68 @@ export type DenchApiTree = {
6199
7324
  people: {
6200
7325
  /** Add one person by email and/or LinkedIn profile URL. (`dench campaign add --name`) */
6201
7326
  add(args: Req<"campaigns.people.add">): Promise<Res<"campaigns.people.add">>;
7327
+ /** Add up to 50 selected recipients without another search. Deduplicates, applies suppression, and preserves the campaign's launch state. (`dench campaign add --people-file`) */
7328
+ addBatch(args: Req<"campaigns.people.addBatch">): Promise<Res<"campaigns.people.addBatch">>;
6202
7329
  /** Add CRM records (up to 100 ids per call) to a campaign; returns how many were added and why others were skipped. (`dench campaign add`) */
6203
7330
  addFromCrm(args: Req<"campaigns.people.addFromCrm">): Promise<Res<"campaigns.people.addFromCrm">>;
7331
+ /** Search and add up to 50 people to an existing campaign. New identities become Leads. Search credits apply; use nextPageToken for another page. (`dench campaign add --search`) */
7332
+ addFromSearch(args: Req<"campaigns.people.addFromSearch">): Promise<Res<"campaigns.people.addFromSearch">>;
7333
+ /** The campaigns a CRM record (a person or a lead) is in, newest first, with the person's status in each and the accounts that send to them. (`dench campaign where`) */
7334
+ forRecord(args: Req<"campaigns.people.forRecord">): Promise<Res<"campaigns.people.forRecord">>;
7335
+ /** Remove a person who was never contacted from a draft campaign. Frees their place in the 300-person cap and keeps the draft launchable; stop anyone already contacted instead. (`dench campaign remove`) */
7336
+ remove(args: Req<"campaigns.people.remove">): Promise<Res<"campaigns.people.remove">>;
6204
7337
  /** Resume one paused person in an active campaign. (`dench campaign resume-person`) */
6205
7338
  resume(args: Req<"campaigns.people.resume">): Promise<Res<"campaigns.people.resume">>;
7339
+ /** Resume every paused person in an active campaign at once, e.g. after a sending account is reconnected. Returns how many were resumed. (`dench campaign resume-person --all`) */
7340
+ resumeAll(args: Req<"campaigns.people.resumeAll">): Promise<Res<"campaigns.people.resumeAll">>;
7341
+ /** Give a person in a draft campaign a new or corrected email address; their linked CRM record gets it too. Only before launch; another person in the campaign can't share it. (`dench campaign person set --email`) */
7342
+ setEmail(args: Req<"campaigns.people.setEmail">): Promise<Res<"campaigns.people.setEmail">>;
7343
+ /** Fill or fix one {{merge field}} for a person in a draft campaign, e.g. a missing Company that blocks launch; a matching column on their CRM record is updated too. Only before launch; written personalized lines are not merge fields and can't be set here. (`dench campaign person set --field`) */
7344
+ setField(args: Req<"campaigns.people.setField">): Promise<Res<"campaigns.people.setField">>;
7345
+ /** Give a person in a draft campaign a new or corrected LinkedIn profile URL; their linked CRM record gets it too. Only before launch. (`dench campaign person set --linkedin-url`) */
7346
+ setLinkedin(args: Req<"campaigns.people.setLinkedin">): Promise<Res<"campaigns.people.setLinkedin">>;
6206
7347
  /** Stop one person: nothing more is sent to them from this campaign. (`dench campaign stop`) */
6207
7348
  stop(args: Req<"campaigns.people.stop">): Promise<Res<"campaigns.people.stop">>;
6208
- };
7349
+ /** Fill each unfinished person's empty email, LinkedIn URL, name and merge fields from their linked CRM record, e.g. after enriching the records. Never overwrites a value the campaign already has; returns how many people changed. (`dench campaign sync`) */
7350
+ sync(args: Req<"campaigns.people.sync">): Promise<Res<"campaigns.people.sync">>;
7351
+ /** Everything a campaign did for one person, step by step: what was sent (subject and text), whether it was opened or clicked, what was skipped and why, waits, failures and retries. (`dench campaign person show`) */
7352
+ timeline(args: Req<"campaigns.people.timeline">): Promise<Res<"campaigns.people.timeline">>;
7353
+ };
7354
+ personalization: {
7355
+ /** Turn off a campaign's personalized lines and cancel the ones not yet written. Refused while a step still uses one of the {{keys}}. (`dench campaign personalize clear`) */
7356
+ clear(args: Req<"campaigns.personalization.clear">): Promise<Res<"campaigns.personalization.clear">>;
7357
+ /** Set one person's personalized line by hand; an empty value undoes the edit. Braces are removed and text past the line's length is cut. (`dench campaign personalize edit`) */
7358
+ edit(args: Req<"campaigns.personalization.edit">): Promise<Res<"campaigns.personalization.edit">>;
7359
+ /** Read a campaign's personalized lines (written for each person): their {{keys}} for steps, instructions and fallbacks, how many people have them, and the cost per person. (`dench campaign personalize get`) */
7360
+ get(args: Req<"campaigns.personalization.get">): Promise<Res<"campaigns.personalization.get">>;
7361
+ /** Write a fresh personalized line for one person: one key, or all of their lines when key is left out. About 3 cents. (`dench campaign personalize rewrite`) */
7362
+ rewrite(args: Req<"campaigns.personalization.rewrite">): Promise<Res<"campaigns.personalization.rewrite">>;
7363
+ /** Define up to 5 personalized lines (each used as {{key}} in steps) and what you sell. Saving starts writing missing lines for up to 100 people, about 3 cents a person; for more it returns needsConfirm and writes nothing until campaigns.personalization.write is confirmed. (`dench campaign personalize set`) */
7364
+ set(args: Req<"campaigns.personalization.set">): Promise<Res<"campaigns.personalization.set">>;
7365
+ /** Write personalized lines for the people missing them (mode missing) or rewrite everyone's (mode all). Rewriting everyone or more than 100 people returns needsConfirm and the estimate until called with confirmed: true. (`dench campaign personalize write`) */
7366
+ write(args: Req<"campaigns.personalization.write">): Promise<Res<"campaigns.personalization.write">>;
7367
+ };
7368
+ /** Where a campaign's people sit in the workspace's lead pipeline right now: each lead Status in order with how many enrolled leads are at it, and how many have no lead or a status outside the pipeline. (`dench campaign pipeline`) */
7369
+ pipeline(args: Req<"campaigns.pipeline">): Promise<Res<"campaigns.pipeline">>;
7370
+ /** Show the message one person gets at one email or LinkedIn step, with their fields and personalized lines filled in: subject, body, sender, recipient, merge fields still missing, warnings, and why the step would be skipped. Nothing is sent, prepared or charged. (`dench campaign preview`) */
7371
+ preview(args: Req<"campaigns.preview">): Promise<Res<"campaigns.preview">>;
6209
7372
  /** Resume a paused campaign. (`dench campaign resume`) */
6210
7373
  resume(args: Req<"campaigns.resume">): Promise<Res<"campaigns.resume">>;
7374
+ sources: {
7375
+ /** Read a campaign's saved signal source, targeting and schedule. (`dench campaign sources get`) */
7376
+ get(args: Req<"campaigns.sources.get">): Promise<Res<"campaigns.sources.get">>;
7377
+ /** Preview a signal source using its current audience. Provider credits may apply; does not enroll people. (`dench campaign sources preview`) */
7378
+ preview(args: Req<"campaigns.sources.preview">): Promise<Res<"campaigns.sources.preview">>;
7379
+ /** Read signal choices, suggested terms and current source configuration. (`dench campaign sources signals`) */
7380
+ signals(args: Req<"campaigns.sources.signals">): Promise<Res<"campaigns.sources.signals">>;
7381
+ /** Update source cadence, pause/resume, targeting, signals or terms. Active sources may perform billable future work. (`dench campaign sources set`) */
7382
+ update(args: Req<"campaigns.sources.update">): Promise<Res<"campaigns.sources.update">>;
7383
+ };
6211
7384
  steps: {
6212
- /** Replace every step of a draft campaign (email, wait, LinkedIn visit, connection request, message). Configure sender pools on the campaign; step sender ids are legacy-only. (`dench campaign steps set`) */
7385
+ /** Replace every step of a draft campaign (email, wait, LinkedIn visit, connection request, message, post reaction, InMail). Steps are checked first: a field the step type would drop, missing text or {TOKEN} single braces are rejected, not saved. Configure sender pools on the campaign; step sender ids are legacy-only. (`dench campaign steps set`) */
6213
7386
  replace(args: Req<"campaigns.steps.replace">): Promise<Res<"campaigns.steps.replace">>;
7387
+ /** Edit the text, waits and conditions of a launched (or paused) campaign's steps in place. Each step keeps its id, type and place; pass the stepId and the updatedAt you read, and only the fields you change. Messages already sent or being prepared keep their text; drafts use campaigns.steps.replace. (`dench campaign steps edit`) */
7388
+ update(args: Req<"campaigns.steps.update">): Promise<Res<"campaigns.steps.update">>;
6214
7389
  };
6215
7390
  /** Change a campaign's name, sender pools, send windows, daily email cap, stop-on-reply, start or end. Works until archived; existing conversations keep their assigned sender. (`dench campaign set`) */
6216
7391
  update(args: Req<"campaigns.update">): Promise<Res<"campaigns.update">>;
@@ -6760,7 +7935,7 @@ export type DenchApiTree = {
6760
7935
  generate(args: Req<"image.generate">): Promise<Res<"image.generate">>;
6761
7936
  };
6762
7937
  integrations: {
6763
- /** List every connected integration — Composio apps plus the Gmail, Outlook, Calendar, LinkedIn and Slack connections Dench brokers itself (Slack rows report source: dench). (`dench integrations`) */
7938
+ /** List every connected integration — connected apps plus the Gmail, Outlook, Calendar, LinkedIn and Slack connections Dench provides itself (Slack rows report source: dench). (`dench integrations`) */
6764
7939
  list(args?: Req<"integrations.list">): Promise<Res<"integrations.list">>;
6765
7940
  };
6766
7941
  lists: {
@@ -6888,7 +8063,7 @@ export type DenchApiTree = {
6888
8063
  };
6889
8064
  };
6890
8065
  tool: {
6891
- /** Create a tool OAuth connection link. Slack is in-house, never Composio: for toolkit slack the CLI prints the first-party install URL (/api/slack/install?slug=<workspace>, org admin) instead of calling this endpoint. (`dench tool connect`) */
8066
+ /** Create a tool OAuth connection link. Slack is in-house, never a third-party connection: for toolkit slack the CLI prints the first-party install URL (/api/slack/install?slug=<workspace>, org admin) instead of calling this endpoint. (`dench tool connect`) */
6892
8067
  connect(args: Req<"tool.connect">): Promise<Res<"tool.connect">>;
6893
8068
  /** Disconnect an external tool account. (`dench tool disconnect`) */
6894
8069
  disconnect(args: Req<"tool.disconnect">): Promise<Res<"tool.disconnect">>;
@@ -6900,7 +8075,7 @@ export type DenchApiTree = {
6900
8075
  /** List human names given to connected accounts. (`dench tool labels`) */
6901
8076
  list(args?: Req<"tool.labels.list">): Promise<Res<"tool.labels.list">>;
6902
8077
  };
6903
- /** Run an external tool action. SLACK_* slugs (SLACK_SEND_MESSAGE with Block Kit blocks/buttons, SLACK_FETCH_HISTORY, SLACK_LIST_CHANNELS, …) run through Dench's in-house Slack app install — any channel in the connected workspace — and are always preferred over Composio Slack. (`dench tool run`) */
8078
+ /** Run an external tool action. SLACK_* slugs (SLACK_SEND_MESSAGE with Block Kit blocks/buttons, SLACK_FETCH_HISTORY, SLACK_LIST_CHANNELS, …) run through Dench's in-house Slack app install — any channel in the connected workspace — and are always preferred over any third-party Slack connection. (`dench tool run`) */
6904
8079
  run(args: Req<"tool.run">): Promise<Res<"tool.run">>;
6905
8080
  /** Search for external tool actions. (`dench tool search`) */
6906
8081
  search(args: Req<"tool.search">): Promise<Res<"tool.search">>;
@@ -7278,10 +8453,56 @@ export interface DenchLists {
7278
8453
  }
7279
8454
 
7280
8455
  export interface DenchCampaigns {
8456
+ /** Create a draft campaign. Permission: `campaigns:write`. Wraps `campaigns.create`. */
8457
+ create(opts: Req<"campaigns.create">): Promise<Res<"campaigns.create">>;
8458
+ /** Create an idempotent draft with available sender pools. Permission: `campaigns:write`. Wraps `campaigns.drafts.create`. */
8459
+ draft(opts: Req<"campaigns.drafts.create">): Promise<Res<"campaigns.drafts.create">>;
8460
+ /** Search people without enrolling them. Search credits apply. Permission: `campaigns:write`. Wraps `campaigns.audience.search`. */
8461
+ search(opts: Req<"campaigns.audience.search">): Promise<Res<"campaigns.audience.search">>;
8462
+ /** Add up to 50 selected recipients without running another search. Permission: `campaigns:write`. Wraps `campaigns.people.addBatch`. */
8463
+ addPeople(opts: Req<"campaigns.people.addBatch">): Promise<Res<"campaigns.people.addBatch">>;
8464
+ /** Search and add up to 50 people to an existing campaign. Permission: `campaigns:write`. Wraps `campaigns.people.addFromSearch`. */
8465
+ addFromSearch(opts: Req<"campaigns.people.addFromSearch">): Promise<Res<"campaigns.people.addFromSearch">>;
8466
+ /** Read the campaign's lead source. Permission: `campaigns:read`. Wraps `campaigns.sources.get`. */
8467
+ sources(sequenceId: string): Promise<Res<"campaigns.sources.get">>;
8468
+ /** Read signal choices and suggestions. Permission: `campaigns:read`. Wraps `campaigns.sources.signals`. */
8469
+ sourceSignals(sequenceId: string): Promise<Res<"campaigns.sources.signals">>;
8470
+ /** Update targeting, signals, cadence or source status. Permission: `campaigns:write`. Wraps `campaigns.sources.update`. */
8471
+ updateSources(opts: Req<"campaigns.sources.update">): Promise<Res<"campaigns.sources.update">>;
8472
+ /** Preview a signal without enrolling people. Provider credits may apply. Permission: `campaigns:write`. Wraps `campaigns.sources.preview`. */
8473
+ previewSignal(opts: Req<"campaigns.sources.preview">): Promise<Res<"campaigns.sources.preview">>;
8474
+ /** Read suggested campaign targeting. Permission: `campaigns:read`. Wraps `campaigns.builder.profile`. */
8475
+ profile(): Promise<Res<"campaigns.builder.profile">>;
8476
+ /** Save signal-draft targeting and choices. Permission: `campaigns:write`. Wraps `campaigns.builder.save`. */
8477
+ saveDraft(opts: Req<"campaigns.builder.save">): Promise<Res<"campaigns.builder.save">>;
8478
+ /** Read preview people, messages and build progress. Permission: `campaigns:read`. Wraps `campaigns.builder.get`. */
8479
+ getDraft(draftId: string): Promise<Res<"campaigns.builder.get">>;
8480
+ /** Start a billable signal draft build. Permission: `campaigns:write`. Wraps `campaigns.builder.build`. */
8481
+ buildDraft(draftId: string): Promise<Res<"campaigns.builder.build">>;
8482
+ /** Create a campaign from a reviewed signal draft, without launching. Permission: `campaigns:write`. Wraps `campaigns.builder.create`. */
8483
+ createFromDraft(opts: Req<"campaigns.builder.create">): Promise<Res<"campaigns.builder.create">>;
8484
+ /** Edit a preview person's opening line. Permission: `campaigns:write`. Wraps `campaigns.builder.opener`. */
8485
+ setDraftOpener(opts: Req<"campaigns.builder.opener">): Promise<Res<"campaigns.builder.opener">>;
8486
+ /** Translate a description into targeting. AI credits apply. Permission: `campaigns:write`. Wraps `campaigns.builder.autofill`. */
8487
+ autofill(opts: Req<"campaigns.builder.autofill">): Promise<Res<"campaigns.builder.autofill">>;
8488
+ /** Suggest signal terms. AI credits apply. Permission: `campaigns:write`. Wraps `campaigns.builder.terms`. */
8489
+ suggestTerms(opts: Req<"campaigns.builder.terms">): Promise<Res<"campaigns.builder.terms">>;
8490
+ /** Estimate audience or signal volume. Permission: `campaigns:write`. Wraps `campaigns.builder.estimate`. */
8491
+ estimate(opts: Req<"campaigns.builder.estimate">): Promise<Res<"campaigns.builder.estimate">>;
8492
+ /** Mailboxes campaigns can send from, with warm-up and daily cap. Permission: `campaigns:read`. Wraps `campaigns.accounts.email`. */
8493
+ mailboxes(): Promise<Res<"campaigns.accounts.email">>;
8494
+ /** LinkedIn accounts campaigns can send from, with capacity. Permission: `campaigns:read`. Wraps `campaigns.accounts.linkedin`. */
8495
+ linkedinAccounts(): Promise<Res<"campaigns.accounts.linkedin">>;
7281
8496
  /** LinkedIn / multi-channel outreach campaigns. Permission: `campaigns:read`. Wraps `campaigns.list`. */
7282
8497
  list(): Promise<Res<"campaigns.list">>;
7283
8498
  /** One campaign. Permission: `campaigns:read`. Wraps `campaigns.get`. */
7284
8499
  get(sequenceId: string): Promise<Res<"campaigns.get">>;
8500
+ /** Replace every step of a draft campaign. Permission: `campaigns:write`. Wraps `campaigns.steps.replace`. */
8501
+ setSteps(opts: Req<"campaigns.steps.replace">): Promise<Res<"campaigns.steps.replace">>;
8502
+ /** Edit launched steps in place by stepId and updatedAt. Permission: `campaigns:write`. Wraps `campaigns.steps.update`. */
8503
+ editSteps(opts: Req<"campaigns.steps.update">): Promise<Res<"campaigns.steps.update">>;
8504
+ /** Copy a campaign into a new draft without its people. Permission: `campaigns:write`. Wraps `campaigns.duplicate`. */
8505
+ duplicate(sequenceId: string): Promise<Res<"campaigns.duplicate">>;
7285
8506
  /** Campaign funnel numbers. Permission: `campaigns:read`. Wraps `campaigns.analytics`. */
7286
8507
  analytics(sequenceId: string): Promise<Res<"campaigns.analytics">>;
7287
8508
  /** Campaign event log. Permission: `campaigns:read`. Wraps `campaigns.events`. */
@@ -7290,6 +8511,40 @@ export interface DenchCampaigns {
7290
8511
  pause(sequenceId: string): Promise<Res<"campaigns.pause">>;
7291
8512
  /** Resume a campaign. Permission: `campaigns:write`. Wraps `campaigns.resume`. */
7292
8513
  resume(sequenceId: string): Promise<Res<"campaigns.resume">>;
8514
+ /** Archive (the app's Delete) a campaign; nothing is erased. Permission: `campaigns:write`. Wraps `campaigns.archive`. */
8515
+ archive(sequenceId: string): Promise<Res<"campaigns.archive">>;
8516
+ /** The message one person gets at one step, fields filled in. Sends nothing. Permission: `campaigns:read`. Wraps `campaigns.preview`. */
8517
+ previewMessage(sequenceId: string, enrollmentId: string, stepId: string): Promise<Res<"campaigns.preview">>;
8518
+ /** Personalized lines, their {{keys}} and how many are written. Permission: `campaigns:read`. Wraps `campaigns.personalization.get`. */
8519
+ personalization(sequenceId: string): Promise<Res<"campaigns.personalization.get">>;
8520
+ /** Define up to 5 personalized lines. Writing them costs credits. Permission: `campaigns:write`. Wraps `campaigns.personalization.set`. */
8521
+ setPersonalization(opts: Req<"campaigns.personalization.set">): Promise<Res<"campaigns.personalization.set">>;
8522
+ /** Turn personalized lines off. Permission: `campaigns:write`. Wraps `campaigns.personalization.clear`. */
8523
+ clearPersonalization(sequenceId: string): Promise<Res<"campaigns.personalization.clear">>;
8524
+ /** Write missing (or all) personalized lines. Costs credits. Permission: `campaigns:write`. Wraps `campaigns.personalization.write`. */
8525
+ writeLines(opts: Req<"campaigns.personalization.write">): Promise<Res<"campaigns.personalization.write">>;
8526
+ /** Set one person's personalized line by hand. Permission: `campaigns:write`. Wraps `campaigns.personalization.edit`. */
8527
+ editLine(enrollmentId: string, key: string, value: string): Promise<Res<"campaigns.personalization.edit">>;
8528
+ /** Write a fresh line for one person. Costs credits. Permission: `campaigns:write`. Wraps `campaigns.personalization.rewrite`. */
8529
+ rewriteLine(enrollmentId: string, key?: string): Promise<Res<"campaigns.personalization.rewrite">>;
8530
+ /** Fill people's empty contact details from their CRM records. Permission: `campaigns:write`. Wraps `campaigns.people.sync`. */
8531
+ syncPeople(sequenceId: string): Promise<Res<"campaigns.people.sync">>;
8532
+ /** Resume every paused person in an active campaign. Permission: `campaigns:write`. Wraps `campaigns.people.resumeAll`. */
8533
+ resumeAllPeople(sequenceId: string): Promise<Res<"campaigns.people.resumeAll">>;
8534
+ /** Fix a draft person's email address. Permission: `campaigns:write`. Wraps `campaigns.people.setEmail`. */
8535
+ setPersonEmail(enrollmentId: string, email: string): Promise<Res<"campaigns.people.setEmail">>;
8536
+ /** Fix a draft person's LinkedIn profile URL. Permission: `campaigns:write`. Wraps `campaigns.people.setLinkedin`. */
8537
+ setPersonLinkedin(enrollmentId: string, linkedinProfileUrl: string): Promise<Res<"campaigns.people.setLinkedin">>;
8538
+ /** Fill one {{merge field}} for a draft person. Permission: `campaigns:write`. Wraps `campaigns.people.setField`. */
8539
+ setPersonField(enrollmentId: string, key: string, value: string): Promise<Res<"campaigns.people.setField">>;
8540
+ /** Where the campaign's people sit in the lead pipeline. Permission: `campaigns:read`. Wraps `campaigns.pipeline`. */
8541
+ pipeline(sequenceId: string): Promise<Res<"campaigns.pipeline">>;
8542
+ /** The campaigns a CRM record is in, with its status in each. Permission: `campaigns:read`. Wraps `campaigns.people.forRecord`. */
8543
+ campaignsForRecord(entryId: string): Promise<Res<"campaigns.people.forRecord">>;
8544
+ /** Everything a campaign did for one person, step by step. Permission: `campaigns:read`. Wraps `campaigns.people.timeline`. */
8545
+ personTimeline(enrollmentId: string): Promise<Res<"campaigns.people.timeline">>;
8546
+ /** Remove a never-contacted person from a draft campaign. Permission: `campaigns:write`. Wraps `campaigns.people.remove`. */
8547
+ removePerson(enrollmentId: string): Promise<Res<"campaigns.people.remove">>;
7293
8548
  }
7294
8549
 
7295
8550
  export interface DenchEmail {