Skip to content

Commit d7662d9

Browse files
committed
fix(smartlead): remove the dead campaign field that could target the wrong campaign
Removing the campaign filters from list_lead_activities and list_inbox_replies left their `activityCampaignId` subblock, its params mapping, and its inputs entry behind. Two problems, the second serious: - On those two operations the field promised campaign scoping the API cannot do. Smartlead rejects every candidate key (`campaign_id`, `campaignId`, `campaign_ids`, `email_campaign_id`), so the value was silently discarded and account-wide results were reported as scoped. - Worse, the field is `mode: 'advanced'`, and advanced subblocks serialize without evaluating their condition. A value left over from listing activities therefore fed `campaignId` on all 32 campaign operations through the `params.campaignId || params.activityCampaignId` fallback. Configuring List Lead Activities with campaign 111, then switching the block to Delete Campaign and leaving Campaign ID blank, would have passed required-validation and deleted campaign 111. Both list tools now also say plainly that Smartlead exposes no campaign filter, rather than advertising one in their descriptions. Also: route mark_lead_complete's next-sequence id through the shared numeric coercion, since Smartlead string-encodes numbers inconsistently and its sibling field already arrives as a string; re-bind the two enum constants that lost their last consumer so the literal descriptions cannot drift undetected; and declare the 17 tool output keys the block was missing — `accounts` most importantly, which is the entire payload of both email-account tools.
1 parent 0548ef6 commit d7662d9

10 files changed

Lines changed: 838 additions & 30 deletions

File tree

apps/docs/content/docs/en/integrations/smartlead.mdx

Lines changed: 801 additions & 2 deletions
Large diffs are not rendered by default.

apps/sim/blocks/blocks/smartlead.ts

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -418,17 +418,6 @@ export const SmartleadBlock: BlockConfig<SmartleadResponse> = {
418418
value: () => 'false',
419419
condition: { field: 'operation', value: 'list_inbox_replies' },
420420
},
421-
{
422-
id: 'activityCampaignId',
423-
title: 'Campaign ID',
424-
type: 'short-input',
425-
placeholder: 'Leave empty for all campaigns',
426-
condition: {
427-
field: 'operation',
428-
value: ['list_lead_activities', 'list_inbox_replies'],
429-
},
430-
mode: 'advanced',
431-
},
432421
{
433422
id: 'clientId',
434423
title: 'Client ID',
@@ -803,9 +792,7 @@ export const SmartleadBlock: BlockConfig<SmartleadResponse> = {
803792
config: {
804793
tool: (params) => `smartlead_${params.operation}`,
805794
params: (params) => ({
806-
// `list_lead_activities` and `list_inbox_replies` scope by campaign through their
807-
// own optional field, since they are not campaign-scoped operations.
808-
campaignId: toNumberParam(params.campaignId || params.activityCampaignId),
795+
campaignId: toNumberParam(params.campaignId),
809796
leadId: toNumberParam(params.leadId),
810797
clientId: toNumberParam(params.clientId),
811798
categoryId: toNumberParam(params.categoryId),
@@ -937,7 +924,6 @@ export const SmartleadBlock: BlockConfig<SmartleadResponse> = {
937924
leadListId: { type: 'number', description: 'Lead list ID' },
938925
listName: { type: 'string', description: 'Lead list name' },
939926
unreadOnly: { type: 'boolean', description: 'Return only unread inbox replies' },
940-
activityCampaignId: { type: 'number', description: 'Campaign to scope results to' },
941927
},
942928
outputs: {
943929
campaigns: { type: 'array', description: 'List of campaigns' },
@@ -1026,6 +1012,26 @@ export const SmartleadBlock: BlockConfig<SmartleadResponse> = {
10261012
active_leads_count: { type: 'number', description: 'Active leads in the list' },
10271013
track_settings: { type: 'array', description: 'Disabled tracking settings' },
10281014
scheduler_cron_value: { type: 'json', description: 'Campaign sending schedule' },
1015+
accounts: {
1016+
type: 'array',
1017+
description: 'Sending email accounts, excluding their stored mailbox credentials',
1018+
},
1019+
user_id: { type: 'number', description: 'Owning Smartlead user ID' },
1020+
min_time_btwn_emails: { type: 'number', description: 'Minimum minutes between emails' },
1021+
max_leads_per_day: { type: 'number', description: 'Maximum new leads per day' },
1022+
stop_lead_settings: { type: 'string', description: 'Activity that stops a lead sequence' },
1023+
schedule_start_time: { type: 'string', description: 'Scheduled start time' },
1024+
enable_ai_esp_matching: { type: 'boolean', description: 'Whether AI ESP matching is enabled' },
1025+
send_as_plain_text: { type: 'boolean', description: 'Whether emails send as plain text' },
1026+
follow_up_percentage: { type: 'number', description: 'Follow-up percentage' },
1027+
unsubscribe_text: { type: 'string', description: 'Unsubscribe text' },
1028+
parent_campaign_id: { type: 'number', description: 'Parent campaign ID' },
1029+
client_id: { type: 'number', description: 'Client ID for agency accounts' },
1030+
client_name: { type: 'string', description: 'Client name' },
1031+
client_email: { type: 'string', description: 'Client email' },
1032+
client_company_name: { type: 'string', description: 'Client company name' },
1033+
tags: { type: 'array', description: 'Tags on the record' },
1034+
email_campaign_id: { type: 'number', description: 'Campaign the webhook belongs to' },
10291035
},
10301036
}
10311037

apps/sim/lib/integrations/integrations.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"updatedAt": "2026-08-06",
2+
"updatedAt": "2026-08-07",
33
"integrations": [
44
{
55
"type": "onepassword",
@@ -17867,7 +17867,7 @@
1786717867
},
1786817868
{
1786917869
"name": "List Lead Activities",
17870-
"description": "Retrieves recent lead activity across Smartlead campaigns — opens, clicks, replies, and status changes."
17870+
"description": "Retrieves recent lead activity across all Smartlead campaigns — opens, clicks, replies, and status changes. Smartlead exposes no campaign filter on this endpoint."
1787117871
},
1787217872
{
1787317873
"name": "Get Lead by ID",
@@ -17891,7 +17891,7 @@
1789117891
},
1789217892
{
1789317893
"name": "List Inbox Replies",
17894-
"description": "Retrieves replies from the Smartlead master inbox, optionally limited to unread replies or a single campaign."
17894+
"description": "Retrieves replies from the Smartlead master inbox across all campaigns, optionally limited to unread replies. Smartlead exposes no campaign filter on this endpoint."
1789517895
},
1789617896
{
1789717897
"name": "List Lead Lists",

apps/sim/tools/generated/tool-metadata.ts

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

apps/sim/tools/smartlead/list_inbox_replies.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const listInboxRepliesTool: ToolConfig<
2828
id: 'smartlead_list_inbox_replies',
2929
name: 'Smartlead List Inbox Replies',
3030
description:
31-
'Retrieves replies from the Smartlead master inbox, optionally limited to unread replies or a single campaign.',
31+
'Retrieves replies from the Smartlead master inbox across all campaigns, optionally limited to unread replies. Smartlead exposes no campaign filter on this endpoint.',
3232
version: '1.0.0',
3333
errorExtractor: ErrorExtractorId.SMARTLEAD_ERRORS,
3434
params: {

apps/sim/tools/smartlead/list_lead_activities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const listLeadActivitiesTool: ToolConfig<
2828
id: 'smartlead_list_lead_activities',
2929
name: 'Smartlead List Lead Activities',
3030
description:
31-
'Retrieves recent lead activity across Smartlead campaigns — opens, clicks, replies, and status changes.',
31+
'Retrieves recent lead activity across all Smartlead campaigns — opens, clicks, replies, and status changes. Smartlead exposes no campaign filter on this endpoint.',
3232
version: '1.0.0',
3333
errorExtractor: ErrorExtractorId.SMARTLEAD_ERRORS,
3434
params: {

apps/sim/tools/smartlead/mark_lead_complete.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
smartleadHeaders,
1414
smartleadRecord,
1515
smartleadUrl,
16+
toNullableNumber,
1617
} from '@/tools/smartlead/utils'
1718
import type { ToolConfig } from '@/tools/types'
1819

@@ -55,17 +56,17 @@ export const markLeadCompleteTool: ToolConfig<
5556
const record = await smartleadRecord(response, 'lead completion')
5657
const status = isRecordLike(record.status) ? record.status : {}
5758
// `nextSequence` is an object ({ id, delayInDays }) when a step remains, else null.
58-
// `delayInDays` arrives as a string and is legitimately "0" for an immediate step.
59+
// Both members go through the shared numeric coercion: Smartlead string-encodes
60+
// numbers inconsistently, and `delayInDays` is legitimately "0" for an immediate step.
5961
const next = isRecordLike(status.nextSequence) ? status.nextSequence : null
60-
const delay = next === null ? Number.NaN : Number(next.delayInDays)
6162

6263
return {
6364
success: true,
6465
output: {
6566
success: isOk(record),
6667
is_last_sequence: typeof status.isLastSequence === 'boolean' ? status.isLastSequence : null,
67-
next_sequence_id: next && typeof next.id === 'number' ? next.id : null,
68-
next_sequence_delay_in_days: Number.isFinite(delay) ? delay : null,
68+
next_sequence_id: next === null ? null : toNullableNumber(next.id),
69+
next_sequence_delay_in_days: next === null ? null : toNullableNumber(next.delayInDays),
6970
},
7071
}
7172
},

apps/sim/tools/smartlead/update_campaign_settings.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
jsonBody,
77
pathSegment,
88
type SMARTLEAD_STOP_LEAD_SETTINGS,
9+
type SMARTLEAD_TRACK_SETTINGS,
910
smartleadBaseParamFields,
1011
smartleadCampaignIdParamField,
1112
smartleadHeaders,
@@ -15,7 +16,7 @@ import {
1516
import type { ToolConfig } from '@/tools/types'
1617

1718
interface UpdateCampaignSettingsParams extends SmartleadCampaignIdParams {
18-
trackSettings?: string[]
19+
trackSettings?: (typeof SMARTLEAD_TRACK_SETTINGS)[number][]
1920
stopLeadSettings?: (typeof SMARTLEAD_STOP_LEAD_SETTINGS)[number]
2021
sendAsPlainText?: boolean
2122
followUpPercentage?: number

apps/sim/tools/smartlead/upsert_campaign_webhook.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
import {
77
mapSavedWebhook,
88
pathSegment,
9+
type SMARTLEAD_WEBHOOK_EVENT_TYPES,
910
smartleadBaseParamFields,
1011
smartleadCampaignIdParamField,
1112
smartleadHeaders,
@@ -18,7 +19,7 @@ import type { ToolConfig } from '@/tools/types'
1819
interface UpsertCampaignWebhookParams extends SmartleadCampaignIdParams {
1920
name: string
2021
webhookUrl: string
21-
eventTypes: string[]
22+
eventTypes: (typeof SMARTLEAD_WEBHOOK_EVENT_TYPES)[number][]
2223
categories: string[]
2324
webhookId?: number
2425
}

apps/sim/tools/smartlead/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ function toStringOrNull(value: unknown): string | null {
572572
}
573573

574574
/** Normalizes Smartlead's string-encoded numbers (`"0"`, `"3499513771"`) to numbers. */
575-
function toNullableNumber(value: unknown): number | null {
575+
export function toNullableNumber(value: unknown): number | null {
576576
if (value === undefined || value === null) return null
577577
if (typeof value === 'number') return Number.isFinite(value) ? value : null
578578
if (typeof value === 'string' && value.trim() !== '') {

0 commit comments

Comments
 (0)