Skip to content

Commit b3662e7

Browse files
authored
Require explicit sendAt for blast campaigns (#12)
1 parent 65dc307 commit b3662e7

1 file changed

Lines changed: 48 additions & 38 deletions

File tree

src/types/campaigns.ts

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -146,45 +146,55 @@ export const CampaignMetricsResponseSchema = z
146146
.describe("Parsed campaign metrics data");
147147

148148
// Campaign creation schemas
149-
export const CreateCampaignParamsSchema = z.object({
150-
name: z.string().describe("The name to use in Iterable for the new campaign"),
151-
templateId: z
152-
.number()
153-
.describe("The ID of a template to associate with the new campaign"),
154-
listIds: z
155-
.array(z.number())
156-
.describe(
157-
"Array of list IDs to which the campaign should be sent (for blast campaigns)"
158-
)
159-
.optional(),
160-
campaignDataFields: z
161-
.record(z.string(), z.any())
162-
.optional()
163-
.describe(
164-
"A JSON object containing campaign-level data fields that are available as merge parameters (for example, {{field}}) during message rendering. These fields are available in templates, data feed URLs, and all other contexts where merge parameters are supported. Campaign-level fields are overridden by user and event data fields of the same name."
149+
export const CreateCampaignParamsSchema = z
150+
.object({
151+
name: z
152+
.string()
153+
.describe("The name to use in Iterable for the new campaign"),
154+
templateId: z
155+
.number()
156+
.describe("The ID of a template to associate with the new campaign"),
157+
listIds: z
158+
.array(z.number())
159+
.describe(
160+
"Array of list IDs to which the campaign should be sent (for blast campaigns)"
161+
)
162+
.optional(),
163+
campaignDataFields: z
164+
.record(z.string(), z.any())
165+
.optional()
166+
.describe(
167+
"A JSON object containing campaign-level data fields that are available as merge parameters (for example, {{field}}) during message rendering. These fields are available in templates, data feed URLs, and all other contexts where merge parameters are supported. Campaign-level fields are overridden by user and event data fields of the same name."
168+
),
169+
sendAt: IterableDateTimeSchema.optional().describe(
170+
"Scheduled send time for blast campaign (YYYY-MM-DD HH:MM:SS UTC). Required when listIds is provided."
165171
),
166-
sendAt: IterableDateTimeSchema.optional().describe(
167-
"Scheduled send time for blast campaign (YYYY-MM-DD HH:MM:SS UTC). If not provided, the campaign will be sent immediately."
168-
),
169-
sendMode: z
170-
.enum(["ProjectTimeZone", "RecipientTimeZone"])
171-
.optional()
172-
.describe("Send mode for blast campaigns"),
173-
startTimeZone: z
174-
.string()
175-
.optional()
176-
.describe("Starting timezone for recipient timezone sends (IANA format)"),
177-
defaultTimeZone: z
178-
.string()
179-
.optional()
180-
.describe(
181-
"Default timezone for recipients without known timezone (IANA format)"
182-
),
183-
suppressionListIds: z
184-
.array(z.number())
185-
.optional()
186-
.describe("Array of suppression list IDs"),
187-
});
172+
sendMode: z
173+
.enum(["ProjectTimeZone", "RecipientTimeZone"])
174+
.optional()
175+
.describe("Send mode for blast campaigns"),
176+
startTimeZone: z
177+
.string()
178+
.optional()
179+
.describe(
180+
"Starting timezone for recipient timezone sends (IANA format)"
181+
),
182+
defaultTimeZone: z
183+
.string()
184+
.optional()
185+
.describe(
186+
"Default timezone for recipients without known timezone (IANA format)"
187+
),
188+
suppressionListIds: z
189+
.array(z.number())
190+
.optional()
191+
.describe("Array of suppression list IDs"),
192+
})
193+
.refine((data) => !data.listIds?.length || data.sendAt, {
194+
message:
195+
"sendAt is required for blast campaigns (when listIds is provided).",
196+
path: ["sendAt"],
197+
});
188198

189199
export const CreateCampaignResponseSchema = z.object({
190200
campaignId: z.number(),

0 commit comments

Comments
 (0)