truagents 0.0.0.dev0__py3-none-any.whl
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.
- truagents/__init__.py +18 -0
- truagents/__version__.py +1 -0
- truagents/auth.py +293 -0
- truagents/client.py +304 -0
- truagents/errors.py +193 -0
- truagents/generated/__init__.py +8 -0
- truagents/generated/api/__init__.py +1 -0
- truagents/generated/api/email_unsubscribe/__init__.py +1 -0
- truagents/generated/api/email_unsubscribe/list_email_unsubscribes.py +290 -0
- truagents/generated/api/email_unsubscribe/push_email_unsubscribes.py +236 -0
- truagents/generated/api/o_auth/__init__.py +1 -0
- truagents/generated/api/o_auth/issue_o_auth_token.py +241 -0
- truagents/generated/api/sms_unsubscribe/__init__.py +1 -0
- truagents/generated/api/sms_unsubscribe/list_sms_unsubscribes.py +290 -0
- truagents/generated/api/sms_unsubscribe/push_sms_unsubscribes.py +232 -0
- truagents/generated/api/voice_unsubscribe/__init__.py +1 -0
- truagents/generated/api/voice_unsubscribe/list_phone_unsubscribes.py +298 -0
- truagents/generated/api/voice_unsubscribe/push_phone_unsubscribes.py +232 -0
- truagents/generated/client.py +282 -0
- truagents/generated/errors.py +16 -0
- truagents/generated/models/__init__.py +65 -0
- truagents/generated/models/email_skipped_item.py +83 -0
- truagents/generated/models/email_skipped_item_reason.py +11 -0
- truagents/generated/models/email_source_enum.py +11 -0
- truagents/generated/models/email_unsubscribe_batch_request.py +93 -0
- truagents/generated/models/email_unsubscribe_batch_response.py +119 -0
- truagents/generated/models/email_unsubscribe_item.py +50 -0
- truagents/generated/models/email_unsubscribe_list_response.py +113 -0
- truagents/generated/models/email_unsubscribe_record.py +98 -0
- truagents/generated/models/email_unsubscribe_updated_entry.py +79 -0
- truagents/generated/models/o_auth_client_credentials_request.py +87 -0
- truagents/generated/models/o_auth_client_credentials_request_grant_type.py +8 -0
- truagents/generated/models/o_auth_error_response.py +83 -0
- truagents/generated/models/o_auth_error_response_error.py +11 -0
- truagents/generated/models/o_auth_refresh_token_request.py +75 -0
- truagents/generated/models/o_auth_refresh_token_request_grant_type.py +8 -0
- truagents/generated/models/o_auth_token_response.py +97 -0
- truagents/generated/models/o_auth_token_response_token_type.py +8 -0
- truagents/generated/models/phone_skipped_item.py +83 -0
- truagents/generated/models/phone_skipped_item_reason.py +11 -0
- truagents/generated/models/phone_source_enum.py +11 -0
- truagents/generated/models/phone_unsubscribe_batch_request.py +92 -0
- truagents/generated/models/phone_unsubscribe_batch_response.py +118 -0
- truagents/generated/models/phone_unsubscribe_item.py +51 -0
- truagents/generated/models/phone_unsubscribe_list_response.py +111 -0
- truagents/generated/models/phone_unsubscribe_record.py +99 -0
- truagents/generated/models/phone_unsubscribe_updated_entry.py +79 -0
- truagents/generated/models/rest_error_response.py +74 -0
- truagents/generated/models/unauthorized_organization_error.py +90 -0
- truagents/generated/models/unauthorized_organization_error_error.py +8 -0
- truagents/generated/types.py +54 -0
- truagents/observability.py +70 -0
- truagents/retry.py +64 -0
- truagents-0.0.0.dev0.dist-info/METADATA +171 -0
- truagents-0.0.0.dev0.dist-info/RECORD +56 -0
- truagents-0.0.0.dev0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
from typing import Any, TypeVar
|
|
5
|
+
|
|
6
|
+
from attrs import define as _attrs_define
|
|
7
|
+
from attrs import field as _attrs_field
|
|
8
|
+
|
|
9
|
+
from ..models.o_auth_token_response_token_type import OAuthTokenResponseTokenType
|
|
10
|
+
|
|
11
|
+
T = TypeVar("T", bound="OAuthTokenResponse")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@_attrs_define
|
|
15
|
+
class OAuthTokenResponse:
|
|
16
|
+
"""
|
|
17
|
+
Attributes:
|
|
18
|
+
access_token (str): Opaque bearer token (prefix `tru_at_`). Send on every API request as `Authorization: Bearer
|
|
19
|
+
<access_token>`. Example: tru_at_<access_token>.
|
|
20
|
+
token_type (OAuthTokenResponseTokenType):
|
|
21
|
+
expires_in (int): Seconds until the access token expires. Example: 900.
|
|
22
|
+
refresh_token (str): Opaque refresh token (prefix `tru_rt_`). Single-use; store atomically. Example:
|
|
23
|
+
tru_rt_<refresh_token>.
|
|
24
|
+
refresh_expires_in (int): Seconds until the refresh token expires. Example: 2592000.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
access_token: str
|
|
28
|
+
token_type: OAuthTokenResponseTokenType
|
|
29
|
+
expires_in: int
|
|
30
|
+
refresh_token: str
|
|
31
|
+
refresh_expires_in: int
|
|
32
|
+
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
|
|
33
|
+
|
|
34
|
+
def to_dict(self) -> dict[str, Any]:
|
|
35
|
+
access_token = self.access_token
|
|
36
|
+
|
|
37
|
+
token_type = self.token_type.value
|
|
38
|
+
|
|
39
|
+
expires_in = self.expires_in
|
|
40
|
+
|
|
41
|
+
refresh_token = self.refresh_token
|
|
42
|
+
|
|
43
|
+
refresh_expires_in = self.refresh_expires_in
|
|
44
|
+
|
|
45
|
+
field_dict: dict[str, Any] = {}
|
|
46
|
+
field_dict.update(self.additional_properties)
|
|
47
|
+
field_dict.update(
|
|
48
|
+
{
|
|
49
|
+
"access_token": access_token,
|
|
50
|
+
"token_type": token_type,
|
|
51
|
+
"expires_in": expires_in,
|
|
52
|
+
"refresh_token": refresh_token,
|
|
53
|
+
"refresh_expires_in": refresh_expires_in,
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
return field_dict
|
|
58
|
+
|
|
59
|
+
@classmethod
|
|
60
|
+
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
|
|
61
|
+
d = dict(src_dict)
|
|
62
|
+
access_token = d.pop("access_token")
|
|
63
|
+
|
|
64
|
+
token_type = OAuthTokenResponseTokenType(d.pop("token_type"))
|
|
65
|
+
|
|
66
|
+
expires_in = d.pop("expires_in")
|
|
67
|
+
|
|
68
|
+
refresh_token = d.pop("refresh_token")
|
|
69
|
+
|
|
70
|
+
refresh_expires_in = d.pop("refresh_expires_in")
|
|
71
|
+
|
|
72
|
+
o_auth_token_response = cls(
|
|
73
|
+
access_token=access_token,
|
|
74
|
+
token_type=token_type,
|
|
75
|
+
expires_in=expires_in,
|
|
76
|
+
refresh_token=refresh_token,
|
|
77
|
+
refresh_expires_in=refresh_expires_in,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
o_auth_token_response.additional_properties = d
|
|
81
|
+
return o_auth_token_response
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def additional_keys(self) -> list[str]:
|
|
85
|
+
return list(self.additional_properties.keys())
|
|
86
|
+
|
|
87
|
+
def __getitem__(self, key: str) -> Any:
|
|
88
|
+
return self.additional_properties[key]
|
|
89
|
+
|
|
90
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
|
91
|
+
self.additional_properties[key] = value
|
|
92
|
+
|
|
93
|
+
def __delitem__(self, key: str) -> None:
|
|
94
|
+
del self.additional_properties[key]
|
|
95
|
+
|
|
96
|
+
def __contains__(self, key: str) -> bool:
|
|
97
|
+
return key in self.additional_properties
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
from typing import Any, TypeVar
|
|
5
|
+
|
|
6
|
+
from attrs import define as _attrs_define
|
|
7
|
+
from attrs import field as _attrs_field
|
|
8
|
+
|
|
9
|
+
from ..models.phone_skipped_item_reason import PhoneSkippedItemReason
|
|
10
|
+
from ..types import UNSET, Unset
|
|
11
|
+
|
|
12
|
+
T = TypeVar("T", bound="PhoneSkippedItem")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@_attrs_define
|
|
16
|
+
class PhoneSkippedItem:
|
|
17
|
+
"""An input item rejected by per-item validation. Echoes the original item fields plus a `reason`.
|
|
18
|
+
|
|
19
|
+
Attributes:
|
|
20
|
+
reason (PhoneSkippedItemReason):
|
|
21
|
+
phone (str | Unset): Echoed from input when present.
|
|
22
|
+
unsubscribed (bool | Unset): Echoed from input when present.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
reason: PhoneSkippedItemReason
|
|
26
|
+
phone: str | Unset = UNSET
|
|
27
|
+
unsubscribed: bool | Unset = UNSET
|
|
28
|
+
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
|
|
29
|
+
|
|
30
|
+
def to_dict(self) -> dict[str, Any]:
|
|
31
|
+
reason = self.reason.value
|
|
32
|
+
|
|
33
|
+
phone = self.phone
|
|
34
|
+
|
|
35
|
+
unsubscribed = self.unsubscribed
|
|
36
|
+
|
|
37
|
+
field_dict: dict[str, Any] = {}
|
|
38
|
+
field_dict.update(self.additional_properties)
|
|
39
|
+
field_dict.update(
|
|
40
|
+
{
|
|
41
|
+
"reason": reason,
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
if phone is not UNSET:
|
|
45
|
+
field_dict["phone"] = phone
|
|
46
|
+
if unsubscribed is not UNSET:
|
|
47
|
+
field_dict["unsubscribed"] = unsubscribed
|
|
48
|
+
|
|
49
|
+
return field_dict
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
|
|
53
|
+
d = dict(src_dict)
|
|
54
|
+
reason = PhoneSkippedItemReason(d.pop("reason"))
|
|
55
|
+
|
|
56
|
+
phone = d.pop("phone", UNSET)
|
|
57
|
+
|
|
58
|
+
unsubscribed = d.pop("unsubscribed", UNSET)
|
|
59
|
+
|
|
60
|
+
phone_skipped_item = cls(
|
|
61
|
+
reason=reason,
|
|
62
|
+
phone=phone,
|
|
63
|
+
unsubscribed=unsubscribed,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
phone_skipped_item.additional_properties = d
|
|
67
|
+
return phone_skipped_item
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def additional_keys(self) -> list[str]:
|
|
71
|
+
return list(self.additional_properties.keys())
|
|
72
|
+
|
|
73
|
+
def __getitem__(self, key: str) -> Any:
|
|
74
|
+
return self.additional_properties[key]
|
|
75
|
+
|
|
76
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
|
77
|
+
self.additional_properties[key] = value
|
|
78
|
+
|
|
79
|
+
def __delitem__(self, key: str) -> None:
|
|
80
|
+
del self.additional_properties[key]
|
|
81
|
+
|
|
82
|
+
def __contains__(self, key: str) -> bool:
|
|
83
|
+
return key in self.additional_properties
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class PhoneSkippedItemReason(str, Enum):
|
|
5
|
+
DUPLICATE_IDENTIFIER = "duplicate identifier"
|
|
6
|
+
INVALID_PHONE_FORMAT = "invalid phone format"
|
|
7
|
+
MISSING_IDENTIFIER = "missing identifier"
|
|
8
|
+
MISSING_UNSUBSCRIBED = "missing unsubscribed"
|
|
9
|
+
|
|
10
|
+
def __str__(self) -> str:
|
|
11
|
+
return str(self.value)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
from typing import TYPE_CHECKING, Any, TypeVar
|
|
5
|
+
|
|
6
|
+
from attrs import define as _attrs_define
|
|
7
|
+
from attrs import field as _attrs_field
|
|
8
|
+
|
|
9
|
+
from ..types import UNSET, Unset
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from ..models.phone_unsubscribe_item import PhoneUnsubscribeItem
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
T = TypeVar("T", bound="PhoneUnsubscribeBatchRequest")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@_attrs_define
|
|
19
|
+
class PhoneUnsubscribeBatchRequest:
|
|
20
|
+
"""
|
|
21
|
+
Example:
|
|
22
|
+
{'org_slug': 'acme-corp', 'items': [{'phone': '+15551234567', 'unsubscribed': True}]}
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
items (list[PhoneUnsubscribeItem]): Up to 10,000 items per request. Items are processed in array order; partial
|
|
26
|
+
failures do not roll back accepted items.
|
|
27
|
+
org_slug (str | Unset): Organization to write to. Must be in your `client_id`'s authorized set. Omit to use the
|
|
28
|
+
key's default organization. One batch targets exactly one organization — to write to several organizations, send
|
|
29
|
+
one request per organization. Example: acme-corp.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
items: list[PhoneUnsubscribeItem]
|
|
33
|
+
org_slug: str | Unset = UNSET
|
|
34
|
+
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
|
|
35
|
+
|
|
36
|
+
def to_dict(self) -> dict[str, Any]:
|
|
37
|
+
items = []
|
|
38
|
+
for items_item_data in self.items:
|
|
39
|
+
items_item = items_item_data.to_dict()
|
|
40
|
+
items.append(items_item)
|
|
41
|
+
|
|
42
|
+
org_slug = self.org_slug
|
|
43
|
+
|
|
44
|
+
field_dict: dict[str, Any] = {}
|
|
45
|
+
field_dict.update(self.additional_properties)
|
|
46
|
+
field_dict.update(
|
|
47
|
+
{
|
|
48
|
+
"items": items,
|
|
49
|
+
}
|
|
50
|
+
)
|
|
51
|
+
if org_slug is not UNSET:
|
|
52
|
+
field_dict["org_slug"] = org_slug
|
|
53
|
+
|
|
54
|
+
return field_dict
|
|
55
|
+
|
|
56
|
+
@classmethod
|
|
57
|
+
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
|
|
58
|
+
from ..models.phone_unsubscribe_item import PhoneUnsubscribeItem
|
|
59
|
+
|
|
60
|
+
d = dict(src_dict)
|
|
61
|
+
items = []
|
|
62
|
+
_items = d.pop("items")
|
|
63
|
+
for items_item_data in _items:
|
|
64
|
+
items_item = PhoneUnsubscribeItem.from_dict(items_item_data)
|
|
65
|
+
|
|
66
|
+
items.append(items_item)
|
|
67
|
+
|
|
68
|
+
org_slug = d.pop("org_slug", UNSET)
|
|
69
|
+
|
|
70
|
+
phone_unsubscribe_batch_request = cls(
|
|
71
|
+
items=items,
|
|
72
|
+
org_slug=org_slug,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
phone_unsubscribe_batch_request.additional_properties = d
|
|
76
|
+
return phone_unsubscribe_batch_request
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def additional_keys(self) -> list[str]:
|
|
80
|
+
return list(self.additional_properties.keys())
|
|
81
|
+
|
|
82
|
+
def __getitem__(self, key: str) -> Any:
|
|
83
|
+
return self.additional_properties[key]
|
|
84
|
+
|
|
85
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
|
86
|
+
self.additional_properties[key] = value
|
|
87
|
+
|
|
88
|
+
def __delitem__(self, key: str) -> None:
|
|
89
|
+
del self.additional_properties[key]
|
|
90
|
+
|
|
91
|
+
def __contains__(self, key: str) -> bool:
|
|
92
|
+
return key in self.additional_properties
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
from typing import TYPE_CHECKING, Any, TypeVar
|
|
5
|
+
|
|
6
|
+
from attrs import define as _attrs_define
|
|
7
|
+
from attrs import field as _attrs_field
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from ..models.phone_skipped_item import PhoneSkippedItem
|
|
11
|
+
from ..models.phone_unsubscribe_updated_entry import PhoneUnsubscribeUpdatedEntry
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
T = TypeVar("T", bound="PhoneUnsubscribeBatchResponse")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@_attrs_define
|
|
18
|
+
class PhoneUnsubscribeBatchResponse:
|
|
19
|
+
"""
|
|
20
|
+
Example:
|
|
21
|
+
{'org_slug': 'acme-corp', 'processed': 1, 'updated': [{'phone': '+15551234567', 'unsubscribed': True,
|
|
22
|
+
'updated_at': '2026-04-15T10:30:00Z'}], 'skipped_items': []}
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
org_slug (str): Organization the batch was applied to — the value you supplied, or your key's default
|
|
26
|
+
organization when you omitted it. Example: acme-corp.
|
|
27
|
+
processed (int): Count of items accepted into `updated` — equal to `items.length − skipped_items.length`.
|
|
28
|
+
Idempotent writes (item already at requested state) are counted.
|
|
29
|
+
updated (list[PhoneUnsubscribeUpdatedEntry]): One entry per accepted input item, in input order.
|
|
30
|
+
skipped_items (list[PhoneSkippedItem]): Items rejected by per-item validation; each carries the original field
|
|
31
|
+
echoes plus a `reason`.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
org_slug: str
|
|
35
|
+
processed: int
|
|
36
|
+
updated: list[PhoneUnsubscribeUpdatedEntry]
|
|
37
|
+
skipped_items: list[PhoneSkippedItem]
|
|
38
|
+
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
|
|
39
|
+
|
|
40
|
+
def to_dict(self) -> dict[str, Any]:
|
|
41
|
+
org_slug = self.org_slug
|
|
42
|
+
|
|
43
|
+
processed = self.processed
|
|
44
|
+
|
|
45
|
+
updated = []
|
|
46
|
+
for updated_item_data in self.updated:
|
|
47
|
+
updated_item = updated_item_data.to_dict()
|
|
48
|
+
updated.append(updated_item)
|
|
49
|
+
|
|
50
|
+
skipped_items = []
|
|
51
|
+
for skipped_items_item_data in self.skipped_items:
|
|
52
|
+
skipped_items_item = skipped_items_item_data.to_dict()
|
|
53
|
+
skipped_items.append(skipped_items_item)
|
|
54
|
+
|
|
55
|
+
field_dict: dict[str, Any] = {}
|
|
56
|
+
field_dict.update(self.additional_properties)
|
|
57
|
+
field_dict.update(
|
|
58
|
+
{
|
|
59
|
+
"org_slug": org_slug,
|
|
60
|
+
"processed": processed,
|
|
61
|
+
"updated": updated,
|
|
62
|
+
"skipped_items": skipped_items,
|
|
63
|
+
}
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
return field_dict
|
|
67
|
+
|
|
68
|
+
@classmethod
|
|
69
|
+
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
|
|
70
|
+
from ..models.phone_skipped_item import PhoneSkippedItem
|
|
71
|
+
from ..models.phone_unsubscribe_updated_entry import (
|
|
72
|
+
PhoneUnsubscribeUpdatedEntry,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
d = dict(src_dict)
|
|
76
|
+
org_slug = d.pop("org_slug")
|
|
77
|
+
|
|
78
|
+
processed = d.pop("processed")
|
|
79
|
+
|
|
80
|
+
updated = []
|
|
81
|
+
_updated = d.pop("updated")
|
|
82
|
+
for updated_item_data in _updated:
|
|
83
|
+
updated_item = PhoneUnsubscribeUpdatedEntry.from_dict(updated_item_data)
|
|
84
|
+
|
|
85
|
+
updated.append(updated_item)
|
|
86
|
+
|
|
87
|
+
skipped_items = []
|
|
88
|
+
_skipped_items = d.pop("skipped_items")
|
|
89
|
+
for skipped_items_item_data in _skipped_items:
|
|
90
|
+
skipped_items_item = PhoneSkippedItem.from_dict(skipped_items_item_data)
|
|
91
|
+
|
|
92
|
+
skipped_items.append(skipped_items_item)
|
|
93
|
+
|
|
94
|
+
phone_unsubscribe_batch_response = cls(
|
|
95
|
+
org_slug=org_slug,
|
|
96
|
+
processed=processed,
|
|
97
|
+
updated=updated,
|
|
98
|
+
skipped_items=skipped_items,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
phone_unsubscribe_batch_response.additional_properties = d
|
|
102
|
+
return phone_unsubscribe_batch_response
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def additional_keys(self) -> list[str]:
|
|
106
|
+
return list(self.additional_properties.keys())
|
|
107
|
+
|
|
108
|
+
def __getitem__(self, key: str) -> Any:
|
|
109
|
+
return self.additional_properties[key]
|
|
110
|
+
|
|
111
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
|
112
|
+
self.additional_properties[key] = value
|
|
113
|
+
|
|
114
|
+
def __delitem__(self, key: str) -> None:
|
|
115
|
+
del self.additional_properties[key]
|
|
116
|
+
|
|
117
|
+
def __contains__(self, key: str) -> bool:
|
|
118
|
+
return key in self.additional_properties
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
from typing import Any, TypeVar
|
|
5
|
+
|
|
6
|
+
from attrs import define as _attrs_define
|
|
7
|
+
|
|
8
|
+
T = TypeVar("T", bound="PhoneUnsubscribeItem")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@_attrs_define
|
|
12
|
+
class PhoneUnsubscribeItem:
|
|
13
|
+
"""
|
|
14
|
+
Attributes:
|
|
15
|
+
phone (str): Phone number in E.164 format. Non-E.164 input is rejected per-item with `reason: "invalid phone
|
|
16
|
+
format"`. Example: +15551234567.
|
|
17
|
+
unsubscribed (bool):
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
phone: str
|
|
21
|
+
unsubscribed: bool
|
|
22
|
+
|
|
23
|
+
def to_dict(self) -> dict[str, Any]:
|
|
24
|
+
phone = self.phone
|
|
25
|
+
|
|
26
|
+
unsubscribed = self.unsubscribed
|
|
27
|
+
|
|
28
|
+
field_dict: dict[str, Any] = {}
|
|
29
|
+
|
|
30
|
+
field_dict.update(
|
|
31
|
+
{
|
|
32
|
+
"phone": phone,
|
|
33
|
+
"unsubscribed": unsubscribed,
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
return field_dict
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
|
|
41
|
+
d = dict(src_dict)
|
|
42
|
+
phone = d.pop("phone")
|
|
43
|
+
|
|
44
|
+
unsubscribed = d.pop("unsubscribed")
|
|
45
|
+
|
|
46
|
+
phone_unsubscribe_item = cls(
|
|
47
|
+
phone=phone,
|
|
48
|
+
unsubscribed=unsubscribed,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
return phone_unsubscribe_item
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
from typing import TYPE_CHECKING, Any, TypeVar, cast
|
|
5
|
+
|
|
6
|
+
from attrs import define as _attrs_define
|
|
7
|
+
from attrs import field as _attrs_field
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from ..models.phone_unsubscribe_record import PhoneUnsubscribeRecord
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
T = TypeVar("T", bound="PhoneUnsubscribeListResponse")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@_attrs_define
|
|
17
|
+
class PhoneUnsubscribeListResponse:
|
|
18
|
+
"""
|
|
19
|
+
Example:
|
|
20
|
+
{'org_slug': 'acme-corp', 'data': [{'phone': '+15551234567', 'unsubscribed': True, 'source': 'twilio',
|
|
21
|
+
'updated_at': '2026-04-12T16:22:01Z'}], 'next_cursor': None, 'has_more': False}
|
|
22
|
+
|
|
23
|
+
Attributes:
|
|
24
|
+
org_slug (str): Organization this page belongs to — the value you supplied, the one carried by `cursor`, or your
|
|
25
|
+
key's default organization when neither was provided. Example: acme-corp.
|
|
26
|
+
data (list[PhoneUnsubscribeRecord]):
|
|
27
|
+
next_cursor (None | str): Pass to the `cursor` query parameter to fetch the next page. `null` when no more
|
|
28
|
+
results are available. See the `Cursor` parameter for the encoding contract.
|
|
29
|
+
has_more (bool):
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
org_slug: str
|
|
33
|
+
data: list[PhoneUnsubscribeRecord]
|
|
34
|
+
next_cursor: None | str
|
|
35
|
+
has_more: bool
|
|
36
|
+
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
|
|
37
|
+
|
|
38
|
+
def to_dict(self) -> dict[str, Any]:
|
|
39
|
+
org_slug = self.org_slug
|
|
40
|
+
|
|
41
|
+
data = []
|
|
42
|
+
for data_item_data in self.data:
|
|
43
|
+
data_item = data_item_data.to_dict()
|
|
44
|
+
data.append(data_item)
|
|
45
|
+
|
|
46
|
+
next_cursor: None | str
|
|
47
|
+
next_cursor = self.next_cursor
|
|
48
|
+
|
|
49
|
+
has_more = self.has_more
|
|
50
|
+
|
|
51
|
+
field_dict: dict[str, Any] = {}
|
|
52
|
+
field_dict.update(self.additional_properties)
|
|
53
|
+
field_dict.update(
|
|
54
|
+
{
|
|
55
|
+
"org_slug": org_slug,
|
|
56
|
+
"data": data,
|
|
57
|
+
"next_cursor": next_cursor,
|
|
58
|
+
"has_more": has_more,
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return field_dict
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
|
|
66
|
+
from ..models.phone_unsubscribe_record import PhoneUnsubscribeRecord
|
|
67
|
+
|
|
68
|
+
d = dict(src_dict)
|
|
69
|
+
org_slug = d.pop("org_slug")
|
|
70
|
+
|
|
71
|
+
data = []
|
|
72
|
+
_data = d.pop("data")
|
|
73
|
+
for data_item_data in _data:
|
|
74
|
+
data_item = PhoneUnsubscribeRecord.from_dict(data_item_data)
|
|
75
|
+
|
|
76
|
+
data.append(data_item)
|
|
77
|
+
|
|
78
|
+
def _parse_next_cursor(data: object) -> None | str:
|
|
79
|
+
if data is None:
|
|
80
|
+
return data
|
|
81
|
+
return cast(None | str, data)
|
|
82
|
+
|
|
83
|
+
next_cursor = _parse_next_cursor(d.pop("next_cursor"))
|
|
84
|
+
|
|
85
|
+
has_more = d.pop("has_more")
|
|
86
|
+
|
|
87
|
+
phone_unsubscribe_list_response = cls(
|
|
88
|
+
org_slug=org_slug,
|
|
89
|
+
data=data,
|
|
90
|
+
next_cursor=next_cursor,
|
|
91
|
+
has_more=has_more,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
phone_unsubscribe_list_response.additional_properties = d
|
|
95
|
+
return phone_unsubscribe_list_response
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def additional_keys(self) -> list[str]:
|
|
99
|
+
return list(self.additional_properties.keys())
|
|
100
|
+
|
|
101
|
+
def __getitem__(self, key: str) -> Any:
|
|
102
|
+
return self.additional_properties[key]
|
|
103
|
+
|
|
104
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
|
105
|
+
self.additional_properties[key] = value
|
|
106
|
+
|
|
107
|
+
def __delitem__(self, key: str) -> None:
|
|
108
|
+
del self.additional_properties[key]
|
|
109
|
+
|
|
110
|
+
def __contains__(self, key: str) -> bool:
|
|
111
|
+
return key in self.additional_properties
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import datetime
|
|
4
|
+
from collections.abc import Mapping
|
|
5
|
+
from typing import Any, TypeVar
|
|
6
|
+
|
|
7
|
+
from attrs import define as _attrs_define
|
|
8
|
+
from attrs import field as _attrs_field
|
|
9
|
+
|
|
10
|
+
from ..models.phone_source_enum import PhoneSourceEnum
|
|
11
|
+
|
|
12
|
+
T = TypeVar("T", bound="PhoneUnsubscribeRecord")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@_attrs_define
|
|
16
|
+
class PhoneUnsubscribeRecord:
|
|
17
|
+
"""Used by both `/api/v1/unsubscribe/sms` and `/api/v1/unsubscribe/phone` — the channel is implicit in the URL.
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
{'phone': '+15551234567', 'unsubscribed': True, 'source': 'twilio', 'updated_at': '2026-04-12T16:22:01Z'}
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
phone (str): Phone number in E.164 format. Example: +15551234567.
|
|
24
|
+
unsubscribed (bool): `true` = opted out (TruAgents will not send on this channel).
|
|
25
|
+
source (PhoneSourceEnum): The category of writer responsible for the row's most recent state change on the SMS
|
|
26
|
+
or voice channel.
|
|
27
|
+
|
|
28
|
+
- `external_api` — pushed by the partner via this API.
|
|
29
|
+
- `twilio` — derived from a Twilio STOP/START message (also visible on `/phone` when an administrator has
|
|
30
|
+
unified the SMS and voice scopes).
|
|
31
|
+
- `admin` — manually changed by a TruAgents administrator.
|
|
32
|
+
- `import` — created during initial backfill from legacy per-contact flags.
|
|
33
|
+
updated_at (datetime.datetime): ISO 8601 timestamp of the most recent state change.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
phone: str
|
|
37
|
+
unsubscribed: bool
|
|
38
|
+
source: PhoneSourceEnum
|
|
39
|
+
updated_at: datetime.datetime
|
|
40
|
+
additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
|
|
41
|
+
|
|
42
|
+
def to_dict(self) -> dict[str, Any]:
|
|
43
|
+
phone = self.phone
|
|
44
|
+
|
|
45
|
+
unsubscribed = self.unsubscribed
|
|
46
|
+
|
|
47
|
+
source = self.source.value
|
|
48
|
+
|
|
49
|
+
updated_at = self.updated_at.isoformat()
|
|
50
|
+
|
|
51
|
+
field_dict: dict[str, Any] = {}
|
|
52
|
+
field_dict.update(self.additional_properties)
|
|
53
|
+
field_dict.update(
|
|
54
|
+
{
|
|
55
|
+
"phone": phone,
|
|
56
|
+
"unsubscribed": unsubscribed,
|
|
57
|
+
"source": source,
|
|
58
|
+
"updated_at": updated_at,
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return field_dict
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
|
|
66
|
+
d = dict(src_dict)
|
|
67
|
+
phone = d.pop("phone")
|
|
68
|
+
|
|
69
|
+
unsubscribed = d.pop("unsubscribed")
|
|
70
|
+
|
|
71
|
+
source = PhoneSourceEnum(d.pop("source"))
|
|
72
|
+
|
|
73
|
+
updated_at = datetime.datetime.fromisoformat(d.pop("updated_at"))
|
|
74
|
+
|
|
75
|
+
phone_unsubscribe_record = cls(
|
|
76
|
+
phone=phone,
|
|
77
|
+
unsubscribed=unsubscribed,
|
|
78
|
+
source=source,
|
|
79
|
+
updated_at=updated_at,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
phone_unsubscribe_record.additional_properties = d
|
|
83
|
+
return phone_unsubscribe_record
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def additional_keys(self) -> list[str]:
|
|
87
|
+
return list(self.additional_properties.keys())
|
|
88
|
+
|
|
89
|
+
def __getitem__(self, key: str) -> Any:
|
|
90
|
+
return self.additional_properties[key]
|
|
91
|
+
|
|
92
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
|
93
|
+
self.additional_properties[key] = value
|
|
94
|
+
|
|
95
|
+
def __delitem__(self, key: str) -> None:
|
|
96
|
+
del self.additional_properties[key]
|
|
97
|
+
|
|
98
|
+
def __contains__(self, key: str) -> bool:
|
|
99
|
+
return key in self.additional_properties
|