@proteos/sdk 0.50.1 → 0.51.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.
@@ -56,6 +56,7 @@ export type ConnectorKey =
56
56
  | 'twilio-phone'
57
57
  | 'aircall'
58
58
  | 'webhook-cti'
59
+ | 'sendgrid'
59
60
 
60
61
  /**
61
62
  * Telephony lifecycle of one phone call, carried in the call conversation's
@@ -465,6 +466,12 @@ export interface Message {
465
466
  */
466
467
  child_conversation_id?: string
467
468
  child_messages_total?: number
469
+ /**
470
+ * Provider-side outcome + engagement projection of an OUTBOUND message on
471
+ * a sending platform (folded from the channel_event ledger); absent on
472
+ * channels that report nothing and on inbound rows.
473
+ */
474
+ delivery?: MessageDelivery
468
475
  metadata: Record<string, unknown>
469
476
  error: string
470
477
  created_at: string
@@ -473,6 +480,31 @@ export interface Message {
473
480
  updated_by: UserRef
474
481
  }
475
482
 
483
+ /**
484
+ * Provider-side outcome of an outbound message — a separate axis from
485
+ * MessageStatus (the message stays `sent` at the platform level once the
486
+ * provider accepted it): sent → delivered | deferred | bounced | dropped.
487
+ */
488
+ export type MessageDeliveryStatus = 'sent' | 'delivered' | 'deferred' | 'bounced' | 'dropped'
489
+
490
+ /** The read-side fold of a message's channel events. */
491
+ export interface MessageDelivery {
492
+ status: MessageDeliveryStatus
493
+ delivered_at?: string
494
+ bounced_at?: string
495
+ dropped_at?: string
496
+ /** First HUMAN open / click; totals count every event (machine opens excluded). */
497
+ opened_at?: string
498
+ opens_total?: number
499
+ clicked_at?: string
500
+ clicks_total?: number
501
+ spam_reported_at?: string
502
+ unsubscribed_at?: string
503
+ /** Latest bounce / drop / deferral text. */
504
+ reason?: string
505
+ last_event_at?: string
506
+ }
507
+
476
508
  /**
477
509
  * Per-trigger configuration, discriminated by the sibling trigger_type: channel
478
510
  * carries external_channel_id, keyword carries phrases, always/mention carry
@@ -631,6 +663,15 @@ export interface SendMessageRequest {
631
663
  * `unsupported_content`.
632
664
  */
633
665
  attachments?: FileRef[]
666
+ /**
667
+ * Overrides the sending identity on a sending-platform email connection: a
668
+ * contact address id on the connection's sender domain
669
+ * (`connections.listSenders`). Without it: the conversation's pinned sender
670
+ * → the acting user's own address on the domain → the connection's default.
671
+ * Off-domain ids fail with `sender_not_found`; connections without a sender
672
+ * domain refuse it with `sender_domain_not_available`.
673
+ */
674
+ sender_address_id?: string
634
675
  }
635
676
 
636
677
  /**
@@ -999,6 +1040,8 @@ export interface ListConversationsQuery extends PaginationQuery {
999
1040
  /** Threads whose roster contains this external party — the person stream. */
1000
1041
  /** Contact stream: threads whose roster contains the resolved person. */
1001
1042
  contact_id?: string
1043
+ /** "Sent as" stream: threads pinned to one sending identity (a contact address id). */
1044
+ sender_address_id?: string
1002
1045
  /** Opt into the root/latest message projection on each row. */
1003
1046
  include?: 'messages_summary'
1004
1047
  }
@@ -1197,7 +1240,19 @@ export type ContactSource = 'sync' | 'ingest' | 'manual' | 'merge'
1197
1240
  export type ContactStatus = 'active' | 'merged' | 'archived' | 'erased'
1198
1241
  export type ConsentStatus = 'unknown' | 'opted_in' | 'opted_out'
1199
1242
  export type PermissionEventType = 'opt_in' | 'opt_out' | 'block' | 'unblock'
1200
- export type PermissionEventSource = 'manual' | 'import' | 'link_click' | 'reply' | 'api' | 'system'
1243
+ /**
1244
+ * Where a permission event came from. `provider` = the sending platform
1245
+ * observed it (its unsubscribe link, a spam complaint relayed by the mailbox
1246
+ * provider, a hard bounce); `link_click` stays for OUR unsubscribe links.
1247
+ */
1248
+ export type PermissionEventSource =
1249
+ | 'manual'
1250
+ | 'import'
1251
+ | 'link_click'
1252
+ | 'reply'
1253
+ | 'api'
1254
+ | 'system'
1255
+ | 'provider'
1201
1256
  export type MergeProposalStatus = 'proposed' | 'approved' | 'rejected' | 'superseded'
1202
1257
  export type ErasureRequestStatus = 'requested' | 'completed'
1203
1258
  export type RoomSource = 'sync' | 'ingest'
@@ -1357,6 +1412,12 @@ export interface ListContactsQuery extends PaginationQuery {
1357
1412
  status?: ContactStatus
1358
1413
  /** Members of one contact group (drives group-member lists). */
1359
1414
  group_key?: string
1415
+ /**
1416
+ * The contact bound to one platform user (at most one active contact per
1417
+ * user per org); `'me'` resolves to the caller — a client's way to its own
1418
+ * contact.
1419
+ */
1420
+ platform_user_id?: string
1360
1421
  }
1361
1422
 
1362
1423
  export interface UpdateContactRequest {
@@ -1380,8 +1441,18 @@ export interface UpdateContactRequest {
1380
1441
  * rejects the create with 409 contact_address_taken.
1381
1442
  */
1382
1443
  export interface CreateContactRequest {
1383
- name: string
1384
- addresses: AttachContactAddressRequest[]
1444
+ /** Required without platform_user_id; with it, fills an empty name only. */
1445
+ name?: string
1446
+ /** Required (≥1) without platform_user_id; with it, attached to the colleague's contact. */
1447
+ addresses?: AttachContactAddressRequest[]
1448
+ /**
1449
+ * Colleague mode: ensure the contact bound to this platform user (created
1450
+ * from the account directory, or the existing one — every colleague has
1451
+ * exactly one) and attach the addresses to it. 200 when it already
1452
+ * existed, 201 when created; 404 `platform_user_not_found`, 409
1453
+ * `contact_platform_user_conflict`.
1454
+ */
1455
+ platform_user_id?: string
1385
1456
  /** IANA zone name; optional, validated as on update. */
1386
1457
  timezone?: string
1387
1458
  /** BCP-47 language tag; optional, validated as on update. */
@@ -1643,7 +1714,7 @@ export interface DispatchMeetingBotRequest {
1643
1714
  * period), frequency_cap (HOW OFTEN one contact may be contacted per rolling
1644
1715
  * period).
1645
1716
  */
1646
- export type SendingRuleType = 'window' | 'limit' | 'frequency_cap'
1717
+ export type SendingRuleType = 'window' | 'limit' | 'frequency_cap' | 'warmup'
1647
1718
  /** Rolling lookback ("last 24 hours from now") — never a calendar day. */
1648
1719
  export type SendingPeriod = 'rolling_24h' | 'rolling_7d' | 'rolling_30d'
1649
1720
  /**
@@ -1684,7 +1755,27 @@ export interface FrequencyCapRuleConfig {
1684
1755
  max_count: number
1685
1756
  period: SendingPeriod
1686
1757
  }
1687
- export type SendingRuleConfig = WindowRuleConfig | LimitRuleConfig | FrequencyCapRuleConfig
1758
+ /**
1759
+ * A limit that RAMPS: `start_count` acts of `action` per rolling `period` on
1760
+ * the day the warmup started, growing by `daily_increase` (a count, or a
1761
+ * percent of the previous day's allowance when `is_increase_percent`) every
1762
+ * UTC calendar day until `max_count`, after which it behaves as a plain
1763
+ * limit. `started_at` may be omitted on create — the server stamps now.
1764
+ */
1765
+ export interface WarmupRuleConfig {
1766
+ action: ChannelActionType
1767
+ start_count: number
1768
+ daily_increase: number
1769
+ is_increase_percent?: boolean
1770
+ max_count: number
1771
+ period: SendingPeriod
1772
+ started_at: string
1773
+ }
1774
+ export type SendingRuleConfig =
1775
+ | WindowRuleConfig
1776
+ | LimitRuleConfig
1777
+ | FrequencyCapRuleConfig
1778
+ | WarmupRuleConfig
1688
1779
 
1689
1780
  /**
1690
1781
  * One outbound send constraint, defined once and LINKED to any number of
@@ -1692,6 +1783,85 @@ export type SendingRuleConfig = WindowRuleConfig | LimitRuleConfig | FrequencyCa
1692
1783
  * specific tier wins at send time: names the connection > names the channel >
1693
1784
  * org-wide. Replies skip the rule when `is_reply_exempt`.
1694
1785
  */
1786
+ // ── Conversation briefs ──────────────────────────────────────────────────────────────
1787
+
1788
+ /**
1789
+ * Lifecycle of a conversation brief: `prepared` (open — editable, waiting for its
1790
+ * call), `used` (attached to a call conversation; terminal), `discarded`
1791
+ * (declined without a call; terminal).
1792
+ */
1793
+ export type ConversationBriefStatus = 'prepared' | 'used' | 'discarded'
1794
+
1795
+ /**
1796
+ * Guidance prepared AHEAD of a conversation — "talk to these people about
1797
+ * this" — the conversation sibling of a draft message. Binding to a
1798
+ * conversation is always explicit: the softphone carries the brief id into
1799
+ * the call (attached at call start), or `attach` names the conversation.
1800
+ * Nothing matches by contact or number, and any number of briefs may be open
1801
+ * for the same people at once. Records that want a brief (an activity) store
1802
+ * its id; every UI surface renders from the id.
1803
+ */
1804
+ export interface ConversationBrief {
1805
+ id: string
1806
+ org_id: string
1807
+ /** Human label ("Renewal call with Dana"); may be empty. */
1808
+ subject: string
1809
+ /** The people the conversation is with (≥ 1, deduplicated, sorted). */
1810
+ contact_ids: string[]
1811
+ /** How the conversation should happen (phone opens the softphone); absent = unspecified. */
1812
+ channel?: Channel
1813
+ /** ConversationType key the conversation is meant to be; stamped on attach. */
1814
+ type_key?: string
1815
+ /** The conversation the brief was used on; absent until used. */
1816
+ conversation_id?: string
1817
+ status: ConversationBriefStatus
1818
+ /** Guidance text (markdown allowed). */
1819
+ content: string
1820
+ used_at?: string
1821
+ created_at: string
1822
+ created_by: UserRef
1823
+ updated_at: string
1824
+ updated_by: UserRef
1825
+ }
1826
+
1827
+ export interface CreateConversationBriefRequest {
1828
+ subject?: string
1829
+ /** The people the conversation is with (≥ 1). */
1830
+ contact_ids: string[]
1831
+ /** Must be a known channel when set. */
1832
+ channel?: Channel
1833
+ /** Must name an existing conversation type when set. */
1834
+ type_key?: string
1835
+ content: string
1836
+ }
1837
+
1838
+ /** PATCH semantics — absent fields keep their value. Only open briefs. */
1839
+ export interface UpdateConversationBriefRequest {
1840
+ subject?: string
1841
+ /** Replaces the set wholesale. */
1842
+ contact_ids?: string[]
1843
+ /** Empty string clears the channel. */
1844
+ channel?: Channel | ''
1845
+ content?: string
1846
+ type_key?: string
1847
+ }
1848
+
1849
+ /** Binds an open brief to a conversation explicitly. */
1850
+ export interface AttachConversationBriefRequest {
1851
+ conversation_id: string
1852
+ }
1853
+
1854
+ export interface ListConversationBriefsQuery extends PaginationQuery {
1855
+ /** Briefs naming this person. */
1856
+ contact_id?: string
1857
+ conversation_id?: string
1858
+ channel?: Channel
1859
+ type_key?: string
1860
+ status?: ConversationBriefStatus
1861
+ sort_by?: string
1862
+ sort?: 'asc' | 'desc'
1863
+ }
1864
+
1695
1865
  export interface SendingRule {
1696
1866
  id: string
1697
1867
  org_id: string
@@ -1747,7 +1917,10 @@ export interface SendingLimitPreset {
1747
1917
  description: string
1748
1918
  connector_keys: ConnectorKey[]
1749
1919
  is_recommended: boolean
1750
- rules: { rule_type: 'limit'; rule_config: LimitRuleConfig }[]
1920
+ rules: (
1921
+ | { rule_type: 'limit'; rule_config: LimitRuleConfig }
1922
+ | { rule_type: 'warmup'; rule_config: WarmupRuleConfig }
1923
+ )[]
1751
1924
  }
1752
1925
 
1753
1926
  export interface ListSendingLimitPresetsQuery {
@@ -1791,6 +1964,271 @@ export interface SendEligibility {
1791
1964
  contact_address_id?: string
1792
1965
  }
1793
1966
 
1967
+ // ── Connector catalog ─────────────────────────────────────────────────────────
1968
+
1969
+ /**
1970
+ * One connector WIRED in this deployment (registry membership decides
1971
+ * availability). `install_modes` lists the install variants the environment
1972
+ * supports for a direct-install connector (a sending platform's own_account /
1973
+ * managed); empty for OAuth / install-free connectors.
1974
+ */
1975
+ /**
1976
+ * ONE sending identity of a domain-authenticated email connection: an email
1977
+ * contact address on the connection's sender domain. A personal sender belongs
1978
+ * to a colleague's contact (`platform_user` set); a shared mailbox (sales@) to
1979
+ * a role contact without one. Computed from the contact directory on read.
1980
+ */
1981
+ export interface EmailSender {
1982
+ contact_address_id: string
1983
+ contact_id: string
1984
+ from_email: string
1985
+ from_name: string
1986
+ platform_user?: UserRef
1987
+ /** The connection's fallback sender when neither the thread nor the user pins one. */
1988
+ is_default: boolean
1989
+ }
1990
+
1991
+ /** Pins a connection's default sender (an address on its sender domain). */
1992
+ export interface SetDefaultSenderRequest {
1993
+ contact_address_id: string
1994
+ }
1995
+
1996
+ export interface ConnectorCatalogEntry {
1997
+ key: ConnectorKey
1998
+ channel: Channel
1999
+ provider: ConnectorProvider
2000
+ install_modes: string[]
2001
+ }
2002
+
2003
+ // ── Email deliverability (sending-platform connections) ──────────────────────
2004
+
2005
+ /** One of a sending platform's suppression lists. */
2006
+ export type EmailSuppressionKind =
2007
+ | 'bounces'
2008
+ | 'blocks'
2009
+ | 'spam_reports'
2010
+ | 'invalid_emails'
2011
+ | 'unsubscribes'
2012
+
2013
+ /**
2014
+ * Ledger rollup over the last `days` days: DISTINCT messages per event type
2015
+ * (machine opens excluded). Rates are fractions (0–1): delivery / bounce /
2016
+ * hard-bounce over sent, open / click / spam / unsubscribe over delivered.
2017
+ */
2018
+ export interface EmailHealthWindow {
2019
+ days: number
2020
+ sent: number
2021
+ delivered: number
2022
+ deferred: number
2023
+ bounced: number
2024
+ hard_bounced: number
2025
+ dropped: number
2026
+ opened: number
2027
+ clicked: number
2028
+ spam_reported: number
2029
+ unsubscribed: number
2030
+ delivery_rate: number
2031
+ bounce_rate: number
2032
+ hard_bounce_rate: number
2033
+ open_rate: number
2034
+ click_rate: number
2035
+ spam_rate: number
2036
+ unsubscribe_rate: number
2037
+ }
2038
+
2039
+ /** The provider's composite sender-quality score (1–5, computed daily). */
2040
+ export interface EmailEngagementQuality {
2041
+ date: string
2042
+ score: number
2043
+ bounce_classification: number
2044
+ bounce_rate: number
2045
+ engagement_recency: number
2046
+ open_rate: number
2047
+ spam_rate: number
2048
+ }
2049
+
2050
+ /** The provider's own counters for this connection's traffic (its category). */
2051
+ export interface EmailProviderStats {
2052
+ days: number
2053
+ requests: number
2054
+ processed: number
2055
+ delivered: number
2056
+ deferred: number
2057
+ bounces: number
2058
+ blocks: number
2059
+ bounce_drops: number
2060
+ invalid_emails: number
2061
+ opens: number
2062
+ unique_opens: number
2063
+ clicks: number
2064
+ unique_clicks: number
2065
+ spam_reports: number
2066
+ spam_report_drops: number
2067
+ unsubscribes: number
2068
+ unsubscribe_drops: number
2069
+ }
2070
+
2071
+ export interface EmailSuppressionCounts {
2072
+ bounces: number
2073
+ blocks: number
2074
+ spam_reports: number
2075
+ invalid_emails: number
2076
+ unsubscribes: number
2077
+ /** A list hit the page cap — the count is a floor. */
2078
+ is_approximate?: boolean
2079
+ }
2080
+
2081
+ export interface EmailDnsRecord {
2082
+ host: string
2083
+ type: string
2084
+ data: string
2085
+ is_valid: boolean
2086
+ reason?: string
2087
+ }
2088
+
2089
+ export interface EmailDomainStatus {
2090
+ domain: string
2091
+ is_valid: boolean
2092
+ dns: EmailDnsRecord[]
2093
+ }
2094
+
2095
+ export interface EmailSenderStatus {
2096
+ from_email: string
2097
+ /** authenticated_domain | single_sender */
2098
+ mode: string
2099
+ is_verified: boolean
2100
+ }
2101
+
2102
+ /** One dedicated IP of the account with its warmup state. */
2103
+ export interface EmailIp {
2104
+ ip: string
2105
+ is_warming_up: boolean
2106
+ warmup_started_at?: string
2107
+ pools: string[]
2108
+ }
2109
+
2110
+ /**
2111
+ * The provider's account-level snapshot (refreshed daily by the connector's
2112
+ * sweep, or on demand with `refresh`). Every section is optional — a plan
2113
+ * without the feature or a failed pull leaves it absent and adds a warning.
2114
+ */
2115
+ export interface EmailProviderHealth {
2116
+ engagement_quality?: EmailEngagementQuality
2117
+ stats?: EmailProviderStats
2118
+ suppressions?: EmailSuppressionCounts
2119
+ domain?: EmailDomainStatus
2120
+ sender?: EmailSenderStatus
2121
+ ips: EmailIp[]
2122
+ warnings?: string[]
2123
+ refreshed_at: string
2124
+ }
2125
+
2126
+ /** GET /connections/:id/health — ledger windows + the provider snapshot. */
2127
+ export interface EmailHealth {
2128
+ connection_id: string
2129
+ windows: EmailHealthWindow[]
2130
+ provider?: EmailProviderHealth
2131
+ }
2132
+
2133
+ export interface GetConnectionHealthQuery {
2134
+ /** Force a live provider pull (slow — several provider calls). */
2135
+ refresh?: boolean
2136
+ }
2137
+
2138
+ /** One address on a provider suppression list. */
2139
+ export interface EmailSuppression {
2140
+ kind: EmailSuppressionKind
2141
+ email: string
2142
+ reason?: string
2143
+ status?: string
2144
+ created_at: string
2145
+ }
2146
+
2147
+ // ── Channel events ────────────────────────────────────────────────────────────
2148
+
2149
+ /**
2150
+ * ONE provider-observed occurrence about an outbound message on a sending
2151
+ * platform: the delivery lifecycle (processed → delivered | deferred |
2152
+ * bounced | dropped) and engagement (opened, clicked, spam_reported,
2153
+ * unsubscribed, resubscribed). Provider vocabularies map onto these inside
2154
+ * the connector.
2155
+ */
2156
+ export type ChannelEventType =
2157
+ | 'processed'
2158
+ | 'delivered'
2159
+ | 'deferred'
2160
+ | 'bounced'
2161
+ | 'dropped'
2162
+ | 'opened'
2163
+ | 'clicked'
2164
+ | 'spam_reported'
2165
+ | 'unsubscribed'
2166
+ | 'resubscribed'
2167
+
2168
+ /** hard = the address is gone (suppressed); soft = this attempt was refused. */
2169
+ export type BounceKind = 'hard' | 'soft'
2170
+
2171
+ /** The provider's category of a bounce / block. */
2172
+ export type BounceClassification =
2173
+ | 'invalid_address'
2174
+ | 'technical_failure'
2175
+ | 'content'
2176
+ | 'reputation'
2177
+ | 'volume'
2178
+ | 'mailbox_unavailable'
2179
+ | 'unclassified'
2180
+
2181
+ /**
2182
+ * One row of the channel_event ledger — the sibling of channel actions (acts
2183
+ * WE perform) and reactions (edges): something the provider or the recipient
2184
+ * did that we record. Append-only, deduped on the provider's event id.
2185
+ * Message.delivery and provider-sourced contact permission events derive
2186
+ * from it.
2187
+ */
2188
+ export interface ChannelEvent {
2189
+ id: string
2190
+ org_id: string
2191
+ connection_id: string
2192
+ connector_key: ConnectorKey
2193
+ channel: Channel
2194
+ /** The message the event is about; absent when unresolvable. */
2195
+ message_id?: string
2196
+ conversation_id?: string
2197
+ contact_id?: string
2198
+ contact_address_id?: string
2199
+ /** The provider's recipient (lowercased email). */
2200
+ recipient_address: string
2201
+ event_type: ChannelEventType
2202
+ external_event_id: string
2203
+ external_message_id?: string
2204
+ occurred_at: string
2205
+ /** Bounce / deferral / drop text (the SMTP response, the drop reason). */
2206
+ reason?: string
2207
+ response?: string
2208
+ bounce_kind?: BounceKind
2209
+ bounce_classification?: BounceClassification
2210
+ /** The clicked link (clicked events). */
2211
+ url?: string
2212
+ /** An opened event a mail client's privacy proxy generated, not the person. */
2213
+ is_machine_open?: boolean
2214
+ metadata: Record<string, unknown>
2215
+ created_at: string
2216
+ created_by: UserRef
2217
+ }
2218
+
2219
+ export interface ListChannelEventsQuery extends PaginationQuery {
2220
+ connection_id?: string
2221
+ message_id?: string
2222
+ conversation_id?: string
2223
+ contact_id?: string
2224
+ event_type?: ChannelEventType
2225
+ /** ISO instants bounding occurred_at (from inclusive, until exclusive). */
2226
+ from?: string
2227
+ until?: string
2228
+ sort_by?: string
2229
+ sort?: 'asc' | 'desc'
2230
+ }
2231
+
1794
2232
  // ── Channel actions ───────────────────────────────────────────────────────────
1795
2233
 
1796
2234
  /**