@sentdm/sentdm 0.39.0 → 0.41.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 (55) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/client.d.mts +2 -0
  3. package/client.d.mts.map +1 -1
  4. package/client.d.ts +2 -0
  5. package/client.d.ts.map +1 -1
  6. package/client.js +2 -0
  7. package/client.js.map +1 -1
  8. package/client.mjs +2 -0
  9. package/client.mjs.map +1 -1
  10. package/package.json +1 -1
  11. package/resources/conversations.d.mts +126 -3
  12. package/resources/conversations.d.mts.map +1 -1
  13. package/resources/conversations.d.ts +126 -3
  14. package/resources/conversations.d.ts.map +1 -1
  15. package/resources/me.d.mts +21 -0
  16. package/resources/me.d.mts.map +1 -1
  17. package/resources/me.d.ts +21 -0
  18. package/resources/me.d.ts.map +1 -1
  19. package/resources/me.js +5 -0
  20. package/resources/me.js.map +1 -1
  21. package/resources/me.mjs +5 -0
  22. package/resources/me.mjs.map +1 -1
  23. package/resources/messages.d.mts +239 -14
  24. package/resources/messages.d.mts.map +1 -1
  25. package/resources/messages.d.ts +239 -14
  26. package/resources/messages.d.ts.map +1 -1
  27. package/resources/messages.js +21 -3
  28. package/resources/messages.js.map +1 -1
  29. package/resources/messages.mjs +21 -3
  30. package/resources/messages.mjs.map +1 -1
  31. package/resources/templates.d.mts +130 -1
  32. package/resources/templates.d.mts.map +1 -1
  33. package/resources/templates.d.ts +130 -1
  34. package/resources/templates.d.ts.map +1 -1
  35. package/resources/templates.js.map +1 -1
  36. package/resources/templates.mjs.map +1 -1
  37. package/resources/webhooks.d.mts +616 -30
  38. package/resources/webhooks.d.mts.map +1 -1
  39. package/resources/webhooks.d.ts +616 -30
  40. package/resources/webhooks.d.ts.map +1 -1
  41. package/resources/webhooks.js +3 -1
  42. package/resources/webhooks.js.map +1 -1
  43. package/resources/webhooks.mjs +3 -1
  44. package/resources/webhooks.mjs.map +1 -1
  45. package/src/client.ts +2 -0
  46. package/src/resources/conversations.ts +140 -3
  47. package/src/resources/me.ts +22 -0
  48. package/src/resources/messages.ts +259 -14
  49. package/src/resources/templates.ts +143 -1
  50. package/src/resources/webhooks.ts +678 -31
  51. package/src/version.ts +1 -1
  52. package/version.d.mts +1 -1
  53. package/version.d.ts +1 -1
  54. package/version.js +1 -1
  55. package/version.mjs +1 -1
@@ -75,7 +75,9 @@ export declare class Webhooks extends APIResource {
75
75
  */
76
76
  listEventTypes(params?: WebhookListEventTypesParams | null | undefined, options?: RequestOptions): APIPromise<WebhookListEventTypesResponse>;
77
77
  /**
78
- * Retrieves a paginated list of delivery events for the specified webhook.
78
+ * Retrieves a paginated list of delivery events for the specified webhook. If the
79
+ * webhook is cloned onto your sender profiles, the list includes what those clones
80
+ * received; read payload.account_id to tell whose event it is.
79
81
  *
80
82
  * @example
81
83
  * ```ts
@@ -248,7 +250,9 @@ export interface ChannelEventPayload {
248
250
  * The account whose market this is, named as on every other family. When an
249
251
  * organization receives an event for one of its sender profiles this is the
250
252
  * profile, so a reseller compares it with its own id and anything different is one
251
- * of its profiles.
253
+ * of its profiles. Matches customer_id on GET /v3/channels and the sender
254
+ * profile's id. Together with channel, country, and number_type, it identifies the
255
+ * market.
252
256
  */
253
257
  account_id?: string;
254
258
  /**
@@ -257,18 +261,44 @@ export interface ChannelEventPayload {
257
261
  * than a channel that can be provisioned.
258
262
  */
259
263
  channel?: string;
264
+ /**
265
+ * What a market has been given: the identity it registers under, its programme,
266
+ * and any documents attached.
267
+ *
268
+ * What it does not carry is what the market asks for. That is the subject of GET
269
+ * /v3/compliance/requirements, and it is the same answer for every caller — a
270
+ * description of what a compliance regime wants, not a record of one customer's
271
+ * progress through it. It was reported here as well for a while, which put the
272
+ * same array in six response shapes and left a caller deciding which of two
273
+ * sources to believe.
274
+ *
275
+ * Present on a list read for markets that register (carrying brand and campaign),
276
+ * but with documents absent — documents are not fetched for a list, because a
277
+ * catalog lookup and a document read per market would multiply across a page.
278
+ * Absent documents is distinct from an empty list: absent says they were not
279
+ * fetched; empty says the market has been given none. The parent object is null
280
+ * only when the market registers with nobody and compliance was not computed —
281
+ * nothing to show at all.
282
+ */
283
+ compliance?: ChannelEventPayload.Compliance | null;
260
284
  /**
261
285
  * The kind of sender the market uses, for example TEN_DLC, LOCAL, or ALPHANUMERIC.
262
286
  * Omitted when the subject has no sender type of its own.
263
287
  */
264
288
  number_type?: string | null;
265
289
  /**
266
- * Why the market reached this state, when a reason was given — a correction
267
- * explained, or a campaign lapse. Free text, passed through from the registry or
268
- * carrier that wrote it, so treat it as a message to show a human rather than a
269
- * value to branch on.
290
+ * Why the market reached this state, as a sentence to show a person: the specific
291
+ * explanation when one was given (a correction explained, a campaign lapse),
292
+ * otherwise what reason_code means for this market. Not a value to branch on.
270
293
  */
271
294
  reason?: string | null;
295
+ /**
296
+ * Why the market is not ACTIVE, as a stable code: an ErrorCodes CHANNEL_xxx value
297
+ * such as CHANNEL_001 (something you owe) or CHANNEL_002 (a correction was
298
+ * requested). The same code the channels resource reports for the market. Switch
299
+ * on this rather than on reason. Omitted while ACTIVE.
300
+ */
301
+ reason_code?: string | null;
272
302
  /**
273
303
  * The sender itself — a number in E.164, or an alphanumeric sender ID.
274
304
  *
@@ -302,6 +332,93 @@ export interface ChannelEventPayload {
302
332
  */
303
333
  updated_at?: string;
304
334
  }
335
+ export declare namespace ChannelEventPayload {
336
+ /**
337
+ * What a market has been given: the identity it registers under, its programme,
338
+ * and any documents attached.
339
+ *
340
+ * What it does not carry is what the market asks for. That is the subject of GET
341
+ * /v3/compliance/requirements, and it is the same answer for every caller — a
342
+ * description of what a compliance regime wants, not a record of one customer's
343
+ * progress through it. It was reported here as well for a while, which put the
344
+ * same array in six response shapes and left a caller deciding which of two
345
+ * sources to believe.
346
+ *
347
+ * Present on a list read for markets that register (carrying brand and campaign),
348
+ * but with documents absent — documents are not fetched for a list, because a
349
+ * catalog lookup and a document read per market would multiply across a page.
350
+ * Absent documents is distinct from an empty list: absent says they were not
351
+ * fetched; empty says the market has been given none. The parent object is null
352
+ * only when the market registers with nobody and compliance was not computed —
353
+ * nothing to show at all.
354
+ */
355
+ interface Compliance {
356
+ /**
357
+ * The identity this market registers under, with inherit saying whose it is.
358
+ *
359
+ * Reported here rather than on the profile because it belongs to the registration
360
+ * this market files, and only one market files one. It was a top-level block for a
361
+ * while, which put a per-registration value beside a list of markets and left a
362
+ * caller to work out which market it belonged to.
363
+ *
364
+ * Absent for a market that registers with nobody — such a market asks for no
365
+ * identity, so there is none to report. Absent and null mean different things:
366
+ * absent says this market does not ask, null would say it asks and nothing was
367
+ * supplied.
368
+ *
369
+ * Untyped, like the request side, because its members are declared by the market's
370
+ * own schema rather than by a C# class. A typed pair here would be a second
371
+ * definition of what a market wants, free to drift from the one that validates.
372
+ */
373
+ brand?: {
374
+ [key: string]: unknown;
375
+ } | null;
376
+ /**
377
+ * The programme this market registers, with inherit saying whose it is.
378
+ *
379
+ * One, not a list. TcrCampaigns permits several and an account built on the admin
380
+ * side may hold them, but this surface offers one — which is what lets the
381
+ * market's PATCH be an upsert rather than a collection with an addressable create
382
+ * behind it. An account holding several is reported as its first and refused on
383
+ * write, rather than half-edited.
384
+ *
385
+ * Carries no id. Nothing addresses a campaign, and an undeclared key would be
386
+ * refused if the caller sent this object back — which it is meant to be able to
387
+ * do.
388
+ */
389
+ campaign?: {
390
+ [key: string]: unknown;
391
+ } | null;
392
+ /**
393
+ * What has been supplied for this market.
394
+ *
395
+ * Files, not values — the declared halves above carry the values. A document
396
+ * cannot be a JSON value, so it is sent as multipart on the channel call and
397
+ * reported here as a reference.
398
+ *
399
+ * Absent on a list read, which fetches identity but does not compute compliance
400
+ * documents per market. Absent and empty mean different things: absent says the
401
+ * documents were not fetched; empty says the market has been given none.
402
+ */
403
+ documents?: Array<Compliance.Document> | null;
404
+ }
405
+ namespace Compliance {
406
+ /**
407
+ * A document a market asked for and has been given.
408
+ */
409
+ interface Document {
410
+ /**
411
+ * Identifier of the upload, for fetching it back through the documents endpoints.
412
+ */
413
+ document_id?: string | null;
414
+ file_name?: string | null;
415
+ /**
416
+ * The catalog's name for this document, matching the requirement it satisfies.
417
+ */
418
+ key?: string;
419
+ }
420
+ }
421
+ }
305
422
  /**
306
423
  * The envelope Sent POSTs to a subscribed webhook endpoint. Every event shares
307
424
  * this shape and varies only in Payload.
@@ -319,17 +436,25 @@ export interface ContactEvent {
319
436
  */
320
437
  field?: string;
321
438
  /**
322
- * Body of a contact.opt_in, contact.opt_out or contact.help event. Delivered when
323
- * a contact signals a consent change or asks for help.
439
+ * Body of a contact.opt_in, contact.opt_out, contact.help or
440
+ * contact.custom_keyword event. Delivered when a contact signals a consent change,
441
+ * asks for help, or sends one of your own auto-reply keywords.
324
442
  *
325
443
  * These events state the signal outright, so you do not have to recognise keywords
326
444
  * in the text of a message.received event. They also cover cases that produce no
327
445
  * inbound message at all, such as a network handling an opt-out on your behalf.
328
446
  *
329
- * Fields are ordered identity → resulting state → provenance → join key. Nothing
330
- * here restates the envelope: which of the three signals occurred is the
331
- * envelope's event, and when it was emitted is its timestamp. Retries carry the
332
- * same X-Webhook-Event-ID header, which is what to deduplicate on.
447
+ * Two of the four change consent and two do not: contact.help and
448
+ * contact.custom_keyword report the state the contact already had. Read opt_out
449
+ * for the state and the envelope's event for what happened, rather than inferring
450
+ * one from the other.
451
+ *
452
+ * Fields are ordered identity → resulting state → provenance → join keys. The two
453
+ * parties are from and to. Note that the message family has not moved to those
454
+ * names yet — message.received still calls the same two parties inbound_number and
455
+ * outbound_number. Nothing here restates the envelope: which signal occurred is
456
+ * the envelope's event, and when it was emitted is its timestamp. Retries carry
457
+ * the same X-Webhook-Event-ID header, which is what to deduplicate on.
333
458
  */
334
459
  payload?: ContactEventPayload | null;
335
460
  /**
@@ -344,23 +469,32 @@ export interface ContactEvent {
344
469
  timestamp?: string;
345
470
  }
346
471
  /**
347
- * Body of a contact.opt_in, contact.opt_out or contact.help event. Delivered when
348
- * a contact signals a consent change or asks for help.
472
+ * Body of a contact.opt_in, contact.opt_out, contact.help or
473
+ * contact.custom_keyword event. Delivered when a contact signals a consent change,
474
+ * asks for help, or sends one of your own auto-reply keywords.
349
475
  *
350
476
  * These events state the signal outright, so you do not have to recognise keywords
351
477
  * in the text of a message.received event. They also cover cases that produce no
352
478
  * inbound message at all, such as a network handling an opt-out on your behalf.
353
479
  *
354
- * Fields are ordered identity → resulting state → provenance → join key. Nothing
355
- * here restates the envelope: which of the three signals occurred is the
356
- * envelope's event, and when it was emitted is its timestamp. Retries carry the
357
- * same X-Webhook-Event-ID header, which is what to deduplicate on.
480
+ * Two of the four change consent and two do not: contact.help and
481
+ * contact.custom_keyword report the state the contact already had. Read opt_out
482
+ * for the state and the envelope's event for what happened, rather than inferring
483
+ * one from the other.
484
+ *
485
+ * Fields are ordered identity → resulting state → provenance → join keys. The two
486
+ * parties are from and to. Note that the message family has not moved to those
487
+ * names yet — message.received still calls the same two parties inbound_number and
488
+ * outbound_number. Nothing here restates the envelope: which signal occurred is
489
+ * the envelope's event, and when it was emitted is its timestamp. Retries carry
490
+ * the same X-Webhook-Event-ID header, which is what to deduplicate on.
358
491
  */
359
492
  export interface ContactEventPayload {
360
493
  /**
361
494
  * Whether the contact is opted out after this signal — the state to write to your
362
- * own record. Same meaning as opt_out on the contact resource. On contact.help
363
- * this reports the contact's existing state, which help does not change.
495
+ * own record. Same meaning as opt_out on the contact resource. On contact.help and
496
+ * contact.custom_keyword this reports the contact's existing state, which neither
497
+ * changes.
364
498
  *
365
499
  * Two signals from the same contact can arrive out of order, because each one is
366
500
  * queued on its own rather than against the contact. Compare the envelope's
@@ -381,16 +515,32 @@ export interface ContactEventPayload {
381
515
  * accounts.
382
516
  */
383
517
  account_id?: string;
518
+ /**
519
+ * The RCS agent the signal reached, when it reached one.
520
+ *
521
+ * Omitted entirely on channels that have no agent, rather than sent as null — an
522
+ * SMS or WhatsApp payload does not carry this key at all. On RCS it is the
523
+ * counterpart to To: a contact reaches an agent rather than a number, so exactly
524
+ * one of the two is populated and never both. If you run more than one agent, this
525
+ * is what tells you which of them the contact acted on.
526
+ */
527
+ agent_id?: string | null;
384
528
  /**
385
529
  * The channel the signal arrived on, for example sms or whatsapp.
386
530
  */
387
531
  channel?: string;
388
532
  /**
389
533
  * The contact who raised the signal. Always populated, including for contact.help
390
- * from a number you have not messaged before — the contact is created if it does
391
- * not exist yet, so this identifier is always resolvable against the contacts API.
534
+ * or contact.custom_keyword from a number you have not messaged before — the
535
+ * contact is created if it does not exist yet, so this identifier is always
536
+ * resolvable against the contacts API.
392
537
  */
393
538
  contact_id?: string;
539
+ /**
540
+ * The contact's number, in E.164 format with the leading + — who raised the
541
+ * signal. The same party message.received publishes as inbound_number.
542
+ */
543
+ from?: string;
394
544
  /**
395
545
  * The inbound message that carried the signal, matching message_id on the
396
546
  * corresponding message.received event so the two can be joined.
@@ -403,16 +553,40 @@ export interface ContactEventPayload {
403
553
  */
404
554
  message_id?: string | null;
405
555
  /**
406
- * The contact's number in E.164 format. Same value as phone_number on the contact
407
- * resource.
556
+ * The auto-reply template whose keyword the contact matched, joinable against the
557
+ * templates API.
558
+ *
559
+ * This is what identifies which signal arrived on contact.custom_keyword: every
560
+ * custom template reports the same event name, so the event alone cannot tell your
561
+ * booking keyword from your opening-hours one. One template holds as many keywords
562
+ * as you configured, so this is steadier to switch on than text.
563
+ *
564
+ * Populated on the compliance sub-types too, where it names the template that
565
+ * replied. Sent as null when no template was involved — a network-reported opt-out
566
+ * matches no keyword. The field is always present, so read it and check for null.
408
567
  */
409
- phone_number?: string;
568
+ template_id?: string | null;
410
569
  /**
411
570
  * The text the contact sent, for example STOP or UNSUBSCRIBE. Sent as null when
412
571
  * the signal did not arrive as text. The field is always present, so read it and
413
572
  * check for null rather than checking whether the key exists.
414
573
  */
415
574
  text?: string | null;
575
+ /**
576
+ * The number of yours that received the signal, in E.164 format with the leading
577
+ * +. Tells a multi-number account which of its senders the contact acted on, which
578
+ * nothing else on this payload answers.
579
+ *
580
+ * This is your number, not the contact's. That is the opposite of what to means on
581
+ * POST /v3/messages, where it is the list of recipients you are sending to. Reply
582
+ * to From, not to this field, or the message goes back to yourself.
583
+ *
584
+ * Sent as null when the signal did not arrive at a number of yours — an RCS signal
585
+ * terminates at an agent rather than a number, and a provider-reported opt-out may
586
+ * name no receiving number at all. The field is always present, so read it and
587
+ * check for null rather than checking whether the key exists.
588
+ */
589
+ to?: string | null;
416
590
  }
417
591
  /**
418
592
  * Error information
@@ -487,9 +661,22 @@ export interface InboundMessageEventPayload {
487
661
  */
488
662
  account_id?: string;
489
663
  /**
490
- * The channel the message arrived on, for example sms or whatsapp.
664
+ * The channel the message arrived on, for example sms or mms.
491
665
  */
492
666
  channel?: string;
667
+ /**
668
+ * Attachments the contact sent, present only on channels that carry them (mms
669
+ * today) and omitted entirely otherwise.
670
+ *
671
+ * Each url points at the carrier's own copy of the file — sent.dm records where
672
+ * the attachment is, not the attachment itself. The link is unauthenticated and
673
+ * expires on the carrier's schedule, which differs between them: assume days, not
674
+ * months. Download what you need on receipt; re-reading the message through GET
675
+ * /v3/messages/{id} returns the same stored link, not a fresh one, so once it
676
+ * lapses the entry remains with whatever the carrier declared about the file but
677
+ * the file is no longer reachable.
678
+ */
679
+ media?: Array<InboundMessageEventPayload.Media> | null;
493
680
  /**
494
681
  * The inbound message.
495
682
  */
@@ -510,6 +697,37 @@ export interface InboundMessageEventPayload {
510
697
  */
511
698
  updated_at?: string;
512
699
  }
700
+ export declare namespace InboundMessageEventPayload {
701
+ /**
702
+ * One attachment on an inbound message.
703
+ */
704
+ interface Media {
705
+ /**
706
+ * SHA-256 of the file as the carrier declared it, when it declares one. Verify
707
+ * what you download against this — sent.dm never reads the bytes, so it is the
708
+ * only integrity signal available.
709
+ */
710
+ hash_sha256?: string | null;
711
+ /**
712
+ * Content type as the carrier reported it, for example image/jpeg.
713
+ */
714
+ mime_type?: string | null;
715
+ /**
716
+ * Size in bytes as the carrier declared it. Absent when it declared none.
717
+ */
718
+ size_bytes?: number | null;
719
+ /**
720
+ * Where the carrier hosts the attachment.
721
+ *
722
+ * This link expires and is not authenticated. sent.dm relays it rather than
723
+ * copying the file, so how long it stays fetchable is the carrier's decision and
724
+ * differs between them — assume days, not months. Anyone holding the URL can fetch
725
+ * it until it lapses. Copy the file on receipt if you need it to outlive that
726
+ * window; do not store this URL as a permanent reference.
727
+ */
728
+ url?: string | null;
729
+ }
730
+ }
513
731
  /**
514
732
  * The envelope Sent POSTs to a subscribed webhook endpoint. Every event shares
515
733
  * this shape and varies only in Payload.
@@ -583,6 +801,31 @@ export interface MessageEventPayload {
583
801
  * The recipient's number in E.164 format.
584
802
  */
585
803
  outbound_number?: string;
804
+ /**
805
+ * A human-readable sentence for ReasonCode, for example "The recipient is not
806
+ * registered on this channel". Omitted whenever reason_code is.
807
+ */
808
+ reason?: string | null;
809
+ /**
810
+ * Why the message reached this status, as a stable platform code such as
811
+ * DELIVERY_007 or BUSINESS_003. Present on message.failed, message.filtered and
812
+ * message.blocked; omitted on every status that needs no explanation. Switch on
813
+ * this rather than on Reason: the code is stable, the wording may be improved. It
814
+ * is the platform's classification of the outcome and never a carrier or vendor
815
+ * code.
816
+ */
817
+ reason_code?: string | null;
818
+ /**
819
+ * message.scheduled only: why the message is held, either because you scheduled it
820
+ * or because the recipient is inside a protected quiet-hours window. Omitted on
821
+ * every other event.
822
+ */
823
+ schedule_reason?: string | null;
824
+ /**
825
+ * message.scheduled only: when the held message will be released for delivery, in
826
+ * UTC (yyyy-MM-ddTHH:mm:ssZ). Omitted on every other event.
827
+ */
828
+ scheduled_at?: string | null;
586
829
  /**
587
830
  * The template the message was sent from, when it was sent from one.
588
831
  */
@@ -822,17 +1065,324 @@ export interface WebhookListEventsResponse {
822
1065
  error_message?: string | null;
823
1066
  /**
824
1067
  * The exact event body that was delivered, or attempted, for this record. One of
825
- * the four webhook envelopes: a message status change, an inbound message, a
826
- * template status change, or a contact consent signal. Read field and event to
827
- * tell which, the same way your endpoint does.
1068
+ * the six webhook envelopes:
1069
+ *
1070
+ * message — an outbound message changed status. message with event:
1071
+ * message.received — someone replied to you. templates — a template was approved,
1072
+ * rejected, paused or similar. channel — one of your markets moved in provisioning
1073
+ * or compliance. contact — a consent signal: opt-in, opt-out or help. link — a
1074
+ * tracked short link was clicked or a hosted file downloaded, or one expired or
1075
+ * was revoked.
1076
+ *
1077
+ * Read field and event to tell which, the same way your endpoint does. The two
1078
+ * message envelopes are the reason that is two fields and not one: they share a
1079
+ * field and differ by event.
1080
+ *
1081
+ * Treat the list as open. It has grown twice — channel and then link — and a
1082
+ * handler that rejects an envelope it does not recognise will break on the next
1083
+ * addition rather than ignore it.
828
1084
  */
829
- event_data?: MessageEvent | InboundMessageEvent | TemplateEvent | ChannelEvent | ContactEvent;
1085
+ event_data?: MessageEvent | InboundMessageEvent | TemplateEvent | ChannelEvent | ContactEvent | WebhookListEventsResponse.SentDmServicesCommonServicesWebhooksContractsWebhookEventOfLinkWebhookPayload | WebhookListEventsResponse.SentDmServicesCommonServicesWebhooksContractsWebhookEventOfCallWebhookPayload;
830
1086
  event_type?: string;
831
1087
  http_status_code?: number | null;
832
1088
  processing_completed_at?: string | null;
833
1089
  processing_started_at?: string | null;
834
1090
  response_body?: string | null;
835
1091
  }
1092
+ export declare namespace WebhookListEventsResponse {
1093
+ /**
1094
+ * The envelope Sent POSTs to a subscribed webhook endpoint. Every event shares
1095
+ * this shape and varies only in Payload.
1096
+ */
1097
+ interface SentDmServicesCommonServicesWebhooksContractsWebhookEventOfLinkWebhookPayload {
1098
+ /**
1099
+ * The specific event within the family, for example message.delivered,
1100
+ * message.received or contact.opt_out. Absent on events that have no subtype, so
1101
+ * treat it as optional.
1102
+ */
1103
+ event?: string | null;
1104
+ /**
1105
+ * The event family, for example message, templates or contact. Route on this
1106
+ * first, then on event for the specific change.
1107
+ */
1108
+ field?: string;
1109
+ /**
1110
+ * Body of a link event: something happened to a tracked link Sent published on the
1111
+ * customer's behalf. A link points either at a URL the customer supplied or at a
1112
+ * file Sent hosts for them; LinkKind says which. Delivered when an eligible
1113
+ * request is served, or when a published link reaches the end of its life.
1114
+ *
1115
+ * A click is a request, not a read receipt. link.clicked means the redirect was
1116
+ * served; link.downloaded means bytes went out. Neither proves a person saw
1117
+ * anything — messaging providers and link scanners fetch URLs on their own, which
1118
+ * is what TrafficClass exists to tell apart. Filter on it before reporting a
1119
+ * click-through rate; treat likely_human as a hint, never as delivery
1120
+ * confirmation.
1121
+ *
1122
+ * RecordId identifies the link; the X-Webhook-Event-ID header identifies the
1123
+ * delivery. One link is hit many times, so those are the two keys a subscriber
1124
+ * needs: group by the first, deduplicate on the second — exactly as on every other
1125
+ * family. The payload carries no event identifier of its own, for the same reason
1126
+ * none of the others do.
1127
+ *
1128
+ * Nothing here identifies the visitor. No IP address and no visitor token crosses
1129
+ * this boundary. Country, Device and Browser are coarse buckets derived at the
1130
+ * edge and are absent whenever the request did not supply enough to derive them.
1131
+ */
1132
+ payload?: SentDmServicesCommonServicesWebhooksContractsWebhookEventOfLinkWebhookPayload.Payload | null;
1133
+ /**
1134
+ * The event-specific body.
1135
+ */
1136
+ request_id?: string | null;
1137
+ /**
1138
+ * When Sent emitted the event, in UTC (yyyy-MM-ddTHH:mm:ssZ). This is the emission
1139
+ * time, not the time the underlying change happened. Use the timestamp inside the
1140
+ * payload for the latter.
1141
+ */
1142
+ timestamp?: string;
1143
+ }
1144
+ namespace SentDmServicesCommonServicesWebhooksContractsWebhookEventOfLinkWebhookPayload {
1145
+ /**
1146
+ * Body of a link event: something happened to a tracked link Sent published on the
1147
+ * customer's behalf. A link points either at a URL the customer supplied or at a
1148
+ * file Sent hosts for them; LinkKind says which. Delivered when an eligible
1149
+ * request is served, or when a published link reaches the end of its life.
1150
+ *
1151
+ * A click is a request, not a read receipt. link.clicked means the redirect was
1152
+ * served; link.downloaded means bytes went out. Neither proves a person saw
1153
+ * anything — messaging providers and link scanners fetch URLs on their own, which
1154
+ * is what TrafficClass exists to tell apart. Filter on it before reporting a
1155
+ * click-through rate; treat likely_human as a hint, never as delivery
1156
+ * confirmation.
1157
+ *
1158
+ * RecordId identifies the link; the X-Webhook-Event-ID header identifies the
1159
+ * delivery. One link is hit many times, so those are the two keys a subscriber
1160
+ * needs: group by the first, deduplicate on the second — exactly as on every other
1161
+ * family. The payload carries no event identifier of its own, for the same reason
1162
+ * none of the others do.
1163
+ *
1164
+ * Nothing here identifies the visitor. No IP address and no visitor token crosses
1165
+ * this boundary. Country, Device and Browser are coarse buckets derived at the
1166
+ * edge and are absent whenever the request did not supply enough to derive them.
1167
+ */
1168
+ interface Payload {
1169
+ /**
1170
+ * The link's public identifier — the eight-character code in the short URL, for
1171
+ * example A78B2BU0. Unique across both kinds, and never reused, so it is the
1172
+ * stable key to group one link's events by.
1173
+ */
1174
+ record_id: string;
1175
+ /**
1176
+ * Where the request appeared to come from, as an ISO 3166-1 alpha-2 code. Named
1177
+ * separately from the country on a channel event, which is a destination market
1178
+ * the customer registered for — this one is a property of a single visitor and is
1179
+ * absent when the edge could not resolve it.
1180
+ */
1181
+ access_country?: string | null;
1182
+ /**
1183
+ * How the request was served, when the edge recorded it. Free text describing the
1184
+ * outcome — show it to a human rather than branching on it.
1185
+ */
1186
+ access_outcome?: string | null;
1187
+ /**
1188
+ * The requesting browser family, for example chrome or safari, or unknown. Derived
1189
+ * from the user agent.
1190
+ */
1191
+ browser?: string | null;
1192
+ /**
1193
+ * How many bytes were served, for a file access. A ranged request reports the
1194
+ * bytes in that range, not the size of the file, so several accesses of one file
1195
+ * can each report a part.
1196
+ */
1197
+ bytes_served?: number | null;
1198
+ /**
1199
+ * The channel the message carrying this link went out on: sms, whatsapp, or rcs.
1200
+ */
1201
+ channel?: string | null;
1202
+ /**
1203
+ * The organization the link belongs to. Always the parent account, never a sender
1204
+ * profile — read SenderProfileId for that.
1205
+ *
1206
+ * This family publishes the owner as an explicit pair rather than the single
1207
+ * account_id the other families use. The pair says which organization and which
1208
+ * profile without the subscriber deriving either, which is the trade: one more key
1209
+ * against not having to know that account_id silently becomes the profile when one
1210
+ * exists.
1211
+ */
1212
+ customer_id?: string;
1213
+ /**
1214
+ * The requesting device class: mobile, tablet, desktop or unknown. Derived from
1215
+ * the user agent.
1216
+ */
1217
+ device?: string | null;
1218
+ /**
1219
+ * What the link points at: url for a destination the customer supplied, file for
1220
+ * media Sent hosts. Always present, and implied by the event — link.clicked is
1221
+ * always url and link.downloaded always file — but published as its own field so a
1222
+ * subscriber can branch on the kind without parsing the event name, the same
1223
+ * separation the channel family keeps between its event and its status.
1224
+ */
1225
+ link_kind?: string;
1226
+ /**
1227
+ * The message the link was published in.
1228
+ *
1229
+ * The event can arrive before the message is readable through GET /v3/messages: a
1230
+ * provider may fetch a link within milliseconds of the send, and nothing here
1231
+ * waits for the message row. Retry the read rather than treating an unknown id as
1232
+ * an error.
1233
+ */
1234
+ message_id?: string | null;
1235
+ /**
1236
+ * When the access or lifecycle change actually happened, in UTC
1237
+ * (yyyy-MM-ddTHH:mm:ssZ). The envelope's timestamp is when Sent emitted the event;
1238
+ * this is when the thing occurred, and the two differ by the ingest delay.
1239
+ */
1240
+ occurred_at?: string;
1241
+ /**
1242
+ * The caller-supplied label tying this link back to a position in the message, for
1243
+ * example body:0 for the first link in the body. Present when the link was created
1244
+ * with one.
1245
+ */
1246
+ reference_key?: string | null;
1247
+ /**
1248
+ * The host of the page that linked here, when the request supplied one. The host
1249
+ * only — never a full referring URL.
1250
+ */
1251
+ referrer_host?: string | null;
1252
+ /**
1253
+ * The HTTP method of the request that was served, for an access event. Omitted on
1254
+ * link.expired and link.revoked, which describe no request.
1255
+ */
1256
+ request_method?: string | null;
1257
+ /**
1258
+ * The sender profile that owns the link, or null when the organization owns it
1259
+ * directly. Always on the wire so a handler reads one shape rather than branching
1260
+ * on whether the key arrived.
1261
+ *
1262
+ * sender_profile_id, not profile_id: the API already publishes
1263
+ * messaging_profile_id and sending_phone_number_profile_id for provider-side
1264
+ * profiles, which are a different thing entirely. The unqualified name would read
1265
+ * as one of those.
1266
+ */
1267
+ sender_profile_id?: string | null;
1268
+ /**
1269
+ * The HTTP status Sent answered the request with: 302 for a link, 200 or 206 for a
1270
+ * file. Omitted on lifecycle events.
1271
+ */
1272
+ status_code?: number | null;
1273
+ /**
1274
+ * A coarse guess at what made the request: likely_human, provider (a messaging
1275
+ * platform prefetching the link), bot, or unknown. Derived from the user agent, so
1276
+ * it is a hint for filtering noise rather than a fact to bill or report on.
1277
+ */
1278
+ traffic_class?: string | null;
1279
+ }
1280
+ }
1281
+ /**
1282
+ * The envelope Sent POSTs to a subscribed webhook endpoint. Every event shares
1283
+ * this shape and varies only in Payload.
1284
+ */
1285
+ interface SentDmServicesCommonServicesWebhooksContractsWebhookEventOfCallWebhookPayload {
1286
+ /**
1287
+ * The specific event within the family, for example message.delivered,
1288
+ * message.received or contact.opt_out. Absent on events that have no subtype, so
1289
+ * treat it as optional.
1290
+ */
1291
+ event?: string | null;
1292
+ /**
1293
+ * The event family, for example message, templates or contact. Route on this
1294
+ * first, then on event for the specific change.
1295
+ */
1296
+ field?: string;
1297
+ /**
1298
+ * Body of a call.initiated, call.answered, call.completed, call.failed or
1299
+ * call.recording_ready event. Which of them occurred is the envelope's event.
1300
+ *
1301
+ * Shaped like the message, inbound, template and channel payloads: account_id
1302
+ * names the account the event is about, channel names the channel, and updated_at
1303
+ * is when the change happened on the call, in the same yyyy-MM-ddTHH:mm:ssZ form.
1304
+ * duration_seconds and price are added on call.completed, reason on call.failed
1305
+ * and recording_id on call.recording_ready; each is omitted rather than sent as
1306
+ * null when it does not apply.
1307
+ *
1308
+ * Casing is snake_case because these ride the same webhook stream customers
1309
+ * already parse message_id from; the question/answer contract is a separate
1310
+ * surface and stays camelCase. Nothing here is provider-shaped: no provider call
1311
+ * id, no namespaced identity.
1312
+ */
1313
+ payload?: SentDmServicesCommonServicesWebhooksContractsWebhookEventOfCallWebhookPayload.Payload | null;
1314
+ /**
1315
+ * The event-specific body.
1316
+ */
1317
+ request_id?: string | null;
1318
+ /**
1319
+ * When Sent emitted the event, in UTC (yyyy-MM-ddTHH:mm:ssZ). This is the emission
1320
+ * time, not the time the underlying change happened. Use the timestamp inside the
1321
+ * payload for the latter.
1322
+ */
1323
+ timestamp?: string;
1324
+ }
1325
+ namespace SentDmServicesCommonServicesWebhooksContractsWebhookEventOfCallWebhookPayload {
1326
+ /**
1327
+ * Body of a call.initiated, call.answered, call.completed, call.failed or
1328
+ * call.recording_ready event. Which of them occurred is the envelope's event.
1329
+ *
1330
+ * Shaped like the message, inbound, template and channel payloads: account_id
1331
+ * names the account the event is about, channel names the channel, and updated_at
1332
+ * is when the change happened on the call, in the same yyyy-MM-ddTHH:mm:ssZ form.
1333
+ * duration_seconds and price are added on call.completed, reason on call.failed
1334
+ * and recording_id on call.recording_ready; each is omitted rather than sent as
1335
+ * null when it does not apply.
1336
+ *
1337
+ * Casing is snake_case because these ride the same webhook stream customers
1338
+ * already parse message_id from; the question/answer contract is a separate
1339
+ * surface and stays camelCase. Nothing here is provider-shaped: no provider call
1340
+ * id, no namespaced identity.
1341
+ */
1342
+ interface Payload {
1343
+ /**
1344
+ * Sent's call id, the same one the customer saw on the first question.
1345
+ */
1346
+ call_id: string;
1347
+ /**
1348
+ * The account the call belongs to: the key's own customer, or the sender profile
1349
+ * it acted as.
1350
+ */
1351
+ account_id?: string;
1352
+ /**
1353
+ * Always voice.
1354
+ */
1355
+ channel?: string;
1356
+ /**
1357
+ * How long the call lasted. Only on call.completed.
1358
+ */
1359
+ duration_seconds?: number | null;
1360
+ /**
1361
+ * The customer number that owns the call, in E.164 format.
1362
+ */
1363
+ number?: string;
1364
+ /**
1365
+ * What the call was charged. Only on call.completed, and omitted there until
1366
+ * billing has recorded the charge.
1367
+ */
1368
+ price?: number | null;
1369
+ /**
1370
+ * The machine-readable reason the call did not complete. Only on call.failed, and
1371
+ * omitted when no reason was recorded.
1372
+ */
1373
+ reason?: string | null;
1374
+ /**
1375
+ * The recording that became available, the same id GET /v3/calls/{id}/recordings
1376
+ * lists it under. Only on call.recording_ready, which is sent once per recording.
1377
+ */
1378
+ recording_id?: string | null;
1379
+ /**
1380
+ * When the change happened on the call, as opposed to when the event was emitted.
1381
+ */
1382
+ updated_at?: string;
1383
+ }
1384
+ }
1385
+ }
836
1386
  /**
837
1387
  * Standard API response envelope for all v3 endpoints
838
1388
  */
@@ -920,6 +1470,12 @@ export interface WebhookCreateParams {
920
1470
  * effects Useful for testing integrations without actual execution
921
1471
  */
922
1472
  sandbox?: boolean;
1473
+ /**
1474
+ * Body param: Request-only: the events an organization webhook's sender profile
1475
+ * clones receive, one clone per existing and future profile. Responses never
1476
+ * return it.
1477
+ */
1478
+ sender_profile?: WebhookCreateParams.SenderProfile | null;
923
1479
  /**
924
1480
  * Body param
925
1481
  */
@@ -937,6 +1493,18 @@ export interface WebhookCreateParams {
937
1493
  */
938
1494
  'x-profile-id'?: string;
939
1495
  }
1496
+ export declare namespace WebhookCreateParams {
1497
+ /**
1498
+ * Request-only: the events an organization webhook's sender profile clones
1499
+ * receive, one clone per existing and future profile. Responses never return it.
1500
+ */
1501
+ interface SenderProfile {
1502
+ event_filters?: {
1503
+ [key: string]: Array<string>;
1504
+ } | null;
1505
+ event_types?: Array<string>;
1506
+ }
1507
+ }
940
1508
  export interface WebhookRetrieveParams {
941
1509
  /**
942
1510
  * Profile UUID to scope the request to a child profile. Only organization API keys
@@ -972,6 +1540,12 @@ export interface WebhookUpdateParams {
972
1540
  * effects Useful for testing integrations without actual execution
973
1541
  */
974
1542
  sandbox?: boolean;
1543
+ /**
1544
+ * Body param: Request-only: the events an organization webhook's sender profile
1545
+ * clones receive, one clone per existing and future profile. Responses never
1546
+ * return it.
1547
+ */
1548
+ sender_profile?: WebhookUpdateParams.SenderProfile | null;
975
1549
  /**
976
1550
  * Body param
977
1551
  */
@@ -989,6 +1563,18 @@ export interface WebhookUpdateParams {
989
1563
  */
990
1564
  'x-profile-id'?: string;
991
1565
  }
1566
+ export declare namespace WebhookUpdateParams {
1567
+ /**
1568
+ * Request-only: the events an organization webhook's sender profile clones
1569
+ * receive, one clone per existing and future profile. Responses never return it.
1570
+ */
1571
+ interface SenderProfile {
1572
+ event_filters?: {
1573
+ [key: string]: Array<string>;
1574
+ } | null;
1575
+ event_types?: Array<string>;
1576
+ }
1577
+ }
992
1578
  export interface WebhookListParams extends WebhooksPageParams {
993
1579
  /**
994
1580
  * Query param