@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/README.md +65 -55
- package/app-sdk.d.ts +1286 -31
- package/apps.ts +1 -1
- package/campaign.ts +1949 -212
- package/crm.ts +21 -12
- package/cron.ts +6 -5
- package/dench.ts +76 -106
- package/fs-daemon.ts +6 -6
- package/image.ts +4 -4
- package/leads.ts +60 -22
- package/lib/api-schemas.ts +1094 -30
- package/lib/app-sdk-catalog.generated.ts +82 -6
- package/lib/app-sdk-surface.ts +240 -0
- package/lib/campaign-agent.ts +1564 -0
- package/lib/campaign-csv.ts +883 -0
- package/lib/campaign-filters.ts +141 -0
- package/lib/campaign-lines.ts +217 -0
- package/lib/campaign-steps.ts +721 -0
- package/lib/campaign-timeline.ts +189 -0
- package/lib/cli-version.ts +14 -0
- package/lib/command-registry.ts +491 -8
- package/lib/connection-source.ts +10 -0
- package/lib/enrichment-gateway.ts +22 -3
- package/lib/public-error.ts +41 -0
- package/lib/search-pricing.ts +9 -0
- package/package.json +1 -1
- package/search.ts +5 -34
- package/tools.ts +51 -42
- package/web.ts +1 -1
package/lib/api-schemas.ts
CHANGED
|
@@ -19,6 +19,17 @@
|
|
|
19
19
|
* stays lossless for the playground.
|
|
20
20
|
*/
|
|
21
21
|
import { type ZodTypeAny, z } from "zod";
|
|
22
|
+
import {
|
|
23
|
+
checkCampaignSteps,
|
|
24
|
+
checkStepEdits,
|
|
25
|
+
LINKEDIN_REACTIONS,
|
|
26
|
+
MAX_CAMPAIGN_STEPS,
|
|
27
|
+
MAX_INMAIL_BODY_CHARS,
|
|
28
|
+
MAX_INMAIL_SUBJECT_CHARS,
|
|
29
|
+
MAX_LIKE_POST_AGE_DAYS,
|
|
30
|
+
MAX_WAIT_HOURS,
|
|
31
|
+
MIN_WITHDRAW_AFTER_HOURS,
|
|
32
|
+
} from "./campaign-steps";
|
|
22
33
|
|
|
23
34
|
// ---------------------------------------------------------------------------
|
|
24
35
|
// Shared enums + fragments (mirror convex validators)
|
|
@@ -330,6 +341,185 @@ const campaignSenderPools = {
|
|
|
330
341
|
),
|
|
331
342
|
};
|
|
332
343
|
|
|
344
|
+
const campaignLineVariable = z
|
|
345
|
+
.object({
|
|
346
|
+
key: z
|
|
347
|
+
.string()
|
|
348
|
+
.describe(
|
|
349
|
+
"The {{key}} used in steps: a letter, then letters, digits or _ (up to 40). Not a built-in field like firstName or company.",
|
|
350
|
+
),
|
|
351
|
+
label: z.string().describe("The line's name, up to 60 characters."),
|
|
352
|
+
prompt: z
|
|
353
|
+
.string()
|
|
354
|
+
.describe("What the writer should say, up to 600 characters."),
|
|
355
|
+
fallback: z
|
|
356
|
+
.string()
|
|
357
|
+
.describe(
|
|
358
|
+
"Sent when there is nothing specific to say; up to 300 characters, no {{variables}}.",
|
|
359
|
+
),
|
|
360
|
+
fallbackFrom: z
|
|
361
|
+
.string()
|
|
362
|
+
.optional()
|
|
363
|
+
.describe("A field to use before the fallback, e.g. Company."),
|
|
364
|
+
maxChars: z
|
|
365
|
+
.number()
|
|
366
|
+
.int()
|
|
367
|
+
.min(20)
|
|
368
|
+
.max(300)
|
|
369
|
+
.optional()
|
|
370
|
+
.describe("The longest line, default 200 characters."),
|
|
371
|
+
})
|
|
372
|
+
.strict()
|
|
373
|
+
.describe("One personalized line.");
|
|
374
|
+
|
|
375
|
+
const campaignLineTemplate = z
|
|
376
|
+
.object({
|
|
377
|
+
variables: z.array(campaignLineVariable).min(1).max(5),
|
|
378
|
+
context: z
|
|
379
|
+
.object({
|
|
380
|
+
sells: z.string().describe("What you sell, up to 1000 characters."),
|
|
381
|
+
offer: z
|
|
382
|
+
.string()
|
|
383
|
+
.optional()
|
|
384
|
+
.describe("The offer or call to action, up to 300 characters."),
|
|
385
|
+
})
|
|
386
|
+
.strict(),
|
|
387
|
+
})
|
|
388
|
+
.strict();
|
|
389
|
+
|
|
390
|
+
const campaignLineBackfill = z.object({
|
|
391
|
+
version: z.number(),
|
|
392
|
+
eligible: z.number().describe("People who would get a line."),
|
|
393
|
+
estimatedCents: z.number().describe("About 3 cents a person."),
|
|
394
|
+
needsConfirm: z
|
|
395
|
+
.boolean()
|
|
396
|
+
.describe(
|
|
397
|
+
"True when nothing was written: confirm with campaigns.personalization.write and confirmed: true.",
|
|
398
|
+
),
|
|
399
|
+
queued: z.number().describe("People whose lines are being written now."),
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
const campaignPreviewedLine = z
|
|
403
|
+
.object({
|
|
404
|
+
key: z.string().describe("The line's {{key}}."),
|
|
405
|
+
label: z.string(),
|
|
406
|
+
value: z
|
|
407
|
+
.string()
|
|
408
|
+
.describe("What this person gets: the written line, or the fallback."),
|
|
409
|
+
state: z
|
|
410
|
+
.enum([
|
|
411
|
+
"written",
|
|
412
|
+
"edited",
|
|
413
|
+
"writing",
|
|
414
|
+
"paused",
|
|
415
|
+
"fallback",
|
|
416
|
+
"not_written",
|
|
417
|
+
])
|
|
418
|
+
.describe(
|
|
419
|
+
"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.",
|
|
420
|
+
),
|
|
421
|
+
source: z
|
|
422
|
+
.enum(["company", "news", "signal", "profile", "fallback"])
|
|
423
|
+
.optional()
|
|
424
|
+
.describe("What the line was written from."),
|
|
425
|
+
maxChars: z.number(),
|
|
426
|
+
rewriting: z
|
|
427
|
+
.enum(["writing", "paused"])
|
|
428
|
+
.optional()
|
|
429
|
+
.describe("A new line is being written over the current one."),
|
|
430
|
+
})
|
|
431
|
+
.passthrough();
|
|
432
|
+
|
|
433
|
+
const campaignMessagePreview = z
|
|
434
|
+
.object({
|
|
435
|
+
channel: z.enum(["email", "linkedin"]),
|
|
436
|
+
subject: z.string().optional().describe("Email steps."),
|
|
437
|
+
textBody: z.string().optional().describe("Email steps: plain text."),
|
|
438
|
+
htmlBody: z.string().optional().describe("Email steps: HTML."),
|
|
439
|
+
messageBody: z
|
|
440
|
+
.string()
|
|
441
|
+
.optional()
|
|
442
|
+
.describe(
|
|
443
|
+
"LinkedIn steps: the note or message, or a line saying no note or message is sent.",
|
|
444
|
+
),
|
|
445
|
+
fromName: z.string().optional().describe("The sending account."),
|
|
446
|
+
fromEmail: z.string().optional(),
|
|
447
|
+
toName: z.string(),
|
|
448
|
+
toEmail: z.string().optional(),
|
|
449
|
+
missingFields: z
|
|
450
|
+
.array(z.string())
|
|
451
|
+
.describe(
|
|
452
|
+
"{{merge fields}} this person has no value for; fill them with campaigns.people.setField.",
|
|
453
|
+
),
|
|
454
|
+
warnings: z.array(z.string()),
|
|
455
|
+
skippedReason: z
|
|
456
|
+
.string()
|
|
457
|
+
.optional()
|
|
458
|
+
.describe(
|
|
459
|
+
"Set when the person would skip this step, e.g. no email address.",
|
|
460
|
+
),
|
|
461
|
+
highlights: z.array(z.string()).optional(),
|
|
462
|
+
personalized: z.array(campaignPreviewedLine).optional(),
|
|
463
|
+
})
|
|
464
|
+
.passthrough();
|
|
465
|
+
|
|
466
|
+
const campaignSenderLabel = z
|
|
467
|
+
.object({
|
|
468
|
+
accountId: z.string(),
|
|
469
|
+
label: z.string().describe("The mailbox address or LinkedIn name."),
|
|
470
|
+
status: z.string(),
|
|
471
|
+
})
|
|
472
|
+
.nullable();
|
|
473
|
+
|
|
474
|
+
const campaignMembership = z
|
|
475
|
+
.object({
|
|
476
|
+
enrollment: z
|
|
477
|
+
.record(z.string(), z.unknown())
|
|
478
|
+
.describe(
|
|
479
|
+
"The person in that campaign: _id, sequenceId, status, currentStepIndex, repliedAt.",
|
|
480
|
+
),
|
|
481
|
+
sequenceName: z.string(),
|
|
482
|
+
isOwner: z.boolean(),
|
|
483
|
+
canManage: z.boolean(),
|
|
484
|
+
senders: z
|
|
485
|
+
.object({ email: campaignSenderLabel, linkedin: campaignSenderLabel })
|
|
486
|
+
.describe("The accounts that send to this person."),
|
|
487
|
+
})
|
|
488
|
+
.passthrough();
|
|
489
|
+
|
|
490
|
+
const campaignMailboxSummary = z
|
|
491
|
+
.object({
|
|
492
|
+
_id: z
|
|
493
|
+
.string()
|
|
494
|
+
.describe("The emailMailboxAccountId to put in emailMailboxAccountIds."),
|
|
495
|
+
email: z.string(),
|
|
496
|
+
provider: z.enum(["gmail", "outlook"]),
|
|
497
|
+
status: z.enum(["running", "disconnected", "errored"]),
|
|
498
|
+
statusReason: z.string().optional(),
|
|
499
|
+
warmupStatus: z
|
|
500
|
+
.enum(["skipped", "pending_auth", "warming", "ready", "error"])
|
|
501
|
+
.describe(
|
|
502
|
+
"ready or skipped: sends at its cap. warming: sends less until readyAt. pending_auth and error need the owner in the app.",
|
|
503
|
+
),
|
|
504
|
+
readyAt: z
|
|
505
|
+
.number()
|
|
506
|
+
.optional()
|
|
507
|
+
.describe(
|
|
508
|
+
"When warm-up finished, or is expected to finish while warming (epoch ms).",
|
|
509
|
+
),
|
|
510
|
+
dailyColdSendCap: z
|
|
511
|
+
.number()
|
|
512
|
+
.describe(
|
|
513
|
+
"The most cold emails a day; the mailbox owner sets it in the app.",
|
|
514
|
+
),
|
|
515
|
+
remainingToday: z.number().describe("Cold emails it can still send today."),
|
|
516
|
+
ownerName: z.string(),
|
|
517
|
+
isOwner: z.boolean(),
|
|
518
|
+
visibility: z.enum(["private", "shared"]),
|
|
519
|
+
})
|
|
520
|
+
.passthrough()
|
|
521
|
+
.describe("One mailbox a campaign can send from.");
|
|
522
|
+
|
|
333
523
|
const campaignLinkedinSenderSummary = z
|
|
334
524
|
.object({
|
|
335
525
|
linkedinAccountId: z
|
|
@@ -405,6 +595,8 @@ const campaignStepType = z
|
|
|
405
595
|
"linkedin_visit",
|
|
406
596
|
"linkedin_connection",
|
|
407
597
|
"linkedin_message",
|
|
598
|
+
"linkedin_like_post",
|
|
599
|
+
"linkedin_inmail",
|
|
408
600
|
])
|
|
409
601
|
.describe("Step type.");
|
|
410
602
|
|
|
@@ -425,8 +617,18 @@ const campaignStepInput = z
|
|
|
425
617
|
.string()
|
|
426
618
|
.optional()
|
|
427
619
|
.describe("email steps: subject; {{Column}} merge tokens allowed."),
|
|
428
|
-
emailHtmlBody: z
|
|
429
|
-
|
|
620
|
+
emailHtmlBody: z
|
|
621
|
+
.string()
|
|
622
|
+
.optional()
|
|
623
|
+
.describe(
|
|
624
|
+
"email steps: HTML body. Sent instead of emailTextBody when both are set, so when you edit the text, update or drop this too.",
|
|
625
|
+
),
|
|
626
|
+
emailTextBody: z
|
|
627
|
+
.string()
|
|
628
|
+
.optional()
|
|
629
|
+
.describe(
|
|
630
|
+
"email steps: plain-text body; used as the email when there is no emailHtmlBody.",
|
|
631
|
+
),
|
|
430
632
|
emailReplyToPrevious: z
|
|
431
633
|
.boolean()
|
|
432
634
|
.optional()
|
|
@@ -437,7 +639,7 @@ const campaignStepInput = z
|
|
|
437
639
|
.enum(["always", "connected", "not_connected"])
|
|
438
640
|
.optional()
|
|
439
641
|
.describe(
|
|
440
|
-
"
|
|
642
|
+
"email and linkedin_like_post only: always (default), connected or not_connected. InMail automatically skips connected people; do not set a condition on it.",
|
|
441
643
|
),
|
|
442
644
|
linkedinAccountId: z
|
|
443
645
|
.string()
|
|
@@ -449,7 +651,7 @@ const campaignStepInput = z
|
|
|
449
651
|
.string()
|
|
450
652
|
.optional()
|
|
451
653
|
.describe(
|
|
452
|
-
|
|
654
|
+
`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 ${MAX_INMAIL_BODY_CHARS} chars).`,
|
|
453
655
|
),
|
|
454
656
|
linkedinMessageMode: z
|
|
455
657
|
.enum(["skip_if_not_connected", "wait_until_connected"])
|
|
@@ -459,13 +661,113 @@ const campaignStepInput = z
|
|
|
459
661
|
),
|
|
460
662
|
connectionTimeoutHours: z
|
|
461
663
|
.number()
|
|
664
|
+
.min(1)
|
|
665
|
+
.max(MAX_WAIT_HOURS)
|
|
666
|
+
.optional()
|
|
667
|
+
.describe(
|
|
668
|
+
`linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-${MAX_WAIT_HOURS} hours for acceptance (default 720). After a connection step this mode is the default.`,
|
|
669
|
+
),
|
|
670
|
+
likeReaction: z
|
|
671
|
+
.enum(LINKEDIN_REACTIONS)
|
|
672
|
+
.optional()
|
|
673
|
+
.describe(
|
|
674
|
+
"linkedin_like_post only: the reaction to leave (default like).",
|
|
675
|
+
),
|
|
676
|
+
likeMaxPostAgeDays: z
|
|
677
|
+
.number()
|
|
678
|
+
.int()
|
|
679
|
+
.min(1)
|
|
680
|
+
.max(MAX_LIKE_POST_AGE_DAYS)
|
|
681
|
+
.optional()
|
|
682
|
+
.describe(
|
|
683
|
+
`linkedin_like_post only: select the newest eligible original post from the last 1-${MAX_LIKE_POST_AGE_DAYS} days (default 30).`,
|
|
684
|
+
),
|
|
685
|
+
likeSkipNextWait: z
|
|
686
|
+
.boolean()
|
|
462
687
|
.optional()
|
|
463
688
|
.describe(
|
|
464
|
-
"
|
|
689
|
+
"linkedin_like_post only: skip consecutive following wait steps whenever the reaction step is skipped (default true). False keeps those waits.",
|
|
690
|
+
),
|
|
691
|
+
inmailSubject: z
|
|
692
|
+
.string()
|
|
693
|
+
.optional()
|
|
694
|
+
.describe(
|
|
695
|
+
`linkedin_inmail only: optional subject, up to ${MAX_INMAIL_SUBJECT_CHARS} characters; merge tokens allowed. Clear with an empty string.`,
|
|
696
|
+
),
|
|
697
|
+
withdrawAfterHours: z
|
|
698
|
+
.number()
|
|
699
|
+
.min(MIN_WITHDRAW_AFTER_HOURS)
|
|
700
|
+
.max(MAX_WAIT_HOURS)
|
|
701
|
+
.nullable()
|
|
702
|
+
.optional()
|
|
703
|
+
.describe(
|
|
704
|
+
`linkedin_connection only: withdraw a still-pending invitation sent by this campaign after ${MIN_WITHDRAW_AFTER_HOURS}-${MAX_WAIT_HOURS} hours (7-90 days). Omitted means off on creation; null turns it off on edit.`,
|
|
465
705
|
),
|
|
466
706
|
})
|
|
467
707
|
.describe("One campaign step, in order.");
|
|
468
708
|
|
|
709
|
+
const campaignTimelineRun = z
|
|
710
|
+
.object({
|
|
711
|
+
_id: z.string(),
|
|
712
|
+
stepId: z.string().describe("The step's _id, as in steps[]."),
|
|
713
|
+
stepIndex: z.number().describe("The step's place, from 0."),
|
|
714
|
+
type: campaignStepType,
|
|
715
|
+
status: z
|
|
716
|
+
.enum([
|
|
717
|
+
"queued",
|
|
718
|
+
"running",
|
|
719
|
+
"waiting",
|
|
720
|
+
"retry",
|
|
721
|
+
"sent",
|
|
722
|
+
"skipped",
|
|
723
|
+
"failed",
|
|
724
|
+
"unknown",
|
|
725
|
+
])
|
|
726
|
+
.describe(
|
|
727
|
+
"sent: done (a wait that finished is sent too). skipped: see result.reason. retry: will be tried again at retryAt. unknown: needs a look.",
|
|
728
|
+
),
|
|
729
|
+
scheduledAt: z.number().optional(),
|
|
730
|
+
startedAt: z.number().optional(),
|
|
731
|
+
waitUntil: z.number().optional(),
|
|
732
|
+
retryAt: z.number().optional(),
|
|
733
|
+
completedAt: z.number().optional(),
|
|
734
|
+
emailMessageId: z
|
|
735
|
+
.string()
|
|
736
|
+
.optional()
|
|
737
|
+
.describe("The email this run sent, in emailMessages[]."),
|
|
738
|
+
lastError: z.string().optional(),
|
|
739
|
+
result: z
|
|
740
|
+
.unknown()
|
|
741
|
+
.optional()
|
|
742
|
+
.describe("For a skipped step, { reason } says why."),
|
|
743
|
+
})
|
|
744
|
+
.passthrough();
|
|
745
|
+
|
|
746
|
+
const campaignPersonTimeline = z
|
|
747
|
+
.object({
|
|
748
|
+
enrollment: z
|
|
749
|
+
.record(z.string(), z.unknown())
|
|
750
|
+
.describe("The person in this campaign: status, lastError, repliedAt."),
|
|
751
|
+
sequence: z.record(z.string(), z.unknown()).nullable(),
|
|
752
|
+
steps: z
|
|
753
|
+
.array(campaignStepInput.passthrough())
|
|
754
|
+
.describe("The campaign's steps in order, each with its _id."),
|
|
755
|
+
runs: z
|
|
756
|
+
.array(campaignTimelineRun)
|
|
757
|
+
.describe("One run for each step the person has reached, in order."),
|
|
758
|
+
emailMessages: z
|
|
759
|
+
.array(z.record(z.string(), z.unknown()))
|
|
760
|
+
.describe(
|
|
761
|
+
"The emails those runs sent: subject, textBody, status, sentAt, firstOpenedAt, firstClickedAt.",
|
|
762
|
+
),
|
|
763
|
+
linkedinMessages: z
|
|
764
|
+
.array(z.record(z.string(), z.unknown()))
|
|
765
|
+
.describe(
|
|
766
|
+
"The LinkedIn messages those runs sent: text, sentAt, deliveredAt, readAt, outreachStepRunId.",
|
|
767
|
+
),
|
|
768
|
+
})
|
|
769
|
+
.passthrough();
|
|
770
|
+
|
|
469
771
|
const campaignStatus = z
|
|
470
772
|
.enum(["draft", "active", "paused", "completed", "archived"])
|
|
471
773
|
.describe("Campaign lifecycle status.");
|
|
@@ -1355,7 +1657,7 @@ const exaResultItem = z
|
|
|
1355
1657
|
),
|
|
1356
1658
|
})
|
|
1357
1659
|
.passthrough()
|
|
1358
|
-
.describe("
|
|
1660
|
+
.describe("A web search result.");
|
|
1359
1661
|
|
|
1360
1662
|
const exaSearchResponse = z
|
|
1361
1663
|
.object({
|
|
@@ -1366,7 +1668,7 @@ const exaSearchResponse = z
|
|
|
1366
1668
|
costDollars: z.record(z.string(), z.unknown()).optional(),
|
|
1367
1669
|
})
|
|
1368
1670
|
.passthrough()
|
|
1369
|
-
.describe("
|
|
1671
|
+
.describe("A web search response.");
|
|
1370
1672
|
|
|
1371
1673
|
const exaAnswerResponse = z
|
|
1372
1674
|
.object({
|
|
@@ -1376,7 +1678,7 @@ const exaAnswerResponse = z
|
|
|
1376
1678
|
})
|
|
1377
1679
|
.passthrough()
|
|
1378
1680
|
.describe(
|
|
1379
|
-
"
|
|
1681
|
+
"An answer with citations. With stream: true the response is text/event-stream instead.",
|
|
1380
1682
|
);
|
|
1381
1683
|
|
|
1382
1684
|
const imageEnvelope = z
|
|
@@ -1428,7 +1730,7 @@ const composioConnection = z
|
|
|
1428
1730
|
reconnect: z.record(z.string(), z.unknown()).optional(),
|
|
1429
1731
|
})
|
|
1430
1732
|
.passthrough()
|
|
1431
|
-
.describe("A
|
|
1733
|
+
.describe("A connected app.");
|
|
1432
1734
|
|
|
1433
1735
|
const composioConnectionsResponse = z
|
|
1434
1736
|
.object({
|
|
@@ -1436,7 +1738,11 @@ const composioConnectionsResponse = z
|
|
|
1436
1738
|
connections: z
|
|
1437
1739
|
.array(composioConnection)
|
|
1438
1740
|
.describe("Alias of items for older clients."),
|
|
1439
|
-
raw: z
|
|
1741
|
+
raw: z
|
|
1742
|
+
.unknown()
|
|
1743
|
+
.describe(
|
|
1744
|
+
"Deprecated: the unprocessed provider response. Do not depend on it.",
|
|
1745
|
+
),
|
|
1440
1746
|
})
|
|
1441
1747
|
.passthrough();
|
|
1442
1748
|
|
|
@@ -1484,7 +1790,7 @@ const toolSearchResponse = z
|
|
|
1484
1790
|
execution_ref_version: z.number().optional(),
|
|
1485
1791
|
})
|
|
1486
1792
|
.passthrough()
|
|
1487
|
-
.describe("
|
|
1793
|
+
.describe("Tool search response with gateway enrichments.");
|
|
1488
1794
|
|
|
1489
1795
|
const toolRunResponse = z
|
|
1490
1796
|
.object({
|
|
@@ -1501,7 +1807,7 @@ const toolRunResponse = z
|
|
|
1501
1807
|
account: z.string().optional(),
|
|
1502
1808
|
})
|
|
1503
1809
|
.passthrough()
|
|
1504
|
-
.describe("
|
|
1810
|
+
.describe("Tool execution result with gateway metadata.");
|
|
1505
1811
|
|
|
1506
1812
|
const enrichmentMetadata = z
|
|
1507
1813
|
.object({
|
|
@@ -1526,6 +1832,21 @@ const enrichmentMetadata = z
|
|
|
1526
1832
|
.passthrough()
|
|
1527
1833
|
.optional();
|
|
1528
1834
|
|
|
1835
|
+
const searchBillingResponse = z.object({
|
|
1836
|
+
estimatedCents: z
|
|
1837
|
+
.number()
|
|
1838
|
+
.int()
|
|
1839
|
+
.nonnegative()
|
|
1840
|
+
.describe("Search cost ceiling authorized by Dench billing, in cents."),
|
|
1841
|
+
chargedCents: z
|
|
1842
|
+
.number()
|
|
1843
|
+
.int()
|
|
1844
|
+
.nonnegative()
|
|
1845
|
+
.describe(
|
|
1846
|
+
"Actual workspace search charge reported by Dench billing, in cents.",
|
|
1847
|
+
),
|
|
1848
|
+
});
|
|
1849
|
+
|
|
1529
1850
|
const enrichedPeopleResponse = z
|
|
1530
1851
|
.object({
|
|
1531
1852
|
source: z.enum(["live", "cache"]),
|
|
@@ -1547,9 +1868,10 @@ const enrichedPeopleResponse = z
|
|
|
1547
1868
|
})
|
|
1548
1869
|
.passthrough(),
|
|
1549
1870
|
)
|
|
1550
|
-
.describe("
|
|
1871
|
+
.describe("Search results normalized to the CRM upsert shape."),
|
|
1551
1872
|
resolvedPersonIds: z.array(z.string()),
|
|
1552
1873
|
creditsCharged: z.number(),
|
|
1874
|
+
billing: searchBillingResponse.optional(),
|
|
1553
1875
|
metadata: enrichmentMetadata,
|
|
1554
1876
|
})
|
|
1555
1877
|
.passthrough();
|
|
@@ -1572,9 +1894,10 @@ const enrichedCompaniesResponse = z
|
|
|
1572
1894
|
})
|
|
1573
1895
|
.passthrough(),
|
|
1574
1896
|
)
|
|
1575
|
-
.describe("
|
|
1897
|
+
.describe("Search results normalized to the CRM upsert shape."),
|
|
1576
1898
|
resolvedCompanyIds: z.array(z.string()),
|
|
1577
1899
|
creditsCharged: z.number(),
|
|
1900
|
+
billing: searchBillingResponse.optional(),
|
|
1578
1901
|
metadata: enrichmentMetadata,
|
|
1579
1902
|
})
|
|
1580
1903
|
.passthrough();
|
|
@@ -1735,7 +2058,7 @@ const composioToolRun = z.object({
|
|
|
1735
2058
|
tool_slug: z
|
|
1736
2059
|
.string()
|
|
1737
2060
|
.optional()
|
|
1738
|
-
.describe("
|
|
2061
|
+
.describe("Tool slug, e.g. GMAIL_FETCH_EMAILS."),
|
|
1739
2062
|
arguments: z
|
|
1740
2063
|
.record(z.string(), z.unknown())
|
|
1741
2064
|
.optional()
|
|
@@ -1907,6 +2230,90 @@ const peopleSearch = z.object({
|
|
|
1907
2230
|
preferCache: z.boolean().optional(),
|
|
1908
2231
|
});
|
|
1909
2232
|
|
|
2233
|
+
export const campaignAudienceFiltersSchema = peopleSearch
|
|
2234
|
+
.omit({
|
|
2235
|
+
limit: true,
|
|
2236
|
+
offset: true,
|
|
2237
|
+
pageToken: true,
|
|
2238
|
+
})
|
|
2239
|
+
.strict();
|
|
2240
|
+
|
|
2241
|
+
const campaignSignal = z.enum([
|
|
2242
|
+
"post_engagement",
|
|
2243
|
+
"keyword",
|
|
2244
|
+
"hiring",
|
|
2245
|
+
"funding",
|
|
2246
|
+
"launch",
|
|
2247
|
+
"new_leader",
|
|
2248
|
+
]);
|
|
2249
|
+
const campaignTargeting = z.object({
|
|
2250
|
+
titles: z.array(z.string()),
|
|
2251
|
+
locations: z.array(z.string()),
|
|
2252
|
+
companySizes: z.array(z.string()),
|
|
2253
|
+
industries: z.array(z.string()),
|
|
2254
|
+
excludes: z.array(z.string()),
|
|
2255
|
+
companies: z.array(z.string()).optional(),
|
|
2256
|
+
});
|
|
2257
|
+
const campaignSignalTerms = z.object({
|
|
2258
|
+
post_engagement: z.array(z.string()).optional(),
|
|
2259
|
+
keyword: z.array(z.string()).optional(),
|
|
2260
|
+
hiring: z.array(z.string()).optional(),
|
|
2261
|
+
});
|
|
2262
|
+
const campaignClientRequestId = z
|
|
2263
|
+
.string()
|
|
2264
|
+
.trim()
|
|
2265
|
+
.min(8)
|
|
2266
|
+
.max(64)
|
|
2267
|
+
.describe(
|
|
2268
|
+
"Your stable id for this request, 8-64 characters. Retrying with the same id returns the same draft instead of creating another.",
|
|
2269
|
+
);
|
|
2270
|
+
const campaignRecipient = z
|
|
2271
|
+
.object({
|
|
2272
|
+
email: z.string().optional(),
|
|
2273
|
+
linkedinProfileUrl: z.string().optional(),
|
|
2274
|
+
displayName: z.string().optional(),
|
|
2275
|
+
personalization: z
|
|
2276
|
+
.record(z.string(), z.unknown())
|
|
2277
|
+
.optional()
|
|
2278
|
+
.describe(
|
|
2279
|
+
'Merge values keyed by name, e.g. {"Company":"Acme"} for {{Company}}.',
|
|
2280
|
+
),
|
|
2281
|
+
})
|
|
2282
|
+
.strict()
|
|
2283
|
+
.describe(
|
|
2284
|
+
"One person. Needs email and/or linkedinProfileUrl; unknown keys are rejected, not dropped.",
|
|
2285
|
+
);
|
|
2286
|
+
const campaignBatchResult = z.object({
|
|
2287
|
+
added: z.number(),
|
|
2288
|
+
requested: z.number(),
|
|
2289
|
+
cappedAtLimit: z.number().nullable(),
|
|
2290
|
+
duplicates: z.number(),
|
|
2291
|
+
duplicatesElsewhere: z.number(),
|
|
2292
|
+
suppressed: z.number(),
|
|
2293
|
+
invalid: z.number(),
|
|
2294
|
+
skippedNoIdentity: z.number(),
|
|
2295
|
+
skippedMissingInfo: z.number(),
|
|
2296
|
+
missingInfoSample: z.unknown().optional(),
|
|
2297
|
+
});
|
|
2298
|
+
const campaignSearchPage = z.object({
|
|
2299
|
+
rows: z.array(z.record(z.string(), z.unknown())),
|
|
2300
|
+
people: z.array(z.unknown()),
|
|
2301
|
+
recipients: z.array(campaignRecipient),
|
|
2302
|
+
metadata: z.record(z.string(), z.unknown()),
|
|
2303
|
+
estimatedCents: z
|
|
2304
|
+
.number()
|
|
2305
|
+
.nullable()
|
|
2306
|
+
.describe(
|
|
2307
|
+
"The search cost ceiling reported by Dench billing, in cents. Null means the receipt is unavailable.",
|
|
2308
|
+
),
|
|
2309
|
+
chargedCents: z
|
|
2310
|
+
.number()
|
|
2311
|
+
.nullable()
|
|
2312
|
+
.describe(
|
|
2313
|
+
"The actual search charge reported by Dench billing, in cents. Null means the receipt is unavailable; results remain valid.",
|
|
2314
|
+
),
|
|
2315
|
+
});
|
|
2316
|
+
|
|
1910
2317
|
const companySearch = z.object({
|
|
1911
2318
|
domain: z.string().optional(),
|
|
1912
2319
|
name: z.string().optional(),
|
|
@@ -2341,11 +2748,178 @@ const analyticsPanelResult = z.object({
|
|
|
2341
2748
|
// ---------------------------------------------------------------------------
|
|
2342
2749
|
|
|
2343
2750
|
export const requestSchemas: Record<string, ZodTypeAny> = {
|
|
2751
|
+
"lists.save": z
|
|
2752
|
+
.object({
|
|
2753
|
+
createdFrom: z
|
|
2754
|
+
.enum([
|
|
2755
|
+
"find_people",
|
|
2756
|
+
"find_companies",
|
|
2757
|
+
"find_jobs",
|
|
2758
|
+
"mixed",
|
|
2759
|
+
"watch_fire",
|
|
2760
|
+
"generate_image",
|
|
2761
|
+
])
|
|
2762
|
+
.describe(
|
|
2763
|
+
"Use find_people, find_companies or find_jobs for a prospect list.",
|
|
2764
|
+
),
|
|
2765
|
+
title: z.string().min(1).describe("Name of the new list."),
|
|
2766
|
+
saved: z
|
|
2767
|
+
.boolean()
|
|
2768
|
+
.optional()
|
|
2769
|
+
.describe(
|
|
2770
|
+
"True makes the list visible in Find. Omitted saves an unlisted draft that can still be read or added to a campaign by id.",
|
|
2771
|
+
),
|
|
2772
|
+
filters: z
|
|
2773
|
+
.unknown()
|
|
2774
|
+
.optional()
|
|
2775
|
+
.describe(
|
|
2776
|
+
"Original search filters to retain with the list. Saving does not run a search.",
|
|
2777
|
+
),
|
|
2778
|
+
people: z
|
|
2779
|
+
.array(z.record(z.string(), z.unknown()))
|
|
2780
|
+
.optional()
|
|
2781
|
+
.describe(
|
|
2782
|
+
"Complete person records from a search, including existing contact details and custom fields.",
|
|
2783
|
+
),
|
|
2784
|
+
companies: z
|
|
2785
|
+
.array(z.record(z.string(), z.unknown()))
|
|
2786
|
+
.optional()
|
|
2787
|
+
.describe("Complete company records from a search."),
|
|
2788
|
+
jobs: z
|
|
2789
|
+
.array(z.record(z.string(), z.unknown()))
|
|
2790
|
+
.optional()
|
|
2791
|
+
.describe("Complete job records from a search."),
|
|
2792
|
+
})
|
|
2793
|
+
.strict(),
|
|
2794
|
+
"lists.update": z
|
|
2795
|
+
.object({
|
|
2796
|
+
artifactId: z.string().describe("The existing list id."),
|
|
2797
|
+
title: z.string().min(1).optional(),
|
|
2798
|
+
filters: z
|
|
2799
|
+
.unknown()
|
|
2800
|
+
.optional()
|
|
2801
|
+
.describe("Replacement filter metadata; does not run a new search."),
|
|
2802
|
+
people: z
|
|
2803
|
+
.array(z.record(z.string(), z.unknown()))
|
|
2804
|
+
.optional()
|
|
2805
|
+
.describe(
|
|
2806
|
+
"Replacement people. Omit to preserve existing rows; an empty array clears them.",
|
|
2807
|
+
),
|
|
2808
|
+
companies: z
|
|
2809
|
+
.array(z.record(z.string(), z.unknown()))
|
|
2810
|
+
.optional()
|
|
2811
|
+
.describe("Replacement companies. Omit to preserve existing rows."),
|
|
2812
|
+
jobs: z
|
|
2813
|
+
.array(z.record(z.string(), z.unknown()))
|
|
2814
|
+
.optional()
|
|
2815
|
+
.describe("Replacement jobs. Omit to preserve existing rows."),
|
|
2816
|
+
})
|
|
2817
|
+
.strict(),
|
|
2344
2818
|
// Meta
|
|
2345
2819
|
"commands.list": noInput,
|
|
2346
2820
|
|
|
2347
2821
|
// Outreach campaigns (dench campaign)
|
|
2822
|
+
"campaigns.drafts.create": z
|
|
2823
|
+
.object({
|
|
2824
|
+
clientRequestId: campaignClientRequestId,
|
|
2825
|
+
name: z.string().max(120).optional(),
|
|
2826
|
+
timezone: z
|
|
2827
|
+
.string()
|
|
2828
|
+
.optional()
|
|
2829
|
+
.describe(
|
|
2830
|
+
"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.",
|
|
2831
|
+
),
|
|
2832
|
+
})
|
|
2833
|
+
.strict(),
|
|
2834
|
+
"campaigns.audience.search": z
|
|
2835
|
+
.object({
|
|
2836
|
+
sequenceId: z.string().optional(),
|
|
2837
|
+
filters: campaignAudienceFiltersSchema,
|
|
2838
|
+
limit: z.number().int().min(1).max(100).optional(),
|
|
2839
|
+
pageToken: z.string().optional(),
|
|
2840
|
+
})
|
|
2841
|
+
.strict(),
|
|
2842
|
+
"campaigns.people.addFromSearch": z
|
|
2843
|
+
.object({
|
|
2844
|
+
sequenceId: z.string(),
|
|
2845
|
+
filters: campaignAudienceFiltersSchema,
|
|
2846
|
+
limit: z.number().int().min(1).max(50).optional(),
|
|
2847
|
+
pageToken: z.string().optional(),
|
|
2848
|
+
checkDuplicatesAcrossWorkspace: z.boolean().optional(),
|
|
2849
|
+
})
|
|
2850
|
+
.strict(),
|
|
2851
|
+
"campaigns.people.addBatch": z
|
|
2852
|
+
.object({
|
|
2853
|
+
sequenceId: z.string(),
|
|
2854
|
+
recipients: z.array(campaignRecipient).min(1).max(50),
|
|
2855
|
+
newRecordsObject: z.enum(["lead", "people"]).optional(),
|
|
2856
|
+
checkDuplicatesAcrossWorkspace: z.boolean().optional(),
|
|
2857
|
+
})
|
|
2858
|
+
.strict(),
|
|
2859
|
+
"campaigns.sources.get": z.object({ sequenceId: z.string() }).strict(),
|
|
2860
|
+
"campaigns.sources.signals": z.object({ sequenceId: z.string() }).strict(),
|
|
2861
|
+
"campaigns.sources.update": z
|
|
2862
|
+
.object({
|
|
2863
|
+
sequenceId: z.string(),
|
|
2864
|
+
status: z.enum(["active", "paused"]).optional(),
|
|
2865
|
+
cadence: z.enum(["daily", "weekly", "monthly"]).optional(),
|
|
2866
|
+
findMoreMatching: z.boolean().optional(),
|
|
2867
|
+
targeting: campaignTargeting.optional(),
|
|
2868
|
+
signal: z
|
|
2869
|
+
.object({ signal: campaignSignal, enabled: z.boolean() })
|
|
2870
|
+
.optional(),
|
|
2871
|
+
terms: z
|
|
2872
|
+
.object({
|
|
2873
|
+
signal: z.enum(["post_engagement", "keyword", "hiring"]),
|
|
2874
|
+
values: z.array(z.string()),
|
|
2875
|
+
})
|
|
2876
|
+
.optional(),
|
|
2877
|
+
})
|
|
2878
|
+
.strict(),
|
|
2879
|
+
"campaigns.sources.preview": z
|
|
2880
|
+
.object({
|
|
2881
|
+
sequenceId: z.string(),
|
|
2882
|
+
signal: campaignSignal,
|
|
2883
|
+
terms: z.array(z.string()).optional(),
|
|
2884
|
+
})
|
|
2885
|
+
.strict(),
|
|
2886
|
+
"campaigns.builder.profile": noInput,
|
|
2887
|
+
"campaigns.builder.save": z
|
|
2888
|
+
.object({
|
|
2889
|
+
clientRequestId: campaignClientRequestId,
|
|
2890
|
+
targeting: campaignTargeting,
|
|
2891
|
+
signals: z.array(campaignSignal),
|
|
2892
|
+
signalTerms: campaignSignalTerms.optional(),
|
|
2893
|
+
})
|
|
2894
|
+
.strict(),
|
|
2895
|
+
"campaigns.builder.get": z.object({ draftId: z.string() }).strict(),
|
|
2896
|
+
"campaigns.builder.build": z.object({ draftId: z.string() }).strict(),
|
|
2897
|
+
"campaigns.builder.create": z
|
|
2898
|
+
.object({
|
|
2899
|
+
draftId: z.string(),
|
|
2900
|
+
name: z.string().max(120).optional(),
|
|
2901
|
+
timezone: z.string().optional(),
|
|
2902
|
+
})
|
|
2903
|
+
.strict(),
|
|
2904
|
+
"campaigns.builder.opener": z
|
|
2905
|
+
.object({ draftId: z.string(), leadId: z.string(), opener: z.string() })
|
|
2906
|
+
.strict(),
|
|
2907
|
+
"campaigns.builder.autofill": z
|
|
2908
|
+
.object({ description: z.string().min(3).max(300) })
|
|
2909
|
+
.strict(),
|
|
2910
|
+
"campaigns.builder.terms": z
|
|
2911
|
+
.object({ targeting: campaignTargeting })
|
|
2912
|
+
.strict(),
|
|
2913
|
+
"campaigns.builder.estimate": z
|
|
2914
|
+
.object({
|
|
2915
|
+
kind: z.enum(["people", "week"]),
|
|
2916
|
+
targeting: campaignTargeting,
|
|
2917
|
+
signals: z.array(campaignSignal).optional(),
|
|
2918
|
+
signalTerms: campaignSignalTerms.optional(),
|
|
2919
|
+
})
|
|
2920
|
+
.strict(),
|
|
2348
2921
|
"campaigns.accounts.linkedin": noInput,
|
|
2922
|
+
"campaigns.accounts.email": noInput,
|
|
2349
2923
|
"campaigns.list": z.object({
|
|
2350
2924
|
includeArchived: z
|
|
2351
2925
|
.boolean()
|
|
@@ -2360,6 +2934,13 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
|
|
|
2360
2934
|
.optional()
|
|
2361
2935
|
.describe("IANA timezone for the default Mon-Fri 9-18 send window."),
|
|
2362
2936
|
}),
|
|
2937
|
+
"campaigns.duplicate": z
|
|
2938
|
+
.object({
|
|
2939
|
+
sequenceId: z
|
|
2940
|
+
.string()
|
|
2941
|
+
.describe("The campaign to copy; any status, including archived."),
|
|
2942
|
+
})
|
|
2943
|
+
.strict(),
|
|
2363
2944
|
"campaigns.get": z.object({ sequenceId: z.string() }),
|
|
2364
2945
|
"campaigns.analytics": z.object({ sequenceId: z.string() }),
|
|
2365
2946
|
"campaigns.live": z.object({ sequenceId: z.string() }),
|
|
@@ -2415,10 +2996,140 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
|
|
|
2415
2996
|
.optional()
|
|
2416
2997
|
.describe("Cold emails per day, 1-100."),
|
|
2417
2998
|
}),
|
|
2418
|
-
"campaigns.steps.replace": z
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2999
|
+
"campaigns.steps.replace": z
|
|
3000
|
+
.object({
|
|
3001
|
+
sequenceId: z.string(),
|
|
3002
|
+
steps: z
|
|
3003
|
+
.array(
|
|
3004
|
+
campaignStepInput.strict().describe("One campaign step, in order."),
|
|
3005
|
+
)
|
|
3006
|
+
.min(1)
|
|
3007
|
+
.max(MAX_CAMPAIGN_STEPS)
|
|
3008
|
+
.describe(
|
|
3009
|
+
"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.",
|
|
3010
|
+
),
|
|
3011
|
+
allowSingleBraces: z
|
|
3012
|
+
.boolean()
|
|
3013
|
+
.optional()
|
|
3014
|
+
.describe(
|
|
3015
|
+
"Send {single braces} exactly as typed instead of rejecting them. Merge tokens always use {{double braces}}.",
|
|
3016
|
+
),
|
|
3017
|
+
})
|
|
3018
|
+
.strict()
|
|
3019
|
+
.superRefine((input, ctx) => {
|
|
3020
|
+
for (const issue of checkCampaignSteps(input.steps, {
|
|
3021
|
+
allowSingleBraces: input.allowSingleBraces,
|
|
3022
|
+
}).errors)
|
|
3023
|
+
ctx.addIssue({
|
|
3024
|
+
code: "custom",
|
|
3025
|
+
message: issue.message,
|
|
3026
|
+
path: issue.step
|
|
3027
|
+
? ["steps", issue.step - 1, ...(issue.field ? [issue.field] : [])]
|
|
3028
|
+
: ["steps"],
|
|
3029
|
+
});
|
|
3030
|
+
}),
|
|
3031
|
+
"campaigns.steps.update": z
|
|
3032
|
+
.object({
|
|
3033
|
+
sequenceId: z.string(),
|
|
3034
|
+
steps: z
|
|
3035
|
+
.array(
|
|
3036
|
+
campaignStepInput
|
|
3037
|
+
.partial()
|
|
3038
|
+
.extend({
|
|
3039
|
+
stepId: z
|
|
3040
|
+
.string()
|
|
3041
|
+
.describe("The step's _id from campaigns.get steps[]."),
|
|
3042
|
+
expectedUpdatedAt: z
|
|
3043
|
+
.number()
|
|
3044
|
+
.describe(
|
|
3045
|
+
"The step's updatedAt when you read it. If someone saved it since, the edit is refused instead of overwriting theirs.",
|
|
3046
|
+
),
|
|
3047
|
+
type: campaignStepType.describe(
|
|
3048
|
+
"The step's current type. A launched step's type can't change.",
|
|
3049
|
+
),
|
|
3050
|
+
})
|
|
3051
|
+
.strict()
|
|
3052
|
+
.describe(
|
|
3053
|
+
"One step edit: only the fields given change. Clear text with an empty string, onlyIf with always, emailReplyToPrevious with false and withdrawAfterHours with null. Like settings are optional; omitted values stay unchanged.",
|
|
3054
|
+
),
|
|
3055
|
+
)
|
|
3056
|
+
.min(1)
|
|
3057
|
+
.max(MAX_CAMPAIGN_STEPS)
|
|
3058
|
+
.describe(
|
|
3059
|
+
"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.",
|
|
3060
|
+
),
|
|
3061
|
+
allowSingleBraces: z
|
|
3062
|
+
.boolean()
|
|
3063
|
+
.optional()
|
|
3064
|
+
.describe(
|
|
3065
|
+
"Send {single braces} exactly as typed instead of rejecting them. Merge tokens always use {{double braces}}.",
|
|
3066
|
+
),
|
|
3067
|
+
})
|
|
3068
|
+
.strict()
|
|
3069
|
+
.superRefine((input, ctx) => {
|
|
3070
|
+
const edits = input.steps.map(
|
|
3071
|
+
({ stepId: _stepId, expectedUpdatedAt: _expected, ...edit }) => edit,
|
|
3072
|
+
);
|
|
3073
|
+
for (const issue of checkStepEdits(edits, {
|
|
3074
|
+
allowSingleBraces: input.allowSingleBraces,
|
|
3075
|
+
}).errors)
|
|
3076
|
+
ctx.addIssue({
|
|
3077
|
+
code: "custom",
|
|
3078
|
+
message: issue.message,
|
|
3079
|
+
path: issue.step
|
|
3080
|
+
? ["steps", issue.step - 1, ...(issue.field ? [issue.field] : [])]
|
|
3081
|
+
: ["steps"],
|
|
3082
|
+
});
|
|
3083
|
+
}),
|
|
3084
|
+
"campaigns.personalization.get": z
|
|
3085
|
+
.object({ sequenceId: z.string() })
|
|
3086
|
+
.strict(),
|
|
3087
|
+
"campaigns.personalization.set": z
|
|
3088
|
+
.object({
|
|
3089
|
+
sequenceId: z.string(),
|
|
3090
|
+
template: campaignLineTemplate
|
|
3091
|
+
.nullable()
|
|
3092
|
+
.describe("The lines and context; null turns personalized lines off."),
|
|
3093
|
+
})
|
|
3094
|
+
.strict(),
|
|
3095
|
+
"campaigns.personalization.clear": z
|
|
3096
|
+
.object({ sequenceId: z.string() })
|
|
3097
|
+
.strict(),
|
|
3098
|
+
"campaigns.personalization.write": z
|
|
3099
|
+
.object({
|
|
3100
|
+
sequenceId: z.string(),
|
|
3101
|
+
mode: z
|
|
3102
|
+
.enum(["missing", "all"])
|
|
3103
|
+
.optional()
|
|
3104
|
+
.describe(
|
|
3105
|
+
"missing (default): only people without lines. all: rewrite everyone's.",
|
|
3106
|
+
),
|
|
3107
|
+
confirmed: z
|
|
3108
|
+
.boolean()
|
|
3109
|
+
.optional()
|
|
3110
|
+
.describe(
|
|
3111
|
+
"true after the user accepts the estimate from needsConfirm.",
|
|
3112
|
+
),
|
|
3113
|
+
})
|
|
3114
|
+
.strict(),
|
|
3115
|
+
"campaigns.personalization.edit": z
|
|
3116
|
+
.object({
|
|
3117
|
+
enrollmentId: z.string().describe("From dench campaign people."),
|
|
3118
|
+
key: z.string().describe("The line's key, as in {{key}}."),
|
|
3119
|
+
value: z
|
|
3120
|
+
.string()
|
|
3121
|
+
.describe("The line to send; an empty string undoes the edit."),
|
|
3122
|
+
})
|
|
3123
|
+
.strict(),
|
|
3124
|
+
"campaigns.personalization.rewrite": z
|
|
3125
|
+
.object({
|
|
3126
|
+
enrollmentId: z.string().describe("From dench campaign people."),
|
|
3127
|
+
key: z
|
|
3128
|
+
.string()
|
|
3129
|
+
.optional()
|
|
3130
|
+
.describe("One line's key; leave out to rewrite all of their lines."),
|
|
3131
|
+
})
|
|
3132
|
+
.strict(),
|
|
2422
3133
|
"campaigns.people.addFromCrm": z.object({
|
|
2423
3134
|
sequenceId: z.string(),
|
|
2424
3135
|
objectName: z
|
|
@@ -2465,6 +3176,19 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
|
|
|
2465
3176
|
personalization: z.record(z.string(), z.unknown()).optional(),
|
|
2466
3177
|
checkDuplicatesAcrossWorkspace: z.boolean().optional(),
|
|
2467
3178
|
}),
|
|
3179
|
+
"campaigns.preview": z
|
|
3180
|
+
.object({
|
|
3181
|
+
sequenceId: z.string(),
|
|
3182
|
+
enrollmentId: z
|
|
3183
|
+
.string()
|
|
3184
|
+
.describe("The person to preview, from dench campaign people."),
|
|
3185
|
+
stepId: z
|
|
3186
|
+
.string()
|
|
3187
|
+
.describe(
|
|
3188
|
+
"An email or LinkedIn step, its _id from campaigns.get steps[]. A wait step sends nothing.",
|
|
3189
|
+
),
|
|
3190
|
+
})
|
|
3191
|
+
.strict(),
|
|
2468
3192
|
"campaigns.launch.preview": z.object({ sequenceId: z.string() }),
|
|
2469
3193
|
"campaigns.launch": z.object({
|
|
2470
3194
|
sequenceId: z.string(),
|
|
@@ -2493,6 +3217,59 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
|
|
|
2493
3217
|
}),
|
|
2494
3218
|
"campaigns.people.stop": z.object({ enrollmentId: z.string() }),
|
|
2495
3219
|
"campaigns.people.resume": z.object({ enrollmentId: z.string() }),
|
|
3220
|
+
"campaigns.people.sync": z.object({ sequenceId: z.string() }).strict(),
|
|
3221
|
+
"campaigns.people.resumeAll": z
|
|
3222
|
+
.object({
|
|
3223
|
+
sequenceId: z.string().describe("An active campaign."),
|
|
3224
|
+
})
|
|
3225
|
+
.strict(),
|
|
3226
|
+
"campaigns.people.setEmail": z
|
|
3227
|
+
.object({
|
|
3228
|
+
enrollmentId: z.string().describe("From dench campaign people."),
|
|
3229
|
+
email: z.string().describe("The address email steps should use."),
|
|
3230
|
+
})
|
|
3231
|
+
.strict(),
|
|
3232
|
+
"campaigns.people.setLinkedin": z
|
|
3233
|
+
.object({
|
|
3234
|
+
enrollmentId: z.string().describe("From dench campaign people."),
|
|
3235
|
+
linkedinProfileUrl: z
|
|
3236
|
+
.string()
|
|
3237
|
+
.describe(
|
|
3238
|
+
"A LinkedIn member profile URL, e.g. https://linkedin.com/in/ada.",
|
|
3239
|
+
),
|
|
3240
|
+
})
|
|
3241
|
+
.strict(),
|
|
3242
|
+
"campaigns.people.setField": z
|
|
3243
|
+
.object({
|
|
3244
|
+
enrollmentId: z.string().describe("From dench campaign people."),
|
|
3245
|
+
key: z
|
|
3246
|
+
.string()
|
|
3247
|
+
.describe(
|
|
3248
|
+
"The merge token name without braces, e.g. Company for {{Company}} or fund for {{fund}}.",
|
|
3249
|
+
),
|
|
3250
|
+
value: z.string().describe("Up to 2000 characters."),
|
|
3251
|
+
})
|
|
3252
|
+
.strict(),
|
|
3253
|
+
"campaigns.pipeline": z.object({ sequenceId: z.string() }).strict(),
|
|
3254
|
+
"campaigns.people.forRecord": z
|
|
3255
|
+
.object({
|
|
3256
|
+
entryId: z
|
|
3257
|
+
.string()
|
|
3258
|
+
.describe("A CRM record's _id: a person, or a lead created from one."),
|
|
3259
|
+
})
|
|
3260
|
+
.strict(),
|
|
3261
|
+
"campaigns.people.timeline": z
|
|
3262
|
+
.object({
|
|
3263
|
+
enrollmentId: z.string().describe("From dench campaign people."),
|
|
3264
|
+
})
|
|
3265
|
+
.strict(),
|
|
3266
|
+
"campaigns.people.remove": z.object({
|
|
3267
|
+
enrollmentId: z
|
|
3268
|
+
.string()
|
|
3269
|
+
.describe(
|
|
3270
|
+
"From dench campaign people; the person must never have been contacted.",
|
|
3271
|
+
),
|
|
3272
|
+
}),
|
|
2496
3273
|
|
|
2497
3274
|
// Auth
|
|
2498
3275
|
"auth.signin.create": z.object({
|
|
@@ -4007,11 +4784,71 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
|
|
|
4007
4784
|
// ---------------------------------------------------------------------------
|
|
4008
4785
|
|
|
4009
4786
|
export const responseSchemas: Record<string, ZodTypeAny> = {
|
|
4787
|
+
"lists.save": z.object({
|
|
4788
|
+
artifactId: z.string(),
|
|
4789
|
+
filePath: z.string(),
|
|
4790
|
+
rowCount: z.number(),
|
|
4791
|
+
previewRows: z.array(z.unknown()),
|
|
4792
|
+
title: z.string(),
|
|
4793
|
+
createdFrom: z.string(),
|
|
4794
|
+
}),
|
|
4795
|
+
"lists.update": z.object({
|
|
4796
|
+
artifactId: z.string(),
|
|
4797
|
+
rowCount: z.number(),
|
|
4798
|
+
previewRows: z.array(z.unknown()),
|
|
4799
|
+
title: z.string(),
|
|
4800
|
+
}),
|
|
4801
|
+
"campaigns.drafts.create": z.object({ sequenceId: z.string() }),
|
|
4802
|
+
"campaigns.audience.search": campaignSearchPage,
|
|
4803
|
+
"campaigns.people.addBatch": campaignBatchResult,
|
|
4804
|
+
"campaigns.people.addFromSearch": campaignSearchPage
|
|
4805
|
+
.merge(campaignBatchResult)
|
|
4806
|
+
.extend({ found: z.number(), skippedSearchProfiles: z.number() }),
|
|
4807
|
+
"campaigns.sources.get": z.record(z.string(), z.unknown()).nullable(),
|
|
4808
|
+
"campaigns.sources.signals": z.record(z.string(), z.unknown()).nullable(),
|
|
4809
|
+
"campaigns.sources.update": z.null(),
|
|
4810
|
+
"campaigns.sources.preview": z.object({ ok: z.boolean() }).passthrough(),
|
|
4811
|
+
"campaigns.builder.profile": z
|
|
4812
|
+
.object({ hasProfile: z.boolean(), targeting: campaignTargeting })
|
|
4813
|
+
.passthrough(),
|
|
4814
|
+
"campaigns.builder.save": z.object({ draftId: z.string() }),
|
|
4815
|
+
"campaigns.builder.get": z
|
|
4816
|
+
.object({
|
|
4817
|
+
status: z.string(),
|
|
4818
|
+
targeting: campaignTargeting,
|
|
4819
|
+
signals: z.array(campaignSignal),
|
|
4820
|
+
people: z.array(z.record(z.string(), z.unknown())),
|
|
4821
|
+
})
|
|
4822
|
+
.passthrough(),
|
|
4823
|
+
"campaigns.builder.build": z.object({
|
|
4824
|
+
ok: z.boolean(),
|
|
4825
|
+
started: z.boolean(),
|
|
4826
|
+
}),
|
|
4827
|
+
"campaigns.builder.create": z.object({
|
|
4828
|
+
sequenceId: z.string(),
|
|
4829
|
+
enrolled: z.number(),
|
|
4830
|
+
}),
|
|
4831
|
+
"campaigns.builder.opener": z.null(),
|
|
4832
|
+
"campaigns.builder.autofill": z
|
|
4833
|
+
.object({ targeting: campaignTargeting })
|
|
4834
|
+
.passthrough(),
|
|
4835
|
+
"campaigns.builder.terms": z
|
|
4836
|
+
.object({ signalTerms: campaignSignalTerms })
|
|
4837
|
+
.passthrough(),
|
|
4838
|
+
"campaigns.builder.estimate": z
|
|
4839
|
+
.object({ count: z.number().nullable() })
|
|
4840
|
+
.passthrough(),
|
|
4010
4841
|
// Meta
|
|
4011
4842
|
// Outreach campaigns (dench campaign)
|
|
4012
4843
|
"campaigns.accounts.linkedin": z.array(campaignLinkedinSenderSummary),
|
|
4844
|
+
"campaigns.accounts.email": z.array(campaignMailboxSummary),
|
|
4013
4845
|
"campaigns.list": z.array(campaignRow),
|
|
4014
4846
|
"campaigns.create": z.object({ sequenceId: z.string() }),
|
|
4847
|
+
"campaigns.duplicate": z.object({
|
|
4848
|
+
sequenceId: z
|
|
4849
|
+
.string()
|
|
4850
|
+
.describe("The new draft. Rename it with campaigns.update."),
|
|
4851
|
+
}),
|
|
4015
4852
|
"campaigns.get": z
|
|
4016
4853
|
.object({
|
|
4017
4854
|
sequence: campaignRow,
|
|
@@ -4077,8 +4914,43 @@ export const responseSchemas: Record<string, ZodTypeAny> = {
|
|
|
4077
4914
|
ok: z.boolean(),
|
|
4078
4915
|
stepCount: z.number(),
|
|
4079
4916
|
}),
|
|
4917
|
+
"campaigns.steps.update": z.object({
|
|
4918
|
+
ok: z.boolean(),
|
|
4919
|
+
stepCount: z.number().describe("How many steps were edited."),
|
|
4920
|
+
}),
|
|
4921
|
+
"campaigns.personalization.get": z
|
|
4922
|
+
.object({
|
|
4923
|
+
template: campaignLineTemplate
|
|
4924
|
+
.extend({ version: z.number(), updatedAt: z.number() })
|
|
4925
|
+
.passthrough()
|
|
4926
|
+
.nullable(),
|
|
4927
|
+
counts: z.object({
|
|
4928
|
+
done: z.number(),
|
|
4929
|
+
pending: z.number(),
|
|
4930
|
+
failed: z.number(),
|
|
4931
|
+
total: z.number(),
|
|
4932
|
+
}),
|
|
4933
|
+
paused: z.boolean(),
|
|
4934
|
+
notice: z
|
|
4935
|
+
.object({ code: z.literal("insufficient_credits"), at: z.number() })
|
|
4936
|
+
.nullable(),
|
|
4937
|
+
suggestedContext: z.object({ sells: z.string().optional() }),
|
|
4938
|
+
estimatedCentsPerPerson: z.number(),
|
|
4939
|
+
eligible: z.number(),
|
|
4940
|
+
})
|
|
4941
|
+
.passthrough(),
|
|
4942
|
+
"campaigns.personalization.set": campaignLineBackfill,
|
|
4943
|
+
"campaigns.personalization.clear": campaignLineBackfill,
|
|
4944
|
+
"campaigns.personalization.write": campaignLineBackfill,
|
|
4945
|
+
"campaigns.personalization.edit": okResponse,
|
|
4946
|
+
"campaigns.personalization.rewrite": z.object({
|
|
4947
|
+
queued: z
|
|
4948
|
+
.boolean()
|
|
4949
|
+
.describe("False when new lines are already being written."),
|
|
4950
|
+
}),
|
|
4080
4951
|
"campaigns.people.addFromCrm": campaignEnrollResult,
|
|
4081
4952
|
"campaigns.people.add": z.object({ enrollmentId: z.string() }),
|
|
4953
|
+
"campaigns.preview": campaignMessagePreview,
|
|
4082
4954
|
"campaigns.launch.preview": campaignReadiness,
|
|
4083
4955
|
"campaigns.launch": z.object({
|
|
4084
4956
|
ok: z.boolean(),
|
|
@@ -4096,6 +4968,37 @@ export const responseSchemas: Record<string, ZodTypeAny> = {
|
|
|
4096
4968
|
.passthrough(),
|
|
4097
4969
|
"campaigns.people.stop": okResponse,
|
|
4098
4970
|
"campaigns.people.resume": okResponse,
|
|
4971
|
+
"campaigns.people.sync": z.object({
|
|
4972
|
+
updated: z
|
|
4973
|
+
.number()
|
|
4974
|
+
.describe("How many people gained a detail from their CRM record."),
|
|
4975
|
+
}),
|
|
4976
|
+
"campaigns.people.resumeAll": z.object({
|
|
4977
|
+
resumed: z.number().describe("How many paused people were resumed."),
|
|
4978
|
+
}),
|
|
4979
|
+
"campaigns.people.setEmail": okResponse,
|
|
4980
|
+
"campaigns.people.setLinkedin": okResponse,
|
|
4981
|
+
"campaigns.people.setField": okResponse,
|
|
4982
|
+
"campaigns.pipeline": z
|
|
4983
|
+
.object({
|
|
4984
|
+
total: z.number().describe("People in the campaign."),
|
|
4985
|
+
statuses: z
|
|
4986
|
+
.array(
|
|
4987
|
+
z.object({
|
|
4988
|
+
name: z.string().describe("A lead Status, as named in the CRM."),
|
|
4989
|
+
color: z.string(),
|
|
4990
|
+
count: z.number().describe("Enrolled leads at this Status."),
|
|
4991
|
+
}),
|
|
4992
|
+
)
|
|
4993
|
+
.describe("The workspace's lead Statuses, in pipeline order."),
|
|
4994
|
+
other: z
|
|
4995
|
+
.number()
|
|
4996
|
+
.describe("People with no lead, or a Status outside the pipeline."),
|
|
4997
|
+
})
|
|
4998
|
+
.nullable(),
|
|
4999
|
+
"campaigns.people.forRecord": z.array(campaignMembership),
|
|
5000
|
+
"campaigns.people.timeline": campaignPersonTimeline,
|
|
5001
|
+
"campaigns.people.remove": okResponse,
|
|
4099
5002
|
|
|
4100
5003
|
"commands.list": z.object({
|
|
4101
5004
|
operations: z.array(
|
|
@@ -4107,7 +5010,7 @@ export const responseSchemas: Record<string, ZodTypeAny> = {
|
|
|
4107
5010
|
aliases: z.array(z.string()),
|
|
4108
5011
|
method: z.string(),
|
|
4109
5012
|
path: z.string(),
|
|
4110
|
-
backend: z.enum(["
|
|
5013
|
+
backend: z.enum(["api", "gateway", "custom", "local"]),
|
|
4111
5014
|
deprecated: z.boolean(),
|
|
4112
5015
|
}),
|
|
4113
5016
|
),
|
|
@@ -4964,7 +5867,7 @@ export const responseSchemas: Record<string, ZodTypeAny> = {
|
|
|
4964
5867
|
connection_id: z.string().optional(),
|
|
4965
5868
|
})
|
|
4966
5869
|
.passthrough()
|
|
4967
|
-
.describe("
|
|
5870
|
+
.describe("Connect-link response."),
|
|
4968
5871
|
"tool.search": toolSearchResponse,
|
|
4969
5872
|
"tool.run": toolRunResponse,
|
|
4970
5873
|
"tool.disconnect": z
|
|
@@ -4973,7 +5876,7 @@ export const responseSchemas: Record<string, ZodTypeAny> = {
|
|
|
4973
5876
|
deleted: z.boolean().optional(),
|
|
4974
5877
|
})
|
|
4975
5878
|
.passthrough()
|
|
4976
|
-
.describe("
|
|
5879
|
+
.describe("Delete response."),
|
|
4977
5880
|
"tool.labels.list": z.object({
|
|
4978
5881
|
labels: z.array(
|
|
4979
5882
|
z.object({ composioConnectionId: z.string(), displayName: z.string() }),
|
|
@@ -5062,6 +5965,19 @@ export type ConvexExtras = {
|
|
|
5062
5965
|
};
|
|
5063
5966
|
|
|
5064
5967
|
export const convexExtras: Record<string, ConvexExtras> = {
|
|
5968
|
+
"campaigns.steps.replace": {
|
|
5969
|
+
transformArgs: ({ allowSingleBraces: _allowSingleBraces, ...input }) =>
|
|
5970
|
+
input,
|
|
5971
|
+
},
|
|
5972
|
+
"campaigns.steps.update": {
|
|
5973
|
+
transformArgs: ({ allowSingleBraces: _allowSingleBraces, ...input }) =>
|
|
5974
|
+
input,
|
|
5975
|
+
},
|
|
5976
|
+
"campaigns.personalization.clear": { fixedArgs: { template: null } },
|
|
5977
|
+
"campaigns.personalization.write": {
|
|
5978
|
+
transformArgs: (input) => ({ ...input, mode: input.mode ?? "missing" }),
|
|
5979
|
+
},
|
|
5980
|
+
"campaigns.preview": { fixedArgs: { stepIndex: 0 } },
|
|
5065
5981
|
// The events query paginates with Convex's `paginationOpts`; the flat
|
|
5066
5982
|
// `numItems` / `cursor` query params are folded into it here.
|
|
5067
5983
|
"campaigns.events": {
|
|
@@ -5222,6 +6138,41 @@ export const requestExamples: Record<string, unknown> = {
|
|
|
5222
6138
|
},
|
|
5223
6139
|
],
|
|
5224
6140
|
},
|
|
6141
|
+
"campaigns.steps.update": {
|
|
6142
|
+
sequenceId: "<sequenceId>",
|
|
6143
|
+
steps: [
|
|
6144
|
+
{
|
|
6145
|
+
stepId: "<stepId>",
|
|
6146
|
+
expectedUpdatedAt: 1765526400000,
|
|
6147
|
+
type: "email",
|
|
6148
|
+
emailSubject: "A quicker question, {{First name}}",
|
|
6149
|
+
},
|
|
6150
|
+
{
|
|
6151
|
+
stepId: "<waitStepId>",
|
|
6152
|
+
expectedUpdatedAt: 1765526400000,
|
|
6153
|
+
type: "wait",
|
|
6154
|
+
waitHours: 96,
|
|
6155
|
+
},
|
|
6156
|
+
],
|
|
6157
|
+
},
|
|
6158
|
+
"campaigns.personalization.set": {
|
|
6159
|
+
sequenceId: "<sequenceId>",
|
|
6160
|
+
template: {
|
|
6161
|
+
variables: [
|
|
6162
|
+
{
|
|
6163
|
+
key: "companyHook",
|
|
6164
|
+
label: "Company hook",
|
|
6165
|
+
prompt:
|
|
6166
|
+
"One sentence about something specific their company does or recently did. 8 to 18 words.",
|
|
6167
|
+
fallback: "Your team caught my eye.",
|
|
6168
|
+
maxChars: 160,
|
|
6169
|
+
},
|
|
6170
|
+
],
|
|
6171
|
+
context: {
|
|
6172
|
+
sells: "Senior engineers who join your team in your time zone.",
|
|
6173
|
+
},
|
|
6174
|
+
},
|
|
6175
|
+
},
|
|
5225
6176
|
"campaigns.people.addFromCrm": {
|
|
5226
6177
|
sequenceId: "<sequenceId>",
|
|
5227
6178
|
objectName: "lead",
|
|
@@ -5549,6 +6500,118 @@ const workspaceStatusExample = {
|
|
|
5549
6500
|
};
|
|
5550
6501
|
|
|
5551
6502
|
export const responseExamples: Record<string, unknown> = {
|
|
6503
|
+
"campaigns.pipeline": {
|
|
6504
|
+
total: 12,
|
|
6505
|
+
statuses: [
|
|
6506
|
+
{ name: "New", color: "#94a3b8", count: 3 },
|
|
6507
|
+
{ name: "Contacted", color: "#3b82f6", count: 5 },
|
|
6508
|
+
{ name: "Replied", color: "#22c55e", count: 2 },
|
|
6509
|
+
],
|
|
6510
|
+
other: 2,
|
|
6511
|
+
},
|
|
6512
|
+
"campaigns.people.forRecord": [
|
|
6513
|
+
{
|
|
6514
|
+
enrollment: {
|
|
6515
|
+
_id: "<enrollmentId>",
|
|
6516
|
+
sequenceId: "<sequenceId>",
|
|
6517
|
+
displayName: "Grace Hopper",
|
|
6518
|
+
status: "active",
|
|
6519
|
+
currentStepIndex: 1,
|
|
6520
|
+
},
|
|
6521
|
+
sequenceName: "Founder outreach",
|
|
6522
|
+
isOwner: true,
|
|
6523
|
+
canManage: true,
|
|
6524
|
+
senders: {
|
|
6525
|
+
email: {
|
|
6526
|
+
accountId: "<emailMailboxAccountId>",
|
|
6527
|
+
label: "ada@example.com",
|
|
6528
|
+
status: "running",
|
|
6529
|
+
},
|
|
6530
|
+
linkedin: null,
|
|
6531
|
+
},
|
|
6532
|
+
},
|
|
6533
|
+
],
|
|
6534
|
+
"campaigns.people.timeline": {
|
|
6535
|
+
enrollment: {
|
|
6536
|
+
_id: "<enrollmentId>",
|
|
6537
|
+
displayName: "Grace Hopper",
|
|
6538
|
+
status: "active",
|
|
6539
|
+
},
|
|
6540
|
+
sequence: { _id: "<sequenceId>", name: "Founder outreach" },
|
|
6541
|
+
steps: [
|
|
6542
|
+
{ _id: "<stepId1>", order: 0, type: "email", emailSubject: "Hello" },
|
|
6543
|
+
{ _id: "<stepId2>", order: 1, type: "wait", waitHours: 72 },
|
|
6544
|
+
],
|
|
6545
|
+
runs: [
|
|
6546
|
+
{
|
|
6547
|
+
_id: "<runId1>",
|
|
6548
|
+
stepId: "<stepId1>",
|
|
6549
|
+
stepIndex: 0,
|
|
6550
|
+
type: "email",
|
|
6551
|
+
status: "sent",
|
|
6552
|
+
completedAt: 1765526400000,
|
|
6553
|
+
emailMessageId: "<emailId1>",
|
|
6554
|
+
},
|
|
6555
|
+
{
|
|
6556
|
+
_id: "<runId2>",
|
|
6557
|
+
stepId: "<stepId2>",
|
|
6558
|
+
stepIndex: 1,
|
|
6559
|
+
type: "wait",
|
|
6560
|
+
status: "waiting",
|
|
6561
|
+
waitUntil: 1765785600000,
|
|
6562
|
+
},
|
|
6563
|
+
],
|
|
6564
|
+
emailMessages: [
|
|
6565
|
+
{
|
|
6566
|
+
_id: "<emailId1>",
|
|
6567
|
+
subject: "Hello",
|
|
6568
|
+
textBody: "Hi Grace, ...",
|
|
6569
|
+
status: "opened",
|
|
6570
|
+
sentAt: 1765526400000,
|
|
6571
|
+
firstOpenedAt: 1765530000000,
|
|
6572
|
+
},
|
|
6573
|
+
],
|
|
6574
|
+
linkedinMessages: [],
|
|
6575
|
+
},
|
|
6576
|
+
"campaigns.preview": {
|
|
6577
|
+
channel: "email",
|
|
6578
|
+
subject: "A quicker question, Grace",
|
|
6579
|
+
textBody:
|
|
6580
|
+
"Hi Grace,\n\nYour team at Acme is hiring senior engineers. We place them in your time zone within two weeks.\n\nWorth a chat?",
|
|
6581
|
+
htmlBody:
|
|
6582
|
+
"<p>Hi Grace,</p><p>Your team at Acme is hiring senior engineers. We place them in your time zone within two weeks.</p><p>Worth a chat?</p>",
|
|
6583
|
+
fromName: "Ada Lovelace",
|
|
6584
|
+
fromEmail: "ada@example.com",
|
|
6585
|
+
toName: "Grace Hopper",
|
|
6586
|
+
toEmail: "grace@acme.com",
|
|
6587
|
+
missingFields: [],
|
|
6588
|
+
warnings: [],
|
|
6589
|
+
personalized: [
|
|
6590
|
+
{
|
|
6591
|
+
key: "companyHook",
|
|
6592
|
+
label: "Company hook",
|
|
6593
|
+
value: "Acme is hiring senior engineers.",
|
|
6594
|
+
state: "written",
|
|
6595
|
+
source: "company",
|
|
6596
|
+
maxChars: 160,
|
|
6597
|
+
},
|
|
6598
|
+
],
|
|
6599
|
+
},
|
|
6600
|
+
"campaigns.accounts.email": [
|
|
6601
|
+
{
|
|
6602
|
+
_id: "<emailMailboxAccountId>",
|
|
6603
|
+
email: "ada@example.com",
|
|
6604
|
+
provider: "gmail",
|
|
6605
|
+
status: "running",
|
|
6606
|
+
warmupStatus: "warming",
|
|
6607
|
+
readyAt: 1765526400000,
|
|
6608
|
+
dailyColdSendCap: 30,
|
|
6609
|
+
remainingToday: 12,
|
|
6610
|
+
ownerName: "Ada",
|
|
6611
|
+
isOwner: true,
|
|
6612
|
+
visibility: "shared",
|
|
6613
|
+
},
|
|
6614
|
+
],
|
|
5552
6615
|
"campaigns.accounts.linkedin": [
|
|
5553
6616
|
{
|
|
5554
6617
|
linkedinAccountId: "<linkedinAccountId>",
|
|
@@ -5580,7 +6643,7 @@ export const responseExamples: Record<string, unknown> = {
|
|
|
5580
6643
|
aliases: [],
|
|
5581
6644
|
method: "POST",
|
|
5582
6645
|
path: "/crm/objects/{objectName}/entries",
|
|
5583
|
-
backend: "
|
|
6646
|
+
backend: "api",
|
|
5584
6647
|
deprecated: false,
|
|
5585
6648
|
},
|
|
5586
6649
|
],
|
|
@@ -6246,6 +7309,7 @@ export const responseExamples: Record<string, unknown> = {
|
|
|
6246
7309
|
],
|
|
6247
7310
|
resolvedPersonIds: ["per_abc123"],
|
|
6248
7311
|
creditsCharged: 1,
|
|
7312
|
+
billing: { estimatedCents: 1, chargedCents: 1 },
|
|
6249
7313
|
metadata: { total: 1, offset: 0 },
|
|
6250
7314
|
},
|
|
6251
7315
|
"crm.companies.search": {
|
|
@@ -6261,6 +7325,7 @@ export const responseExamples: Record<string, unknown> = {
|
|
|
6261
7325
|
],
|
|
6262
7326
|
resolvedCompanyIds: ["com_abc123"],
|
|
6263
7327
|
creditsCharged: 1,
|
|
7328
|
+
billing: { estimatedCents: 1, chargedCents: 1 },
|
|
6264
7329
|
metadata: { total: 1, offset: 0 },
|
|
6265
7330
|
},
|
|
6266
7331
|
"enrichment.jobs.search": {
|
|
@@ -6681,8 +7746,7 @@ export const responseExamples: Record<string, unknown> = {
|
|
|
6681
7746
|
downloadable: true,
|
|
6682
7747
|
},
|
|
6683
7748
|
"files.write": { path: "/reports/q2.md", contentHash: "9f86d081884c7d65" },
|
|
6684
|
-
"files.downloadUrl":
|
|
6685
|
-
"https://happy-animal-123.convex.cloud/api/storage/abc123?download=README.md",
|
|
7749
|
+
"files.downloadUrl": "https://files.example.com/abc123?download=README.md",
|
|
6686
7750
|
"files.delete": { path: "/README.md" },
|
|
6687
7751
|
"files.move": {
|
|
6688
7752
|
ok: true,
|
|
@@ -6741,7 +7805,7 @@ export const responseExamples: Record<string, unknown> = {
|
|
|
6741
7805
|
},
|
|
6742
7806
|
"image.generate": {
|
|
6743
7807
|
ok: true,
|
|
6744
|
-
model: "
|
|
7808
|
+
model: "image-model",
|
|
6745
7809
|
endpoint: "generations",
|
|
6746
7810
|
prompt: "A minimal flat-vector app icon",
|
|
6747
7811
|
quality: "auto",
|
|
@@ -6751,13 +7815,13 @@ export const responseExamples: Record<string, unknown> = {
|
|
|
6751
7815
|
estimatedCostUsd: 0.053,
|
|
6752
7816
|
b64_json: "iVBORw0KGgoAAAANS...",
|
|
6753
7817
|
path: "/image-generations/20260612-app-icon.png",
|
|
6754
|
-
signedUrl: "https://
|
|
7818
|
+
signedUrl: "https://files.example.com/img123",
|
|
6755
7819
|
sizeBytes: 245760,
|
|
6756
7820
|
usage: { inputTokens: 12, outputTokens: 1056, totalTokens: 1068 },
|
|
6757
7821
|
},
|
|
6758
7822
|
"image.edit": {
|
|
6759
7823
|
ok: true,
|
|
6760
|
-
model: "
|
|
7824
|
+
model: "image-model",
|
|
6761
7825
|
endpoint: "edits",
|
|
6762
7826
|
prompt: "Make the background transparent",
|
|
6763
7827
|
quality: "auto",
|
|
@@ -6767,7 +7831,7 @@ export const responseExamples: Record<string, unknown> = {
|
|
|
6767
7831
|
estimatedCostUsd: 0.066,
|
|
6768
7832
|
b64_json: "iVBORw0KGgoAAAANS...",
|
|
6769
7833
|
path: "/image-generations/20260612-app-icon-edit.png",
|
|
6770
|
-
signedUrl: "https://
|
|
7834
|
+
signedUrl: "https://files.example.com/img124",
|
|
6771
7835
|
sizeBytes: 198432,
|
|
6772
7836
|
},
|
|
6773
7837
|
"integrations.list": {
|
|
@@ -6829,7 +7893,7 @@ export const responseExamples: Record<string, unknown> = {
|
|
|
6829
7893
|
raw: [],
|
|
6830
7894
|
},
|
|
6831
7895
|
"tool.connect": {
|
|
6832
|
-
redirect_url: "https://
|
|
7896
|
+
redirect_url: "https://connect.dench.com/s/abc123",
|
|
6833
7897
|
connection_id: "ca_github01",
|
|
6834
7898
|
},
|
|
6835
7899
|
"tool.search": {
|