@dench.com/cli 3.8.0-staging.389 → 3.8.1-staging.390

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
@@ -2594,7 +2594,7 @@ export interface ApiRequests {
2594
2594
  "campaigns.get": {
2595
2595
  sequenceId: string;
2596
2596
  };
2597
- /** Campaign funnel: enrolled, contacted, invited, accepted, messaged, replied, opens and clicks. — `dench campaign get` — GET /api/v1/campaigns/{sequenceId}/analytics */
2597
+ /** Campaign funnel: enrolled, contacted, invited, accepted, messaged, replied, opens and clicks, and for a workflow how many people took each If / else and Wait for them to accept path (branchStats). — `dench campaign get` — GET /api/v1/campaigns/{sequenceId}/analytics */
2598
2598
  "campaigns.analytics": {
2599
2599
  sequenceId: string;
2600
2600
  };
@@ -2643,13 +2643,13 @@ export interface ApiRequests {
2643
2643
  /** Cold emails per day, 1-100. */
2644
2644
  dailySendCap?: number;
2645
2645
  };
2646
- /** 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 */
2646
+ /** Replace every step of a draft campaign (email, wait, LinkedIn visit, connection request, message, post reaction, InMail, If / else, Wait for them to accept). A workflow (stepModel workflow, or steps with key, next, yesNext or noNext) branches: condition and wait_for_connection steps continue on yesNext or noNext, other steps on next; each points at another step's key or end. Steps are checked first: a field the step type would drop, missing text, {TOKEN} single braces or paths that don't hold together 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 */
2647
2647
  "campaigns.steps.replace": {
2648
2648
  sequenceId: string;
2649
- /** 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. */
2649
+ /** Every step, in send order (a workflow may list them in any order; they are stored in path 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, condition fields its check ignores), a missing subject or required body, an overlength note/message/InMail subject, out-of-range wait/withdrawal/post-age/acceptance values, {TOKEN} single braces, which would be sent as typed, and workflow paths that don't hold together (duplicate keys, a target that isn't a key or end, a condition or wait_for_connection without both yesNext and noNext, or any other step with them). */
2650
2650
  steps: Array<{
2651
- /** Step type. */
2652
- type: "email" | "wait" | "linkedin_visit" | "linkedin_connection" | "linkedin_message" | "linkedin_like_post" | "linkedin_inmail";
2651
+ /** Step type. condition (If / else) and wait_for_connection (Wait for them to accept) send nothing; they continue on yesNext or noNext and make the campaign a workflow. */
2652
+ type: "wait" | "email" | "linkedin_connection" | "linkedin_message" | "linkedin_visit" | "linkedin_like_post" | "linkedin_inmail" | "condition" | "wait_for_connection";
2653
2653
  /** wait steps: hours to wait before the next step. */
2654
2654
  waitHours?: number;
2655
2655
  /** Legacy email step sender. Pool campaigns choose senders in emailMailboxAccountIds on the campaign, not on individual steps. */
@@ -2664,35 +2664,57 @@ export interface ApiRequests {
2664
2664
  emailReplyToPrevious?: boolean;
2665
2665
  /** email and linkedin_like_post only: always (default), connected or not_connected. InMail automatically skips connected people; do not set a condition on it. */
2666
2666
  onlyIf?: "always" | "connected" | "not_connected";
2667
- /** Legacy LinkedIn step sender. Pool campaigns use the campaign's linkedinAccountIds instead. */
2667
+ /** Legacy LinkedIn step sender (also on wait_for_connection, and on a condition that checks linkedin_connected). Pool campaigns use the campaign's linkedinAccountIds instead. */
2668
2668
  linkedinAccountId?: string;
2669
2669
  /** 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). */
2670
2670
  linkedinMessageBody?: string;
2671
2671
  /** linkedin_message: what to do when the invite is still pending. */
2672
2672
  linkedinMessageMode?: "skip_if_not_connected" | "wait_until_connected";
2673
- /** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720). After a connection step this mode is the default. */
2673
+ /** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720); after a connection step this mode is the default in a linear campaign. wait_for_connection: wait 24-2160 hours (1-90 days, default 720) before taking the Not accepted path. */
2674
2674
  connectionTimeoutHours?: number;
2675
2675
  /** linkedin_like_post only: the reaction to leave (default like). */
2676
2676
  likeReaction?: "like" | "celebrate" | "support" | "love" | "insightful" | "funny";
2677
2677
  /** linkedin_like_post only: select the newest eligible original post from the last 1-365 days (default 30). */
2678
2678
  likeMaxPostAgeDays?: number;
2679
+ /** linkedin_like_post only: before the immediately preceding wait starts, check for eligible posts. If none exist, skip that wait and the like step, keeping following waits. Defaults to false when omitted. */
2680
+ likeSkipPreviousWait?: boolean;
2679
2681
  /** linkedin_like_post only: skip consecutive following wait steps whenever the reaction step is skipped (default true). False keeps those waits. */
2680
2682
  likeSkipNextWait?: boolean;
2683
+ /** linkedin_like_post only: how many recent posts to react to, 1-3 (default 1). */
2684
+ likeCount?: number;
2681
2685
  /** linkedin_inmail only: optional subject, up to 200 characters; merge tokens allowed. Clear with an empty string. */
2682
2686
  inmailSubject?: string;
2683
2687
  /** 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. */
2684
2688
  withdrawAfterHours?: number | null;
2689
+ /** Workflow steps: this step's id, unique in the campaign, which next, yesNext and noNext point at (not "end"). Left out, one is made. */
2690
+ key?: string;
2691
+ /** Workflow steps: where a step that isn't a condition or wait_for_connection goes; left out, the following step: another step's key, or "end" to stop there. Fixed once the campaign launches. */
2692
+ next?: string;
2693
+ /** Workflow steps: condition and wait_for_connection only, required: where the Yes (Accepted) path goes: another step's key, or "end" to stop there. Fixed once the campaign launches. */
2694
+ yesNext?: string;
2695
+ /** Workflow steps: condition and wait_for_connection only, required: where the No (Not accepted) path goes: another step's key, or "end" to stop there. Fixed once the campaign launches. */
2696
+ noNext?: string;
2697
+ /** condition only, required: linkedin_connected, has_email, opened_last_email (needs an email before it on every path) or field_value. Fixed once the campaign launches. */
2698
+ check?: "linkedin_connected" | "has_email" | "opened_last_email" | "field_value";
2699
+ /** condition with check=field_value: the lead field to check, like "Job Title" or "Source" (the campaign itself changes Status, Last touch and LinkedIn connection). Fixed once the campaign launches. */
2700
+ conditionField?: string;
2701
+ /** condition with check=field_value: is, is_not, contains, is_empty or is_not_empty (all case-insensitive). Fixed once the campaign launches. */
2702
+ conditionOperator?: "is" | "is_not" | "is_empty" | "is_not_empty" | "contains";
2703
+ /** condition with check=field_value and is, is_not or contains: the text to compare with. Editable after launch. */
2704
+ conditionValue?: string;
2685
2705
  }>;
2706
+ /** linear: steps run in order. workflow: steps have keys and paths (next, yesNext, noNext) and may include condition and wait_for_connection. Left out, a workflow stays one and steps with keys, paths or those types make one; nothing turns a workflow back into a list. When replacing a workflow's steps, send workflow, so steps without keys or paths are checked here the way they will be saved. */
2707
+ stepModel?: "linear" | "workflow";
2686
2708
  /** Send {single braces} exactly as typed instead of rejecting them. Merge tokens always use {{double braces}}. */
2687
2709
  allowSingleBraces?: boolean;
2688
2710
  };
2689
- /** 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 */
2711
+ /** 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. A workflow keeps its paths and what each If / else checks (key, next, yesNext, noNext, check, conditionField, conditionOperator); conditionValue and acceptance waits stay editable. Messages already sent or being prepared keep their text; drafts use campaigns.steps.replace. — `dench campaign steps edit` — PATCH /api/v1/campaigns/{sequenceId}/steps */
2690
2712
  "campaigns.steps.update": {
2691
2713
  sequenceId: string;
2692
- /** 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. */
2714
+ /** 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/acceptance values, {TOKEN} single braces, and a changed path or If / else check. */
2693
2715
  steps: Array<{
2694
2716
  /** The step's current type. A launched step's type can't change. */
2695
- type: "email" | "wait" | "linkedin_visit" | "linkedin_connection" | "linkedin_message" | "linkedin_like_post" | "linkedin_inmail";
2717
+ type: "wait" | "email" | "linkedin_connection" | "linkedin_message" | "linkedin_visit" | "linkedin_like_post" | "linkedin_inmail" | "condition" | "wait_for_connection";
2696
2718
  /** wait steps: hours to wait before the next step. */
2697
2719
  waitHours?: number;
2698
2720
  /** Legacy email step sender. Pool campaigns choose senders in emailMailboxAccountIds on the campaign, not on individual steps. */
@@ -2707,24 +2729,44 @@ export interface ApiRequests {
2707
2729
  emailReplyToPrevious?: boolean;
2708
2730
  /** email and linkedin_like_post only: always (default), connected or not_connected. InMail automatically skips connected people; do not set a condition on it. */
2709
2731
  onlyIf?: "always" | "connected" | "not_connected";
2710
- /** Legacy LinkedIn step sender. Pool campaigns use the campaign's linkedinAccountIds instead. */
2732
+ /** Legacy LinkedIn step sender (also on wait_for_connection, and on a condition that checks linkedin_connected). Pool campaigns use the campaign's linkedinAccountIds instead. */
2711
2733
  linkedinAccountId?: string;
2712
2734
  /** 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). */
2713
2735
  linkedinMessageBody?: string;
2714
2736
  /** linkedin_message: what to do when the invite is still pending. */
2715
2737
  linkedinMessageMode?: "skip_if_not_connected" | "wait_until_connected";
2716
- /** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720). After a connection step this mode is the default. */
2738
+ /** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720); after a connection step this mode is the default in a linear campaign. wait_for_connection: wait 24-2160 hours (1-90 days, default 720) before taking the Not accepted path. */
2717
2739
  connectionTimeoutHours?: number;
2718
2740
  /** linkedin_like_post only: the reaction to leave (default like). */
2719
2741
  likeReaction?: "like" | "celebrate" | "support" | "love" | "insightful" | "funny";
2720
2742
  /** linkedin_like_post only: select the newest eligible original post from the last 1-365 days (default 30). */
2721
2743
  likeMaxPostAgeDays?: number;
2744
+ /** linkedin_like_post only: before the immediately preceding wait starts, check for eligible posts. If none exist, skip that wait and the like step, keeping following waits. Defaults to false when omitted. */
2745
+ likeSkipPreviousWait?: boolean;
2722
2746
  /** linkedin_like_post only: skip consecutive following wait steps whenever the reaction step is skipped (default true). False keeps those waits. */
2723
2747
  likeSkipNextWait?: boolean;
2748
+ /** linkedin_like_post only: how many recent posts to react to, 1-3 (default 1). */
2749
+ likeCount?: number;
2724
2750
  /** linkedin_inmail only: optional subject, up to 200 characters; merge tokens allowed. Clear with an empty string. */
2725
2751
  inmailSubject?: string;
2726
2752
  /** 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. */
2727
2753
  withdrawAfterHours?: number | null;
2754
+ /** Workflow steps: this step's id, unique in the campaign, which next, yesNext and noNext point at (not "end"). Left out, one is made. */
2755
+ key?: string;
2756
+ /** Workflow steps: where a step that isn't a condition or wait_for_connection goes; left out, the following step: another step's key, or "end" to stop there. Fixed once the campaign launches. */
2757
+ next?: string;
2758
+ /** Workflow steps: condition and wait_for_connection only, required: where the Yes (Accepted) path goes: another step's key, or "end" to stop there. Fixed once the campaign launches. */
2759
+ yesNext?: string;
2760
+ /** Workflow steps: condition and wait_for_connection only, required: where the No (Not accepted) path goes: another step's key, or "end" to stop there. Fixed once the campaign launches. */
2761
+ noNext?: string;
2762
+ /** condition only, required: linkedin_connected, has_email, opened_last_email (needs an email before it on every path) or field_value. Fixed once the campaign launches. */
2763
+ check?: "linkedin_connected" | "has_email" | "opened_last_email" | "field_value";
2764
+ /** condition with check=field_value: the lead field to check, like "Job Title" or "Source" (the campaign itself changes Status, Last touch and LinkedIn connection). Fixed once the campaign launches. */
2765
+ conditionField?: string;
2766
+ /** condition with check=field_value: is, is_not, contains, is_empty or is_not_empty (all case-insensitive). Fixed once the campaign launches. */
2767
+ conditionOperator?: "is" | "is_not" | "is_empty" | "is_not_empty" | "contains";
2768
+ /** condition with check=field_value and is, is_not or contains: the text to compare with. Editable after launch. */
2769
+ conditionValue?: string;
2728
2770
  /** The step's _id from campaigns.get steps[]. */
2729
2771
  stepId: string;
2730
2772
  /** The step's updatedAt when you read it. If someone saved it since, the edit is refused instead of overwriting theirs. */
@@ -6117,6 +6159,8 @@ export interface ApiResponses {
6117
6159
  }[];
6118
6160
  dailySendCap?: number;
6119
6161
  stepCount: number;
6162
+ /** linear: steps run in order. workflow: steps have keys and paths (next, yesNext, noNext) and may include condition and wait_for_connection. Left out, a workflow stays one and steps with keys, paths or those types make one; nothing turns a workflow back into a list. */
6163
+ stepModel?: "linear" | "workflow";
6120
6164
  totalEnrolled: number;
6121
6165
  activeCount: number;
6122
6166
  pausedCount: number;
@@ -6166,6 +6210,8 @@ export interface ApiResponses {
6166
6210
  }[];
6167
6211
  dailySendCap?: number;
6168
6212
  stepCount: number;
6213
+ /** linear: steps run in order. workflow: steps have keys and paths (next, yesNext, noNext) and may include condition and wait_for_connection. Left out, a workflow stays one and steps with keys, paths or those types make one; nothing turns a workflow back into a list. */
6214
+ stepModel?: "linear" | "workflow";
6169
6215
  totalEnrolled: number;
6170
6216
  activeCount: number;
6171
6217
  pausedCount: number;
@@ -6180,9 +6226,10 @@ export interface ApiResponses {
6180
6226
  updatedAt: number;
6181
6227
  [key: string]: unknown;
6182
6228
  };
6229
+ /** The steps in order, each with its _id. condition and wait_for_connection steps also carry a readable label. */
6183
6230
  steps: Array<{
6184
- /** Step type. */
6185
- type: "email" | "wait" | "linkedin_visit" | "linkedin_connection" | "linkedin_message" | "linkedin_like_post" | "linkedin_inmail";
6231
+ /** Step type. condition (If / else) and wait_for_connection (Wait for them to accept) send nothing; they continue on yesNext or noNext and make the campaign a workflow. */
6232
+ type: "wait" | "email" | "linkedin_connection" | "linkedin_message" | "linkedin_visit" | "linkedin_like_post" | "linkedin_inmail" | "condition" | "wait_for_connection";
6186
6233
  /** wait steps: hours to wait before the next step. */
6187
6234
  waitHours?: number;
6188
6235
  /** Legacy email step sender. Pool campaigns choose senders in emailMailboxAccountIds on the campaign, not on individual steps. */
@@ -6197,24 +6244,44 @@ export interface ApiResponses {
6197
6244
  emailReplyToPrevious?: boolean;
6198
6245
  /** email and linkedin_like_post only: always (default), connected or not_connected. InMail automatically skips connected people; do not set a condition on it. */
6199
6246
  onlyIf?: "always" | "connected" | "not_connected";
6200
- /** Legacy LinkedIn step sender. Pool campaigns use the campaign's linkedinAccountIds instead. */
6247
+ /** Legacy LinkedIn step sender (also on wait_for_connection, and on a condition that checks linkedin_connected). Pool campaigns use the campaign's linkedinAccountIds instead. */
6201
6248
  linkedinAccountId?: string;
6202
6249
  /** 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). */
6203
6250
  linkedinMessageBody?: string;
6204
6251
  /** linkedin_message: what to do when the invite is still pending. */
6205
6252
  linkedinMessageMode?: "skip_if_not_connected" | "wait_until_connected";
6206
- /** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720). After a connection step this mode is the default. */
6253
+ /** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720); after a connection step this mode is the default in a linear campaign. wait_for_connection: wait 24-2160 hours (1-90 days, default 720) before taking the Not accepted path. */
6207
6254
  connectionTimeoutHours?: number;
6208
6255
  /** linkedin_like_post only: the reaction to leave (default like). */
6209
6256
  likeReaction?: "like" | "celebrate" | "support" | "love" | "insightful" | "funny";
6210
6257
  /** linkedin_like_post only: select the newest eligible original post from the last 1-365 days (default 30). */
6211
6258
  likeMaxPostAgeDays?: number;
6259
+ /** linkedin_like_post only: before the immediately preceding wait starts, check for eligible posts. If none exist, skip that wait and the like step, keeping following waits. Defaults to false when omitted. */
6260
+ likeSkipPreviousWait?: boolean;
6212
6261
  /** linkedin_like_post only: skip consecutive following wait steps whenever the reaction step is skipped (default true). False keeps those waits. */
6213
6262
  likeSkipNextWait?: boolean;
6263
+ /** linkedin_like_post only: how many recent posts to react to, 1-3 (default 1). */
6264
+ likeCount?: number;
6214
6265
  /** linkedin_inmail only: optional subject, up to 200 characters; merge tokens allowed. Clear with an empty string. */
6215
6266
  inmailSubject?: string;
6216
6267
  /** 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. */
6217
6268
  withdrawAfterHours?: number | null;
6269
+ /** Workflow steps: this step's id, unique in the campaign, which next, yesNext and noNext point at (not "end"). Left out, one is made. */
6270
+ key?: string;
6271
+ /** Workflow steps: where a step that isn't a condition or wait_for_connection goes; left out, the following step: another step's key, or "end" to stop there. Fixed once the campaign launches. */
6272
+ next?: string;
6273
+ /** Workflow steps: condition and wait_for_connection only, required: where the Yes (Accepted) path goes: another step's key, or "end" to stop there. Fixed once the campaign launches. */
6274
+ yesNext?: string;
6275
+ /** Workflow steps: condition and wait_for_connection only, required: where the No (Not accepted) path goes: another step's key, or "end" to stop there. Fixed once the campaign launches. */
6276
+ noNext?: string;
6277
+ /** condition only, required: linkedin_connected, has_email, opened_last_email (needs an email before it on every path) or field_value. Fixed once the campaign launches. */
6278
+ check?: "linkedin_connected" | "has_email" | "opened_last_email" | "field_value";
6279
+ /** condition with check=field_value: the lead field to check, like "Job Title" or "Source" (the campaign itself changes Status, Last touch and LinkedIn connection). Fixed once the campaign launches. */
6280
+ conditionField?: string;
6281
+ /** condition with check=field_value: is, is_not, contains, is_empty or is_not_empty (all case-insensitive). Fixed once the campaign launches. */
6282
+ conditionOperator?: "is" | "is_not" | "is_empty" | "is_not_empty" | "contains";
6283
+ /** condition with check=field_value and is, is_not or contains: the text to compare with. Editable after launch. */
6284
+ conditionValue?: string;
6218
6285
  [key: string]: unknown;
6219
6286
  }>;
6220
6287
  enrollments: Record<string, unknown>[];
@@ -6250,6 +6317,14 @@ export interface ApiResponses {
6250
6317
  replyRate: number;
6251
6318
  openRate: number;
6252
6319
  clickRate: number;
6320
+ /** Workflows only: each condition and wait_for_connection step, in step order, with how many people took each path. */
6321
+ branchStats?: {
6322
+ stepId: string;
6323
+ /** People who took the Yes (Accepted) path. */
6324
+ yes: number;
6325
+ /** People who took the No (Not accepted) path. */
6326
+ no: number;
6327
+ }[];
6253
6328
  truncated: boolean;
6254
6329
  [key: string]: unknown;
6255
6330
  };
@@ -6262,7 +6337,15 @@ export interface ApiResponses {
6262
6337
  dailySendCap: number | null;
6263
6338
  nextEmailAt: number | null;
6264
6339
  now: Record<string, unknown> | null;
6265
- next: Record<string, unknown> | null;
6340
+ next: {
6341
+ /** profile, visit, invite, message, like, inmail, withdraw, email, wait or check (an If / else). */
6342
+ kind: string;
6343
+ /** Waiting for them to accept: when the wait ends either way. */
6344
+ acceptanceDeadline?: number;
6345
+ /** kind check: what the If / else checks, e.g. "Has an email address". */
6346
+ label?: string;
6347
+ [key: string]: unknown;
6348
+ } | null;
6266
6349
  paused: Record<string, unknown> | null;
6267
6350
  senders: Record<string, unknown>[];
6268
6351
  [key: string]: unknown;
@@ -6538,8 +6621,8 @@ export interface ApiResponses {
6538
6621
  sequence: Record<string, unknown> | null;
6539
6622
  /** The campaign's steps in order, each with its _id. */
6540
6623
  steps: Array<{
6541
- /** Step type. */
6542
- type: "email" | "wait" | "linkedin_visit" | "linkedin_connection" | "linkedin_message" | "linkedin_like_post" | "linkedin_inmail";
6624
+ /** Step type. condition (If / else) and wait_for_connection (Wait for them to accept) send nothing; they continue on yesNext or noNext and make the campaign a workflow. */
6625
+ type: "wait" | "email" | "linkedin_connection" | "linkedin_message" | "linkedin_visit" | "linkedin_like_post" | "linkedin_inmail" | "condition" | "wait_for_connection";
6543
6626
  /** wait steps: hours to wait before the next step. */
6544
6627
  waitHours?: number;
6545
6628
  /** Legacy email step sender. Pool campaigns choose senders in emailMailboxAccountIds on the campaign, not on individual steps. */
@@ -6554,24 +6637,44 @@ export interface ApiResponses {
6554
6637
  emailReplyToPrevious?: boolean;
6555
6638
  /** email and linkedin_like_post only: always (default), connected or not_connected. InMail automatically skips connected people; do not set a condition on it. */
6556
6639
  onlyIf?: "always" | "connected" | "not_connected";
6557
- /** Legacy LinkedIn step sender. Pool campaigns use the campaign's linkedinAccountIds instead. */
6640
+ /** Legacy LinkedIn step sender (also on wait_for_connection, and on a condition that checks linkedin_connected). Pool campaigns use the campaign's linkedinAccountIds instead. */
6558
6641
  linkedinAccountId?: string;
6559
6642
  /** 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). */
6560
6643
  linkedinMessageBody?: string;
6561
6644
  /** linkedin_message: what to do when the invite is still pending. */
6562
6645
  linkedinMessageMode?: "skip_if_not_connected" | "wait_until_connected";
6563
- /** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720). After a connection step this mode is the default. */
6646
+ /** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720); after a connection step this mode is the default in a linear campaign. wait_for_connection: wait 24-2160 hours (1-90 days, default 720) before taking the Not accepted path. */
6564
6647
  connectionTimeoutHours?: number;
6565
6648
  /** linkedin_like_post only: the reaction to leave (default like). */
6566
6649
  likeReaction?: "like" | "celebrate" | "support" | "love" | "insightful" | "funny";
6567
6650
  /** linkedin_like_post only: select the newest eligible original post from the last 1-365 days (default 30). */
6568
6651
  likeMaxPostAgeDays?: number;
6652
+ /** linkedin_like_post only: before the immediately preceding wait starts, check for eligible posts. If none exist, skip that wait and the like step, keeping following waits. Defaults to false when omitted. */
6653
+ likeSkipPreviousWait?: boolean;
6569
6654
  /** linkedin_like_post only: skip consecutive following wait steps whenever the reaction step is skipped (default true). False keeps those waits. */
6570
6655
  likeSkipNextWait?: boolean;
6656
+ /** linkedin_like_post only: how many recent posts to react to, 1-3 (default 1). */
6657
+ likeCount?: number;
6571
6658
  /** linkedin_inmail only: optional subject, up to 200 characters; merge tokens allowed. Clear with an empty string. */
6572
6659
  inmailSubject?: string;
6573
6660
  /** 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. */
6574
6661
  withdrawAfterHours?: number | null;
6662
+ /** Workflow steps: this step's id, unique in the campaign, which next, yesNext and noNext point at (not "end"). Left out, one is made. */
6663
+ key?: string;
6664
+ /** Workflow steps: where a step that isn't a condition or wait_for_connection goes; left out, the following step: another step's key, or "end" to stop there. Fixed once the campaign launches. */
6665
+ next?: string;
6666
+ /** Workflow steps: condition and wait_for_connection only, required: where the Yes (Accepted) path goes: another step's key, or "end" to stop there. Fixed once the campaign launches. */
6667
+ yesNext?: string;
6668
+ /** Workflow steps: condition and wait_for_connection only, required: where the No (Not accepted) path goes: another step's key, or "end" to stop there. Fixed once the campaign launches. */
6669
+ noNext?: string;
6670
+ /** condition only, required: linkedin_connected, has_email, opened_last_email (needs an email before it on every path) or field_value. Fixed once the campaign launches. */
6671
+ check?: "linkedin_connected" | "has_email" | "opened_last_email" | "field_value";
6672
+ /** condition with check=field_value: the lead field to check, like "Job Title" or "Source" (the campaign itself changes Status, Last touch and LinkedIn connection). Fixed once the campaign launches. */
6673
+ conditionField?: string;
6674
+ /** condition with check=field_value: is, is_not, contains, is_empty or is_not_empty (all case-insensitive). Fixed once the campaign launches. */
6675
+ conditionOperator?: "is" | "is_not" | "is_empty" | "is_not_empty" | "contains";
6676
+ /** condition with check=field_value and is, is_not or contains: the text to compare with. Editable after launch. */
6677
+ conditionValue?: string;
6575
6678
  [key: string]: unknown;
6576
6679
  }>;
6577
6680
  /** One run for each step the person has reached, in order. */
@@ -6581,8 +6684,8 @@ export interface ApiResponses {
6581
6684
  stepId: string;
6582
6685
  /** The step's place, from 0. */
6583
6686
  stepIndex: number;
6584
- /** Step type. */
6585
- type: "email" | "wait" | "linkedin_visit" | "linkedin_connection" | "linkedin_message" | "linkedin_like_post" | "linkedin_inmail";
6687
+ /** Step type. condition (If / else) and wait_for_connection (Wait for them to accept) send nothing; they continue on yesNext or noNext and make the campaign a workflow. */
6688
+ type: "wait" | "email" | "linkedin_connection" | "linkedin_message" | "linkedin_visit" | "linkedin_like_post" | "linkedin_inmail" | "condition" | "wait_for_connection";
6586
6689
  /** sent: done (a wait that finished is sent too). skipped: see result.reason. retry: will be tried again at retryAt. unknown: needs a look. */
6587
6690
  status: "queued" | "running" | "waiting" | "retry" | "sent" | "skipped" | "failed" | "unknown";
6588
6691
  scheduledAt?: number;
@@ -6593,7 +6696,9 @@ export interface ApiResponses {
6593
6696
  /** The email this run sent, in emailMessages[]. */
6594
6697
  emailMessageId?: string;
6595
6698
  lastError?: string;
6596
- /** For a skipped step, { reason } says why. */
6699
+ /** wait_for_connection: when it stops waiting for the accept. */
6700
+ timeoutAt?: number;
6701
+ /** For a skipped step, { reason } says why. A finished condition or wait_for_connection has { branch: "yes" | "no" } (Yes / Accepted or No / Not accepted), and { reason } for some No paths. */
6597
6702
  result?: unknown;
6598
6703
  [key: string]: unknown;
6599
6704
  }>;
@@ -7760,7 +7865,7 @@ export type DenchApiTree = {
7760
7865
  /** Discover LinkedIn sender ids, labels, availability and remaining capacity visible to the acting workspace member. Never returns provider credentials. (`dench campaign accounts`) */
7761
7866
  linkedin(args?: Req<"campaigns.accounts.linkedin">): Promise<Res<"campaigns.accounts.linkedin">>;
7762
7867
  };
7763
- /** Campaign funnel: enrolled, contacted, invited, accepted, messaged, replied, opens and clicks. (`dench campaign get`) */
7868
+ /** Campaign funnel: enrolled, contacted, invited, accepted, messaged, replied, opens and clicks, and for a workflow how many people took each If / else and Wait for them to accept path (branchStats). (`dench campaign get`) */
7764
7869
  analytics(args: Req<"campaigns.analytics">): Promise<Res<"campaigns.analytics">>;
7765
7870
  /** 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`) */
7766
7871
  archive(args: Req<"campaigns.archive">): Promise<Res<"campaigns.archive">>;
@@ -7874,9 +7979,9 @@ export type DenchApiTree = {
7874
7979
  update(args: Req<"campaigns.sources.update">): Promise<Res<"campaigns.sources.update">>;
7875
7980
  };
7876
7981
  steps: {
7877
- /** 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`) */
7982
+ /** Replace every step of a draft campaign (email, wait, LinkedIn visit, connection request, message, post reaction, InMail, If / else, Wait for them to accept). A workflow (stepModel workflow, or steps with key, next, yesNext or noNext) branches: condition and wait_for_connection steps continue on yesNext or noNext, other steps on next; each points at another step's key or end. Steps are checked first: a field the step type would drop, missing text, {TOKEN} single braces or paths that don't hold together are rejected, not saved. Configure sender pools on the campaign; step sender ids are legacy-only. (`dench campaign steps set`) */
7878
7983
  replace(args: Req<"campaigns.steps.replace">): Promise<Res<"campaigns.steps.replace">>;
7879
- /** 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`) */
7984
+ /** 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. A workflow keeps its paths and what each If / else checks (key, next, yesNext, noNext, check, conditionField, conditionOperator); conditionValue and acceptance waits stay editable. Messages already sent or being prepared keep their text; drafts use campaigns.steps.replace. (`dench campaign steps edit`) */
7880
7985
  update(args: Req<"campaigns.steps.update">): Promise<Res<"campaigns.steps.update">>;
7881
7986
  };
7882
7987
  /** 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`) */