@elevasis/core 0.22.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/dist/index.d.ts +3214 -2501
  2. package/dist/index.js +3112 -1222
  3. package/dist/knowledge/index.d.ts +1108 -1264
  4. package/dist/knowledge/index.js +112 -9
  5. package/dist/organization-model/index.d.ts +3214 -2501
  6. package/dist/organization-model/index.js +3112 -1222
  7. package/dist/test-utils/index.d.ts +985 -1103
  8. package/dist/test-utils/index.js +2464 -1165
  9. package/package.json +5 -5
  10. package/src/README.md +14 -14
  11. package/src/__tests__/publish.test.ts +24 -24
  12. package/src/__tests__/template-core-compatibility.test.ts +9 -80
  13. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +2389 -2121
  14. package/src/_gen/__tests__/scaffold-contracts.test.ts +30 -30
  15. package/src/auth/multi-tenancy/credentials/__tests__/encryption.test.ts +217 -217
  16. package/src/auth/multi-tenancy/credentials/server/encryption.ts +69 -69
  17. package/src/auth/multi-tenancy/credentials/server/kek-loader.ts +37 -37
  18. package/src/auth/multi-tenancy/index.ts +26 -26
  19. package/src/auth/multi-tenancy/invitations/api-schemas.ts +104 -104
  20. package/src/auth/multi-tenancy/memberships/api-schemas.ts +143 -143
  21. package/src/auth/multi-tenancy/memberships/index.ts +26 -26
  22. package/src/auth/multi-tenancy/memberships/membership.ts +130 -130
  23. package/src/auth/multi-tenancy/organizations/__tests__/api-schemas.test.ts +194 -194
  24. package/src/auth/multi-tenancy/organizations/api-schemas.ts +136 -136
  25. package/src/auth/multi-tenancy/permissions.test.ts +42 -42
  26. package/src/auth/multi-tenancy/permissions.ts +123 -123
  27. package/src/auth/multi-tenancy/role-management/api-schemas.ts +78 -78
  28. package/src/auth/multi-tenancy/role-management/index.ts +16 -16
  29. package/src/auth/multi-tenancy/theme-presets.ts +45 -45
  30. package/src/auth/multi-tenancy/types.ts +57 -57
  31. package/src/auth/multi-tenancy/users/api-schemas.ts +165 -165
  32. package/src/business/README.md +2 -2
  33. package/src/business/acquisition/activity-events.test.ts +250 -250
  34. package/src/business/acquisition/activity-events.ts +93 -93
  35. package/src/business/acquisition/api-schemas.test.ts +1883 -1843
  36. package/src/business/acquisition/api-schemas.ts +1493 -1500
  37. package/src/business/acquisition/build-templates.test.ts +240 -240
  38. package/src/business/acquisition/build-templates.ts +83 -41
  39. package/src/business/acquisition/crm-next-action.test.ts +262 -262
  40. package/src/business/acquisition/crm-next-action.ts +220 -220
  41. package/src/business/acquisition/crm-priority.test.ts +216 -216
  42. package/src/business/acquisition/crm-priority.ts +349 -349
  43. package/src/business/acquisition/crm-state-actions.test.ts +153 -151
  44. package/src/business/acquisition/deal-ownership.test.ts +351 -351
  45. package/src/business/acquisition/deal-ownership.ts +120 -120
  46. package/src/business/acquisition/derive-actions.test.ts +129 -104
  47. package/src/business/acquisition/derive-actions.ts +74 -84
  48. package/src/business/acquisition/index.ts +171 -170
  49. package/src/business/acquisition/ontology-validation.ts +309 -0
  50. package/src/business/acquisition/stateful.ts +30 -30
  51. package/src/business/acquisition/types.ts +396 -392
  52. package/src/business/clients/api-schemas.test.ts +115 -115
  53. package/src/business/clients/api-schemas.ts +158 -158
  54. package/src/business/clients/index.ts +1 -1
  55. package/src/business/crm/api-schemas.ts +40 -40
  56. package/src/business/crm/index.ts +1 -1
  57. package/src/business/deals/api-schemas.ts +87 -87
  58. package/src/business/deals/index.ts +1 -1
  59. package/src/business/index.ts +5 -5
  60. package/src/business/projects/types.ts +144 -144
  61. package/src/commands/queue/types/task.ts +15 -15
  62. package/src/execution/core/runner-types.ts +61 -61
  63. package/src/execution/core/sse-executions.ts +7 -7
  64. package/src/execution/engine/__tests__/fixtures/test-agents.ts +10 -10
  65. package/src/execution/engine/agent/core/__tests__/agent.test.ts +16 -16
  66. package/src/execution/engine/agent/core/__tests__/error-passthrough.test.ts +4 -4
  67. package/src/execution/engine/agent/core/types.ts +25 -25
  68. package/src/execution/engine/agent/index.ts +6 -6
  69. package/src/execution/engine/agent/reasoning/__tests__/request-builder.test.ts +24 -24
  70. package/src/execution/engine/index.ts +443 -443
  71. package/src/execution/engine/tools/integration/server/adapters/apify/__tests__/apify-run-actor.integration.test.ts +298 -298
  72. package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.test.ts +55 -55
  73. package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.ts +107 -107
  74. package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.test.ts +48 -48
  75. package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.ts +99 -99
  76. package/src/execution/engine/tools/integration/server/adapters/apollo/index.ts +1 -1
  77. package/src/execution/engine/tools/integration/server/adapters/attio/__tests__/attio-crud.integration.test.ts +363 -363
  78. package/src/execution/engine/tools/integration/server/adapters/attio/fetch/get-record/index.test.ts +162 -162
  79. package/src/execution/engine/tools/integration/server/adapters/attio/fetch/list-records/index.test.ts +316 -316
  80. package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.test.ts +18 -18
  81. package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.ts +194 -194
  82. package/src/execution/engine/tools/integration/server/adapters/clickup/index.ts +7 -7
  83. package/src/execution/engine/tools/integration/server/adapters/gmail/gmail-adapter.ts +204 -204
  84. package/src/execution/engine/tools/integration/server/adapters/gmail/gmail-tools.ts +105 -105
  85. package/src/execution/engine/tools/integration/server/adapters/google-calendar/google-calendar-adapter.ts +428 -428
  86. package/src/execution/engine/tools/integration/server/adapters/google-calendar/index.ts +2 -2
  87. package/src/execution/engine/tools/integration/server/adapters/google-sheets/__tests__/google-sheets.integration.test.ts +261 -261
  88. package/src/execution/engine/tools/integration/server/adapters/instantly/instantly-tools.ts +1474 -1474
  89. package/src/execution/engine/tools/integration/server/adapters/millionverifier/millionverifier-tools.ts +103 -103
  90. package/src/execution/engine/tools/integration/server/adapters/resend/fetch/send-email/index.test.ts +88 -88
  91. package/src/execution/engine/tools/integration/server/adapters/resend/fetch/send-email/index.ts +141 -141
  92. package/src/execution/engine/tools/integration/server/adapters/resend/fetch/utils/types.ts +76 -76
  93. package/src/execution/engine/tools/integration/server/adapters/signature-api/signature-api-tools.ts +182 -182
  94. package/src/execution/engine/tools/integration/server/adapters/stripe/stripe-tools.ts +310 -310
  95. package/src/execution/engine/tools/integration/service.test.ts +239 -239
  96. package/src/execution/engine/tools/integration/service.ts +172 -172
  97. package/src/execution/engine/tools/integration/tool.ts +255 -255
  98. package/src/execution/engine/tools/lead-service-types.ts +1005 -1005
  99. package/src/execution/engine/tools/messages.ts +43 -43
  100. package/src/execution/engine/tools/platform/acquisition/company-tools.ts +7 -7
  101. package/src/execution/engine/tools/platform/acquisition/contact-tools.ts +6 -6
  102. package/src/execution/engine/tools/platform/acquisition/list-tools.ts +6 -6
  103. package/src/execution/engine/tools/platform/acquisition/types.ts +280 -280
  104. package/src/execution/engine/tools/platform/email/types.ts +97 -97
  105. package/src/execution/engine/tools/registry.ts +704 -704
  106. package/src/execution/engine/tools/tool-maps.ts +831 -831
  107. package/src/execution/engine/tools/types.ts +234 -234
  108. package/src/execution/engine/workflow/types.ts +202 -202
  109. package/src/execution/external/__tests__/api-schemas.test.ts +127 -127
  110. package/src/execution/external/api-schemas.ts +40 -40
  111. package/src/execution/external/index.ts +1 -1
  112. package/src/index.ts +18 -18
  113. package/src/integrations/credentials/__tests__/api-schemas.test.ts +420 -420
  114. package/src/integrations/credentials/api-schemas.ts +146 -146
  115. package/src/integrations/credentials/schemas.ts +200 -200
  116. package/src/integrations/oauth/__tests__/provider-registry.test.ts +7 -7
  117. package/src/integrations/oauth/provider-registry.ts +74 -74
  118. package/src/integrations/oauth/server/credentials.ts +43 -43
  119. package/src/integrations/webhook-endpoints/__tests__/api-schemas.test.ts +327 -327
  120. package/src/integrations/webhook-endpoints/api-schemas.ts +103 -103
  121. package/src/integrations/webhook-endpoints/types.ts +58 -58
  122. package/src/knowledge/README.md +33 -32
  123. package/src/knowledge/__tests__/queries.test.ts +633 -541
  124. package/src/knowledge/format.ts +100 -99
  125. package/src/knowledge/index.ts +5 -5
  126. package/src/knowledge/published.ts +5 -5
  127. package/src/knowledge/queries.ts +274 -222
  128. package/src/operations/activities/api-schemas.ts +80 -80
  129. package/src/operations/activities/types.ts +64 -64
  130. package/src/organization-model/README.md +149 -109
  131. package/src/organization-model/__tests__/content-kinds-registry.test.ts +210 -0
  132. package/src/organization-model/__tests__/defaults.test.ts +168 -194
  133. package/src/organization-model/__tests__/domains/actions.test.ts +78 -0
  134. package/src/organization-model/__tests__/domains/customers.test.ts +48 -44
  135. package/src/organization-model/__tests__/domains/entities.test.ts +56 -0
  136. package/src/organization-model/__tests__/domains/goals.test.ts +110 -96
  137. package/src/organization-model/__tests__/domains/identity.test.ts +4 -3
  138. package/src/organization-model/__tests__/domains/navigation.test.ts +222 -166
  139. package/src/organization-model/__tests__/domains/offerings.test.ts +83 -88
  140. package/src/organization-model/__tests__/domains/policies.test.ts +323 -0
  141. package/src/organization-model/__tests__/domains/resource-mappings.test.ts +30 -30
  142. package/src/organization-model/__tests__/domains/resources.test.ts +396 -175
  143. package/src/organization-model/__tests__/domains/roles.test.ts +463 -402
  144. package/src/organization-model/__tests__/domains/statuses.test.ts +13 -10
  145. package/src/organization-model/__tests__/domains/systems.test.ts +209 -193
  146. package/src/organization-model/__tests__/flatten-additive-merge.test.ts +362 -0
  147. package/src/organization-model/__tests__/foundation.test.ts +47 -75
  148. package/src/organization-model/__tests__/get-resources-for-system.test.ts +144 -0
  149. package/src/organization-model/__tests__/graph.test.ts +1336 -149
  150. package/src/organization-model/__tests__/icons.test.ts +10 -1
  151. package/src/organization-model/__tests__/knowledge.test.ts +418 -61
  152. package/src/organization-model/__tests__/lookup-helpers.test.ts +438 -0
  153. package/src/organization-model/__tests__/migration-helpers.test.ts +591 -0
  154. package/src/organization-model/__tests__/prospecting-ssot.test.ts +103 -94
  155. package/src/organization-model/__tests__/recursive-system-schema.test.ts +549 -0
  156. package/src/organization-model/__tests__/resolve.test.ts +303 -42
  157. package/src/organization-model/__tests__/schema.test.ts +863 -153
  158. package/src/organization-model/__tests__/surface-projection.test.ts +284 -174
  159. package/src/organization-model/catalogs/lead-gen.ts +144 -0
  160. package/src/organization-model/content-kinds/config.ts +36 -0
  161. package/src/organization-model/content-kinds/index.ts +78 -0
  162. package/src/organization-model/content-kinds/pipeline.ts +68 -0
  163. package/src/organization-model/content-kinds/registry.ts +44 -0
  164. package/src/organization-model/content-kinds/status.ts +71 -0
  165. package/src/organization-model/content-kinds/template.ts +83 -0
  166. package/src/organization-model/content-kinds/types.ts +117 -0
  167. package/src/organization-model/contracts.ts +27 -17
  168. package/src/organization-model/defaults.ts +489 -107
  169. package/src/organization-model/domains/actions.ts +333 -0
  170. package/src/organization-model/domains/customers.ts +10 -7
  171. package/src/organization-model/domains/entities.ts +144 -0
  172. package/src/organization-model/domains/goals.ts +9 -6
  173. package/src/organization-model/domains/knowledge.ts +128 -54
  174. package/src/organization-model/domains/navigation.ts +139 -416
  175. package/src/organization-model/domains/offerings.ts +15 -10
  176. package/src/organization-model/domains/policies.ts +102 -0
  177. package/src/organization-model/domains/projects.ts +6 -40
  178. package/src/organization-model/domains/prospecting.ts +395 -514
  179. package/src/organization-model/domains/resources.ts +173 -81
  180. package/src/organization-model/domains/roles.ts +96 -93
  181. package/src/organization-model/domains/sales.test.ts +218 -218
  182. package/src/organization-model/domains/sales.ts +380 -589
  183. package/src/organization-model/domains/shared.ts +8 -8
  184. package/src/organization-model/domains/statuses.ts +298 -89
  185. package/src/organization-model/domains/systems.ts +240 -38
  186. package/src/organization-model/foundation.ts +35 -48
  187. package/src/organization-model/graph/build.ts +1035 -279
  188. package/src/organization-model/graph/index.ts +4 -4
  189. package/src/organization-model/graph/link.ts +10 -10
  190. package/src/organization-model/graph/schema.ts +77 -56
  191. package/src/organization-model/graph/types.ts +75 -56
  192. package/src/organization-model/helpers.ts +312 -59
  193. package/src/organization-model/icons.ts +78 -66
  194. package/src/organization-model/index.ts +129 -16
  195. package/src/organization-model/migration-helpers.ts +252 -0
  196. package/src/organization-model/ontology.ts +661 -0
  197. package/src/organization-model/organization-graph.mdx +110 -89
  198. package/src/organization-model/organization-model.mdx +226 -171
  199. package/src/organization-model/published.ts +295 -139
  200. package/src/organization-model/resolve.ts +139 -21
  201. package/src/organization-model/schema.ts +841 -301
  202. package/src/organization-model/surface-projection.ts +212 -218
  203. package/src/organization-model/types.ts +181 -90
  204. package/src/platform/api/types.ts +38 -38
  205. package/src/platform/constants/versions.ts +3 -3
  206. package/src/platform/index.ts +23 -23
  207. package/src/platform/registry/__tests__/command-view.test.ts +5 -7
  208. package/src/platform/registry/__tests__/resource-link.test.ts +35 -30
  209. package/src/platform/registry/__tests__/resource-registry.integration.test.ts +17 -32
  210. package/src/platform/registry/__tests__/resource-registry.nested-systems.test.ts +245 -0
  211. package/src/platform/registry/__tests__/resource-registry.test.ts +2053 -2051
  212. package/src/platform/registry/__tests__/validation.test.ts +1347 -1343
  213. package/src/platform/registry/command-view.ts +10 -10
  214. package/src/platform/registry/index.ts +103 -103
  215. package/src/platform/registry/resource-link.ts +32 -32
  216. package/src/platform/registry/resource-registry.ts +890 -878
  217. package/src/platform/registry/serialization.ts +295 -295
  218. package/src/platform/registry/serialized-types.ts +166 -166
  219. package/src/platform/registry/stats-types.ts +68 -68
  220. package/src/platform/registry/types.ts +425 -425
  221. package/src/platform/registry/validation.ts +745 -743
  222. package/src/platform/utils/__tests__/validation.test.ts +1084 -1084
  223. package/src/platform/utils/validation.ts +425 -425
  224. package/src/projects/api-schemas.test.ts +39 -39
  225. package/src/projects/api-schemas.ts +291 -291
  226. package/src/reference/_generated/contracts.md +2389 -2121
  227. package/src/reference/glossary.md +76 -76
  228. package/src/scaffold-registry/__tests__/index.test.ts +206 -206
  229. package/src/scaffold-registry/__tests__/schema.test.ts +166 -166
  230. package/src/scaffold-registry/index.ts +392 -392
  231. package/src/scaffold-registry/schema.ts +243 -243
  232. package/src/server.ts +289 -289
  233. package/src/supabase/database.types.ts +3153 -3093
  234. package/src/test-utils/README.md +37 -37
  235. package/src/test-utils/entities.ts +108 -108
  236. package/src/test-utils/fixtures/memberships.ts +82 -82
  237. package/src/test-utils/index.ts +12 -12
  238. package/src/test-utils/organization-model.ts +65 -65
  239. package/src/test-utils/published.ts +6 -6
  240. package/src/test-utils/rls/RLSTestContext.ts +588 -588
  241. package/src/test-utils/test-utils.test.ts +44 -49
  242. package/src/organization-model/__tests__/domains/operations.test.ts +0 -203
  243. package/src/organization-model/domains/features.ts +0 -31
  244. package/src/organization-model/domains/operations.ts +0 -85
@@ -1,1474 +1,1474 @@
1
- import { z } from 'zod'
2
- import { createIntegrationTool } from '../../../tool'
3
- import type { Tool } from '../../../../types'
4
- import { EmailSchema } from '../../../../../../../platform/utils/validation'
5
-
6
- /**
7
- * Create Instantly send reply tool
8
- *
9
- * Sends a reply to an email thread maintaining proper threading.
10
- *
11
- * @param credentialName - Name of credential in credentials table
12
- * @returns Tool that sends email replies via Instantly
13
- *
14
- * @example
15
- * const sendReply = createInstantlySendReplyTool('instantly-elevasis')
16
- */
17
- export function createInstantlySendReplyTool(credentialName: string): Tool {
18
- return createIntegrationTool({
19
- name: 'instantly_send_reply',
20
- description: `Send a reply to an email thread via Instantly.ai
21
-
22
- USE CASES:
23
- - Send a personalized reply to a prospect who responded to your outreach campaign
24
- - Maintain email threading for organized conversations
25
- - Schedule replies for future delivery
26
-
27
- REQUIRED PARAMETERS:
28
- - eaccount: Email account that will send the reply (must be connected to workspace)
29
- - reply_to_uuid: UUID of the email you are replying to (from webhook payload)
30
- - subject: Subject line of the reply (typically "Re: Original Subject")
31
- - body: Email body (must provide either text or html)
32
-
33
- OPTIONAL PARAMETERS:
34
- - timestamp: ISO timestamp to schedule reply for future
35
-
36
- EXAMPLE:
37
- {
38
- "eaccount": "alex@elevasis.com",
39
- "reply_to_uuid": "123e4567-e89b-12d3-a456-426614174000",
40
- "subject": "Re: Automate your client acquisition",
41
- "body": {
42
- "text": "Thanks for your interest! Here's my calendar: https://calendly.com/..."
43
- }
44
- }
45
-
46
- OUTPUT:
47
- {
48
- "success": true,
49
- "email_id": "email-abc123",
50
- "thread_id": "thread-xyz789",
51
- "sent_at": "2025-12-22T14:30:00Z"
52
- }`,
53
-
54
- inputSchema: z.object({
55
- eaccount: z.string().describe('Email account that will send the reply (must be connected to workspace)'),
56
- reply_to_uuid: z.string().describe('UUID of the email you are replying to (from webhook payload)'),
57
- subject: z.string().describe('Subject line of the reply (typically "Re: Original Subject")'),
58
- body: z
59
- .object({
60
- text: z.string().optional().describe('Plain text email body'),
61
- html: z.string().optional().describe('HTML email body')
62
- })
63
- .refine((data) => data.text || data.html, {
64
- message: 'Must provide either text or html body'
65
- }),
66
- timestamp: z.string().optional().describe('ISO timestamp to schedule reply for future (optional)')
67
- }),
68
-
69
- outputSchema: z.object({
70
- success: z.boolean().describe('Whether reply was sent successfully'),
71
- email_id: z.string().describe('ID of the sent email'),
72
- thread_id: z.string().describe('Thread ID for conversation tracking'),
73
- sent_at: z.string().describe('Timestamp when email was sent')
74
- }),
75
-
76
- integration: 'instantly' as const,
77
- method: 'sendReply' as const,
78
- credentialName
79
- })
80
- }
81
-
82
- /**
83
- * Create Instantly remove from subsequence tool
84
- *
85
- * Removes a lead from a campaign sequence to stop further outreach.
86
- *
87
- * @param credentialName - Name of credential in credentials table
88
- * @returns Tool that removes leads from campaigns
89
- *
90
- * @example
91
- * const removeFromCampaign = createInstantlyRemoveFromSubsequenceTool('instantly-elevasis')
92
- */
93
- export function createInstantlyRemoveFromSubsequenceTool(credentialName: string): Tool {
94
- return createIntegrationTool({
95
- name: 'instantly_remove_from_subsequence',
96
- description: `Remove a lead from an Instantly campaign subsequence
97
-
98
- USE CASES:
99
- - Stop a lead from receiving further emails in a campaign
100
- - Use after positive reply, hard-no, or disqualification
101
- - Prevent over-emailing engaged prospects
102
-
103
- REQUIRED PARAMETERS:
104
- - lead_email: Email address of the lead to remove
105
- - campaign_id: Campaign ID to remove lead from
106
-
107
- EXAMPLE:
108
- {
109
- "lead_email": "prospect@agency.com",
110
- "campaign_id": "campaign-123"
111
- }
112
-
113
- OUTPUT:
114
- {
115
- "success": true,
116
- "lead_email": "prospect@agency.com",
117
- "campaign_id": "campaign-123"
118
- }`,
119
-
120
- inputSchema: z.object({
121
- lead_email: EmailSchema.describe('Email address of the lead to remove'),
122
- campaign_id: z.string().describe('Campaign ID to remove lead from')
123
- }),
124
-
125
- outputSchema: z.object({
126
- success: z.boolean().describe('Whether removal was successful'),
127
- lead_email: z.string().describe('Email of the removed lead'),
128
- campaign_id: z.string().describe('Campaign ID lead was removed from')
129
- }),
130
-
131
- integration: 'instantly' as const,
132
- method: 'removeFromSubsequence' as const,
133
- credentialName
134
- })
135
- }
136
-
137
- /**
138
- * Create Instantly get emails tool
139
- *
140
- * Fetches email data from Instantly workspace with optional filtering and pagination.
141
- *
142
- * @param credentialName - Name of credential in credentials table
143
- * @returns Tool that retrieves email data
144
- */
145
- export function createInstantlyGetEmailsTool(credentialName: string): Tool {
146
- return createIntegrationTool({
147
- name: 'instantly_get_emails',
148
- description: `Get emails from Instantly workspace
149
-
150
- USE CASES:
151
- - Fetch a specific email by ID for reply processing
152
- - Retrieve full email threads by thread ID
153
- - Filter emails by campaign, lead, or type
154
- - List recent emails with cursor pagination
155
-
156
- OPTIONAL PARAMETERS:
157
- - email_id: Specific email ID to fetch (returns single email)
158
- - search: Email address OR "thread:{thread_id}" for thread retrieval
159
- - campaign_id: Filter by campaign UUID
160
- - lead: Filter by lead email address
161
- - email_type: Filter by type (received, sent, manual)
162
- - eaccount: Filter by sending account (comma-separated)
163
- - sort_order: Sort by creation date (asc, desc; default: desc)
164
- - preview_only: Return preview only (lighter response)
165
- - is_unread: Filter by unread status
166
- - limit: Items per page (1-100)
167
- - starting_after: Cursor for pagination (from next_starting_after in previous response)
168
-
169
- EXAMPLE (Single Email):
170
- {
171
- "email_id": "email-abc123"
172
- }
173
-
174
- EXAMPLE (Thread Retrieval):
175
- {
176
- "search": "thread:019a449c-f57a-73b2-91b5-75537ca85008",
177
- "sort_order": "asc",
178
- "limit": 50
179
- }
180
-
181
- EXAMPLE (Lead Emails in Campaign):
182
- {
183
- "lead": "jondoe@example.com",
184
- "campaign_id": "019a449c-f57a-73b2-91b5-754f1fca9f44",
185
- "sort_order": "asc"
186
- }
187
-
188
- OUTPUT:
189
- {
190
- "emails": [...email data...],
191
- "total_count": 3,
192
- "next_starting_after": "cursor-token-or-undefined"
193
- }`,
194
-
195
- inputSchema: z.object({
196
- email_id: z.string().optional().describe('Specific email ID to fetch'),
197
- search: z
198
- .string()
199
- .optional()
200
- .describe('Search query: email address or "thread:{thread_id}" for thread retrieval'),
201
- campaign_id: z.string().optional().describe('Filter by campaign UUID'),
202
- lead: z.string().optional().describe('Filter by lead email address'),
203
- email_type: z.enum(['received', 'sent', 'manual']).optional().describe('Filter by email type'),
204
- eaccount: z.string().optional().describe('Filter by sending account (comma-separated)'),
205
- sort_order: z.enum(['asc', 'desc']).optional().describe('Sort order by creation date (default: desc)'),
206
- preview_only: z.boolean().optional().describe('Return preview only (lighter response)'),
207
- is_unread: z.boolean().optional().describe('Filter by unread status'),
208
- limit: z.number().min(1).max(100).optional().describe('Items per page (1-100)'),
209
- starting_after: z.string().optional().describe('Cursor for pagination (from next_starting_after)')
210
- }),
211
-
212
- outputSchema: z.object({
213
- emails: z.array(z.unknown()).describe('Array of email data'),
214
- total_count: z.number().describe('Count of emails returned'),
215
- next_starting_after: z.string().optional().describe('Cursor for next page (undefined = no more)')
216
- }),
217
-
218
- integration: 'instantly' as const,
219
- method: 'getEmails' as const,
220
- credentialName
221
- })
222
- }
223
-
224
- /**
225
- * Create Instantly update interest status tool
226
- *
227
- * Updates the interest status of a lead, which can stop email sequences,
228
- * mark leads as interested, or reset to default status.
229
- *
230
- * @param credentialName - Name of credential in credentials table
231
- * @returns Tool that updates lead interest status
232
- *
233
- * @example
234
- * const updateStatus = createInstantlyUpdateInterestStatusTool('instantly-elevasis')
235
- */
236
- export function createInstantlyUpdateInterestStatusTool(credentialName: string): Tool {
237
- return createIntegrationTool({
238
- name: 'instantly_update_interest_status',
239
- description: `Update interest status of a lead in Instantly
240
-
241
- USE CASES:
242
- - Stop email sequence for leads who reply with "unsubscribe" or "not interested" (set interest_value: -1)
243
- - Mark engaged leads as interested for prioritization (set interest_value: 1)
244
- - Reset lead status back to default (set interest_value: 0)
245
- - Comply with opt-out requests to protect sender reputation
246
-
247
- INTEREST VALUES:
248
- - 1: Interested - Marks lead as interested
249
- - 0: Lead (default) - Resets to default status
250
- - -1: Not Interested - STOPS sequence (no more emails sent)
251
-
252
- REQUIRED PARAMETERS:
253
- - lead_email: Email address of the lead
254
- - interest_value: Status value (1, 0, or -1)
255
-
256
- OPTIONAL PARAMETERS:
257
- - campaign_id: Limit status update to specific campaign (UUID)
258
- - disable_auto_interest: Disable AI auto-tagging for this lead
259
-
260
- EXAMPLE (Stop Sequence):
261
- {
262
- "lead_email": "prospect@agency.com",
263
- "interest_value": -1
264
- }
265
-
266
- EXAMPLE (Mark Interested in Specific Campaign):
267
- {
268
- "lead_email": "prospect@agency.com",
269
- "interest_value": 1,
270
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
271
- }
272
-
273
- OUTPUT:
274
- {
275
- "success": true,
276
- "lead_email": "prospect@agency.com"
277
- }`,
278
-
279
- inputSchema: z.object({
280
- lead_email: EmailSchema.describe('Email address of the lead'),
281
- interest_value: z
282
- .number()
283
- .int()
284
- .min(-1)
285
- .max(1)
286
- .describe('Interest status: 1 (interested), 0 (default), -1 (not interested - stops sequence)'),
287
- campaign_id: z.string().optional().describe('Campaign ID to limit status update to (UUID)'),
288
- disable_auto_interest: z.boolean().optional().describe('Disable AI auto-tagging for this lead')
289
- }),
290
-
291
- outputSchema: z.object({
292
- success: z.boolean().describe('Whether status update was successful'),
293
- lead_email: z.string().describe('Email of the updated lead')
294
- }),
295
-
296
- integration: 'instantly' as const,
297
- method: 'updateInterestStatus' as const,
298
- credentialName
299
- })
300
- }
301
-
302
- /**
303
- * Create Instantly add to campaign tool
304
- *
305
- * Adds leads to an Instantly campaign to begin the email sequence.
306
- *
307
- * @param credentialName - Name of credential in credentials table
308
- * @returns Tool that adds leads to a campaign
309
- *
310
- * @example
311
- * const addToCampaign = createInstantlyAddToCampaignTool('instantly-elevasis')
312
- */
313
- export function createInstantlyAddToCampaignTool(credentialName: string): Tool {
314
- return createIntegrationTool({
315
- name: 'instantly_add_to_campaign',
316
- description: `Add leads to an Instantly campaign
317
-
318
- USE CASES:
319
- - Add interested leads to a follow-up campaign after initial outreach
320
- - Start a drip sequence for leads who requested more information
321
- - Enroll new leads into automated nurture campaigns
322
-
323
- REQUIRED PARAMETERS:
324
- - campaign_id: UUID of the Instantly campaign to add leads to
325
- - leads: Array of lead objects (at least one required)
326
-
327
- LEAD OBJECT FIELDS:
328
- - email: (required) Email address of the lead
329
- - first_name: (optional) First name for personalization
330
- - last_name: (optional) Last name for personalization
331
- - company_name: (optional) Company name for personalization
332
-
333
- IMPORTANT: When leads are added, they begin receiving the campaign sequence immediately.
334
- "Day 0" starts at the moment of addition.
335
-
336
- EXAMPLE:
337
- {
338
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
339
- "leads": [
340
- {
341
- "email": "prospect@agency.com",
342
- "first_name": "John",
343
- "last_name": "Smith",
344
- "company_name": "Acme Agency"
345
- }
346
- ]
347
- }
348
-
349
- OUTPUT:
350
- {
351
- "success": true,
352
- "added_count": 1,
353
- "errors": null
354
- }`,
355
-
356
- inputSchema: z.object({
357
- campaign_id: z.string().describe('UUID of the Instantly campaign to add leads to'),
358
- leads: z
359
- .array(
360
- z.object({
361
- email: EmailSchema.describe('Email address of the lead'),
362
- first_name: z.string().optional().describe('First name for personalization'),
363
- last_name: z.string().optional().describe('Last name for personalization'),
364
- company_name: z.string().optional().describe('Company name for personalization')
365
- })
366
- )
367
- .min(1)
368
- .describe('Array of leads to add (at least one required)')
369
- }),
370
-
371
- outputSchema: z.object({
372
- success: z.boolean().describe('Whether leads were added successfully'),
373
- added_count: z.number().describe('Number of leads successfully added'),
374
- errors: z.array(z.string()).optional().describe('Array of error messages if any failures occurred')
375
- }),
376
-
377
- integration: 'instantly' as const,
378
- method: 'addToCampaign' as const,
379
- credentialName
380
- })
381
- }
382
-
383
- /**
384
- * Create Instantly list campaigns tool
385
- *
386
- * Lists all campaigns in the workspace with optional filtering and pagination.
387
- *
388
- * @param credentialName - Name of credential in credentials table
389
- * @returns Tool that lists Instantly campaigns
390
- *
391
- * @example
392
- * const listCampaigns = createInstantlyListCampaignsTool('instantly-elevasis')
393
- */
394
- export function createInstantlyListCampaignsTool(credentialName: string): Tool {
395
- return createIntegrationTool({
396
- name: 'instantly_list_campaigns',
397
- description: `List all campaigns in the Instantly workspace
398
-
399
- USE CASES:
400
- - Discover available campaigns before adding leads or fetching analytics
401
- - Filter campaigns by status to find active or paused campaigns
402
- - Search campaigns by name to locate a specific campaign ID
403
- - Paginate through large campaign lists using cursor-based pagination
404
-
405
- OPTIONAL PARAMETERS:
406
- - limit: Number of campaigns to return per page (default: 10)
407
- - starting_after: Cursor from previous response for pagination
408
- - status: Filter by campaign status (e.g. "active", "paused", "completed")
409
- - search: Search term to filter campaigns by name
410
-
411
- EXAMPLE (List Active Campaigns):
412
- {
413
- "status": "active",
414
- "limit": 20
415
- }
416
-
417
- EXAMPLE (Search by Name):
418
- {
419
- "search": "cold outreach Q1"
420
- }
421
-
422
- OUTPUT:
423
- {
424
- "campaigns": [
425
- {
426
- "id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
427
- "name": "Cold Outreach Q1",
428
- "status": "active",
429
- "created_at": "2025-01-15T09:00:00Z"
430
- }
431
- ],
432
- "next_starting_after": "cursor-token"
433
- }`,
434
-
435
- inputSchema: z.object({
436
- limit: z.number().min(1).max(100).optional().describe('Number of campaigns per page (default: 10)'),
437
- starting_after: z
438
- .string()
439
- .optional()
440
- .describe('Cursor for pagination (from next_starting_after in previous response)'),
441
- status: z.string().optional().describe('Filter by campaign status (e.g. "active", "paused", "completed")'),
442
- search: z.string().optional().describe('Search term to filter campaigns by name')
443
- }),
444
-
445
- outputSchema: z.object({
446
- campaigns: z
447
- .array(
448
- z.object({
449
- id: z.string().describe('Campaign UUID'),
450
- name: z.string().describe('Campaign name'),
451
- status: z.string().describe('Campaign status'),
452
- created_at: z.string().describe('Campaign creation timestamp')
453
- })
454
- )
455
- .describe('Array of campaigns'),
456
- next_starting_after: z.string().optional().describe('Cursor for next page (undefined = no more pages)')
457
- }),
458
-
459
- integration: 'instantly' as const,
460
- method: 'listCampaigns' as const,
461
- credentialName
462
- })
463
- }
464
-
465
- /**
466
- * Create Instantly get campaign tool
467
- *
468
- * Fetches full details for a single campaign including sequences and configuration.
469
- *
470
- * @param credentialName - Name of credential in credentials table
471
- * @returns Tool that retrieves a single Instantly campaign
472
- *
473
- * @example
474
- * const getCampaign = createInstantlyGetCampaignTool('instantly-elevasis')
475
- */
476
- export function createInstantlyGetCampaignTool(credentialName: string): Tool {
477
- return createIntegrationTool({
478
- name: 'instantly_get_campaign',
479
- description: `Get full details of a specific Instantly campaign
480
-
481
- USE CASES:
482
- - Inspect campaign sequences and step configurations before modifying
483
- - Verify campaign status before activating or pausing
484
- - Retrieve sending settings such as daily limits and reply handling
485
- - Confirm the campaign name and metadata before referencing in reports
486
-
487
- REQUIRED PARAMETERS:
488
- - campaign_id: UUID of the campaign to retrieve
489
-
490
- EXAMPLE:
491
- {
492
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
493
- }
494
-
495
- OUTPUT:
496
- {
497
- "id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
498
- "name": "Cold Outreach Q1",
499
- "status": "active",
500
- "sequences": [...],
501
- "created_at": "2025-01-15T09:00:00Z"
502
- }`,
503
-
504
- inputSchema: z.object({
505
- campaign_id: z.string().describe('UUID of the campaign to retrieve')
506
- }),
507
-
508
- outputSchema: z.object({
509
- id: z.string().describe('Campaign UUID'),
510
- name: z.string().describe('Campaign name'),
511
- status: z.string().describe('Campaign status'),
512
- sequences: z.array(z.unknown()).describe('Campaign sequence steps'),
513
- created_at: z.string().describe('Campaign creation timestamp')
514
- }),
515
-
516
- integration: 'instantly' as const,
517
- method: 'getCampaign' as const,
518
- credentialName
519
- })
520
- }
521
-
522
- /**
523
- * Create Instantly update campaign tool
524
- *
525
- * Partially updates a campaign's fields such as name, sequences, or sending limits.
526
- *
527
- * @param credentialName - Name of credential in credentials table
528
- * @returns Tool that updates an Instantly campaign
529
- *
530
- * @example
531
- * const updateCampaign = createInstantlyUpdateCampaignTool('instantly-elevasis')
532
- */
533
- export function createInstantlyUpdateCampaignTool(credentialName: string): Tool {
534
- return createIntegrationTool({
535
- name: 'instantly_update_campaign',
536
- description: `Update fields on an existing Instantly campaign
537
-
538
- USE CASES:
539
- - Rename a campaign to reflect updated targeting or messaging
540
- - Adjust the daily sending limit to control volume
541
- - Replace or edit campaign sequences and email steps
542
- - Toggle stop-on-reply to pause the sequence when a lead responds
543
-
544
- REQUIRED PARAMETERS:
545
- - campaign_id: UUID of the campaign to update
546
-
547
- OPTIONAL PARAMETERS (at least one must be provided):
548
- - name: New campaign name
549
- - sequences: Full replacement of campaign sequences (array of step objects)
550
- - daily_limit: Maximum emails to send per day
551
- - stop_on_reply: Whether to stop sending when a lead replies (true/false)
552
-
553
- EXAMPLE (Rename and Adjust Limit):
554
- {
555
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
556
- "name": "Cold Outreach Q2",
557
- "daily_limit": 50
558
- }
559
-
560
- OUTPUT:
561
- {
562
- "success": true,
563
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
564
- }`,
565
-
566
- inputSchema: z.object({
567
- campaign_id: z.string().describe('UUID of the campaign to update'),
568
- name: z.string().optional().describe('New campaign name'),
569
- sequences: z.array(z.unknown()).optional().describe('Replacement campaign sequences (array of step objects)'),
570
- daily_limit: z.number().int().min(1).optional().describe('Maximum emails to send per day'),
571
- stop_on_reply: z.boolean().optional().describe('Whether to stop the sequence when a lead replies')
572
- }),
573
-
574
- outputSchema: z.object({
575
- success: z.boolean().describe('Whether the update was successful'),
576
- campaign_id: z.string().describe('UUID of the updated campaign')
577
- }),
578
-
579
- integration: 'instantly' as const,
580
- method: 'updateCampaign' as const,
581
- credentialName
582
- })
583
- }
584
-
585
- /**
586
- * Create Instantly pause campaign tool
587
- *
588
- * Pauses an active campaign to stop email sends until reactivated.
589
- *
590
- * @param credentialName - Name of credential in credentials table
591
- * @returns Tool that pauses an Instantly campaign
592
- *
593
- * @example
594
- * const pauseCampaign = createInstantlyPauseCampaignTool('instantly-elevasis')
595
- */
596
- export function createInstantlyPauseCampaignTool(credentialName: string): Tool {
597
- return createIntegrationTool({
598
- name: 'instantly_pause_campaign',
599
- description: `Pause an active Instantly campaign
600
-
601
- USE CASES:
602
- - Temporarily halt outreach while reviewing campaign performance
603
- - Pause before making sequence edits to avoid sending stale content
604
- - Stop sends during public holidays or blackout periods
605
- - Hold sends when a domain reputation issue is detected
606
-
607
- REQUIRED PARAMETERS:
608
- - campaign_id: UUID of the campaign to pause
609
-
610
- EXAMPLE:
611
- {
612
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
613
- }
614
-
615
- OUTPUT:
616
- {
617
- "success": true,
618
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
619
- }`,
620
-
621
- inputSchema: z.object({
622
- campaign_id: z.string().describe('UUID of the campaign to pause')
623
- }),
624
-
625
- outputSchema: z.object({
626
- success: z.boolean().describe('Whether the campaign was paused successfully'),
627
- campaign_id: z.string().describe('UUID of the paused campaign')
628
- }),
629
-
630
- integration: 'instantly' as const,
631
- method: 'pauseCampaign' as const,
632
- credentialName
633
- })
634
- }
635
-
636
- /**
637
- * Create Instantly delete campaign tool
638
- *
639
- * Permanently deletes a campaign and all associated data.
640
- *
641
- * @param credentialName - Name of credential in credentials table
642
- * @returns Tool that deletes an Instantly campaign
643
- *
644
- * @example
645
- * const deleteCampaign = createInstantlyDeleteCampaignTool('instantly-elevasis')
646
- */
647
- export function createInstantlyDeleteCampaignTool(credentialName: string): Tool {
648
- return createIntegrationTool({
649
- name: 'instantly_delete_campaign',
650
- description: `Permanently delete an Instantly campaign
651
-
652
- USE CASES:
653
- - Clean up test or draft campaigns after diagnostic runs
654
- - Remove campaigns that are no longer needed
655
- - Delete accidentally created campaigns
656
-
657
- REQUIRED PARAMETERS:
658
- - campaign_id: UUID of the campaign to delete
659
-
660
- EXAMPLE:
661
- {
662
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
663
- }
664
-
665
- OUTPUT:
666
- {
667
- "success": true,
668
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
669
- }`,
670
-
671
- inputSchema: z.object({
672
- campaign_id: z.string().describe('UUID of the campaign to delete')
673
- }),
674
-
675
- outputSchema: z.object({
676
- success: z.boolean().describe('Whether the campaign was deleted successfully'),
677
- campaign_id: z.string().describe('UUID of the deleted campaign')
678
- }),
679
-
680
- integration: 'instantly' as const,
681
- method: 'deleteCampaign' as const,
682
- credentialName
683
- })
684
- }
685
-
686
- /**
687
- * Create Instantly activate campaign tool
688
- *
689
- * Activates or resumes a paused or draft campaign to begin sending.
690
- *
691
- * @param credentialName - Name of credential in credentials table
692
- * @returns Tool that activates an Instantly campaign
693
- *
694
- * @example
695
- * const activateCampaign = createInstantlyActivateCampaignTool('instantly-elevasis')
696
- */
697
- export function createInstantlyActivateCampaignTool(credentialName: string): Tool {
698
- return createIntegrationTool({
699
- name: 'instantly_activate_campaign',
700
- description: `Activate or resume an Instantly campaign
701
-
702
- USE CASES:
703
- - Launch a newly created campaign to begin sending to enrolled leads
704
- - Resume a paused campaign after completing edits or reviews
705
- - Re-activate a campaign after resolving domain reputation issues
706
- - Start scheduled outreach at the beginning of a new period
707
-
708
- REQUIRED PARAMETERS:
709
- - campaign_id: UUID of the campaign to activate
710
-
711
- EXAMPLE:
712
- {
713
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
714
- }
715
-
716
- OUTPUT:
717
- {
718
- "success": true,
719
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
720
- }`,
721
-
722
- inputSchema: z.object({
723
- campaign_id: z.string().describe('UUID of the campaign to activate')
724
- }),
725
-
726
- outputSchema: z.object({
727
- success: z.boolean().describe('Whether the campaign was activated successfully'),
728
- campaign_id: z.string().describe('UUID of the activated campaign')
729
- }),
730
-
731
- integration: 'instantly' as const,
732
- method: 'activateCampaign' as const,
733
- credentialName
734
- })
735
- }
736
-
737
- /**
738
- * Create Instantly get campaign analytics tool
739
- *
740
- * Retrieves aggregate engagement statistics for a campaign.
741
- *
742
- * @param credentialName - Name of credential in credentials table
743
- * @returns Tool that fetches campaign-level analytics
744
- *
745
- * @example
746
- * const getAnalytics = createInstantlyGetCampaignAnalyticsTool('instantly-elevasis')
747
- */
748
- export function createInstantlyGetCampaignAnalyticsTool(credentialName: string): Tool {
749
- return createIntegrationTool({
750
- name: 'instantly_get_campaign_analytics',
751
- description: `Get aggregate analytics for an Instantly campaign
752
-
753
- USE CASES:
754
- - Review overall campaign performance including open rate, reply rate, and bounce rate
755
- - Compare send volume against replies to evaluate outreach effectiveness
756
- - Monitor unsubscribes to maintain sender reputation
757
- - Scope analytics to a date range for period-specific reporting
758
-
759
- REQUIRED PARAMETERS:
760
- - campaign_id: UUID of the campaign
761
-
762
- OPTIONAL PARAMETERS:
763
- - start_date: ISO date string to filter analytics from (e.g. "2025-01-01")
764
- - end_date: ISO date string to filter analytics to (e.g. "2025-03-31")
765
-
766
- EXAMPLE:
767
- {
768
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
769
- "start_date": "2025-01-01",
770
- "end_date": "2025-03-31"
771
- }
772
-
773
- OUTPUT:
774
- {
775
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
776
- "sent": 450,
777
- "opened": 180,
778
- "unique_opened": 160,
779
- "replied": 35,
780
- "unique_replied": 30,
781
- "bounced": 5,
782
- "unsubscribed": 2
783
- }`,
784
-
785
- inputSchema: z.object({
786
- campaign_id: z.string().describe('UUID of the campaign to fetch analytics for'),
787
- start_date: z.string().optional().describe('Start date for analytics range (ISO date string, e.g. "2025-01-01")'),
788
- end_date: z.string().optional().describe('End date for analytics range (ISO date string, e.g. "2025-03-31")')
789
- }),
790
-
791
- outputSchema: z.object({
792
- campaign_id: z.string().describe('Campaign UUID'),
793
- sent: z.number().describe('Total emails sent'),
794
- opened: z.number().describe('Total open events'),
795
- unique_opened: z.number().describe('Unique leads who opened'),
796
- replied: z.number().describe('Total reply events'),
797
- unique_replied: z.number().describe('Unique leads who replied'),
798
- bounced: z.number().describe('Total bounced emails'),
799
- unsubscribed: z.number().describe('Total unsubscribes')
800
- }),
801
-
802
- integration: 'instantly' as const,
803
- method: 'getCampaignAnalytics' as const,
804
- credentialName
805
- })
806
- }
807
-
808
- /**
809
- * Create Instantly get step analytics tool
810
- *
811
- * Retrieves per-step and per-variant analytics for a campaign sequence.
812
- *
813
- * @param credentialName - Name of credential in credentials table
814
- * @returns Tool that fetches step-level analytics
815
- *
816
- * @example
817
- * const getStepAnalytics = createInstantlyGetStepAnalyticsTool('instantly-elevasis')
818
- */
819
- export function createInstantlyGetStepAnalyticsTool(credentialName: string): Tool {
820
- return createIntegrationTool({
821
- name: 'instantly_get_step_analytics',
822
- description: `Get per-step and per-variant analytics for an Instantly campaign
823
-
824
- USE CASES:
825
- - Identify which sequence step has the highest reply rate
826
- - Compare A/B subject line variants to determine the winning version
827
- - Diagnose a drop-off point where prospects stop engaging
828
- - Optimize multi-step sequences based on step-level performance data
829
-
830
- REQUIRED PARAMETERS:
831
- - campaign_id: UUID of the campaign
832
-
833
- EXAMPLE:
834
- {
835
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
836
- }
837
-
838
- OUTPUT:
839
- {
840
- "steps": [
841
- {
842
- "step": "1",
843
- "variant": "A",
844
- "sent": 200,
845
- "opened": 90,
846
- "unique_opened": 80,
847
- "replies": 20,
848
- "unique_replies": 18
849
- },
850
- {
851
- "step": "2",
852
- "variant": "A",
853
- "sent": 160,
854
- "opened": 55,
855
- "unique_opened": 50,
856
- "replies": 10,
857
- "unique_replies": 9
858
- }
859
- ]
860
- }`,
861
-
862
- inputSchema: z.object({
863
- campaign_id: z.string().describe('UUID of the campaign to fetch step analytics for')
864
- }),
865
-
866
- outputSchema: z.object({
867
- steps: z
868
- .array(
869
- z.object({
870
- step: z.string().describe('Step number in the sequence'),
871
- variant: z.string().describe('Variant label (e.g. "A", "B")'),
872
- sent: z.number().describe('Emails sent for this step/variant'),
873
- opened: z.number().describe('Total open events'),
874
- unique_opened: z.number().describe('Unique leads who opened'),
875
- replies: z.number().describe('Total reply events'),
876
- unique_replies: z.number().describe('Unique leads who replied')
877
- })
878
- )
879
- .describe('Per-step, per-variant analytics entries')
880
- }),
881
-
882
- integration: 'instantly' as const,
883
- method: 'getStepAnalytics' as const,
884
- credentialName
885
- })
886
- }
887
-
888
- /**
889
- * Create Instantly bulk add leads tool
890
- *
891
- * Adds up to 1000 leads to a campaign in a single request.
892
- *
893
- * @param credentialName - Name of credential in credentials table
894
- * @returns Tool that bulk-uploads leads to an Instantly campaign
895
- *
896
- * @example
897
- * const bulkAddLeads = createInstantlyBulkAddLeadsTool('instantly-elevasis')
898
- */
899
- export function createInstantlyBulkAddLeadsTool(credentialName: string): Tool {
900
- return createIntegrationTool({
901
- name: 'instantly_bulk_add_leads',
902
- description: `Bulk upload up to 1000 leads to an Instantly campaign
903
-
904
- USE CASES:
905
- - Import a large list of qualified prospects into a campaign at once
906
- - Enroll leads exported from a CRM or enrichment tool into outreach
907
- - Upload leads with custom variables for deep personalization
908
- - Add leads with website and company data for context-aware sequences
909
-
910
- REQUIRED PARAMETERS:
911
- - campaign_id: UUID of the campaign to add leads to
912
- - leads: Array of lead objects (1–1000 leads)
913
-
914
- LEAD OBJECT FIELDS:
915
- - email: (required) Email address of the lead
916
- - first_name: (optional) First name for personalization
917
- - last_name: (optional) Last name for personalization
918
- - company_name: (optional) Company name for personalization
919
- - website: (optional) Company website URL
920
- - custom_variables: (optional) Key-value map of custom merge fields
921
-
922
- EXAMPLE:
923
- {
924
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
925
- "leads": [
926
- {
927
- "email": "ceo@agency.com",
928
- "first_name": "Sarah",
929
- "last_name": "Chen",
930
- "company_name": "Growth Agency",
931
- "website": "https://growthagency.com",
932
- "custom_variables": { "pain_point": "manual lead gen" }
933
- }
934
- ]
935
- }
936
-
937
- OUTPUT:
938
- {
939
- "success": true,
940
- "added_count": 1,
941
- "failed_count": 0
942
- }`,
943
-
944
- inputSchema: z.object({
945
- campaign_id: z.string().describe('UUID of the campaign to add leads to'),
946
- leads: z
947
- .array(
948
- z.object({
949
- email: EmailSchema.describe('Email address of the lead'),
950
- first_name: z.string().optional().describe('First name for personalization'),
951
- last_name: z.string().optional().describe('Last name for personalization'),
952
- company_name: z.string().optional().describe('Company name for personalization'),
953
- website: z.string().optional().describe('Company website URL'),
954
- custom_variables: z
955
- .record(z.string(), z.string())
956
- .optional()
957
- .describe('Key-value map of custom merge field values')
958
- })
959
- )
960
- .min(1)
961
- .max(1000)
962
- .describe('Array of leads to upload (1–1000)')
963
- }),
964
-
965
- outputSchema: z.object({
966
- success: z.boolean().describe('True if all leads were added without errors'),
967
- added_count: z.number().describe('Number of leads successfully added'),
968
- failed_count: z.number().describe('Number of leads that failed to add'),
969
- errors: z
970
- .array(
971
- z.object({
972
- email: z.string().describe('Email of the lead that failed'),
973
- error: z.string().describe('Error message for this lead')
974
- })
975
- )
976
- .optional()
977
- .describe('Per-lead error details when failures occurred')
978
- }),
979
-
980
- integration: 'instantly' as const,
981
- method: 'bulkAddLeads' as const,
982
- credentialName
983
- })
984
- }
985
-
986
- /**
987
- * Create Instantly get account health tool
988
- *
989
- * Lists email sending accounts with warmup status and health scores.
990
- *
991
- * @param credentialName - Name of credential in credentials table
992
- * @returns Tool that retrieves account health data
993
- *
994
- * @example
995
- * const getAccountHealth = createInstantlyGetAccountHealthTool('instantly-elevasis')
996
- */
997
- export function createInstantlyGetAccountHealthTool(credentialName: string): Tool {
998
- return createIntegrationTool({
999
- name: 'instantly_get_account_health',
1000
- description: `List email accounts with health status and warmup information
1001
-
1002
- USE CASES:
1003
- - Audit all connected sending accounts before launching a campaign
1004
- - Identify accounts with low health scores that may cause deliverability issues
1005
- - Verify warmup status to ensure accounts are ready for full sending volume
1006
- - Monitor account portfolio health as part of regular sender hygiene checks
1007
-
1008
- OPTIONAL PARAMETERS:
1009
- - limit: Number of accounts to return per page
1010
- - starting_after: Cursor from previous response for pagination
1011
-
1012
- EXAMPLE:
1013
- {
1014
- "limit": 20
1015
- }
1016
-
1017
- OUTPUT:
1018
- {
1019
- "accounts": [
1020
- {
1021
- "id": "acct-abc123",
1022
- "email": "alex@elevasis.com",
1023
- "status": "active",
1024
- "warmup_enabled": true,
1025
- "health_score": 92
1026
- }
1027
- ],
1028
- "next_starting_after": "cursor-token"
1029
- }`,
1030
-
1031
- inputSchema: z.object({
1032
- limit: z.number().min(1).max(100).optional().describe('Number of accounts per page'),
1033
- starting_after: z
1034
- .string()
1035
- .optional()
1036
- .describe('Cursor for pagination (from next_starting_after in previous response)')
1037
- }),
1038
-
1039
- outputSchema: z.object({
1040
- accounts: z
1041
- .array(
1042
- z.object({
1043
- id: z.string().describe('Account ID'),
1044
- email: z.string().describe('Sending email address'),
1045
- status: z.string().describe('Account status'),
1046
- warmup_enabled: z.boolean().describe('Whether warmup is active for this account'),
1047
- health_score: z.number().optional().describe('Health score (0–100)')
1048
- })
1049
- )
1050
- .describe('Array of sending accounts with health data'),
1051
- next_starting_after: z.string().optional().describe('Cursor for next page (undefined = no more pages)')
1052
- }),
1053
-
1054
- integration: 'instantly' as const,
1055
- method: 'getAccountHealth' as const,
1056
- credentialName
1057
- })
1058
- }
1059
-
1060
- /**
1061
- * Create Instantly create campaign tool
1062
- *
1063
- * Creates a new campaign in Instantly with optional sequences and sending configuration.
1064
- *
1065
- * @param credentialName - Name of credential in credentials table
1066
- * @returns Tool that creates a new Instantly campaign
1067
- *
1068
- * @example
1069
- * const createCampaign = createInstantlyCreateCampaignTool('instantly-elevasis')
1070
- */
1071
- export function createInstantlyCreateCampaignTool(credentialName: string): Tool {
1072
- return createIntegrationTool({
1073
- name: 'instantly_create_campaign',
1074
- description: `Create a new Instantly campaign
1075
-
1076
- USE CASES:
1077
- - Set up a new cold outreach campaign with custom sequences
1078
- - Create a campaign with predefined email steps and A/B variants
1079
- - Configure sending limits and reply handling at creation time
1080
- - Prepare a campaign shell to be populated with leads and activated later
1081
-
1082
- REQUIRED PARAMETERS:
1083
- - name: Display name of the new campaign
1084
-
1085
- OPTIONAL PARAMETERS:
1086
- - sequences: Array of sequence objects with email steps and optional A/B variants
1087
- - email_list: Array of sending account emails to use for the campaign
1088
- - daily_limit: Maximum emails to send per day
1089
- - stop_on_reply: Whether to stop the sequence when a lead replies
1090
- - stop_on_auto_reply: Whether to stop on auto-replies
1091
- - track_opens: Whether to track email opens
1092
- - track_clicks: Whether to track link clicks
1093
- - text_only: Whether to send text-only emails (no HTML)
1094
-
1095
- EXAMPLE (Simple Campaign):
1096
- {
1097
- "name": "Cold Outreach Q2 2025",
1098
- "daily_limit": 50,
1099
- "stop_on_reply": true
1100
- }
1101
-
1102
- EXAMPLE (Campaign with Sequence):
1103
- {
1104
- "name": "Agency Outreach",
1105
- "sequences": [
1106
- {
1107
- "steps": [
1108
- {
1109
- "subject": "Quick question about {{company_name}}",
1110
- "body": "Hi {{first_name}}, I noticed..."
1111
- },
1112
- {
1113
- "subject": "Following up",
1114
- "body": "Hi {{first_name}}, just wanted to circle back..."
1115
- }
1116
- ]
1117
- }
1118
- ],
1119
- "daily_limit": 30,
1120
- "stop_on_reply": true
1121
- }
1122
-
1123
- OUTPUT:
1124
- {
1125
- "success": true,
1126
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
1127
- "name": "Cold Outreach Q2 2025"
1128
- }`,
1129
-
1130
- inputSchema: z.object({
1131
- name: z.string().describe('Display name of the new campaign'),
1132
- sequences: z
1133
- .array(
1134
- z.object({
1135
- steps: z.array(
1136
- z.object({
1137
- subject: z.string().describe('Email subject line for this step'),
1138
- body: z.string().describe('Email body for this step'),
1139
- variants: z
1140
- .array(
1141
- z.object({
1142
- subject: z.string().describe('A/B variant subject line'),
1143
- body: z.string().describe('A/B variant body')
1144
- })
1145
- )
1146
- .optional()
1147
- .describe('A/B test variants for this step')
1148
- })
1149
- )
1150
- })
1151
- )
1152
- .optional()
1153
- .describe('Campaign sequences with email steps'),
1154
- email_list: z.array(z.string()).optional().describe('Sending account emails to use for the campaign'),
1155
- daily_limit: z.number().int().min(1).optional().describe('Maximum emails to send per day'),
1156
- stop_on_reply: z.boolean().optional().describe('Whether to stop the sequence when a lead replies'),
1157
- stop_on_auto_reply: z.boolean().optional().describe('Whether to stop the sequence on auto-replies'),
1158
- track_opens: z.boolean().optional().describe('Whether to track email opens'),
1159
- track_clicks: z.boolean().optional().describe('Whether to track link clicks'),
1160
- text_only: z.boolean().optional().describe('Whether to send text-only emails (no HTML)')
1161
- }),
1162
-
1163
- outputSchema: z.object({
1164
- success: z.boolean().describe('Whether the campaign was created successfully'),
1165
- campaign_id: z.string().describe('UUID of the newly created campaign'),
1166
- name: z.string().describe('Name of the created campaign')
1167
- }),
1168
-
1169
- integration: 'instantly' as const,
1170
- method: 'createCampaign' as const,
1171
- credentialName
1172
- })
1173
- }
1174
-
1175
- /**
1176
- * Create Instantly create inbox test tool
1177
- *
1178
- * Initiates an inbox placement test to diagnose deliverability for a sending account.
1179
- *
1180
- * @param credentialName - Name of credential in credentials table
1181
- * @returns Tool that creates an Instantly inbox placement test
1182
- *
1183
- * @example
1184
- * const createInboxTest = createInstantlyCreateInboxTestTool('instantly-elevasis')
1185
- */
1186
- export function createInstantlyCreateInboxTestTool(credentialName: string): Tool {
1187
- return createIntegrationTool({
1188
- name: 'instantly_create_inbox_test',
1189
- description: `Create an inbox placement test for an Instantly sending account
1190
-
1191
- USE CASES:
1192
- - Verify deliverability before launching a high-volume campaign
1193
- - Diagnose spam filtering issues on a specific sending account
1194
- - Test whether custom subject lines land in inbox or spam
1195
- - Monitor placement across Gmail, Outlook, and other major providers
1196
-
1197
- REQUIRED PARAMETERS:
1198
- - email_account: The sending account to test (must be connected to workspace)
1199
-
1200
- OPTIONAL PARAMETERS:
1201
- - subject: Custom subject line to use in the test email
1202
- - body: Custom body text to use in the test email
1203
-
1204
- EXAMPLE:
1205
- {
1206
- "email_account": "alex@elevasis.com",
1207
- "subject": "Quick question about your agency",
1208
- "body": "Hi, I wanted to reach out about..."
1209
- }
1210
-
1211
- OUTPUT:
1212
- {
1213
- "success": true,
1214
- "test_id": "test-abc123",
1215
- "status": "pending"
1216
- }`,
1217
-
1218
- inputSchema: z.object({
1219
- email_account: z.string().describe('Sending account email address to test (must be connected to workspace)'),
1220
- subject: z.string().optional().describe('Custom subject line for the test email'),
1221
- body: z.string().optional().describe('Custom body text for the test email')
1222
- }),
1223
-
1224
- outputSchema: z.object({
1225
- success: z.boolean().describe('Whether the test was created successfully'),
1226
- test_id: z.string().describe('Unique ID of the inbox placement test'),
1227
- status: z.string().describe('Initial test status (e.g. "pending")')
1228
- }),
1229
-
1230
- integration: 'instantly' as const,
1231
- method: 'createInboxTest' as const,
1232
- credentialName
1233
- })
1234
- }
1235
-
1236
- /**
1237
- * Create Instantly get daily campaign analytics tool
1238
- *
1239
- * Retrieves day-by-day engagement breakdown for campaigns.
1240
- *
1241
- * @param credentialName - Name of credential in credentials table
1242
- * @returns Tool that fetches daily campaign analytics
1243
- *
1244
- * @example
1245
- * const getDailyAnalytics = createInstantlyGetDailyCampaignAnalyticsTool('instantly-elevasis')
1246
- */
1247
- export function createInstantlyGetDailyCampaignAnalyticsTool(credentialName: string): Tool {
1248
- return createIntegrationTool({
1249
- name: 'instantly_get_daily_campaign_analytics',
1250
- description: `Get day-by-day analytics breakdown for Instantly campaigns
1251
-
1252
- USE CASES:
1253
- - Analyze send and open trends over a date range to identify patterns
1254
- - Spot peak engagement days to optimize future send scheduling
1255
- - Compare daily click and reply volumes across a campaign period
1256
- - Get cross-campaign aggregate metrics when no campaign_id is specified
1257
-
1258
- OPTIONAL PARAMETERS:
1259
- - campaign_id: Filter analytics to a specific campaign UUID (omit for all campaigns)
1260
- - start_date: Start of date range (ISO date, e.g. "2025-01-01")
1261
- - end_date: End of date range (ISO date, e.g. "2025-03-31")
1262
-
1263
- EXAMPLE (Single Campaign):
1264
- {
1265
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
1266
- "start_date": "2025-01-01",
1267
- "end_date": "2025-01-31"
1268
- }
1269
-
1270
- EXAMPLE (All Campaigns):
1271
- {
1272
- "start_date": "2025-01-01",
1273
- "end_date": "2025-01-31"
1274
- }
1275
-
1276
- OUTPUT:
1277
- {
1278
- "data": [
1279
- {
1280
- "date": "2025-01-15",
1281
- "sent": 120,
1282
- "opened": 48,
1283
- "unique_opened": 42,
1284
- "replied": 8,
1285
- "unique_replied": 7,
1286
- "bounced": 1,
1287
- "clicks": 12,
1288
- "unique_clicks": 10
1289
- }
1290
- ]
1291
- }`,
1292
-
1293
- inputSchema: z.object({
1294
- campaign_id: z.string().optional().describe('Campaign UUID to filter analytics (omit to get all campaigns)'),
1295
- start_date: z.string().optional().describe('Start of date range (ISO date, e.g. "2025-01-01")'),
1296
- end_date: z.string().optional().describe('End of date range (ISO date, e.g. "2025-03-31")')
1297
- }),
1298
-
1299
- outputSchema: z.object({
1300
- data: z
1301
- .array(
1302
- z.object({
1303
- date: z.string().describe('Date (YYYY-MM-DD)'),
1304
- sent: z.number().describe('Emails sent on this date'),
1305
- opened: z.number().describe('Total open events'),
1306
- unique_opened: z.number().describe('Unique leads who opened'),
1307
- replied: z.number().describe('Total reply events'),
1308
- unique_replied: z.number().describe('Unique leads who replied'),
1309
- bounced: z.number().describe('Emails bounced'),
1310
- clicks: z.number().describe('Total link click events'),
1311
- unique_clicks: z.number().describe('Unique leads who clicked')
1312
- })
1313
- )
1314
- .describe('Array of daily analytics entries')
1315
- }),
1316
-
1317
- integration: 'instantly' as const,
1318
- method: 'getDailyCampaignAnalytics' as const,
1319
- credentialName
1320
- })
1321
- }
1322
-
1323
- /**
1324
- * Create Instantly list leads tool
1325
- *
1326
- * Lists leads with optional filtering by campaign or email and cursor pagination.
1327
- *
1328
- * @param credentialName - Name of credential in credentials table
1329
- * @returns Tool that lists Instantly leads
1330
- *
1331
- * @example
1332
- * const listLeads = createInstantlyListLeadsTool('instantly-elevasis')
1333
- */
1334
- export function createInstantlyListLeadsTool(credentialName: string): Tool {
1335
- return createIntegrationTool({
1336
- name: 'instantly_list_leads',
1337
- description: `List leads in Instantly with optional filtering and pagination
1338
-
1339
- USE CASES:
1340
- - Retrieve all leads enrolled in a specific campaign for auditing
1341
- - Look up a specific lead by email address to check their status
1342
- - Paginate through a large lead list using cursor-based pagination
1343
- - Review lead metadata including status, timestamps, and campaign assignment
1344
-
1345
- OPTIONAL PARAMETERS:
1346
- - campaign_id: Filter leads by campaign UUID
1347
- - email: Filter by specific lead email address
1348
- - limit: Number of leads per page
1349
- - starting_after: Cursor from previous response for pagination
1350
-
1351
- NOTE: This uses a POST endpoint per Instantly API design (complex filter arguments).
1352
-
1353
- EXAMPLE (Campaign Leads):
1354
- {
1355
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
1356
- "limit": 50
1357
- }
1358
-
1359
- EXAMPLE (Single Lead Lookup):
1360
- {
1361
- "email": "prospect@agency.com"
1362
- }
1363
-
1364
- OUTPUT:
1365
- {
1366
- "items": [
1367
- {
1368
- "id": "lead-abc123",
1369
- "email": "prospect@agency.com",
1370
- "first_name": "John",
1371
- "last_name": "Smith",
1372
- "company_name": "Acme Agency",
1373
- "status": "active",
1374
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
1375
- "timestamp_created": "2025-01-15T09:00:00Z"
1376
- }
1377
- ],
1378
- "next_starting_after": "cursor-token"
1379
- }`,
1380
-
1381
- inputSchema: z.object({
1382
- campaign_id: z.string().optional().describe('Filter leads by campaign UUID'),
1383
- email: z.string().optional().describe('Filter by specific lead email address'),
1384
- limit: z.number().min(1).max(100).optional().describe('Number of leads per page'),
1385
- starting_after: z
1386
- .string()
1387
- .optional()
1388
- .describe('Cursor for pagination (from next_starting_after in previous response)')
1389
- }),
1390
-
1391
- outputSchema: z.object({
1392
- items: z
1393
- .array(
1394
- z.object({
1395
- id: z.string().describe('Lead ID'),
1396
- email: z.string().describe('Lead email address'),
1397
- first_name: z.string().optional().describe('Lead first name'),
1398
- last_name: z.string().optional().describe('Lead last name'),
1399
- company_name: z.string().optional().describe('Lead company name'),
1400
- status: z.string().describe('Lead status in campaign'),
1401
- campaign_id: z.string().optional().describe('Campaign this lead belongs to'),
1402
- timestamp_created: z.string().optional().describe('Lead creation timestamp')
1403
- })
1404
- )
1405
- .describe('Array of leads'),
1406
- next_starting_after: z.string().optional().describe('Cursor for next page (undefined = no more pages)')
1407
- }),
1408
-
1409
- integration: 'instantly' as const,
1410
- method: 'listLeads' as const,
1411
- credentialName
1412
- })
1413
- }
1414
-
1415
- /**
1416
- * Create Instantly bulk delete leads tool
1417
- *
1418
- * Deletes leads in bulk by IDs, campaign, or list with an optional limit.
1419
- *
1420
- * @param credentialName - Name of credential in credentials table
1421
- * @returns Tool that bulk-deletes Instantly leads
1422
- *
1423
- * @example
1424
- * const bulkDeleteLeads = createInstantlyBulkDeleteLeadsTool('instantly-elevasis')
1425
- */
1426
- export function createInstantlyBulkDeleteLeadsTool(credentialName: string): Tool {
1427
- return createIntegrationTool({
1428
- name: 'instantly_bulk_delete_leads',
1429
- description: `Bulk delete leads from Instantly by IDs, campaign, or list
1430
-
1431
- USE CASES:
1432
- - Remove a batch of disqualified leads from a campaign at once
1433
- - Clean up leads from a completed campaign before archiving
1434
- - Delete leads from a specific list to maintain database hygiene
1435
- - Remove a set of specific leads by their IDs after a data audit
1436
-
1437
- OPTIONAL PARAMETERS (at least one filter recommended):
1438
- - ids: Array of specific lead IDs to delete
1439
- - campaign_id: Delete all leads from this campaign
1440
- - list_id: Delete all leads from this list
1441
- - limit: Maximum number of leads to delete in this operation (1-10000)
1442
-
1443
- EXAMPLE (Delete by IDs):
1444
- {
1445
- "ids": ["lead-abc123", "lead-def456"]
1446
- }
1447
-
1448
- EXAMPLE (Delete from Campaign):
1449
- {
1450
- "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
1451
- "limit": 100
1452
- }
1453
-
1454
- OUTPUT:
1455
- {
1456
- "deleted_count": 42
1457
- }`,
1458
-
1459
- inputSchema: z.object({
1460
- ids: z.array(z.string()).optional().describe('Specific lead IDs to delete'),
1461
- campaign_id: z.string().optional().describe('Delete leads from this campaign'),
1462
- list_id: z.string().optional().describe('Delete leads from this list'),
1463
- limit: z.number().int().min(1).optional().describe('Maximum number of leads to delete')
1464
- }),
1465
-
1466
- outputSchema: z.object({
1467
- deleted_count: z.number().describe('Number of leads deleted')
1468
- }),
1469
-
1470
- integration: 'instantly' as const,
1471
- method: 'bulkDeleteLeads' as const,
1472
- credentialName
1473
- })
1474
- }
1
+ import { z } from 'zod'
2
+ import { createIntegrationTool } from '../../../tool'
3
+ import type { Tool } from '../../../../types'
4
+ import { EmailSchema } from '../../../../../../../platform/utils/validation'
5
+
6
+ /**
7
+ * Create Instantly send reply tool
8
+ *
9
+ * Sends a reply to an email thread maintaining proper threading.
10
+ *
11
+ * @param credentialName - Name of credential in credentials table
12
+ * @returns Tool that sends email replies via Instantly
13
+ *
14
+ * @example
15
+ * const sendReply = createInstantlySendReplyTool('instantly-elevasis')
16
+ */
17
+ export function createInstantlySendReplyTool(credentialName: string): Tool {
18
+ return createIntegrationTool({
19
+ name: 'instantly_send_reply',
20
+ description: `Send a reply to an email thread via Instantly.ai
21
+
22
+ USE CASES:
23
+ - Send a personalized reply to a prospect who responded to your outreach campaign
24
+ - Maintain email threading for organized conversations
25
+ - Schedule replies for future delivery
26
+
27
+ REQUIRED PARAMETERS:
28
+ - eaccount: Email account that will send the reply (must be connected to workspace)
29
+ - reply_to_uuid: UUID of the email you are replying to (from webhook payload)
30
+ - subject: Subject line of the reply (typically "Re: Original Subject")
31
+ - body: Email body (must provide either text or html)
32
+
33
+ OPTIONAL PARAMETERS:
34
+ - timestamp: ISO timestamp to schedule reply for future
35
+
36
+ EXAMPLE:
37
+ {
38
+ "eaccount": "alex@elevasis.com",
39
+ "reply_to_uuid": "123e4567-e89b-12d3-a456-426614174000",
40
+ "subject": "Re: Automate your client acquisition",
41
+ "body": {
42
+ "text": "Thanks for your interest! Here's my calendar: https://calendly.com/..."
43
+ }
44
+ }
45
+
46
+ OUTPUT:
47
+ {
48
+ "success": true,
49
+ "email_id": "email-abc123",
50
+ "thread_id": "thread-xyz789",
51
+ "sent_at": "2025-12-22T14:30:00Z"
52
+ }`,
53
+
54
+ inputSchema: z.object({
55
+ eaccount: z.string().describe('Email account that will send the reply (must be connected to workspace)'),
56
+ reply_to_uuid: z.string().describe('UUID of the email you are replying to (from webhook payload)'),
57
+ subject: z.string().describe('Subject line of the reply (typically "Re: Original Subject")'),
58
+ body: z
59
+ .object({
60
+ text: z.string().optional().describe('Plain text email body'),
61
+ html: z.string().optional().describe('HTML email body')
62
+ })
63
+ .refine((data) => data.text || data.html, {
64
+ message: 'Must provide either text or html body'
65
+ }),
66
+ timestamp: z.string().optional().describe('ISO timestamp to schedule reply for future (optional)')
67
+ }),
68
+
69
+ outputSchema: z.object({
70
+ success: z.boolean().describe('Whether reply was sent successfully'),
71
+ email_id: z.string().describe('ID of the sent email'),
72
+ thread_id: z.string().describe('Thread ID for conversation tracking'),
73
+ sent_at: z.string().describe('Timestamp when email was sent')
74
+ }),
75
+
76
+ integration: 'instantly' as const,
77
+ method: 'sendReply' as const,
78
+ credentialName
79
+ })
80
+ }
81
+
82
+ /**
83
+ * Create Instantly remove from subsequence tool
84
+ *
85
+ * Removes a lead from a campaign sequence to stop further outreach.
86
+ *
87
+ * @param credentialName - Name of credential in credentials table
88
+ * @returns Tool that removes leads from campaigns
89
+ *
90
+ * @example
91
+ * const removeFromCampaign = createInstantlyRemoveFromSubsequenceTool('instantly-elevasis')
92
+ */
93
+ export function createInstantlyRemoveFromSubsequenceTool(credentialName: string): Tool {
94
+ return createIntegrationTool({
95
+ name: 'instantly_remove_from_subsequence',
96
+ description: `Remove a lead from an Instantly campaign subsequence
97
+
98
+ USE CASES:
99
+ - Stop a lead from receiving further emails in a campaign
100
+ - Use after positive reply, hard-no, or disqualification
101
+ - Prevent over-emailing engaged prospects
102
+
103
+ REQUIRED PARAMETERS:
104
+ - lead_email: Email address of the lead to remove
105
+ - campaign_id: Campaign ID to remove lead from
106
+
107
+ EXAMPLE:
108
+ {
109
+ "lead_email": "prospect@agency.com",
110
+ "campaign_id": "campaign-123"
111
+ }
112
+
113
+ OUTPUT:
114
+ {
115
+ "success": true,
116
+ "lead_email": "prospect@agency.com",
117
+ "campaign_id": "campaign-123"
118
+ }`,
119
+
120
+ inputSchema: z.object({
121
+ lead_email: EmailSchema.describe('Email address of the lead to remove'),
122
+ campaign_id: z.string().describe('Campaign ID to remove lead from')
123
+ }),
124
+
125
+ outputSchema: z.object({
126
+ success: z.boolean().describe('Whether removal was successful'),
127
+ lead_email: z.string().describe('Email of the removed lead'),
128
+ campaign_id: z.string().describe('Campaign ID lead was removed from')
129
+ }),
130
+
131
+ integration: 'instantly' as const,
132
+ method: 'removeFromSubsequence' as const,
133
+ credentialName
134
+ })
135
+ }
136
+
137
+ /**
138
+ * Create Instantly get emails tool
139
+ *
140
+ * Fetches email data from Instantly workspace with optional filtering and pagination.
141
+ *
142
+ * @param credentialName - Name of credential in credentials table
143
+ * @returns Tool that retrieves email data
144
+ */
145
+ export function createInstantlyGetEmailsTool(credentialName: string): Tool {
146
+ return createIntegrationTool({
147
+ name: 'instantly_get_emails',
148
+ description: `Get emails from Instantly workspace
149
+
150
+ USE CASES:
151
+ - Fetch a specific email by ID for reply processing
152
+ - Retrieve full email threads by thread ID
153
+ - Filter emails by campaign, lead, or type
154
+ - List recent emails with cursor pagination
155
+
156
+ OPTIONAL PARAMETERS:
157
+ - email_id: Specific email ID to fetch (returns single email)
158
+ - search: Email address OR "thread:{thread_id}" for thread retrieval
159
+ - campaign_id: Filter by campaign UUID
160
+ - lead: Filter by lead email address
161
+ - email_type: Filter by type (received, sent, manual)
162
+ - eaccount: Filter by sending account (comma-separated)
163
+ - sort_order: Sort by creation date (asc, desc; default: desc)
164
+ - preview_only: Return preview only (lighter response)
165
+ - is_unread: Filter by unread status
166
+ - limit: Items per page (1-100)
167
+ - starting_after: Cursor for pagination (from next_starting_after in previous response)
168
+
169
+ EXAMPLE (Single Email):
170
+ {
171
+ "email_id": "email-abc123"
172
+ }
173
+
174
+ EXAMPLE (Thread Retrieval):
175
+ {
176
+ "search": "thread:019a449c-f57a-73b2-91b5-75537ca85008",
177
+ "sort_order": "asc",
178
+ "limit": 50
179
+ }
180
+
181
+ EXAMPLE (Lead Emails in Campaign):
182
+ {
183
+ "lead": "jondoe@example.com",
184
+ "campaign_id": "019a449c-f57a-73b2-91b5-754f1fca9f44",
185
+ "sort_order": "asc"
186
+ }
187
+
188
+ OUTPUT:
189
+ {
190
+ "emails": [...email data...],
191
+ "total_count": 3,
192
+ "next_starting_after": "cursor-token-or-undefined"
193
+ }`,
194
+
195
+ inputSchema: z.object({
196
+ email_id: z.string().optional().describe('Specific email ID to fetch'),
197
+ search: z
198
+ .string()
199
+ .optional()
200
+ .describe('Search query: email address or "thread:{thread_id}" for thread retrieval'),
201
+ campaign_id: z.string().optional().describe('Filter by campaign UUID'),
202
+ lead: z.string().optional().describe('Filter by lead email address'),
203
+ email_type: z.enum(['received', 'sent', 'manual']).optional().describe('Filter by email type'),
204
+ eaccount: z.string().optional().describe('Filter by sending account (comma-separated)'),
205
+ sort_order: z.enum(['asc', 'desc']).optional().describe('Sort order by creation date (default: desc)'),
206
+ preview_only: z.boolean().optional().describe('Return preview only (lighter response)'),
207
+ is_unread: z.boolean().optional().describe('Filter by unread status'),
208
+ limit: z.number().min(1).max(100).optional().describe('Items per page (1-100)'),
209
+ starting_after: z.string().optional().describe('Cursor for pagination (from next_starting_after)')
210
+ }),
211
+
212
+ outputSchema: z.object({
213
+ emails: z.array(z.unknown()).describe('Array of email data'),
214
+ total_count: z.number().describe('Count of emails returned'),
215
+ next_starting_after: z.string().optional().describe('Cursor for next page (undefined = no more)')
216
+ }),
217
+
218
+ integration: 'instantly' as const,
219
+ method: 'getEmails' as const,
220
+ credentialName
221
+ })
222
+ }
223
+
224
+ /**
225
+ * Create Instantly update interest status tool
226
+ *
227
+ * Updates the interest status of a lead, which can stop email sequences,
228
+ * mark leads as interested, or reset to default status.
229
+ *
230
+ * @param credentialName - Name of credential in credentials table
231
+ * @returns Tool that updates lead interest status
232
+ *
233
+ * @example
234
+ * const updateStatus = createInstantlyUpdateInterestStatusTool('instantly-elevasis')
235
+ */
236
+ export function createInstantlyUpdateInterestStatusTool(credentialName: string): Tool {
237
+ return createIntegrationTool({
238
+ name: 'instantly_update_interest_status',
239
+ description: `Update interest status of a lead in Instantly
240
+
241
+ USE CASES:
242
+ - Stop email sequence for leads who reply with "unsubscribe" or "not interested" (set interest_value: -1)
243
+ - Mark engaged leads as interested for prioritization (set interest_value: 1)
244
+ - Reset lead status back to default (set interest_value: 0)
245
+ - Comply with opt-out requests to protect sender reputation
246
+
247
+ INTEREST VALUES:
248
+ - 1: Interested - Marks lead as interested
249
+ - 0: Lead (default) - Resets to default status
250
+ - -1: Not Interested - STOPS sequence (no more emails sent)
251
+
252
+ REQUIRED PARAMETERS:
253
+ - lead_email: Email address of the lead
254
+ - interest_value: Status value (1, 0, or -1)
255
+
256
+ OPTIONAL PARAMETERS:
257
+ - campaign_id: Limit status update to specific campaign (UUID)
258
+ - disable_auto_interest: Disable AI auto-tagging for this lead
259
+
260
+ EXAMPLE (Stop Sequence):
261
+ {
262
+ "lead_email": "prospect@agency.com",
263
+ "interest_value": -1
264
+ }
265
+
266
+ EXAMPLE (Mark Interested in Specific Campaign):
267
+ {
268
+ "lead_email": "prospect@agency.com",
269
+ "interest_value": 1,
270
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
271
+ }
272
+
273
+ OUTPUT:
274
+ {
275
+ "success": true,
276
+ "lead_email": "prospect@agency.com"
277
+ }`,
278
+
279
+ inputSchema: z.object({
280
+ lead_email: EmailSchema.describe('Email address of the lead'),
281
+ interest_value: z
282
+ .number()
283
+ .int()
284
+ .min(-1)
285
+ .max(1)
286
+ .describe('Interest status: 1 (interested), 0 (default), -1 (not interested - stops sequence)'),
287
+ campaign_id: z.string().optional().describe('Campaign ID to limit status update to (UUID)'),
288
+ disable_auto_interest: z.boolean().optional().describe('Disable AI auto-tagging for this lead')
289
+ }),
290
+
291
+ outputSchema: z.object({
292
+ success: z.boolean().describe('Whether status update was successful'),
293
+ lead_email: z.string().describe('Email of the updated lead')
294
+ }),
295
+
296
+ integration: 'instantly' as const,
297
+ method: 'updateInterestStatus' as const,
298
+ credentialName
299
+ })
300
+ }
301
+
302
+ /**
303
+ * Create Instantly add to campaign tool
304
+ *
305
+ * Adds leads to an Instantly campaign to begin the email sequence.
306
+ *
307
+ * @param credentialName - Name of credential in credentials table
308
+ * @returns Tool that adds leads to a campaign
309
+ *
310
+ * @example
311
+ * const addToCampaign = createInstantlyAddToCampaignTool('instantly-elevasis')
312
+ */
313
+ export function createInstantlyAddToCampaignTool(credentialName: string): Tool {
314
+ return createIntegrationTool({
315
+ name: 'instantly_add_to_campaign',
316
+ description: `Add leads to an Instantly campaign
317
+
318
+ USE CASES:
319
+ - Add interested leads to a follow-up campaign after initial outreach
320
+ - Start a drip sequence for leads who requested more information
321
+ - Enroll new leads into automated nurture campaigns
322
+
323
+ REQUIRED PARAMETERS:
324
+ - campaign_id: UUID of the Instantly campaign to add leads to
325
+ - leads: Array of lead objects (at least one required)
326
+
327
+ LEAD OBJECT FIELDS:
328
+ - email: (required) Email address of the lead
329
+ - first_name: (optional) First name for personalization
330
+ - last_name: (optional) Last name for personalization
331
+ - company_name: (optional) Company name for personalization
332
+
333
+ IMPORTANT: When leads are added, they begin receiving the campaign sequence immediately.
334
+ "Day 0" starts at the moment of addition.
335
+
336
+ EXAMPLE:
337
+ {
338
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
339
+ "leads": [
340
+ {
341
+ "email": "prospect@agency.com",
342
+ "first_name": "John",
343
+ "last_name": "Smith",
344
+ "company_name": "Acme Agency"
345
+ }
346
+ ]
347
+ }
348
+
349
+ OUTPUT:
350
+ {
351
+ "success": true,
352
+ "added_count": 1,
353
+ "errors": null
354
+ }`,
355
+
356
+ inputSchema: z.object({
357
+ campaign_id: z.string().describe('UUID of the Instantly campaign to add leads to'),
358
+ leads: z
359
+ .array(
360
+ z.object({
361
+ email: EmailSchema.describe('Email address of the lead'),
362
+ first_name: z.string().optional().describe('First name for personalization'),
363
+ last_name: z.string().optional().describe('Last name for personalization'),
364
+ company_name: z.string().optional().describe('Company name for personalization')
365
+ })
366
+ )
367
+ .min(1)
368
+ .describe('Array of leads to add (at least one required)')
369
+ }),
370
+
371
+ outputSchema: z.object({
372
+ success: z.boolean().describe('Whether leads were added successfully'),
373
+ added_count: z.number().describe('Number of leads successfully added'),
374
+ errors: z.array(z.string()).optional().describe('Array of error messages if any failures occurred')
375
+ }),
376
+
377
+ integration: 'instantly' as const,
378
+ method: 'addToCampaign' as const,
379
+ credentialName
380
+ })
381
+ }
382
+
383
+ /**
384
+ * Create Instantly list campaigns tool
385
+ *
386
+ * Lists all campaigns in the workspace with optional filtering and pagination.
387
+ *
388
+ * @param credentialName - Name of credential in credentials table
389
+ * @returns Tool that lists Instantly campaigns
390
+ *
391
+ * @example
392
+ * const listCampaigns = createInstantlyListCampaignsTool('instantly-elevasis')
393
+ */
394
+ export function createInstantlyListCampaignsTool(credentialName: string): Tool {
395
+ return createIntegrationTool({
396
+ name: 'instantly_list_campaigns',
397
+ description: `List all campaigns in the Instantly workspace
398
+
399
+ USE CASES:
400
+ - Discover available campaigns before adding leads or fetching analytics
401
+ - Filter campaigns by status to find active or paused campaigns
402
+ - Search campaigns by name to locate a specific campaign ID
403
+ - Paginate through large campaign lists using cursor-based pagination
404
+
405
+ OPTIONAL PARAMETERS:
406
+ - limit: Number of campaigns to return per page (default: 10)
407
+ - starting_after: Cursor from previous response for pagination
408
+ - status: Filter by campaign status (e.g. "active", "paused", "completed")
409
+ - search: Search term to filter campaigns by name
410
+
411
+ EXAMPLE (List Active Campaigns):
412
+ {
413
+ "status": "active",
414
+ "limit": 20
415
+ }
416
+
417
+ EXAMPLE (Search by Name):
418
+ {
419
+ "search": "cold outreach Q1"
420
+ }
421
+
422
+ OUTPUT:
423
+ {
424
+ "campaigns": [
425
+ {
426
+ "id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
427
+ "name": "Cold Outreach Q1",
428
+ "status": "active",
429
+ "created_at": "2025-01-15T09:00:00Z"
430
+ }
431
+ ],
432
+ "next_starting_after": "cursor-token"
433
+ }`,
434
+
435
+ inputSchema: z.object({
436
+ limit: z.number().min(1).max(100).optional().describe('Number of campaigns per page (default: 10)'),
437
+ starting_after: z
438
+ .string()
439
+ .optional()
440
+ .describe('Cursor for pagination (from next_starting_after in previous response)'),
441
+ status: z.string().optional().describe('Filter by campaign status (e.g. "active", "paused", "completed")'),
442
+ search: z.string().optional().describe('Search term to filter campaigns by name')
443
+ }),
444
+
445
+ outputSchema: z.object({
446
+ campaigns: z
447
+ .array(
448
+ z.object({
449
+ id: z.string().describe('Campaign UUID'),
450
+ name: z.string().describe('Campaign name'),
451
+ status: z.string().describe('Campaign status'),
452
+ created_at: z.string().describe('Campaign creation timestamp')
453
+ })
454
+ )
455
+ .describe('Array of campaigns'),
456
+ next_starting_after: z.string().optional().describe('Cursor for next page (undefined = no more pages)')
457
+ }),
458
+
459
+ integration: 'instantly' as const,
460
+ method: 'listCampaigns' as const,
461
+ credentialName
462
+ })
463
+ }
464
+
465
+ /**
466
+ * Create Instantly get campaign tool
467
+ *
468
+ * Fetches full details for a single campaign including sequences and configuration.
469
+ *
470
+ * @param credentialName - Name of credential in credentials table
471
+ * @returns Tool that retrieves a single Instantly campaign
472
+ *
473
+ * @example
474
+ * const getCampaign = createInstantlyGetCampaignTool('instantly-elevasis')
475
+ */
476
+ export function createInstantlyGetCampaignTool(credentialName: string): Tool {
477
+ return createIntegrationTool({
478
+ name: 'instantly_get_campaign',
479
+ description: `Get full details of a specific Instantly campaign
480
+
481
+ USE CASES:
482
+ - Inspect campaign sequences and step configurations before modifying
483
+ - Verify campaign status before activating or pausing
484
+ - Retrieve sending settings such as daily limits and reply handling
485
+ - Confirm the campaign name and metadata before referencing in reports
486
+
487
+ REQUIRED PARAMETERS:
488
+ - campaign_id: UUID of the campaign to retrieve
489
+
490
+ EXAMPLE:
491
+ {
492
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
493
+ }
494
+
495
+ OUTPUT:
496
+ {
497
+ "id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
498
+ "name": "Cold Outreach Q1",
499
+ "status": "active",
500
+ "sequences": [...],
501
+ "created_at": "2025-01-15T09:00:00Z"
502
+ }`,
503
+
504
+ inputSchema: z.object({
505
+ campaign_id: z.string().describe('UUID of the campaign to retrieve')
506
+ }),
507
+
508
+ outputSchema: z.object({
509
+ id: z.string().describe('Campaign UUID'),
510
+ name: z.string().describe('Campaign name'),
511
+ status: z.string().describe('Campaign status'),
512
+ sequences: z.array(z.unknown()).describe('Campaign sequence steps'),
513
+ created_at: z.string().describe('Campaign creation timestamp')
514
+ }),
515
+
516
+ integration: 'instantly' as const,
517
+ method: 'getCampaign' as const,
518
+ credentialName
519
+ })
520
+ }
521
+
522
+ /**
523
+ * Create Instantly update campaign tool
524
+ *
525
+ * Partially updates a campaign's fields such as name, sequences, or sending limits.
526
+ *
527
+ * @param credentialName - Name of credential in credentials table
528
+ * @returns Tool that updates an Instantly campaign
529
+ *
530
+ * @example
531
+ * const updateCampaign = createInstantlyUpdateCampaignTool('instantly-elevasis')
532
+ */
533
+ export function createInstantlyUpdateCampaignTool(credentialName: string): Tool {
534
+ return createIntegrationTool({
535
+ name: 'instantly_update_campaign',
536
+ description: `Update fields on an existing Instantly campaign
537
+
538
+ USE CASES:
539
+ - Rename a campaign to reflect updated targeting or messaging
540
+ - Adjust the daily sending limit to control volume
541
+ - Replace or edit campaign sequences and email steps
542
+ - Toggle stop-on-reply to pause the sequence when a lead responds
543
+
544
+ REQUIRED PARAMETERS:
545
+ - campaign_id: UUID of the campaign to update
546
+
547
+ OPTIONAL PARAMETERS (at least one must be provided):
548
+ - name: New campaign name
549
+ - sequences: Full replacement of campaign sequences (array of step objects)
550
+ - daily_limit: Maximum emails to send per day
551
+ - stop_on_reply: Whether to stop sending when a lead replies (true/false)
552
+
553
+ EXAMPLE (Rename and Adjust Limit):
554
+ {
555
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
556
+ "name": "Cold Outreach Q2",
557
+ "daily_limit": 50
558
+ }
559
+
560
+ OUTPUT:
561
+ {
562
+ "success": true,
563
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
564
+ }`,
565
+
566
+ inputSchema: z.object({
567
+ campaign_id: z.string().describe('UUID of the campaign to update'),
568
+ name: z.string().optional().describe('New campaign name'),
569
+ sequences: z.array(z.unknown()).optional().describe('Replacement campaign sequences (array of step objects)'),
570
+ daily_limit: z.number().int().min(1).optional().describe('Maximum emails to send per day'),
571
+ stop_on_reply: z.boolean().optional().describe('Whether to stop the sequence when a lead replies')
572
+ }),
573
+
574
+ outputSchema: z.object({
575
+ success: z.boolean().describe('Whether the update was successful'),
576
+ campaign_id: z.string().describe('UUID of the updated campaign')
577
+ }),
578
+
579
+ integration: 'instantly' as const,
580
+ method: 'updateCampaign' as const,
581
+ credentialName
582
+ })
583
+ }
584
+
585
+ /**
586
+ * Create Instantly pause campaign tool
587
+ *
588
+ * Pauses an active campaign to stop email sends until reactivated.
589
+ *
590
+ * @param credentialName - Name of credential in credentials table
591
+ * @returns Tool that pauses an Instantly campaign
592
+ *
593
+ * @example
594
+ * const pauseCampaign = createInstantlyPauseCampaignTool('instantly-elevasis')
595
+ */
596
+ export function createInstantlyPauseCampaignTool(credentialName: string): Tool {
597
+ return createIntegrationTool({
598
+ name: 'instantly_pause_campaign',
599
+ description: `Pause an active Instantly campaign
600
+
601
+ USE CASES:
602
+ - Temporarily halt outreach while reviewing campaign performance
603
+ - Pause before making sequence edits to avoid sending stale content
604
+ - Stop sends during public holidays or blackout periods
605
+ - Hold sends when a domain reputation issue is detected
606
+
607
+ REQUIRED PARAMETERS:
608
+ - campaign_id: UUID of the campaign to pause
609
+
610
+ EXAMPLE:
611
+ {
612
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
613
+ }
614
+
615
+ OUTPUT:
616
+ {
617
+ "success": true,
618
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
619
+ }`,
620
+
621
+ inputSchema: z.object({
622
+ campaign_id: z.string().describe('UUID of the campaign to pause')
623
+ }),
624
+
625
+ outputSchema: z.object({
626
+ success: z.boolean().describe('Whether the campaign was paused successfully'),
627
+ campaign_id: z.string().describe('UUID of the paused campaign')
628
+ }),
629
+
630
+ integration: 'instantly' as const,
631
+ method: 'pauseCampaign' as const,
632
+ credentialName
633
+ })
634
+ }
635
+
636
+ /**
637
+ * Create Instantly delete campaign tool
638
+ *
639
+ * Permanently deletes a campaign and all associated data.
640
+ *
641
+ * @param credentialName - Name of credential in credentials table
642
+ * @returns Tool that deletes an Instantly campaign
643
+ *
644
+ * @example
645
+ * const deleteCampaign = createInstantlyDeleteCampaignTool('instantly-elevasis')
646
+ */
647
+ export function createInstantlyDeleteCampaignTool(credentialName: string): Tool {
648
+ return createIntegrationTool({
649
+ name: 'instantly_delete_campaign',
650
+ description: `Permanently delete an Instantly campaign
651
+
652
+ USE CASES:
653
+ - Clean up test or draft campaigns after diagnostic runs
654
+ - Remove campaigns that are no longer needed
655
+ - Delete accidentally created campaigns
656
+
657
+ REQUIRED PARAMETERS:
658
+ - campaign_id: UUID of the campaign to delete
659
+
660
+ EXAMPLE:
661
+ {
662
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
663
+ }
664
+
665
+ OUTPUT:
666
+ {
667
+ "success": true,
668
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
669
+ }`,
670
+
671
+ inputSchema: z.object({
672
+ campaign_id: z.string().describe('UUID of the campaign to delete')
673
+ }),
674
+
675
+ outputSchema: z.object({
676
+ success: z.boolean().describe('Whether the campaign was deleted successfully'),
677
+ campaign_id: z.string().describe('UUID of the deleted campaign')
678
+ }),
679
+
680
+ integration: 'instantly' as const,
681
+ method: 'deleteCampaign' as const,
682
+ credentialName
683
+ })
684
+ }
685
+
686
+ /**
687
+ * Create Instantly activate campaign tool
688
+ *
689
+ * Activates or resumes a paused or draft campaign to begin sending.
690
+ *
691
+ * @param credentialName - Name of credential in credentials table
692
+ * @returns Tool that activates an Instantly campaign
693
+ *
694
+ * @example
695
+ * const activateCampaign = createInstantlyActivateCampaignTool('instantly-elevasis')
696
+ */
697
+ export function createInstantlyActivateCampaignTool(credentialName: string): Tool {
698
+ return createIntegrationTool({
699
+ name: 'instantly_activate_campaign',
700
+ description: `Activate or resume an Instantly campaign
701
+
702
+ USE CASES:
703
+ - Launch a newly created campaign to begin sending to enrolled leads
704
+ - Resume a paused campaign after completing edits or reviews
705
+ - Re-activate a campaign after resolving domain reputation issues
706
+ - Start scheduled outreach at the beginning of a new period
707
+
708
+ REQUIRED PARAMETERS:
709
+ - campaign_id: UUID of the campaign to activate
710
+
711
+ EXAMPLE:
712
+ {
713
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
714
+ }
715
+
716
+ OUTPUT:
717
+ {
718
+ "success": true,
719
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
720
+ }`,
721
+
722
+ inputSchema: z.object({
723
+ campaign_id: z.string().describe('UUID of the campaign to activate')
724
+ }),
725
+
726
+ outputSchema: z.object({
727
+ success: z.boolean().describe('Whether the campaign was activated successfully'),
728
+ campaign_id: z.string().describe('UUID of the activated campaign')
729
+ }),
730
+
731
+ integration: 'instantly' as const,
732
+ method: 'activateCampaign' as const,
733
+ credentialName
734
+ })
735
+ }
736
+
737
+ /**
738
+ * Create Instantly get campaign analytics tool
739
+ *
740
+ * Retrieves aggregate engagement statistics for a campaign.
741
+ *
742
+ * @param credentialName - Name of credential in credentials table
743
+ * @returns Tool that fetches campaign-level analytics
744
+ *
745
+ * @example
746
+ * const getAnalytics = createInstantlyGetCampaignAnalyticsTool('instantly-elevasis')
747
+ */
748
+ export function createInstantlyGetCampaignAnalyticsTool(credentialName: string): Tool {
749
+ return createIntegrationTool({
750
+ name: 'instantly_get_campaign_analytics',
751
+ description: `Get aggregate analytics for an Instantly campaign
752
+
753
+ USE CASES:
754
+ - Review overall campaign performance including open rate, reply rate, and bounce rate
755
+ - Compare send volume against replies to evaluate outreach effectiveness
756
+ - Monitor unsubscribes to maintain sender reputation
757
+ - Scope analytics to a date range for period-specific reporting
758
+
759
+ REQUIRED PARAMETERS:
760
+ - campaign_id: UUID of the campaign
761
+
762
+ OPTIONAL PARAMETERS:
763
+ - start_date: ISO date string to filter analytics from (e.g. "2025-01-01")
764
+ - end_date: ISO date string to filter analytics to (e.g. "2025-03-31")
765
+
766
+ EXAMPLE:
767
+ {
768
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
769
+ "start_date": "2025-01-01",
770
+ "end_date": "2025-03-31"
771
+ }
772
+
773
+ OUTPUT:
774
+ {
775
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
776
+ "sent": 450,
777
+ "opened": 180,
778
+ "unique_opened": 160,
779
+ "replied": 35,
780
+ "unique_replied": 30,
781
+ "bounced": 5,
782
+ "unsubscribed": 2
783
+ }`,
784
+
785
+ inputSchema: z.object({
786
+ campaign_id: z.string().describe('UUID of the campaign to fetch analytics for'),
787
+ start_date: z.string().optional().describe('Start date for analytics range (ISO date string, e.g. "2025-01-01")'),
788
+ end_date: z.string().optional().describe('End date for analytics range (ISO date string, e.g. "2025-03-31")')
789
+ }),
790
+
791
+ outputSchema: z.object({
792
+ campaign_id: z.string().describe('Campaign UUID'),
793
+ sent: z.number().describe('Total emails sent'),
794
+ opened: z.number().describe('Total open events'),
795
+ unique_opened: z.number().describe('Unique leads who opened'),
796
+ replied: z.number().describe('Total reply events'),
797
+ unique_replied: z.number().describe('Unique leads who replied'),
798
+ bounced: z.number().describe('Total bounced emails'),
799
+ unsubscribed: z.number().describe('Total unsubscribes')
800
+ }),
801
+
802
+ integration: 'instantly' as const,
803
+ method: 'getCampaignAnalytics' as const,
804
+ credentialName
805
+ })
806
+ }
807
+
808
+ /**
809
+ * Create Instantly get step analytics tool
810
+ *
811
+ * Retrieves per-step and per-variant analytics for a campaign sequence.
812
+ *
813
+ * @param credentialName - Name of credential in credentials table
814
+ * @returns Tool that fetches step-level analytics
815
+ *
816
+ * @example
817
+ * const getStepAnalytics = createInstantlyGetStepAnalyticsTool('instantly-elevasis')
818
+ */
819
+ export function createInstantlyGetStepAnalyticsTool(credentialName: string): Tool {
820
+ return createIntegrationTool({
821
+ name: 'instantly_get_step_analytics',
822
+ description: `Get per-step and per-variant analytics for an Instantly campaign
823
+
824
+ USE CASES:
825
+ - Identify which sequence step has the highest reply rate
826
+ - Compare A/B subject line variants to determine the winning version
827
+ - Diagnose a drop-off point where prospects stop engaging
828
+ - Optimize multi-step sequences based on step-level performance data
829
+
830
+ REQUIRED PARAMETERS:
831
+ - campaign_id: UUID of the campaign
832
+
833
+ EXAMPLE:
834
+ {
835
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43"
836
+ }
837
+
838
+ OUTPUT:
839
+ {
840
+ "steps": [
841
+ {
842
+ "step": "1",
843
+ "variant": "A",
844
+ "sent": 200,
845
+ "opened": 90,
846
+ "unique_opened": 80,
847
+ "replies": 20,
848
+ "unique_replies": 18
849
+ },
850
+ {
851
+ "step": "2",
852
+ "variant": "A",
853
+ "sent": 160,
854
+ "opened": 55,
855
+ "unique_opened": 50,
856
+ "replies": 10,
857
+ "unique_replies": 9
858
+ }
859
+ ]
860
+ }`,
861
+
862
+ inputSchema: z.object({
863
+ campaign_id: z.string().describe('UUID of the campaign to fetch step analytics for')
864
+ }),
865
+
866
+ outputSchema: z.object({
867
+ steps: z
868
+ .array(
869
+ z.object({
870
+ step: z.string().describe('Step number in the sequence'),
871
+ variant: z.string().describe('Variant label (e.g. "A", "B")'),
872
+ sent: z.number().describe('Emails sent for this step/variant'),
873
+ opened: z.number().describe('Total open events'),
874
+ unique_opened: z.number().describe('Unique leads who opened'),
875
+ replies: z.number().describe('Total reply events'),
876
+ unique_replies: z.number().describe('Unique leads who replied')
877
+ })
878
+ )
879
+ .describe('Per-step, per-variant analytics entries')
880
+ }),
881
+
882
+ integration: 'instantly' as const,
883
+ method: 'getStepAnalytics' as const,
884
+ credentialName
885
+ })
886
+ }
887
+
888
+ /**
889
+ * Create Instantly bulk add leads tool
890
+ *
891
+ * Adds up to 1000 leads to a campaign in a single request.
892
+ *
893
+ * @param credentialName - Name of credential in credentials table
894
+ * @returns Tool that bulk-uploads leads to an Instantly campaign
895
+ *
896
+ * @example
897
+ * const bulkAddLeads = createInstantlyBulkAddLeadsTool('instantly-elevasis')
898
+ */
899
+ export function createInstantlyBulkAddLeadsTool(credentialName: string): Tool {
900
+ return createIntegrationTool({
901
+ name: 'instantly_bulk_add_leads',
902
+ description: `Bulk upload up to 1000 leads to an Instantly campaign
903
+
904
+ USE CASES:
905
+ - Import a large list of qualified prospects into a campaign at once
906
+ - Enroll leads exported from a CRM or enrichment tool into outreach
907
+ - Upload leads with custom variables for deep personalization
908
+ - Add leads with website and company data for context-aware sequences
909
+
910
+ REQUIRED PARAMETERS:
911
+ - campaign_id: UUID of the campaign to add leads to
912
+ - leads: Array of lead objects (1–1000 leads)
913
+
914
+ LEAD OBJECT FIELDS:
915
+ - email: (required) Email address of the lead
916
+ - first_name: (optional) First name for personalization
917
+ - last_name: (optional) Last name for personalization
918
+ - company_name: (optional) Company name for personalization
919
+ - website: (optional) Company website URL
920
+ - custom_variables: (optional) Key-value map of custom merge fields
921
+
922
+ EXAMPLE:
923
+ {
924
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
925
+ "leads": [
926
+ {
927
+ "email": "ceo@agency.com",
928
+ "first_name": "Sarah",
929
+ "last_name": "Chen",
930
+ "company_name": "Growth Agency",
931
+ "website": "https://growthagency.com",
932
+ "custom_variables": { "pain_point": "manual lead gen" }
933
+ }
934
+ ]
935
+ }
936
+
937
+ OUTPUT:
938
+ {
939
+ "success": true,
940
+ "added_count": 1,
941
+ "failed_count": 0
942
+ }`,
943
+
944
+ inputSchema: z.object({
945
+ campaign_id: z.string().describe('UUID of the campaign to add leads to'),
946
+ leads: z
947
+ .array(
948
+ z.object({
949
+ email: EmailSchema.describe('Email address of the lead'),
950
+ first_name: z.string().optional().describe('First name for personalization'),
951
+ last_name: z.string().optional().describe('Last name for personalization'),
952
+ company_name: z.string().optional().describe('Company name for personalization'),
953
+ website: z.string().optional().describe('Company website URL'),
954
+ custom_variables: z
955
+ .record(z.string(), z.string())
956
+ .optional()
957
+ .describe('Key-value map of custom merge field values')
958
+ })
959
+ )
960
+ .min(1)
961
+ .max(1000)
962
+ .describe('Array of leads to upload (1–1000)')
963
+ }),
964
+
965
+ outputSchema: z.object({
966
+ success: z.boolean().describe('True if all leads were added without errors'),
967
+ added_count: z.number().describe('Number of leads successfully added'),
968
+ failed_count: z.number().describe('Number of leads that failed to add'),
969
+ errors: z
970
+ .array(
971
+ z.object({
972
+ email: z.string().describe('Email of the lead that failed'),
973
+ error: z.string().describe('Error message for this lead')
974
+ })
975
+ )
976
+ .optional()
977
+ .describe('Per-lead error details when failures occurred')
978
+ }),
979
+
980
+ integration: 'instantly' as const,
981
+ method: 'bulkAddLeads' as const,
982
+ credentialName
983
+ })
984
+ }
985
+
986
+ /**
987
+ * Create Instantly get account health tool
988
+ *
989
+ * Lists email sending accounts with warmup status and health scores.
990
+ *
991
+ * @param credentialName - Name of credential in credentials table
992
+ * @returns Tool that retrieves account health data
993
+ *
994
+ * @example
995
+ * const getAccountHealth = createInstantlyGetAccountHealthTool('instantly-elevasis')
996
+ */
997
+ export function createInstantlyGetAccountHealthTool(credentialName: string): Tool {
998
+ return createIntegrationTool({
999
+ name: 'instantly_get_account_health',
1000
+ description: `List email accounts with health status and warmup information
1001
+
1002
+ USE CASES:
1003
+ - Audit all connected sending accounts before launching a campaign
1004
+ - Identify accounts with low health scores that may cause deliverability issues
1005
+ - Verify warmup status to ensure accounts are ready for full sending volume
1006
+ - Monitor account portfolio health as part of regular sender hygiene checks
1007
+
1008
+ OPTIONAL PARAMETERS:
1009
+ - limit: Number of accounts to return per page
1010
+ - starting_after: Cursor from previous response for pagination
1011
+
1012
+ EXAMPLE:
1013
+ {
1014
+ "limit": 20
1015
+ }
1016
+
1017
+ OUTPUT:
1018
+ {
1019
+ "accounts": [
1020
+ {
1021
+ "id": "acct-abc123",
1022
+ "email": "alex@elevasis.com",
1023
+ "status": "active",
1024
+ "warmup_enabled": true,
1025
+ "health_score": 92
1026
+ }
1027
+ ],
1028
+ "next_starting_after": "cursor-token"
1029
+ }`,
1030
+
1031
+ inputSchema: z.object({
1032
+ limit: z.number().min(1).max(100).optional().describe('Number of accounts per page'),
1033
+ starting_after: z
1034
+ .string()
1035
+ .optional()
1036
+ .describe('Cursor for pagination (from next_starting_after in previous response)')
1037
+ }),
1038
+
1039
+ outputSchema: z.object({
1040
+ accounts: z
1041
+ .array(
1042
+ z.object({
1043
+ id: z.string().describe('Account ID'),
1044
+ email: z.string().describe('Sending email address'),
1045
+ status: z.string().describe('Account status'),
1046
+ warmup_enabled: z.boolean().describe('Whether warmup is active for this account'),
1047
+ health_score: z.number().optional().describe('Health score (0–100)')
1048
+ })
1049
+ )
1050
+ .describe('Array of sending accounts with health data'),
1051
+ next_starting_after: z.string().optional().describe('Cursor for next page (undefined = no more pages)')
1052
+ }),
1053
+
1054
+ integration: 'instantly' as const,
1055
+ method: 'getAccountHealth' as const,
1056
+ credentialName
1057
+ })
1058
+ }
1059
+
1060
+ /**
1061
+ * Create Instantly create campaign tool
1062
+ *
1063
+ * Creates a new campaign in Instantly with optional sequences and sending configuration.
1064
+ *
1065
+ * @param credentialName - Name of credential in credentials table
1066
+ * @returns Tool that creates a new Instantly campaign
1067
+ *
1068
+ * @example
1069
+ * const createCampaign = createInstantlyCreateCampaignTool('instantly-elevasis')
1070
+ */
1071
+ export function createInstantlyCreateCampaignTool(credentialName: string): Tool {
1072
+ return createIntegrationTool({
1073
+ name: 'instantly_create_campaign',
1074
+ description: `Create a new Instantly campaign
1075
+
1076
+ USE CASES:
1077
+ - Set up a new cold outreach campaign with custom sequences
1078
+ - Create a campaign with predefined email steps and A/B variants
1079
+ - Configure sending limits and reply handling at creation time
1080
+ - Prepare a campaign shell to be populated with leads and activated later
1081
+
1082
+ REQUIRED PARAMETERS:
1083
+ - name: Display name of the new campaign
1084
+
1085
+ OPTIONAL PARAMETERS:
1086
+ - sequences: Array of sequence objects with email steps and optional A/B variants
1087
+ - email_list: Array of sending account emails to use for the campaign
1088
+ - daily_limit: Maximum emails to send per day
1089
+ - stop_on_reply: Whether to stop the sequence when a lead replies
1090
+ - stop_on_auto_reply: Whether to stop on auto-replies
1091
+ - track_opens: Whether to track email opens
1092
+ - track_clicks: Whether to track link clicks
1093
+ - text_only: Whether to send text-only emails (no HTML)
1094
+
1095
+ EXAMPLE (Simple Campaign):
1096
+ {
1097
+ "name": "Cold Outreach Q2 2025",
1098
+ "daily_limit": 50,
1099
+ "stop_on_reply": true
1100
+ }
1101
+
1102
+ EXAMPLE (Campaign with Sequence):
1103
+ {
1104
+ "name": "Agency Outreach",
1105
+ "sequences": [
1106
+ {
1107
+ "steps": [
1108
+ {
1109
+ "subject": "Quick question about {{company_name}}",
1110
+ "body": "Hi {{first_name}}, I noticed..."
1111
+ },
1112
+ {
1113
+ "subject": "Following up",
1114
+ "body": "Hi {{first_name}}, just wanted to circle back..."
1115
+ }
1116
+ ]
1117
+ }
1118
+ ],
1119
+ "daily_limit": 30,
1120
+ "stop_on_reply": true
1121
+ }
1122
+
1123
+ OUTPUT:
1124
+ {
1125
+ "success": true,
1126
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
1127
+ "name": "Cold Outreach Q2 2025"
1128
+ }`,
1129
+
1130
+ inputSchema: z.object({
1131
+ name: z.string().describe('Display name of the new campaign'),
1132
+ sequences: z
1133
+ .array(
1134
+ z.object({
1135
+ steps: z.array(
1136
+ z.object({
1137
+ subject: z.string().describe('Email subject line for this step'),
1138
+ body: z.string().describe('Email body for this step'),
1139
+ variants: z
1140
+ .array(
1141
+ z.object({
1142
+ subject: z.string().describe('A/B variant subject line'),
1143
+ body: z.string().describe('A/B variant body')
1144
+ })
1145
+ )
1146
+ .optional()
1147
+ .describe('A/B test variants for this step')
1148
+ })
1149
+ )
1150
+ })
1151
+ )
1152
+ .optional()
1153
+ .describe('Campaign sequences with email steps'),
1154
+ email_list: z.array(z.string()).optional().describe('Sending account emails to use for the campaign'),
1155
+ daily_limit: z.number().int().min(1).optional().describe('Maximum emails to send per day'),
1156
+ stop_on_reply: z.boolean().optional().describe('Whether to stop the sequence when a lead replies'),
1157
+ stop_on_auto_reply: z.boolean().optional().describe('Whether to stop the sequence on auto-replies'),
1158
+ track_opens: z.boolean().optional().describe('Whether to track email opens'),
1159
+ track_clicks: z.boolean().optional().describe('Whether to track link clicks'),
1160
+ text_only: z.boolean().optional().describe('Whether to send text-only emails (no HTML)')
1161
+ }),
1162
+
1163
+ outputSchema: z.object({
1164
+ success: z.boolean().describe('Whether the campaign was created successfully'),
1165
+ campaign_id: z.string().describe('UUID of the newly created campaign'),
1166
+ name: z.string().describe('Name of the created campaign')
1167
+ }),
1168
+
1169
+ integration: 'instantly' as const,
1170
+ method: 'createCampaign' as const,
1171
+ credentialName
1172
+ })
1173
+ }
1174
+
1175
+ /**
1176
+ * Create Instantly create inbox test tool
1177
+ *
1178
+ * Initiates an inbox placement test to diagnose deliverability for a sending account.
1179
+ *
1180
+ * @param credentialName - Name of credential in credentials table
1181
+ * @returns Tool that creates an Instantly inbox placement test
1182
+ *
1183
+ * @example
1184
+ * const createInboxTest = createInstantlyCreateInboxTestTool('instantly-elevasis')
1185
+ */
1186
+ export function createInstantlyCreateInboxTestTool(credentialName: string): Tool {
1187
+ return createIntegrationTool({
1188
+ name: 'instantly_create_inbox_test',
1189
+ description: `Create an inbox placement test for an Instantly sending account
1190
+
1191
+ USE CASES:
1192
+ - Verify deliverability before launching a high-volume campaign
1193
+ - Diagnose spam filtering issues on a specific sending account
1194
+ - Test whether custom subject lines land in inbox or spam
1195
+ - Monitor placement across Gmail, Outlook, and other major providers
1196
+
1197
+ REQUIRED PARAMETERS:
1198
+ - email_account: The sending account to test (must be connected to workspace)
1199
+
1200
+ OPTIONAL PARAMETERS:
1201
+ - subject: Custom subject line to use in the test email
1202
+ - body: Custom body text to use in the test email
1203
+
1204
+ EXAMPLE:
1205
+ {
1206
+ "email_account": "alex@elevasis.com",
1207
+ "subject": "Quick question about your agency",
1208
+ "body": "Hi, I wanted to reach out about..."
1209
+ }
1210
+
1211
+ OUTPUT:
1212
+ {
1213
+ "success": true,
1214
+ "test_id": "test-abc123",
1215
+ "status": "pending"
1216
+ }`,
1217
+
1218
+ inputSchema: z.object({
1219
+ email_account: z.string().describe('Sending account email address to test (must be connected to workspace)'),
1220
+ subject: z.string().optional().describe('Custom subject line for the test email'),
1221
+ body: z.string().optional().describe('Custom body text for the test email')
1222
+ }),
1223
+
1224
+ outputSchema: z.object({
1225
+ success: z.boolean().describe('Whether the test was created successfully'),
1226
+ test_id: z.string().describe('Unique ID of the inbox placement test'),
1227
+ status: z.string().describe('Initial test status (e.g. "pending")')
1228
+ }),
1229
+
1230
+ integration: 'instantly' as const,
1231
+ method: 'createInboxTest' as const,
1232
+ credentialName
1233
+ })
1234
+ }
1235
+
1236
+ /**
1237
+ * Create Instantly get daily campaign analytics tool
1238
+ *
1239
+ * Retrieves day-by-day engagement breakdown for campaigns.
1240
+ *
1241
+ * @param credentialName - Name of credential in credentials table
1242
+ * @returns Tool that fetches daily campaign analytics
1243
+ *
1244
+ * @example
1245
+ * const getDailyAnalytics = createInstantlyGetDailyCampaignAnalyticsTool('instantly-elevasis')
1246
+ */
1247
+ export function createInstantlyGetDailyCampaignAnalyticsTool(credentialName: string): Tool {
1248
+ return createIntegrationTool({
1249
+ name: 'instantly_get_daily_campaign_analytics',
1250
+ description: `Get day-by-day analytics breakdown for Instantly campaigns
1251
+
1252
+ USE CASES:
1253
+ - Analyze send and open trends over a date range to identify patterns
1254
+ - Spot peak engagement days to optimize future send scheduling
1255
+ - Compare daily click and reply volumes across a campaign period
1256
+ - Get cross-campaign aggregate metrics when no campaign_id is specified
1257
+
1258
+ OPTIONAL PARAMETERS:
1259
+ - campaign_id: Filter analytics to a specific campaign UUID (omit for all campaigns)
1260
+ - start_date: Start of date range (ISO date, e.g. "2025-01-01")
1261
+ - end_date: End of date range (ISO date, e.g. "2025-03-31")
1262
+
1263
+ EXAMPLE (Single Campaign):
1264
+ {
1265
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
1266
+ "start_date": "2025-01-01",
1267
+ "end_date": "2025-01-31"
1268
+ }
1269
+
1270
+ EXAMPLE (All Campaigns):
1271
+ {
1272
+ "start_date": "2025-01-01",
1273
+ "end_date": "2025-01-31"
1274
+ }
1275
+
1276
+ OUTPUT:
1277
+ {
1278
+ "data": [
1279
+ {
1280
+ "date": "2025-01-15",
1281
+ "sent": 120,
1282
+ "opened": 48,
1283
+ "unique_opened": 42,
1284
+ "replied": 8,
1285
+ "unique_replied": 7,
1286
+ "bounced": 1,
1287
+ "clicks": 12,
1288
+ "unique_clicks": 10
1289
+ }
1290
+ ]
1291
+ }`,
1292
+
1293
+ inputSchema: z.object({
1294
+ campaign_id: z.string().optional().describe('Campaign UUID to filter analytics (omit to get all campaigns)'),
1295
+ start_date: z.string().optional().describe('Start of date range (ISO date, e.g. "2025-01-01")'),
1296
+ end_date: z.string().optional().describe('End of date range (ISO date, e.g. "2025-03-31")')
1297
+ }),
1298
+
1299
+ outputSchema: z.object({
1300
+ data: z
1301
+ .array(
1302
+ z.object({
1303
+ date: z.string().describe('Date (YYYY-MM-DD)'),
1304
+ sent: z.number().describe('Emails sent on this date'),
1305
+ opened: z.number().describe('Total open events'),
1306
+ unique_opened: z.number().describe('Unique leads who opened'),
1307
+ replied: z.number().describe('Total reply events'),
1308
+ unique_replied: z.number().describe('Unique leads who replied'),
1309
+ bounced: z.number().describe('Emails bounced'),
1310
+ clicks: z.number().describe('Total link click events'),
1311
+ unique_clicks: z.number().describe('Unique leads who clicked')
1312
+ })
1313
+ )
1314
+ .describe('Array of daily analytics entries')
1315
+ }),
1316
+
1317
+ integration: 'instantly' as const,
1318
+ method: 'getDailyCampaignAnalytics' as const,
1319
+ credentialName
1320
+ })
1321
+ }
1322
+
1323
+ /**
1324
+ * Create Instantly list leads tool
1325
+ *
1326
+ * Lists leads with optional filtering by campaign or email and cursor pagination.
1327
+ *
1328
+ * @param credentialName - Name of credential in credentials table
1329
+ * @returns Tool that lists Instantly leads
1330
+ *
1331
+ * @example
1332
+ * const listLeads = createInstantlyListLeadsTool('instantly-elevasis')
1333
+ */
1334
+ export function createInstantlyListLeadsTool(credentialName: string): Tool {
1335
+ return createIntegrationTool({
1336
+ name: 'instantly_list_leads',
1337
+ description: `List leads in Instantly with optional filtering and pagination
1338
+
1339
+ USE CASES:
1340
+ - Retrieve all leads enrolled in a specific campaign for auditing
1341
+ - Look up a specific lead by email address to check their status
1342
+ - Paginate through a large lead list using cursor-based pagination
1343
+ - Review lead metadata including status, timestamps, and campaign assignment
1344
+
1345
+ OPTIONAL PARAMETERS:
1346
+ - campaign_id: Filter leads by campaign UUID
1347
+ - email: Filter by specific lead email address
1348
+ - limit: Number of leads per page
1349
+ - starting_after: Cursor from previous response for pagination
1350
+
1351
+ NOTE: This uses a POST endpoint per Instantly API design (complex filter arguments).
1352
+
1353
+ EXAMPLE (Campaign Leads):
1354
+ {
1355
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
1356
+ "limit": 50
1357
+ }
1358
+
1359
+ EXAMPLE (Single Lead Lookup):
1360
+ {
1361
+ "email": "prospect@agency.com"
1362
+ }
1363
+
1364
+ OUTPUT:
1365
+ {
1366
+ "items": [
1367
+ {
1368
+ "id": "lead-abc123",
1369
+ "email": "prospect@agency.com",
1370
+ "first_name": "John",
1371
+ "last_name": "Smith",
1372
+ "company_name": "Acme Agency",
1373
+ "status": "active",
1374
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
1375
+ "timestamp_created": "2025-01-15T09:00:00Z"
1376
+ }
1377
+ ],
1378
+ "next_starting_after": "cursor-token"
1379
+ }`,
1380
+
1381
+ inputSchema: z.object({
1382
+ campaign_id: z.string().optional().describe('Filter leads by campaign UUID'),
1383
+ email: z.string().optional().describe('Filter by specific lead email address'),
1384
+ limit: z.number().min(1).max(100).optional().describe('Number of leads per page'),
1385
+ starting_after: z
1386
+ .string()
1387
+ .optional()
1388
+ .describe('Cursor for pagination (from next_starting_after in previous response)')
1389
+ }),
1390
+
1391
+ outputSchema: z.object({
1392
+ items: z
1393
+ .array(
1394
+ z.object({
1395
+ id: z.string().describe('Lead ID'),
1396
+ email: z.string().describe('Lead email address'),
1397
+ first_name: z.string().optional().describe('Lead first name'),
1398
+ last_name: z.string().optional().describe('Lead last name'),
1399
+ company_name: z.string().optional().describe('Lead company name'),
1400
+ status: z.string().describe('Lead status in campaign'),
1401
+ campaign_id: z.string().optional().describe('Campaign this lead belongs to'),
1402
+ timestamp_created: z.string().optional().describe('Lead creation timestamp')
1403
+ })
1404
+ )
1405
+ .describe('Array of leads'),
1406
+ next_starting_after: z.string().optional().describe('Cursor for next page (undefined = no more pages)')
1407
+ }),
1408
+
1409
+ integration: 'instantly' as const,
1410
+ method: 'listLeads' as const,
1411
+ credentialName
1412
+ })
1413
+ }
1414
+
1415
+ /**
1416
+ * Create Instantly bulk delete leads tool
1417
+ *
1418
+ * Deletes leads in bulk by IDs, campaign, or list with an optional limit.
1419
+ *
1420
+ * @param credentialName - Name of credential in credentials table
1421
+ * @returns Tool that bulk-deletes Instantly leads
1422
+ *
1423
+ * @example
1424
+ * const bulkDeleteLeads = createInstantlyBulkDeleteLeadsTool('instantly-elevasis')
1425
+ */
1426
+ export function createInstantlyBulkDeleteLeadsTool(credentialName: string): Tool {
1427
+ return createIntegrationTool({
1428
+ name: 'instantly_bulk_delete_leads',
1429
+ description: `Bulk delete leads from Instantly by IDs, campaign, or list
1430
+
1431
+ USE CASES:
1432
+ - Remove a batch of disqualified leads from a campaign at once
1433
+ - Clean up leads from a completed campaign before archiving
1434
+ - Delete leads from a specific list to maintain database hygiene
1435
+ - Remove a set of specific leads by their IDs after a data audit
1436
+
1437
+ OPTIONAL PARAMETERS (at least one filter recommended):
1438
+ - ids: Array of specific lead IDs to delete
1439
+ - campaign_id: Delete all leads from this campaign
1440
+ - list_id: Delete all leads from this list
1441
+ - limit: Maximum number of leads to delete in this operation (1-10000)
1442
+
1443
+ EXAMPLE (Delete by IDs):
1444
+ {
1445
+ "ids": ["lead-abc123", "lead-def456"]
1446
+ }
1447
+
1448
+ EXAMPLE (Delete from Campaign):
1449
+ {
1450
+ "campaign_id": "019bb2e9-5d96-7f1d-9bc1-c0ef73001b43",
1451
+ "limit": 100
1452
+ }
1453
+
1454
+ OUTPUT:
1455
+ {
1456
+ "deleted_count": 42
1457
+ }`,
1458
+
1459
+ inputSchema: z.object({
1460
+ ids: z.array(z.string()).optional().describe('Specific lead IDs to delete'),
1461
+ campaign_id: z.string().optional().describe('Delete leads from this campaign'),
1462
+ list_id: z.string().optional().describe('Delete leads from this list'),
1463
+ limit: z.number().int().min(1).optional().describe('Maximum number of leads to delete')
1464
+ }),
1465
+
1466
+ outputSchema: z.object({
1467
+ deleted_count: z.number().describe('Number of leads deleted')
1468
+ }),
1469
+
1470
+ integration: 'instantly' as const,
1471
+ method: 'bulkDeleteLeads' as const,
1472
+ credentialName
1473
+ })
1474
+ }