@sentdm/sentdm 0.38.0 → 0.39.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.
@@ -17,7 +17,9 @@ export class Templates extends APIResource {
17
17
  /**
18
18
  * Creates a new message template with header, body, footer, and buttons. The
19
19
  * template can be submitted for review immediately or saved as draft for later
20
- * submission.
20
+ * submission. There is no `name` field on create — the display name is derived
21
+ * from the template's content and can be changed afterwards with
22
+ * `PUT /v3/templates/{id}`.
21
23
  *
22
24
  * @example
23
25
  * ```ts
@@ -67,7 +69,31 @@ export class Templates extends APIResource {
67
69
 
68
70
  /**
69
71
  * Updates an existing template's name, category, language, definition, or submits
70
- * it for review.
72
+ * it for review. While the template is in review (status PENDING, or any channel
73
+ * awaiting a verdict) its definition, category and language are frozen and a
74
+ * resubmission is refused — those requests answer 409 CONFLICT_006. The display
75
+ * name stays editable throughout.
76
+ *
77
+ * `definition`, `category` and `language` are editable only from status DRAFT,
78
+ * REJECTED or APPROVED. An edit to any of them on a template in another state
79
+ * (PAUSED, DISABLED or REVOKED) is refused with 400 VALIDATION_001 and the detail
80
+ * "Template (except display name) cannot be updated unless it is in draft or
81
+ * rejected status"; `name` stays editable in every state. `submit_for_review` on a
82
+ * PAUSED, DISABLED or REVOKED template is accepted and answers 200, but opens no
83
+ * review and does not move the status — only the reviewer can reinstate it.
84
+ *
85
+ * Editing an APPROVED template is a live edit: the new content is stored
86
+ * immediately, and sending `submit_for_review: true` re-opens review, which
87
+ * returns the affected channels to PENDING so they stop sending until they are
88
+ * approved again. The previously approved content is never sent during re-review.
89
+ * Watch the per-channel `templates` webhook events rather than assuming the
90
+ * template-level status.
91
+ *
92
+ * Templates provisioned by Sent (light-onboarding templates, whose names carry the
93
+ * reserved `sent_` prefix) are read-only: every field is refused with 400
94
+ * VALIDATION*001 and the detail "This template is read-only. Only 'submit for
95
+ * review' is allowed.", and only `submit_for_review` is accepted. A `name`
96
+ * starting with `sent*` is refused for the same reason — the prefix is reserved.
71
97
  *
72
98
  * @example
73
99
  * ```ts
@@ -205,13 +231,40 @@ export interface Template {
205
231
  */
206
232
  id?: string;
207
233
 
234
+ /**
235
+ * Which consent keyword this template answers, when it is one of Sent's
236
+ * auto-replies: OPT_IN, OPT_OUT, HELP, or OTHER for a customer-defined keyword.
237
+ * Null for an ordinary template, and omitted from the response, so its presence is
238
+ * the answer to "is this an auto-reply".
239
+ *
240
+ * Deliberately not required, unlike CustomerId, even though the same "no single
241
+ * mapper" argument applies: NJsonSchema publishes a C# required member in the
242
+ * schema's required array, so the contract would have advertised a field this
243
+ * response omits for every ordinary template, and a generated client could refuse
244
+ * the common case. A compile-time guard is not worth a wrong published contract.
245
+ * Every mapping site sets it explicitly, and TemplateResponseSchemaTests pins the
246
+ * field as optional so it cannot be reintroduced.
247
+ */
248
+ auto_reply_action?: string | null;
249
+
208
250
  /**
209
251
  * Template category: MARKETING, UTILITY, AUTHENTICATION
210
252
  */
211
253
  category?: string;
212
254
 
213
255
  /**
214
- * Supported channels: sms, whatsapp
256
+ * The channels this template's definition can render on, in canonical order: sms,
257
+ * whatsapp, rcs.
258
+ *
259
+ * Derived from the definition's body, mirroring each channel's send-time fallback
260
+ * chain, so a channel is listed only when a real body would be produced for it:
261
+ * SMS reads sms ?? multiChannel, WhatsApp reads whatsapp ?? multiChannel, and RCS
262
+ * reads rcs ?? multiChannel ?? sms. A multiChannel body therefore reports all
263
+ * three, and the extra SMS fallback on RCS is why an sms/whatsapp pair reports RCS
264
+ * too.
265
+ *
266
+ * This says what the content can render on, not what may be sent: sending also
267
+ * needs the template approved for that channel.
215
268
  */
216
269
  channels?: Array<string> | null;
217
270
 
@@ -236,7 +289,8 @@ export interface Template {
236
289
  name?: string;
237
290
 
238
291
  /**
239
- * Template status: APPROVED, PENDING, REJECTED
292
+ * Template status: DRAFT, PENDING, APPROVED, REJECTED. A template created with
293
+ * submit_for_review: false starts as DRAFT and stays there until it is submitted.
240
294
  */
241
295
  status?: string;
242
296
 
@@ -252,37 +306,79 @@ export interface Template {
252
306
  }
253
307
 
254
308
  /**
255
- * Body section of a message template with channel-specific content
309
+ * Body section of a message template.
310
+ *
311
+ * A body picks one of two authoring strategies, and mixing them is refused
312
+ * (TemplateDefinitionValidator.HaveValidChannelConfiguration): a shared
313
+ * multiChannel body on its own, or an explicit sms + whatsapp pair, both present.
314
+ *
315
+ * multiChannel together with sms or whatsapp is rejected, and so is sms or
316
+ * whatsapp on its own — every template is expected to be deliverable on every
317
+ * channel. rcs is the one true override: it may accompany either strategy to vary
318
+ * the copy, but cannot stand alone.
256
319
  */
257
320
  export interface TemplateBody {
258
321
  /**
259
- * Content that will be used for all channels (SMS and WhatsApp) unless
260
- * channel-specific content is provided
322
+ * The shared body, used for every channel. One half of the choice described above.
261
323
  */
262
324
  multiChannel?: TemplateBodyContent | null;
263
325
 
264
326
  /**
265
- * RCS-specific content that overrides multi-channel content for RCS messages
327
+ * RCS-specific copy that overrides the chosen strategy for RCS only. The one true
328
+ * override: optional on top of either strategy, but it cannot be the only body
329
+ * present. Its length cap is the higher one described on Template.
266
330
  */
267
331
  rcs?: TemplateBodyContent | null;
268
332
 
269
333
  /**
270
- * SMS-specific content that overrides multi-channel content for SMS messages
334
+ * The SMS body. It does not override multiChannel, it replaces it.
271
335
  */
272
336
  sms?: TemplateBodyContent | null;
273
337
 
274
338
  /**
275
- * WhatsApp-specific content that overrides multi-channel content for WhatsApp
276
- * messages
339
+ * The WhatsApp body. It does not override multiChannel, it replaces it.
277
340
  */
278
341
  whatsapp?: TemplateBodyContent | null;
279
342
  }
280
343
 
281
344
  export interface TemplateBodyContent {
345
+ /**
346
+ * The body copy, with variables written as {{index:variable}}.
347
+ *
348
+ * Length cap depends on which channel this body belongs to:
349
+ * TemplateContentLimits.MaxBodyLength (1024) for multiChannel, sms and whatsapp —
350
+ * Meta's BODY limit, which a multiChannel body may be delivered under — and
351
+ * TemplateContentLimits.MaxRcsBodyLength (3072) for an rcs body, which never
352
+ * reaches Meta. The maxLength advertised on this schema is the 1024 one, because
353
+ * all four channel bodies share this single schema — an rcs body between the two
354
+ * is accepted.
355
+ *
356
+ * Meta requires every variable to carry surrounding context, so a body is refused
357
+ * unless it also satisfies all of the following (enforced by
358
+ * TemplateDefinitionValidator): At least one letter before the first variable and
359
+ * after the last — trailing punctuation such as "... {{1:variable}}." does not
360
+ * count. At least (2 × variable count) + 1 words once the placeholders are
361
+ * removed. No two variables adjacent with only whitespace between them. No leading
362
+ * or trailing newline, no more than two consecutive line breaks, and no more than
363
+ * four consecutive spaces.
364
+ *
365
+ * Example: "Hello {{0:variable}}! Welcome to {{1:variable}}. We are glad to have
366
+ * you on board." — two variables, so at least five words are required, and the
367
+ * copy after the final variable contains letters.
368
+ */
282
369
  template: string;
283
370
 
371
+ /**
372
+ * The type of body content — send "text". It is dropped from the stored definition
373
+ * when null, so a body posted without it is saved with no type key at all and the
374
+ * template editor has nothing to render the block from.
375
+ */
284
376
  type?: string | null;
285
377
 
378
+ /**
379
+ * The variables referenced by the body copy, one entry per {{index:variable}}
380
+ * placeholder.
381
+ */
286
382
  variables?: Array<TemplateVariable> | null;
287
383
  }
288
384
 
@@ -301,7 +397,13 @@ export interface TemplateButton {
301
397
  type: string;
302
398
 
303
399
  /**
304
- * The unique identifier of the button (1-based index)
400
+ * The button's identifier (1-based index), unique within the template.
401
+ *
402
+ * Omitting it is only safe for a template holding a single button. The field is a
403
+ * non-nullable int, so every button that leaves it out defaults to 0, and two such
404
+ * buttons are refused by the unique-id rule ("Button IDs must be unique"). Number
405
+ * them from 1 in the order they should appear — order matters on RCS, where only
406
+ * the first four buttons render.
305
407
  */
306
408
  id?: number;
307
409
  }
@@ -317,6 +419,19 @@ export interface TemplateButtonProps {
317
419
 
318
420
  quickReplyType: string;
319
421
 
422
+ /**
423
+ * The button's label. Required for every button type, and capped at
424
+ * TemplateContentLimits.MaxButtonTextLength (25) characters.
425
+ *
426
+ * Meta accepts only static text here, so a label is refused when it contains a
427
+ * {{...}} variable placeholder, a newline, an emoji, or WhatsApp formatting markup
428
+ * (\*, \_, ~) — enforced by ApplyButtonLabelContentRules in
429
+ * TemplateButtonValidator. Meta reports all four as one error: "Buttons can't have
430
+ * any variables, newlines, emojis, or formatting characters."
431
+ *
432
+ * AUTHENTICATION OTP buttons are the exception: Meta auto-localizes their label
433
+ * from the template language, and the converter drops whatever text was sent.
434
+ */
320
435
  text: string;
321
436
 
322
437
  url: string;
@@ -345,7 +460,16 @@ export interface TemplateButtonProps {
345
460
  */
346
461
  export interface TemplateDefinition {
347
462
  /**
348
- * Body section of a message template with channel-specific content
463
+ * Body section of a message template.
464
+ *
465
+ * A body picks one of two authoring strategies, and mixing them is refused
466
+ * (TemplateDefinitionValidator.HaveValidChannelConfiguration): a shared
467
+ * multiChannel body on its own, or an explicit sms + whatsapp pair, both present.
468
+ *
469
+ * multiChannel together with sms or whatsapp is rejected, and so is sms or
470
+ * whatsapp on its own — every template is expected to be deliverable on every
471
+ * channel. rcs is the one true override: it may accompany either strategy to vary
472
+ * the copy, but cannot stand alone.
349
473
  */
350
474
  body: TemplateBody;
351
475
 
@@ -417,12 +541,29 @@ export interface TemplateHeader {
417
541
  }
418
542
 
419
543
  export interface TemplateVariable {
544
+ /**
545
+ * The variable's name, and the key callers use for it in a send request's
546
+ * parameters object. Must start with a letter and hold only letters, digits and
547
+ * underscores.
548
+ */
420
549
  name: string;
421
550
 
422
551
  props: TemplateVariable.Props;
423
552
 
553
+ /**
554
+ * One of variable, link or media. Decides which Props fields are required.
555
+ */
424
556
  type: string;
425
557
 
558
+ /**
559
+ * The variable's index, and the number its {{index:variable}} placeholder refers
560
+ * to.
561
+ *
562
+ * Omitting it is only safe for a section holding a single variable. The field is a
563
+ * non-nullable int, so every variable that leaves it out defaults to 0, and a
564
+ * section with two such variables is refused by the unique-id rule ("variables
565
+ * must have unique IDs"). Number them from 0 in the order they appear.
566
+ */
426
567
  id?: number;
427
568
  }
428
569