@proteos/sdk 0.49.0 → 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
@@ -290,6 +291,14 @@ export interface Connection {
290
291
  supports_reactions: boolean
291
292
  /** The capability descriptor; absent when unsupported. */
292
293
  reactions?: ReactionCapability
294
+ /**
295
+ * Computed on read like reactions: the channel actions the connector
296
+ * performs through this connection (invitation, profile_visit, inmail, …).
297
+ * A separate list from reactions — a reaction toggles an edge on a
298
+ * message, an action is a performed act with its own lifecycle. Absent
299
+ * when the connector performs none.
300
+ */
301
+ actions?: ChannelActionCapability[]
293
302
  /**
294
303
  * Computed on read like supports_reactions: who operates the integration
295
304
  * (native | unipile). Absent when the connector is not registered in this
@@ -457,6 +466,12 @@ export interface Message {
457
466
  */
458
467
  child_conversation_id?: string
459
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
460
475
  metadata: Record<string, unknown>
461
476
  error: string
462
477
  created_at: string
@@ -465,6 +480,31 @@ export interface Message {
465
480
  updated_by: UserRef
466
481
  }
467
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
+
468
508
  /**
469
509
  * Per-trigger configuration, discriminated by the sibling trigger_type: channel
470
510
  * carries external_channel_id, keyword carries phrases, always/mention carry
@@ -623,6 +663,15 @@ export interface SendMessageRequest {
623
663
  * `unsupported_content`.
624
664
  */
625
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
626
675
  }
627
676
 
628
677
  /**
@@ -991,6 +1040,8 @@ export interface ListConversationsQuery extends PaginationQuery {
991
1040
  /** Threads whose roster contains this external party — the person stream. */
992
1041
  /** Contact stream: threads whose roster contains the resolved person. */
993
1042
  contact_id?: string
1043
+ /** "Sent as" stream: threads pinned to one sending identity (a contact address id). */
1044
+ sender_address_id?: string
994
1045
  /** Opt into the root/latest message projection on each row. */
995
1046
  include?: 'messages_summary'
996
1047
  }
@@ -1189,7 +1240,19 @@ export type ContactSource = 'sync' | 'ingest' | 'manual' | 'merge'
1189
1240
  export type ContactStatus = 'active' | 'merged' | 'archived' | 'erased'
1190
1241
  export type ConsentStatus = 'unknown' | 'opted_in' | 'opted_out'
1191
1242
  export type PermissionEventType = 'opt_in' | 'opt_out' | 'block' | 'unblock'
1192
- 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'
1193
1256
  export type MergeProposalStatus = 'proposed' | 'approved' | 'rejected' | 'superseded'
1194
1257
  export type ErasureRequestStatus = 'requested' | 'completed'
1195
1258
  export type RoomSource = 'sync' | 'ingest'
@@ -1220,6 +1283,14 @@ export interface Contact {
1220
1283
  /** Merge tombstone redirect (set when status is 'merged'). */
1221
1284
  merged_into_contact_id?: string
1222
1285
  source: ContactSource
1286
+ /** IANA zone name (Europe/Berlin); absent = unknown. Filled from directory sweeps while empty. */
1287
+ timezone?: string
1288
+ /**
1289
+ * BCP-47 language tag with optional region (de, de-CH, pt-BR); absent =
1290
+ * unknown. Named locale, not language: the region carries formatting
1291
+ * conventions on top of the language.
1292
+ */
1293
+ locale?: string
1223
1294
  /** ContactGroup membership (one group per contact); absent = unassigned. */
1224
1295
  group_key?: string
1225
1296
  /**
@@ -1341,12 +1412,22 @@ export interface ListContactsQuery extends PaginationQuery {
1341
1412
  status?: ContactStatus
1342
1413
  /** Members of one contact group (drives group-member lists). */
1343
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
1344
1421
  }
1345
1422
 
1346
1423
  export interface UpdateContactRequest {
1347
1424
  name?: string
1348
1425
  status?: 'active' | 'archived'
1349
1426
  has_legal_hold?: boolean
1427
+ /** IANA zone name; normalized server-side, 400 contact_timezone_invalid when unparseable; '' clears. */
1428
+ timezone?: string
1429
+ /** BCP-47 language tag; normalized server-side, 400 contact_locale_invalid when unparseable; '' clears. */
1430
+ locale?: string
1350
1431
  /**
1351
1432
  * Assigns the contact to a contact group ('' clears). A PATCH assignment is
1352
1433
  * stamped group_source='manual' — tone synthesis never overrides it.
@@ -1360,8 +1441,22 @@ export interface UpdateContactRequest {
1360
1441
  * rejects the create with 409 contact_address_taken.
1361
1442
  */
1362
1443
  export interface CreateContactRequest {
1363
- name: string
1364
- 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
1456
+ /** IANA zone name; optional, validated as on update. */
1457
+ timezone?: string
1458
+ /** BCP-47 language tag; optional, validated as on update. */
1459
+ locale?: string
1365
1460
  }
1366
1461
 
1367
1462
  export interface AttachContactAddressRequest {
@@ -1610,3 +1705,636 @@ export interface DispatchMeetingBotRequest {
1610
1705
  */
1611
1706
  language?: string
1612
1707
  }
1708
+
1709
+ // ── Sending rules ─────────────────────────────────────────────────────────────
1710
+
1711
+ /**
1712
+ * Discriminates a sending rule: window (WHEN sending is allowed, recipient-
1713
+ * local weekday ranges), limit (HOW MUCH one connection may send per rolling
1714
+ * period), frequency_cap (HOW OFTEN one contact may be contacted per rolling
1715
+ * period).
1716
+ */
1717
+ export type SendingRuleType = 'window' | 'limit' | 'frequency_cap' | 'warmup'
1718
+ /** Rolling lookback ("last 24 hours from now") — never a calendar day. */
1719
+ export type SendingPeriod = 'rolling_24h' | 'rolling_7d' | 'rolling_30d'
1720
+ /**
1721
+ * ONE kind of act performed through a channel connection — shared by a
1722
+ * limit's `action` (what it counts), a channel action's `action_type` (what
1723
+ * was performed) and the eligibility check. `message` is the plain send
1724
+ * (valid on a limit, never on a channel action row).
1725
+ */
1726
+ export type ChannelActionType = 'message' | 'invitation' | 'inmail' | 'profile_visit'
1727
+ export type Weekday =
1728
+ | 'monday'
1729
+ | 'tuesday'
1730
+ | 'wednesday'
1731
+ | 'thursday'
1732
+ | 'friday'
1733
+ | 'saturday'
1734
+ | 'sunday'
1735
+
1736
+ /** One open range on one weekday, "HH:MM" wall-clock, from < until, same day. */
1737
+ export interface WindowDay {
1738
+ day: Weekday
1739
+ from: string
1740
+ until: string
1741
+ }
1742
+ export interface WindowRuleConfig {
1743
+ days: WindowDay[]
1744
+ /** IANA zone used for contacts without a timezone. */
1745
+ fallback_timezone: string
1746
+ }
1747
+ export interface LimitRuleConfig {
1748
+ action: ChannelActionType
1749
+ max_count: number
1750
+ period: SendingPeriod
1751
+ /** Minimum spacing between consecutive sends; 0/absent = none. */
1752
+ min_gap_seconds?: number
1753
+ }
1754
+ export interface FrequencyCapRuleConfig {
1755
+ max_count: number
1756
+ period: SendingPeriod
1757
+ }
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
1779
+
1780
+ /**
1781
+ * One outbound send constraint, defined once and LINKED to any number of
1782
+ * connections and/or channels (both empty = org-wide). Per rule type the most
1783
+ * specific tier wins at send time: names the connection > names the channel >
1784
+ * org-wide. Replies skip the rule when `is_reply_exempt`.
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
+
1865
+ export interface SendingRule {
1866
+ id: string
1867
+ org_id: string
1868
+ name: string
1869
+ connection_ids: string[]
1870
+ channels: Channel[]
1871
+ rule_type: SendingRuleType
1872
+ rule_config?: SendingRuleConfig
1873
+ is_enabled: boolean
1874
+ is_reply_exempt: boolean
1875
+ created_at: string
1876
+ created_by: UserRef
1877
+ updated_at: string
1878
+ updated_by: UserRef
1879
+ }
1880
+
1881
+ export interface CreateSendingRuleRequest {
1882
+ name?: string
1883
+ connection_ids?: string[]
1884
+ channels?: Channel[]
1885
+ rule_type: SendingRuleType
1886
+ rule_config: Record<string, unknown>
1887
+ /** Defaults to true. */
1888
+ is_enabled?: boolean
1889
+ /** Defaults per type: window + frequency_cap true, limit false. */
1890
+ is_reply_exempt?: boolean
1891
+ }
1892
+
1893
+ export interface UpdateSendingRuleRequest {
1894
+ name?: string
1895
+ /** Replaces the stored links wholesale when present. */
1896
+ connection_ids?: string[]
1897
+ channels?: Channel[]
1898
+ /** rule_type and rule_config must be sent together. */
1899
+ rule_type?: SendingRuleType
1900
+ rule_config?: Record<string, unknown>
1901
+ is_enabled?: boolean
1902
+ is_reply_exempt?: boolean
1903
+ }
1904
+
1905
+ export interface ListSendingRulesQuery extends PaginationQuery {
1906
+ /** Rules LINKED to this connection. */
1907
+ connection_id?: string
1908
+ channel?: Channel
1909
+ rule_type?: SendingRuleType
1910
+ is_enabled?: boolean
1911
+ }
1912
+
1913
+ /** A recommended limit bundle for one class of sender account (static catalog). */
1914
+ export interface SendingLimitPreset {
1915
+ key: string
1916
+ name: string
1917
+ description: string
1918
+ connector_keys: ConnectorKey[]
1919
+ is_recommended: boolean
1920
+ rules: (
1921
+ | { rule_type: 'limit'; rule_config: LimitRuleConfig }
1922
+ | { rule_type: 'warmup'; rule_config: WarmupRuleConfig }
1923
+ )[]
1924
+ }
1925
+
1926
+ export interface ListSendingLimitPresetsQuery {
1927
+ connector_key?: ConnectorKey
1928
+ }
1929
+
1930
+ export interface ApplySendingLimitPresetRequest {
1931
+ connection_ids: string[]
1932
+ preset_key: string
1933
+ }
1934
+
1935
+ /** Dry-run twin of SendMessageRequest: addressing only, nothing minted. */
1936
+ export interface SendEligibilityRequest {
1937
+ conversation_id?: string
1938
+ reply_to_message_id?: string
1939
+ connection_id?: string
1940
+ to?: SendRecipient[]
1941
+ cc?: SendRecipient[]
1942
+ bcc?: SendRecipient[]
1943
+ /**
1944
+ * Widens the check to a channel action (invitation, profile_visit, inmail):
1945
+ * originate mode only, the first `to` recipient is the target. Absent =
1946
+ * message.
1947
+ */
1948
+ action_type?: ChannelActionType
1949
+ }
1950
+
1951
+ /**
1952
+ * "May this send go out now?" — `reason` is the error code a real send would
1953
+ * fail with (sending_window_closed | sending_limit_reached |
1954
+ * frequency_cap_reached | contact_blocked | contact_opted_out);
1955
+ * `earliest_allowed_at` is set for the temporal three.
1956
+ */
1957
+ export interface SendEligibility {
1958
+ is_allowed: boolean
1959
+ reason?: string
1960
+ rule_id?: string
1961
+ rule_type?: SendingRuleType
1962
+ earliest_allowed_at?: string
1963
+ contact_id?: string
1964
+ contact_address_id?: string
1965
+ }
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
+
2232
+ // ── Channel actions ───────────────────────────────────────────────────────────
2233
+
2234
+ /**
2235
+ * Lifecycle of a channel action. Execution: pending → performed | failed.
2236
+ * Outcome (invitations): performed → accepted | declined | withdrawn |
2237
+ * expired; an inbound received invitation starts pending and ends
2238
+ * accepted | declined | expired.
2239
+ */
2240
+ export type ChannelActionStatus =
2241
+ | 'pending'
2242
+ | 'performed'
2243
+ | 'failed'
2244
+ | 'accepted'
2245
+ | 'declined'
2246
+ | 'withdrawn'
2247
+ | 'expired'
2248
+ /** Our answer to an inbound channel action (a received invitation). */
2249
+ export type ChannelActionResponse = 'accept' | 'decline'
2250
+ /** What an action type acts on: a person on the channel, or an external object. */
2251
+ export type ChannelActionTargetKind = 'contact-address' | 'external'
2252
+
2253
+ /**
2254
+ * One action type a connector performs, projected onto `connection.actions`.
2255
+ */
2256
+ export interface ChannelActionCapability {
2257
+ action_type: ChannelActionType
2258
+ target_kind: ChannelActionTargetKind
2259
+ /** The act can be withdrawn after performing (an invitation). */
2260
+ is_cancelable: boolean
2261
+ /** An inbound act of this type can be answered (accept / decline). */
2262
+ is_respondable: boolean
2263
+ /** Performing also sends a message that lands as a Message + Conversation (InMail). */
2264
+ is_message_minting: boolean
2265
+ /** Bound of the free-text note the act carries (LinkedIn invitation: 300). */
2266
+ max_note_length?: number
2267
+ }
2268
+
2269
+ export interface InvitationParams {
2270
+ note?: string
2271
+ email?: string
2272
+ }
2273
+ export type ProfileVisitParams = Record<string, never>
2274
+ export interface InmailParams {
2275
+ subject?: string
2276
+ content: ContentBlock[]
2277
+ }
2278
+ export type ChannelActionParams = InvitationParams | ProfileVisitParams | InmailParams
2279
+
2280
+ /**
2281
+ * One act performed through a channel connection that is neither a message
2282
+ * nor a reaction — a LinkedIn invitation, a profile visit, an InMail (which
2283
+ * ALSO mints a message, see message_id). A LEDGER row: appended, transitioned
2284
+ * along its lifecycle, never toggled. `direction` outbound = we acted;
2285
+ * inbound = someone acted on us (a received invitation you may answer).
2286
+ * `created_by` is the performer on outbound rows (user or agent), the system
2287
+ * on ingested inbound rows; `updated_by` who accepted / declined / withdrew.
2288
+ */
2289
+ export interface ChannelAction {
2290
+ id: string
2291
+ org_id: string
2292
+ connection_id: string
2293
+ connector_key: ConnectorKey
2294
+ channel: Channel
2295
+ action_type: ChannelActionType
2296
+ direction: MessageDirection
2297
+ status: ChannelActionStatus
2298
+ contact_id?: string
2299
+ contact_address_id?: string
2300
+ /** The provider-side identity acted on (a LinkedIn member id). */
2301
+ target_external_id: string
2302
+ contact: ContactRef
2303
+ /** An InMail's minted message; an invitation's note-chat once accepted. */
2304
+ message_id?: string
2305
+ conversation_id?: string
2306
+ params?: ChannelActionParams
2307
+ /** The provider handle (Unipile invitation id) — cancel / respond key. */
2308
+ external_action_id?: string
2309
+ error?: string
2310
+ occurred_at: string
2311
+ resolved_at?: string
2312
+ /** Provider enrichment: invitation usage %, network_distance, … */
2313
+ metadata: Record<string, unknown>
2314
+ created_at: string
2315
+ created_by: UserRef
2316
+ updated_at: string
2317
+ updated_by: UserRef
2318
+ }
2319
+
2320
+ /** Performs one act. `target` is the person acted on (kind contact-address + the connector-side external id). */
2321
+ export interface PerformChannelActionRequest {
2322
+ connection_id: string
2323
+ action_type: ChannelActionType
2324
+ target: SendRecipient
2325
+ /** Per-type input: invitation {note?, email?}; profile_visit {}; inmail {subject?, content}. */
2326
+ params?: Record<string, unknown>
2327
+ }
2328
+
2329
+ export interface RespondChannelActionRequest {
2330
+ response: ChannelActionResponse
2331
+ }
2332
+
2333
+ export interface ListChannelActionsQuery extends PaginationQuery {
2334
+ channel?: Channel
2335
+ connection_id?: string
2336
+ action_type?: ChannelActionType
2337
+ direction?: MessageDirection
2338
+ status?: ChannelActionStatus
2339
+ contact_id?: string
2340
+ }