perspectapi-ts-sdk 7.2.6 → 7.4.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.
@@ -8,11 +8,18 @@ import type { V2EmailSendParams, V2EmailSendResult } from '../types';
8
8
  export class EmailV2Client extends BaseV2Client {
9
9
 
10
10
  /**
11
- * Send a transactional email using the site's configured email provider.
11
+ * Send a transactional email through the site's email provider.
12
12
  *
13
- * Requires a server-side API key — never call this from a browser.
14
- * The site must have an email provider configured in its settings.
15
- * At least one of `html` or `text` must be provided.
13
+ * Requires a server-side API key — never call this from a browser. Sites
14
+ * without a configured provider fall back to the platform default with
15
+ * policy restrictions (owner-only recipients, daily quota).
16
+ *
17
+ * Provide content one of two ways (mutually exclusive):
18
+ * - Raw: `subject` plus at least one of `html` / `text`.
19
+ * - Template: `template_type` (published template for that type) or
20
+ * `template_id` (published template by ID) plus optional `variables`; the
21
+ * template is rendered server-side. `subject` is optional here and
22
+ * overrides the rendered one.
16
23
  */
17
24
  async send(siteName: string, params: V2EmailSendParams): Promise<V2EmailSendResult> {
18
25
  return this.post<V2EmailSendResult>(
@@ -0,0 +1,113 @@
1
+ /**
2
+ * v2 Email Templates Client — versioned CRUD for site email templates.
3
+ *
4
+ * Mirrors the email_template_* MCP tools. Templates live under
5
+ * /sites/:siteName/email/templates. Use `listTypes` / `getTypeVariables` to
6
+ * discover the allowed substitution variables for each template type before
7
+ * authoring, then create/clone/publish versions.
8
+ */
9
+
10
+ import { BaseV2Client } from './base-v2-client';
11
+ import type { CachePolicy } from '../../cache/types';
12
+ import type {
13
+ V2EmailTemplate,
14
+ V2EmailTemplateType,
15
+ V2EmailTemplateType_Listing,
16
+ V2EmailTemplateListParams,
17
+ V2EmailTemplateCreateParams,
18
+ V2EmailTemplateCloneParams,
19
+ V2List,
20
+ } from '../types';
21
+
22
+ export class EmailTemplatesV2Client extends BaseV2Client {
23
+ private path(siteName: string, suffix = ''): string {
24
+ return this.sitePath(siteName, 'email', suffix ? `templates/${suffix}` : 'templates');
25
+ }
26
+
27
+ /** List every supported template type with its allowed variables. */
28
+ async listTypes(
29
+ siteName: string,
30
+ cachePolicy?: CachePolicy,
31
+ ): Promise<V2List<V2EmailTemplateType_Listing>> {
32
+ return this.getList<V2EmailTemplateType_Listing>(
33
+ this.path(siteName, 'types'),
34
+ undefined,
35
+ cachePolicy,
36
+ );
37
+ }
38
+
39
+ /** Get the allowed variables for a single template type. */
40
+ async getTypeVariables(
41
+ siteName: string,
42
+ templateType: V2EmailTemplateType,
43
+ cachePolicy?: CachePolicy,
44
+ ): Promise<V2EmailTemplateType_Listing> {
45
+ return this.getOne<V2EmailTemplateType_Listing>(
46
+ this.path(siteName, `types/${templateType}`),
47
+ undefined,
48
+ cachePolicy,
49
+ );
50
+ }
51
+
52
+ /** List template versions, optionally filtered by type and/or status. */
53
+ async list(
54
+ siteName: string,
55
+ params?: V2EmailTemplateListParams,
56
+ cachePolicy?: CachePolicy,
57
+ ): Promise<V2List<V2EmailTemplate>> {
58
+ return this.getList<V2EmailTemplate>(this.path(siteName), params, cachePolicy);
59
+ }
60
+
61
+ /** Get a specific template version by ID (`etpl_…`). */
62
+ async get(
63
+ siteName: string,
64
+ templateId: string,
65
+ cachePolicy?: CachePolicy,
66
+ ): Promise<V2EmailTemplate> {
67
+ return this.getOne<V2EmailTemplate>(
68
+ this.path(siteName, encodeURIComponent(templateId)),
69
+ undefined,
70
+ cachePolicy,
71
+ );
72
+ }
73
+
74
+ /** Get the currently published version for a template type. */
75
+ async getPublished(
76
+ siteName: string,
77
+ templateType: V2EmailTemplateType,
78
+ cachePolicy?: CachePolicy,
79
+ ): Promise<V2EmailTemplate> {
80
+ return this.getOne<V2EmailTemplate>(
81
+ this.path(siteName, `published/${templateType}`),
82
+ undefined,
83
+ cachePolicy,
84
+ );
85
+ }
86
+
87
+ /** Create a new template version. */
88
+ async create(
89
+ siteName: string,
90
+ params: V2EmailTemplateCreateParams,
91
+ ): Promise<V2EmailTemplate> {
92
+ return this.post<V2EmailTemplate>(this.path(siteName), params);
93
+ }
94
+
95
+ /** Clone a template version, optionally overriding fields. */
96
+ async clone(
97
+ siteName: string,
98
+ templateId: string,
99
+ params?: V2EmailTemplateCloneParams,
100
+ ): Promise<V2EmailTemplate> {
101
+ return this.post<V2EmailTemplate>(
102
+ this.path(siteName, `${encodeURIComponent(templateId)}/clone`),
103
+ params ?? {},
104
+ );
105
+ }
106
+
107
+ /** Publish a template version (archives the previously published one). */
108
+ async publish(siteName: string, templateId: string): Promise<V2EmailTemplate> {
109
+ return this.post<V2EmailTemplate>(
110
+ this.path(siteName, `${encodeURIComponent(templateId)}/publish`),
111
+ );
112
+ }
113
+ }
@@ -6,11 +6,16 @@ import { BaseV2Client } from './base-v2-client';
6
6
  import type { CachePolicy } from '../../cache/types';
7
7
  import type {
8
8
  V2NewsletterSubscription, V2NewsletterList, V2NewsletterCampaign,
9
+ V2NewsletterSeries, V2NewsletterStatistics,
9
10
  V2PaginationParams, V2List, V2Deleted, V2NewsletterTrackingResponse,
10
11
  V2NewsletterListCreateParams, V2NewsletterListUpdateParams,
11
12
  V2NewsletterSyncInput, V2NewsletterSyncResult,
12
13
  V2NewsletterSubscriptionListMembershipUpdate,
13
14
  V2NewsletterImportRequest, V2NewsletterImportResult,
15
+ V2NewsletterCampaignCreateParams, V2NewsletterCampaignUpdateParams,
16
+ V2NewsletterSeriesCreateParams, V2NewsletterSeriesUpdateParams,
17
+ V2NewsletterStatisticsParams, V2NewsletterSubscriptionStatusUpdate,
18
+ V2NewsletterBulkParams, V2NewsletterBulkResult,
14
19
  } from '../types';
15
20
 
16
21
  export class NewsletterV2Client extends BaseV2Client {
@@ -206,4 +211,155 @@ export class NewsletterV2Client extends BaseV2Client {
206
211
  data,
207
212
  );
208
213
  }
214
+
215
+ // --- Lists (get by id) ---
216
+
217
+ async getListById(
218
+ siteName: string,
219
+ id: string,
220
+ cachePolicy?: CachePolicy,
221
+ ): Promise<V2NewsletterList> {
222
+ return this.getOne<V2NewsletterList>(
223
+ this.sitePath(siteName, 'newsletter', `lists/${encodeURIComponent(id)}`),
224
+ undefined,
225
+ cachePolicy,
226
+ );
227
+ }
228
+
229
+ // --- Subscriptions (admin: lookup / status / delete / bulk) ---
230
+
231
+ async getSubscriptionByEmail(
232
+ siteName: string,
233
+ email: string,
234
+ cachePolicy?: CachePolicy,
235
+ ): Promise<V2NewsletterSubscription> {
236
+ return this.getOne<V2NewsletterSubscription>(
237
+ this.sitePath(siteName, 'newsletter', 'subscriptions/by-email'),
238
+ { email },
239
+ cachePolicy,
240
+ );
241
+ }
242
+
243
+ async updateSubscriptionStatus(
244
+ siteName: string,
245
+ id: string,
246
+ data: V2NewsletterSubscriptionStatusUpdate,
247
+ ): Promise<V2NewsletterSubscription> {
248
+ return this.post<V2NewsletterSubscription>(
249
+ this.sitePath(siteName, 'newsletter', `subscriptions/${encodeURIComponent(id)}/status`),
250
+ data,
251
+ );
252
+ }
253
+
254
+ async deleteSubscription(siteName: string, id: string): Promise<V2Deleted> {
255
+ return this.deleteOne(
256
+ this.sitePath(siteName, 'newsletter', `subscriptions/${encodeURIComponent(id)}`),
257
+ );
258
+ }
259
+
260
+ async bulkUpdateSubscriptions(
261
+ siteName: string,
262
+ data: V2NewsletterBulkParams,
263
+ ): Promise<V2NewsletterBulkResult> {
264
+ return this.post<V2NewsletterBulkResult>(
265
+ this.sitePath(siteName, 'newsletter', 'subscriptions/bulk'),
266
+ data,
267
+ );
268
+ }
269
+
270
+ // --- Statistics ---
271
+
272
+ async getStatistics(
273
+ siteName: string,
274
+ params?: V2NewsletterStatisticsParams,
275
+ cachePolicy?: CachePolicy,
276
+ ): Promise<V2NewsletterStatistics> {
277
+ return this.getOne<V2NewsletterStatistics>(
278
+ this.sitePath(siteName, 'newsletter', 'statistics'),
279
+ params,
280
+ cachePolicy,
281
+ );
282
+ }
283
+
284
+ // --- Campaigns (create / update / delete) ---
285
+
286
+ async createCampaign(
287
+ siteName: string,
288
+ data: V2NewsletterCampaignCreateParams,
289
+ ): Promise<V2NewsletterCampaign> {
290
+ return this.post<V2NewsletterCampaign>(
291
+ this.sitePath(siteName, 'newsletter', 'campaigns'),
292
+ data,
293
+ );
294
+ }
295
+
296
+ async updateCampaign(
297
+ siteName: string,
298
+ id: string,
299
+ data: V2NewsletterCampaignUpdateParams,
300
+ ): Promise<V2NewsletterCampaign> {
301
+ return this.patchOne<V2NewsletterCampaign>(
302
+ this.sitePath(siteName, 'newsletter', `campaigns/${encodeURIComponent(id)}`),
303
+ data,
304
+ );
305
+ }
306
+
307
+ async deleteCampaign(siteName: string, id: string): Promise<V2Deleted> {
308
+ return this.deleteOne(
309
+ this.sitePath(siteName, 'newsletter', `campaigns/${encodeURIComponent(id)}`),
310
+ );
311
+ }
312
+
313
+ // --- Series ---
314
+
315
+ async listSeries(
316
+ siteName: string,
317
+ params?: { status?: 'active' | 'paused' | 'archived' },
318
+ cachePolicy?: CachePolicy,
319
+ ): Promise<V2List<V2NewsletterSeries>> {
320
+ return this.getList<V2NewsletterSeries>(
321
+ this.sitePath(siteName, 'newsletter', 'series'),
322
+ params,
323
+ cachePolicy,
324
+ );
325
+ }
326
+
327
+ async getSeries(
328
+ siteName: string,
329
+ id: string,
330
+ cachePolicy?: CachePolicy,
331
+ ): Promise<V2NewsletterSeries> {
332
+ return this.getOne<V2NewsletterSeries>(
333
+ this.sitePath(siteName, 'newsletter', `series/${encodeURIComponent(id)}`),
334
+ undefined,
335
+ cachePolicy,
336
+ );
337
+ }
338
+
339
+ async createSeries(
340
+ siteName: string,
341
+ data: V2NewsletterSeriesCreateParams,
342
+ ): Promise<V2NewsletterSeries> {
343
+ return this.post<V2NewsletterSeries>(
344
+ this.sitePath(siteName, 'newsletter', 'series'),
345
+ data,
346
+ );
347
+ }
348
+
349
+ async updateSeries(
350
+ siteName: string,
351
+ id: string,
352
+ data: V2NewsletterSeriesUpdateParams,
353
+ ): Promise<V2NewsletterSeries> {
354
+ return this.patchOne<V2NewsletterSeries>(
355
+ this.sitePath(siteName, 'newsletter', `series/${encodeURIComponent(id)}`),
356
+ data,
357
+ );
358
+ }
359
+
360
+ async deleteSeries(siteName: string, id: string): Promise<V2Deleted> {
361
+ return this.deleteOne(
362
+ this.sitePath(siteName, 'newsletter', `series/${encodeURIComponent(id)}`),
363
+ );
364
+ }
209
365
  }
package/src/v2/index.ts CHANGED
@@ -30,6 +30,7 @@ import { WebhooksV2Client } from './client/webhooks-client';
30
30
  import { SubscriptionsV2Client } from './client/subscriptions-client';
31
31
  import { CreditsV2Client } from './client/credits-client';
32
32
  import { EmailV2Client } from './client/email-client';
33
+ import { EmailTemplatesV2Client } from './client/email-templates-client';
33
34
 
34
35
  export interface PerspectApiV2Config extends PerspectApiConfig {
35
36
  cache?: CacheConfig;
@@ -54,6 +55,7 @@ export class PerspectApiV2Client {
54
55
  readonly subscriptions: SubscriptionsV2Client;
55
56
  readonly credits: CreditsV2Client;
56
57
  readonly email: EmailV2Client;
58
+ readonly emailTemplates: EmailTemplatesV2Client;
57
59
 
58
60
  constructor(config: PerspectApiV2Config) {
59
61
  // Ensure base URL points to /api/v2
@@ -82,6 +84,7 @@ export class PerspectApiV2Client {
82
84
  this.subscriptions = new SubscriptionsV2Client(this.http, basePath, cache);
83
85
  this.credits = new CreditsV2Client(this.http, basePath, cache);
84
86
  this.email = new EmailV2Client(this.http, basePath, cache);
87
+ this.emailTemplates = new EmailTemplatesV2Client(this.http, basePath, cache);
85
88
  }
86
89
 
87
90
  /** Update the JWT token for authenticated requests. */
@@ -124,3 +127,4 @@ export { WebhooksV2Client } from './client/webhooks-client';
124
127
  export { SubscriptionsV2Client } from './client/subscriptions-client';
125
128
  export { CreditsV2Client } from './client/credits-client';
126
129
  export { EmailV2Client } from './client/email-client';
130
+ export { EmailTemplatesV2Client } from './client/email-templates-client';
package/src/v2/types.ts CHANGED
@@ -507,23 +507,77 @@ export interface V2NewsletterList extends V2Object {
507
507
  updated_at: string | null;
508
508
  }
509
509
 
510
+ export type V2NewsletterCampaignStatus =
511
+ | "draft"
512
+ | "scheduled"
513
+ | "sending"
514
+ | "sent"
515
+ | "cancelled";
516
+
510
517
  export interface V2NewsletterCampaign extends V2Object {
511
518
  object: "newsletter_campaign";
512
519
  name: string;
513
520
  slug: string | null;
521
+ slug_prefix?: string | null;
514
522
  subject: string;
515
523
  preview_text: string | null;
516
- status: string;
524
+ markdown_content?: string | null;
525
+ series_id?: string | null;
526
+ series_name?: string | null;
527
+ template_id?: string | null;
528
+ list_ids?: string[];
529
+ tags?: string[] | null;
530
+ notes?: string | null;
531
+ from_name?: string | null;
532
+ from_email?: string | null;
533
+ reply_to_email?: string | null;
534
+ send_to_all?: boolean;
535
+ status: V2NewsletterCampaignStatus | string;
536
+ scheduled_at?: string | null;
517
537
  sent_at: string | null;
518
538
  completed_at: string | null;
519
539
  total_recipients: number;
520
540
  sent_count: number;
541
+ delivered_count?: number;
521
542
  opened_count: number;
522
543
  clicked_count: number;
544
+ unsubscribed_count?: number;
545
+ bounced_count?: number;
546
+ complained_count?: number;
547
+ created_at: string | null;
548
+ updated_at: string | null;
549
+ }
550
+
551
+ export interface V2NewsletterSeries extends V2Object {
552
+ object: "newsletter_series";
553
+ name: string;
554
+ description: string | null;
555
+ list_ids: string[];
556
+ from_name: string | null;
557
+ from_email: string | null;
558
+ reply_to_email: string | null;
559
+ subject_prefix: string | null;
560
+ cadence: "manual" | "daily" | "weekly" | "monthly" | string;
561
+ timezone: string | null;
562
+ send_time: string | null;
563
+ day_of_week: number | null;
564
+ day_of_month: number | null;
565
+ status: "active" | "paused" | "archived" | string;
566
+ last_sent_at: string | null;
567
+ next_send_at: string | null;
568
+ tags: string[] | null;
569
+ notes: string | null;
523
570
  created_at: string | null;
524
571
  updated_at: string | null;
525
572
  }
526
573
 
574
+ export interface V2NewsletterStatistics {
575
+ object: "newsletter_statistics";
576
+ total: number;
577
+ by_status: Record<string, number>;
578
+ recent_activity: Array<{ date: string; count: number }>;
579
+ }
580
+
527
581
  export interface V2NewsletterTrackingResponse {
528
582
  success: boolean;
529
583
  }
@@ -606,6 +660,93 @@ export interface V2NewsletterImportResult {
606
660
  }>;
607
661
  }
608
662
 
663
+ // --- Newsletter campaigns / series / statistics (admin) ---
664
+
665
+ export interface V2NewsletterCampaignCreateParams {
666
+ campaign_name: string;
667
+ subject: string;
668
+ /** Markdown body; rendered to HTML/text server-side. */
669
+ markdown_content: string;
670
+ slug?: string;
671
+ slug_prefix?: string | null;
672
+ /**
673
+ * `scheduled` requires a `scheduled_at`, the newsletter plan entitlement, and
674
+ * the `newsletters.publish` permission on the API key (creating/updating a
675
+ * draft only needs `newsletters.create`/`newsletters.update`).
676
+ */
677
+ status?: "draft" | "scheduled" | "cancelled";
678
+ /** Local datetime (YYYY-MM-DDTHH:MM[:SS]) in the site/series timezone. */
679
+ scheduled_at?: string | null;
680
+ preview_text?: string;
681
+ from_name?: string;
682
+ from_email?: string;
683
+ reply_to_email?: string;
684
+ /** Newsletter template version ID (`etpl_…`). */
685
+ template_id?: string | null;
686
+ /** Series ID (`nsr_…`). */
687
+ series_id?: string | null;
688
+ /** Target list IDs (`nll_…`). */
689
+ list_ids?: string[];
690
+ tags?: string[];
691
+ notes?: string;
692
+ }
693
+
694
+ export type V2NewsletterCampaignUpdateParams = Partial<
695
+ Omit<V2NewsletterCampaignCreateParams, "campaign_name" | "subject" | "markdown_content">
696
+ > & {
697
+ campaign_name?: string;
698
+ subject?: string;
699
+ markdown_content?: string;
700
+ };
701
+
702
+ export interface V2NewsletterSeriesCreateParams {
703
+ series_name: string;
704
+ description?: string;
705
+ status?: "active" | "paused" | "archived";
706
+ cadence?: "manual" | "daily" | "weekly" | "monthly";
707
+ timezone?: string;
708
+ send_time?: string;
709
+ day_of_week?: number;
710
+ day_of_month?: number;
711
+ next_send_at?: string | null;
712
+ list_ids?: string[];
713
+ from_name?: string;
714
+ from_email?: string;
715
+ reply_to_email?: string;
716
+ subject_prefix?: string;
717
+ tags?: string[];
718
+ notes?: string;
719
+ }
720
+
721
+ export type V2NewsletterSeriesUpdateParams = Partial<V2NewsletterSeriesCreateParams>;
722
+
723
+ export interface V2NewsletterStatisticsParams {
724
+ start_date?: string;
725
+ end_date?: string;
726
+ list_id?: string;
727
+ }
728
+
729
+ export interface V2NewsletterSubscriptionStatusUpdate {
730
+ status: "confirmed" | "unsubscribed" | "bounced" | "complained";
731
+ notes?: string;
732
+ }
733
+
734
+ export interface V2NewsletterBulkParams {
735
+ ids: string[];
736
+ action: "confirm" | "unsubscribe" | "delete" | "add_to_list" | "remove_from_list";
737
+ /** Required for add_to_list / remove_from_list. */
738
+ list_id?: string;
739
+ }
740
+
741
+ export interface V2NewsletterBulkResult {
742
+ object: "newsletter_bulk_result";
743
+ succeeded: number;
744
+ failed: number;
745
+ /** Per-id failures (id + reason) for the subscriptions that did not apply. */
746
+ failures: Array<{ id: string; error: string }>;
747
+ [key: string]: unknown;
748
+ }
749
+
609
750
  // --- Contact ---
610
751
 
611
752
  export interface V2ContactSubmission extends V2Object {
@@ -818,15 +959,105 @@ export interface V2GrantCreditResult {
818
959
 
819
960
  // --- Email ---
820
961
 
962
+ export type V2EmailTemplateType =
963
+ | "order_customer_receipt"
964
+ | "order_admin_notification"
965
+ | "signup_welcome"
966
+ | "order_fulfillment_notification"
967
+ | "order_cancellation_notification"
968
+ | "subscription_cancelled"
969
+ | "subscription_cancellation_admin_notification"
970
+ | "subscription_plan_changed"
971
+ | "subscription_plan_changed_admin_notification"
972
+ | "newsletter"
973
+ | "customer_support";
974
+
975
+ export type V2EmailTemplateStatus = "draft" | "published" | "archived";
976
+
821
977
  export interface V2EmailSendParams {
822
978
  to: string | string[];
823
- subject: string;
979
+ /** Required for raw sends; optional (overrides the rendered subject) for template sends. */
980
+ subject?: string;
824
981
  html?: string;
825
982
  text?: string;
826
983
  from?: string;
827
984
  reply_to?: string;
828
985
  cc?: string | string[];
829
986
  bcc?: string | string[];
987
+ /**
988
+ * Template-based send. Provide exactly one of `template_id` (a published
989
+ * template by ID) or `template_type` (the published template for that type);
990
+ * the template is rendered server-side with `variables` substituted in.
991
+ * Mutually exclusive with `html`/`text`.
992
+ */
993
+ template_id?: string;
994
+ template_type?: V2EmailTemplateType;
995
+ variables?: Record<string, string | number | null>;
996
+ /**
997
+ * When true, every placeholder referenced by the template must be present in
998
+ * `variables` (null counts as provided) — otherwise the API rejects the send
999
+ * instead of rendering the missing placeholders as empty strings.
1000
+ */
1001
+ strict?: boolean;
1002
+ }
1003
+
1004
+ export interface V2EmailTemplate extends V2Object {
1005
+ object: "email_template";
1006
+ template_type: V2EmailTemplateType;
1007
+ template_name: string;
1008
+ description: string | null;
1009
+ subject_template: string;
1010
+ html_template: string;
1011
+ text_template: string;
1012
+ status: V2EmailTemplateStatus;
1013
+ version: number;
1014
+ variables: string[];
1015
+ created_by: string | null;
1016
+ created_at: string;
1017
+ updated_at: string;
1018
+ published_at: string | null;
1019
+ /** Present on clone responses: the source template ID. */
1020
+ source_template_id?: string;
1021
+ }
1022
+
1023
+ export interface V2EmailTemplateType_Listing {
1024
+ object: "email_template_type";
1025
+ template_type: V2EmailTemplateType;
1026
+ variables: string[];
1027
+ }
1028
+
1029
+ export interface V2EmailTemplateListParams {
1030
+ template_type?: V2EmailTemplateType;
1031
+ status?: V2EmailTemplateStatus;
1032
+ }
1033
+
1034
+ export interface V2EmailTemplateCreateParams {
1035
+ template_type: V2EmailTemplateType;
1036
+ template_name: string;
1037
+ subject_template: string;
1038
+ html_template: string;
1039
+ text_template: string;
1040
+ description?: string;
1041
+ /**
1042
+ * Defaults to "draft". Creating directly into "published" additionally
1043
+ * requires the `templates.publish` permission (and the custom-email plan
1044
+ * entitlement, like all template mutations); otherwise the API returns 403.
1045
+ */
1046
+ status?: "draft" | "published";
1047
+ }
1048
+
1049
+ export interface V2EmailTemplateCloneParams {
1050
+ template_name?: string;
1051
+ subject_template?: string;
1052
+ html_template?: string;
1053
+ text_template?: string;
1054
+ description?: string;
1055
+ /**
1056
+ * Defaults to "draft". Creating directly into "published" additionally
1057
+ * requires the `templates.publish` permission (and the custom-email plan
1058
+ * entitlement, like all template mutations); otherwise the API returns 403.
1059
+ */
1060
+ status?: "draft" | "published";
830
1061
  }
831
1062
 
832
1063
  export interface V2EmailSendResult {