universal-mcp-applications 0.1.1__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.
Files changed (268) hide show
  1. universal_mcp/applications/ahrefs/README.md +51 -0
  2. universal_mcp/applications/ahrefs/__init__.py +1 -0
  3. universal_mcp/applications/ahrefs/app.py +2291 -0
  4. universal_mcp/applications/airtable/README.md +22 -0
  5. universal_mcp/applications/airtable/__init__.py +1 -0
  6. universal_mcp/applications/airtable/app.py +479 -0
  7. universal_mcp/applications/apollo/README.md +44 -0
  8. universal_mcp/applications/apollo/__init__.py +1 -0
  9. universal_mcp/applications/apollo/app.py +1847 -0
  10. universal_mcp/applications/asana/README.md +199 -0
  11. universal_mcp/applications/asana/__init__.py +1 -0
  12. universal_mcp/applications/asana/app.py +9509 -0
  13. universal_mcp/applications/aws-s3/README.md +0 -0
  14. universal_mcp/applications/aws-s3/__init__.py +1 -0
  15. universal_mcp/applications/aws-s3/app.py +552 -0
  16. universal_mcp/applications/bill/README.md +0 -0
  17. universal_mcp/applications/bill/__init__.py +1 -0
  18. universal_mcp/applications/bill/app.py +8705 -0
  19. universal_mcp/applications/box/README.md +307 -0
  20. universal_mcp/applications/box/__init__.py +1 -0
  21. universal_mcp/applications/box/app.py +15987 -0
  22. universal_mcp/applications/braze/README.md +106 -0
  23. universal_mcp/applications/braze/__init__.py +1 -0
  24. universal_mcp/applications/braze/app.py +4754 -0
  25. universal_mcp/applications/cal-com-v2/README.md +150 -0
  26. universal_mcp/applications/cal-com-v2/__init__.py +1 -0
  27. universal_mcp/applications/cal-com-v2/app.py +5541 -0
  28. universal_mcp/applications/calendly/README.md +53 -0
  29. universal_mcp/applications/calendly/__init__.py +1 -0
  30. universal_mcp/applications/calendly/app.py +1436 -0
  31. universal_mcp/applications/canva/README.md +43 -0
  32. universal_mcp/applications/canva/__init__.py +1 -0
  33. universal_mcp/applications/canva/app.py +941 -0
  34. universal_mcp/applications/clickup/README.md +135 -0
  35. universal_mcp/applications/clickup/__init__.py +1 -0
  36. universal_mcp/applications/clickup/app.py +5009 -0
  37. universal_mcp/applications/coda/README.md +108 -0
  38. universal_mcp/applications/coda/__init__.py +1 -0
  39. universal_mcp/applications/coda/app.py +3671 -0
  40. universal_mcp/applications/confluence/README.md +198 -0
  41. universal_mcp/applications/confluence/__init__.py +1 -0
  42. universal_mcp/applications/confluence/app.py +6273 -0
  43. universal_mcp/applications/contentful/README.md +17 -0
  44. universal_mcp/applications/contentful/__init__.py +1 -0
  45. universal_mcp/applications/contentful/app.py +364 -0
  46. universal_mcp/applications/crustdata/README.md +25 -0
  47. universal_mcp/applications/crustdata/__init__.py +1 -0
  48. universal_mcp/applications/crustdata/app.py +586 -0
  49. universal_mcp/applications/dialpad/README.md +202 -0
  50. universal_mcp/applications/dialpad/__init__.py +1 -0
  51. universal_mcp/applications/dialpad/app.py +5949 -0
  52. universal_mcp/applications/digitalocean/README.md +463 -0
  53. universal_mcp/applications/digitalocean/__init__.py +1 -0
  54. universal_mcp/applications/digitalocean/app.py +20835 -0
  55. universal_mcp/applications/domain-checker/README.md +13 -0
  56. universal_mcp/applications/domain-checker/__init__.py +1 -0
  57. universal_mcp/applications/domain-checker/app.py +265 -0
  58. universal_mcp/applications/e2b/README.md +12 -0
  59. universal_mcp/applications/e2b/__init__.py +1 -0
  60. universal_mcp/applications/e2b/app.py +187 -0
  61. universal_mcp/applications/elevenlabs/README.md +88 -0
  62. universal_mcp/applications/elevenlabs/__init__.py +1 -0
  63. universal_mcp/applications/elevenlabs/app.py +3235 -0
  64. universal_mcp/applications/exa/README.md +15 -0
  65. universal_mcp/applications/exa/__init__.py +1 -0
  66. universal_mcp/applications/exa/app.py +221 -0
  67. universal_mcp/applications/falai/README.md +17 -0
  68. universal_mcp/applications/falai/__init__.py +1 -0
  69. universal_mcp/applications/falai/app.py +331 -0
  70. universal_mcp/applications/figma/README.md +49 -0
  71. universal_mcp/applications/figma/__init__.py +1 -0
  72. universal_mcp/applications/figma/app.py +1090 -0
  73. universal_mcp/applications/firecrawl/README.md +20 -0
  74. universal_mcp/applications/firecrawl/__init__.py +1 -0
  75. universal_mcp/applications/firecrawl/app.py +514 -0
  76. universal_mcp/applications/fireflies/README.md +25 -0
  77. universal_mcp/applications/fireflies/__init__.py +1 -0
  78. universal_mcp/applications/fireflies/app.py +506 -0
  79. universal_mcp/applications/fpl/README.md +23 -0
  80. universal_mcp/applications/fpl/__init__.py +1 -0
  81. universal_mcp/applications/fpl/app.py +1327 -0
  82. universal_mcp/applications/fpl/utils/api.py +142 -0
  83. universal_mcp/applications/fpl/utils/fixtures.py +629 -0
  84. universal_mcp/applications/fpl/utils/helper.py +982 -0
  85. universal_mcp/applications/fpl/utils/league_utils.py +546 -0
  86. universal_mcp/applications/fpl/utils/position_utils.py +68 -0
  87. universal_mcp/applications/ghost-content/README.md +25 -0
  88. universal_mcp/applications/ghost-content/__init__.py +1 -0
  89. universal_mcp/applications/ghost-content/app.py +654 -0
  90. universal_mcp/applications/github/README.md +1049 -0
  91. universal_mcp/applications/github/__init__.py +1 -0
  92. universal_mcp/applications/github/app.py +50600 -0
  93. universal_mcp/applications/gong/README.md +63 -0
  94. universal_mcp/applications/gong/__init__.py +1 -0
  95. universal_mcp/applications/gong/app.py +2297 -0
  96. universal_mcp/applications/google-ads/README.md +0 -0
  97. universal_mcp/applications/google-ads/__init__.py +1 -0
  98. universal_mcp/applications/google-ads/app.py +23 -0
  99. universal_mcp/applications/google-calendar/README.md +21 -0
  100. universal_mcp/applications/google-calendar/__init__.py +1 -0
  101. universal_mcp/applications/google-calendar/app.py +574 -0
  102. universal_mcp/applications/google-docs/README.md +25 -0
  103. universal_mcp/applications/google-docs/__init__.py +1 -0
  104. universal_mcp/applications/google-docs/app.py +760 -0
  105. universal_mcp/applications/google-drive/README.md +68 -0
  106. universal_mcp/applications/google-drive/__init__.py +1 -0
  107. universal_mcp/applications/google-drive/app.py +4936 -0
  108. universal_mcp/applications/google-gemini/README.md +25 -0
  109. universal_mcp/applications/google-gemini/__init__.py +1 -0
  110. universal_mcp/applications/google-gemini/app.py +663 -0
  111. universal_mcp/applications/google-mail/README.md +31 -0
  112. universal_mcp/applications/google-mail/__init__.py +1 -0
  113. universal_mcp/applications/google-mail/app.py +1354 -0
  114. universal_mcp/applications/google-searchconsole/README.md +21 -0
  115. universal_mcp/applications/google-searchconsole/__init__.py +1 -0
  116. universal_mcp/applications/google-searchconsole/app.py +320 -0
  117. universal_mcp/applications/google-sheet/README.md +36 -0
  118. universal_mcp/applications/google-sheet/__init__.py +1 -0
  119. universal_mcp/applications/google-sheet/app.py +1941 -0
  120. universal_mcp/applications/hashnode/README.md +20 -0
  121. universal_mcp/applications/hashnode/__init__.py +1 -0
  122. universal_mcp/applications/hashnode/app.py +455 -0
  123. universal_mcp/applications/heygen/README.md +44 -0
  124. universal_mcp/applications/heygen/__init__.py +1 -0
  125. universal_mcp/applications/heygen/app.py +961 -0
  126. universal_mcp/applications/http-tools/README.md +16 -0
  127. universal_mcp/applications/http-tools/__init__.py +1 -0
  128. universal_mcp/applications/http-tools/app.py +153 -0
  129. universal_mcp/applications/hubspot/README.md +239 -0
  130. universal_mcp/applications/hubspot/__init__.py +1 -0
  131. universal_mcp/applications/hubspot/app.py +416 -0
  132. universal_mcp/applications/jira/README.md +600 -0
  133. universal_mcp/applications/jira/__init__.py +1 -0
  134. universal_mcp/applications/jira/app.py +28804 -0
  135. universal_mcp/applications/klaviyo/README.md +313 -0
  136. universal_mcp/applications/klaviyo/__init__.py +1 -0
  137. universal_mcp/applications/klaviyo/app.py +11236 -0
  138. universal_mcp/applications/linkedin/README.md +15 -0
  139. universal_mcp/applications/linkedin/__init__.py +1 -0
  140. universal_mcp/applications/linkedin/app.py +243 -0
  141. universal_mcp/applications/mailchimp/README.md +281 -0
  142. universal_mcp/applications/mailchimp/__init__.py +1 -0
  143. universal_mcp/applications/mailchimp/app.py +10937 -0
  144. universal_mcp/applications/markitdown/README.md +12 -0
  145. universal_mcp/applications/markitdown/__init__.py +1 -0
  146. universal_mcp/applications/markitdown/app.py +63 -0
  147. universal_mcp/applications/miro/README.md +151 -0
  148. universal_mcp/applications/miro/__init__.py +1 -0
  149. universal_mcp/applications/miro/app.py +5429 -0
  150. universal_mcp/applications/ms-teams/README.md +42 -0
  151. universal_mcp/applications/ms-teams/__init__.py +1 -0
  152. universal_mcp/applications/ms-teams/app.py +1823 -0
  153. universal_mcp/applications/neon/README.md +74 -0
  154. universal_mcp/applications/neon/__init__.py +1 -0
  155. universal_mcp/applications/neon/app.py +2018 -0
  156. universal_mcp/applications/notion/README.md +30 -0
  157. universal_mcp/applications/notion/__init__.py +1 -0
  158. universal_mcp/applications/notion/app.py +527 -0
  159. universal_mcp/applications/openai/README.md +22 -0
  160. universal_mcp/applications/openai/__init__.py +1 -0
  161. universal_mcp/applications/openai/app.py +759 -0
  162. universal_mcp/applications/outlook/README.md +20 -0
  163. universal_mcp/applications/outlook/__init__.py +1 -0
  164. universal_mcp/applications/outlook/app.py +444 -0
  165. universal_mcp/applications/perplexity/README.md +12 -0
  166. universal_mcp/applications/perplexity/__init__.py +1 -0
  167. universal_mcp/applications/perplexity/app.py +65 -0
  168. universal_mcp/applications/pipedrive/README.md +284 -0
  169. universal_mcp/applications/pipedrive/__init__.py +1 -0
  170. universal_mcp/applications/pipedrive/app.py +12924 -0
  171. universal_mcp/applications/posthog/README.md +132 -0
  172. universal_mcp/applications/posthog/__init__.py +1 -0
  173. universal_mcp/applications/posthog/app.py +7125 -0
  174. universal_mcp/applications/reddit/README.md +135 -0
  175. universal_mcp/applications/reddit/__init__.py +1 -0
  176. universal_mcp/applications/reddit/app.py +4652 -0
  177. universal_mcp/applications/replicate/README.md +18 -0
  178. universal_mcp/applications/replicate/__init__.py +1 -0
  179. universal_mcp/applications/replicate/app.py +495 -0
  180. universal_mcp/applications/resend/README.md +40 -0
  181. universal_mcp/applications/resend/__init__.py +1 -0
  182. universal_mcp/applications/resend/app.py +881 -0
  183. universal_mcp/applications/retell/README.md +21 -0
  184. universal_mcp/applications/retell/__init__.py +1 -0
  185. universal_mcp/applications/retell/app.py +333 -0
  186. universal_mcp/applications/rocketlane/README.md +70 -0
  187. universal_mcp/applications/rocketlane/__init__.py +1 -0
  188. universal_mcp/applications/rocketlane/app.py +4346 -0
  189. universal_mcp/applications/semanticscholar/README.md +25 -0
  190. universal_mcp/applications/semanticscholar/__init__.py +1 -0
  191. universal_mcp/applications/semanticscholar/app.py +482 -0
  192. universal_mcp/applications/semrush/README.md +44 -0
  193. universal_mcp/applications/semrush/__init__.py +1 -0
  194. universal_mcp/applications/semrush/app.py +2081 -0
  195. universal_mcp/applications/sendgrid/README.md +362 -0
  196. universal_mcp/applications/sendgrid/__init__.py +1 -0
  197. universal_mcp/applications/sendgrid/app.py +9752 -0
  198. universal_mcp/applications/sentry/README.md +186 -0
  199. universal_mcp/applications/sentry/__init__.py +1 -0
  200. universal_mcp/applications/sentry/app.py +7471 -0
  201. universal_mcp/applications/serpapi/README.md +14 -0
  202. universal_mcp/applications/serpapi/__init__.py +1 -0
  203. universal_mcp/applications/serpapi/app.py +293 -0
  204. universal_mcp/applications/sharepoint/README.md +0 -0
  205. universal_mcp/applications/sharepoint/__init__.py +1 -0
  206. universal_mcp/applications/sharepoint/app.py +215 -0
  207. universal_mcp/applications/shopify/README.md +321 -0
  208. universal_mcp/applications/shopify/__init__.py +1 -0
  209. universal_mcp/applications/shopify/app.py +15392 -0
  210. universal_mcp/applications/shortcut/README.md +128 -0
  211. universal_mcp/applications/shortcut/__init__.py +1 -0
  212. universal_mcp/applications/shortcut/app.py +4478 -0
  213. universal_mcp/applications/slack/README.md +0 -0
  214. universal_mcp/applications/slack/__init__.py +1 -0
  215. universal_mcp/applications/slack/app.py +570 -0
  216. universal_mcp/applications/spotify/README.md +91 -0
  217. universal_mcp/applications/spotify/__init__.py +1 -0
  218. universal_mcp/applications/spotify/app.py +2526 -0
  219. universal_mcp/applications/supabase/README.md +87 -0
  220. universal_mcp/applications/supabase/__init__.py +1 -0
  221. universal_mcp/applications/supabase/app.py +2970 -0
  222. universal_mcp/applications/tavily/README.md +12 -0
  223. universal_mcp/applications/tavily/__init__.py +1 -0
  224. universal_mcp/applications/tavily/app.py +51 -0
  225. universal_mcp/applications/trello/README.md +266 -0
  226. universal_mcp/applications/trello/__init__.py +1 -0
  227. universal_mcp/applications/trello/app.py +10875 -0
  228. universal_mcp/applications/twillo/README.md +0 -0
  229. universal_mcp/applications/twillo/__init__.py +1 -0
  230. universal_mcp/applications/twillo/app.py +269 -0
  231. universal_mcp/applications/twitter/README.md +100 -0
  232. universal_mcp/applications/twitter/__init__.py +1 -0
  233. universal_mcp/applications/twitter/api_segments/__init__.py +0 -0
  234. universal_mcp/applications/twitter/api_segments/api_segment_base.py +51 -0
  235. universal_mcp/applications/twitter/api_segments/compliance_api.py +122 -0
  236. universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +255 -0
  237. universal_mcp/applications/twitter/api_segments/dm_events_api.py +140 -0
  238. universal_mcp/applications/twitter/api_segments/likes_api.py +159 -0
  239. universal_mcp/applications/twitter/api_segments/lists_api.py +395 -0
  240. universal_mcp/applications/twitter/api_segments/openapi_json_api.py +34 -0
  241. universal_mcp/applications/twitter/api_segments/spaces_api.py +309 -0
  242. universal_mcp/applications/twitter/api_segments/trends_api.py +40 -0
  243. universal_mcp/applications/twitter/api_segments/tweets_api.py +1403 -0
  244. universal_mcp/applications/twitter/api_segments/usage_api.py +40 -0
  245. universal_mcp/applications/twitter/api_segments/users_api.py +1498 -0
  246. universal_mcp/applications/twitter/app.py +46 -0
  247. universal_mcp/applications/unipile/README.md +28 -0
  248. universal_mcp/applications/unipile/__init__.py +1 -0
  249. universal_mcp/applications/unipile/app.py +829 -0
  250. universal_mcp/applications/whatsapp/README.md +23 -0
  251. universal_mcp/applications/whatsapp/__init__.py +1 -0
  252. universal_mcp/applications/whatsapp/app.py +595 -0
  253. universal_mcp/applications/whatsapp-business/README.md +34 -0
  254. universal_mcp/applications/whatsapp-business/__init__.py +1 -0
  255. universal_mcp/applications/whatsapp-business/app.py +1065 -0
  256. universal_mcp/applications/wrike/README.md +46 -0
  257. universal_mcp/applications/wrike/__init__.py +1 -0
  258. universal_mcp/applications/wrike/app.py +1583 -0
  259. universal_mcp/applications/youtube/README.md +57 -0
  260. universal_mcp/applications/youtube/__init__.py +1 -0
  261. universal_mcp/applications/youtube/app.py +1696 -0
  262. universal_mcp/applications/zenquotes/README.md +12 -0
  263. universal_mcp/applications/zenquotes/__init__.py +1 -0
  264. universal_mcp/applications/zenquotes/app.py +31 -0
  265. universal_mcp_applications-0.1.1.dist-info/METADATA +172 -0
  266. universal_mcp_applications-0.1.1.dist-info/RECORD +268 -0
  267. universal_mcp_applications-0.1.1.dist-info/WHEEL +4 -0
  268. universal_mcp_applications-0.1.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,4754 @@
1
+ from typing import Any
2
+
3
+ from universal_mcp.applications.application import APIApplication
4
+ from universal_mcp.integrations import Integration
5
+
6
+
7
+ class BrazeApp(APIApplication):
8
+ def __init__(self, integration: Integration = None, **kwargs) -> None:
9
+ super().__init__(name="braze", integration=integration, **kwargs)
10
+ self.base_url = "https://rest.iad-01.braze.com"
11
+
12
+ def update_email_template(
13
+ self,
14
+ email_template_id: str | None = None,
15
+ template_name: str | None = None,
16
+ subject: str | None = None,
17
+ body: str | None = None,
18
+ plaintext_body: str | None = None,
19
+ preheader: str | None = None,
20
+ tags: list[str] | None = None,
21
+ ) -> dict[str, Any]:
22
+ """
23
+ Update Email Template
24
+
25
+ Args:
26
+ email_template_id (string): email_template_id Example: 'email_template_id'.
27
+ template_name (string): template_name Example: 'Weekly Newsletter'.
28
+ subject (string): subject Example: "This Week's Styles".
29
+ body (string): body Example: "Check out this week's digital lookbook to inspire your outfits. Take a look at https://www.braze.com/".
30
+ plaintext_body (string): plaintext_body Example: 'This is the updated text within my email body and here is a link to https://www.braze.com/.'.
31
+ preheader (string): preheader Example: 'We want you to have the best looks this Summer'.
32
+ tags (array): tags Example: ['Tag1', 'Tag2'].
33
+
34
+ Returns:
35
+ dict[str, Any]: Successful response
36
+
37
+ Raises:
38
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
39
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
40
+
41
+ Tags:
42
+ Templates > Email Templates
43
+ """
44
+ request_body_data = None
45
+ request_body_data = {
46
+ "email_template_id": email_template_id,
47
+ "template_name": template_name,
48
+ "subject": subject,
49
+ "body": body,
50
+ "plaintext_body": plaintext_body,
51
+ "preheader": preheader,
52
+ "tags": tags,
53
+ }
54
+ request_body_data = {
55
+ k: v for k, v in request_body_data.items() if v is not None
56
+ }
57
+ url = f"{self.base_url}/templates/email/update"
58
+ query_params = {}
59
+ response = self._post(
60
+ url,
61
+ data=request_body_data,
62
+ params=query_params,
63
+ content_type="application/json",
64
+ )
65
+ response.raise_for_status()
66
+ if (
67
+ response.status_code == 204
68
+ or not response.content
69
+ or not response.text.strip()
70
+ ):
71
+ return None
72
+ try:
73
+ return response.json()
74
+ except ValueError:
75
+ return None
76
+
77
+ def track_user_activity(
78
+ self,
79
+ attributes: list[dict[str, Any]] | None = None,
80
+ events: list[dict[str, Any]] | None = None,
81
+ purchases: list[dict[str, Any]] | None = None,
82
+ ) -> dict[str, Any]:
83
+ """
84
+ Track Users
85
+
86
+ Args:
87
+ attributes (array): attributes Example: [{'external_id': 'rachel_feinberg', 'string_attribute': 'fruit', 'boolean_attribute_1': True, 'integer_attribute': 25, 'array_attribute': ['banana', 'apple']}].
88
+ events (array): events Example: [{'external_id': 'user_identifier', 'app_id': 'your_app_identifier', 'name': 'rented_movie', 'time': '2022-12-06T19:20:45+01:00', 'properties': {'release': {'studio': 'FilmStudio', 'year': '2022'}, 'cast': [{'name': 'Actor1'}, {'name': 'Actor2'}]}}, {'user_alias': {'alias_name': 'device123', 'alias_label': 'my_device_identifier'}, 'app_id': 'your_app_identifier', 'name': 'rented_movie', 'time': '2013-07-16T19:20:50+01:00'}].
89
+ purchases (array): purchases Example: [{'external_id': 'user_identifier', 'app_id': 'your_app_identifier', 'product_id': 'product_name', 'currency': 'USD', 'price': 12.12, 'quantity': 6, 'time': '2017-05-12T18:47:12Z', 'properties': {'color': 'red', 'monogram': 'ABC', 'checkout_duration': 180, 'size': 'Large', 'brand': 'Backpack Locker'}}].
90
+
91
+ Returns:
92
+ dict[str, Any]: Successful response
93
+
94
+ Raises:
95
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
96
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
97
+
98
+ Tags:
99
+ User Data
100
+ """
101
+ request_body_data = None
102
+ request_body_data = {
103
+ "attributes": attributes,
104
+ "events": events,
105
+ "purchases": purchases,
106
+ }
107
+ request_body_data = {
108
+ k: v for k, v in request_body_data.items() if v is not None
109
+ }
110
+ url = f"{self.base_url}/users/track"
111
+ query_params = {}
112
+ response = self._post(
113
+ url,
114
+ data=request_body_data,
115
+ params=query_params,
116
+ content_type="application/json",
117
+ )
118
+ response.raise_for_status()
119
+ if (
120
+ response.status_code == 204
121
+ or not response.content
122
+ or not response.text.strip()
123
+ ):
124
+ return None
125
+ try:
126
+ return response.json()
127
+ except ValueError:
128
+ return None
129
+
130
+ def delete_catalog_by_name(self, catalog_name: str) -> dict[str, Any]:
131
+ """
132
+ Delete Catalog
133
+
134
+ Args:
135
+ catalog_name (string): catalog_name
136
+
137
+ Returns:
138
+ dict[str, Any]: Successful response
139
+
140
+ Raises:
141
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
142
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
143
+
144
+ Tags:
145
+ Catalogs > Catalog Management > Synchronous
146
+ """
147
+ if catalog_name is None:
148
+ raise ValueError("Missing required parameter 'catalog_name'.")
149
+ url = f"{self.base_url}/catalogs/{catalog_name}"
150
+ query_params = {}
151
+ response = self._delete(url, params=query_params)
152
+ response.raise_for_status()
153
+ if (
154
+ response.status_code == 204
155
+ or not response.content
156
+ or not response.text.strip()
157
+ ):
158
+ return None
159
+ try:
160
+ return response.json()
161
+ except ValueError:
162
+ return None
163
+
164
+ def list_catalogs(self) -> dict[str, Any]:
165
+ """
166
+ List Catalogs
167
+
168
+ Returns:
169
+ dict[str, Any]: Successful response
170
+
171
+ Raises:
172
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
173
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
174
+
175
+ Tags:
176
+ Catalogs > Catalog Management > Synchronous, important
177
+ """
178
+ url = f"{self.base_url}/catalogs"
179
+ query_params = {}
180
+ response = self._get(url, params=query_params)
181
+ response.raise_for_status()
182
+ if (
183
+ response.status_code == 204
184
+ or not response.content
185
+ or not response.text.strip()
186
+ ):
187
+ return None
188
+ try:
189
+ return response.json()
190
+ except ValueError:
191
+ return None
192
+
193
+ def create_catalog(
194
+ self, catalogs: list[dict[str, Any]] | None = None
195
+ ) -> dict[str, Any]:
196
+ """
197
+ Create Catalog
198
+
199
+ Args:
200
+ catalogs (array): catalogs Example: [{'name': 'restaurants', 'description': 'My Restaurants', 'fields': [{'name': 'id', 'type': 'string'}]}].
201
+
202
+ Returns:
203
+ dict[str, Any]: Successful response
204
+
205
+ Raises:
206
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
207
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
208
+
209
+ Tags:
210
+ Catalogs > Catalog Management > Synchronous, important
211
+ """
212
+ request_body_data = None
213
+ request_body_data = {
214
+ "catalogs": catalogs,
215
+ }
216
+ request_body_data = {
217
+ k: v for k, v in request_body_data.items() if v is not None
218
+ }
219
+ url = f"{self.base_url}/catalogs"
220
+ query_params = {}
221
+ response = self._post(
222
+ url,
223
+ data=request_body_data,
224
+ params=query_params,
225
+ content_type="application/json",
226
+ )
227
+ response.raise_for_status()
228
+ if (
229
+ response.status_code == 204
230
+ or not response.content
231
+ or not response.text.strip()
232
+ ):
233
+ return None
234
+ try:
235
+ return response.json()
236
+ except ValueError:
237
+ return None
238
+
239
+ def delete_catalog_item(self, catalog_name: str) -> dict[str, Any]:
240
+ """
241
+ Delete Multiple Catalog Items
242
+
243
+ Args:
244
+ catalog_name (string): catalog_name
245
+
246
+ Returns:
247
+ dict[str, Any]: Successful response
248
+
249
+ Raises:
250
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
251
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
252
+
253
+ Tags:
254
+ Catalogs > Catalog Items > Asynchronous, important
255
+ """
256
+ if catalog_name is None:
257
+ raise ValueError("Missing required parameter 'catalog_name'.")
258
+ url = f"{self.base_url}/catalogs/{catalog_name}/items"
259
+ query_params = {}
260
+ response = self._delete(url, params=query_params)
261
+ response.raise_for_status()
262
+ if (
263
+ response.status_code == 204
264
+ or not response.content
265
+ or not response.text.strip()
266
+ ):
267
+ return None
268
+ try:
269
+ return response.json()
270
+ except ValueError:
271
+ return None
272
+
273
+ def edit_catalog_item(
274
+ self, catalog_name: str, items: list[dict[str, Any]] | None = None
275
+ ) -> dict[str, Any]:
276
+ """
277
+ Edit Multiple Catalog Items
278
+
279
+ Args:
280
+ catalog_name (string): catalog_name
281
+ items (array): items Example: [{'id': 'restaurant1'}].
282
+
283
+ Returns:
284
+ dict[str, Any]: Successful response
285
+
286
+ Raises:
287
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
288
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
289
+
290
+ Tags:
291
+ Catalogs > Catalog Items > Asynchronous, important
292
+ """
293
+ if catalog_name is None:
294
+ raise ValueError("Missing required parameter 'catalog_name'.")
295
+ request_body_data = None
296
+ request_body_data = {
297
+ "items": items,
298
+ }
299
+ request_body_data = {
300
+ k: v for k, v in request_body_data.items() if v is not None
301
+ }
302
+ url = f"{self.base_url}/catalogs/{catalog_name}/items"
303
+ query_params = {}
304
+ response = self._patch(url, data=request_body_data, params=query_params)
305
+ response.raise_for_status()
306
+ if (
307
+ response.status_code == 204
308
+ or not response.content
309
+ or not response.text.strip()
310
+ ):
311
+ return None
312
+ try:
313
+ return response.json()
314
+ except ValueError:
315
+ return None
316
+
317
+ def create_catalog_item(
318
+ self, catalog_name: str, items: list[dict[str, Any]] | None = None
319
+ ) -> dict[str, Any]:
320
+ """
321
+ Create Multiple Catalog Items
322
+
323
+ Args:
324
+ catalog_name (string): catalog_name
325
+ items (array): items Example: [{'id': 'restaurant1', 'Name': 'Restaurant1', 'City': 'New York', 'Cuisine': 'American', 'Rating': 5, 'Loyalty_Program': True, 'Created_At': '2022-11-01T09:03:19.967+00:00'}].
326
+
327
+ Returns:
328
+ dict[str, Any]: Successful response
329
+
330
+ Raises:
331
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
332
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
333
+
334
+ Tags:
335
+ Catalogs > Catalog Items > Asynchronous
336
+ """
337
+ if catalog_name is None:
338
+ raise ValueError("Missing required parameter 'catalog_name'.")
339
+ request_body_data = None
340
+ request_body_data = {
341
+ "items": items,
342
+ }
343
+ request_body_data = {
344
+ k: v for k, v in request_body_data.items() if v is not None
345
+ }
346
+ url = f"{self.base_url}/catalogs/{catalog_name}/items"
347
+ query_params = {}
348
+ response = self._post(
349
+ url,
350
+ data=request_body_data,
351
+ params=query_params,
352
+ content_type="application/json",
353
+ )
354
+ response.raise_for_status()
355
+ if (
356
+ response.status_code == 204
357
+ or not response.content
358
+ or not response.text.strip()
359
+ ):
360
+ return None
361
+ try:
362
+ return response.json()
363
+ except ValueError:
364
+ return None
365
+
366
+ def update_catalog_items(
367
+ self, catalog_name: str, items: list[dict[str, Any]] | None = None
368
+ ) -> dict[str, Any]:
369
+ """
370
+ Update Catalog Item
371
+
372
+ Args:
373
+ catalog_name (string): catalog_name
374
+ items (array): items Example: [{'Name': 'Restaurant', 'Loyalty_Program': False, 'Location': {'Latitude': 33.6112, 'Longitude': -117.8711}, 'Open_Time': '2021-09-03T09:03:19.967+00:00'}].
375
+
376
+ Returns:
377
+ dict[str, Any]: Successful response
378
+
379
+ Raises:
380
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
381
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
382
+
383
+ Tags:
384
+ Catalogs > Catalog Items > Asynchronous
385
+ """
386
+ if catalog_name is None:
387
+ raise ValueError("Missing required parameter 'catalog_name'.")
388
+ request_body_data = None
389
+ request_body_data = {
390
+ "items": items,
391
+ }
392
+ request_body_data = {
393
+ k: v for k, v in request_body_data.items() if v is not None
394
+ }
395
+ url = f"{self.base_url}/catalogs/{catalog_name}/items"
396
+ query_params = {}
397
+ response = self._put(
398
+ url,
399
+ data=request_body_data,
400
+ params=query_params,
401
+ content_type="application/json",
402
+ )
403
+ response.raise_for_status()
404
+ if (
405
+ response.status_code == 204
406
+ or not response.content
407
+ or not response.text.strip()
408
+ ):
409
+ return None
410
+ try:
411
+ return response.json()
412
+ except ValueError:
413
+ return None
414
+
415
+ def list_catalog_items(self, catalog_name: str) -> dict[str, Any]:
416
+ """
417
+ List Multiple Catalog Item Details
418
+
419
+ Args:
420
+ catalog_name (string): catalog_name
421
+
422
+ Returns:
423
+ dict[str, Any]: Successful response
424
+
425
+ Raises:
426
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
427
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
428
+
429
+ Tags:
430
+ Catalogs > Catalog Items > Synchronous
431
+ """
432
+ if catalog_name is None:
433
+ raise ValueError("Missing required parameter 'catalog_name'.")
434
+ url = f"{self.base_url}/catalogs/{catalog_name}/items"
435
+ query_params = {}
436
+ response = self._get(url, params=query_params)
437
+ response.raise_for_status()
438
+ if (
439
+ response.status_code == 204
440
+ or not response.content
441
+ or not response.text.strip()
442
+ ):
443
+ return None
444
+ try:
445
+ return response.json()
446
+ except ValueError:
447
+ return None
448
+
449
+ def delete_catalog_item_by_id(
450
+ self, catalog_name: str, item_id: str
451
+ ) -> dict[str, Any]:
452
+ """
453
+ Delete a Catalog Item
454
+
455
+ Args:
456
+ catalog_name (string): catalog_name
457
+ item_id (string): item_id
458
+
459
+ Returns:
460
+ dict[str, Any]: Successful response
461
+
462
+ Raises:
463
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
464
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
465
+
466
+ Tags:
467
+ Catalogs > Catalog Items > Synchronous
468
+ """
469
+ if catalog_name is None:
470
+ raise ValueError("Missing required parameter 'catalog_name'.")
471
+ if item_id is None:
472
+ raise ValueError("Missing required parameter 'item_id'.")
473
+ url = f"{self.base_url}/catalogs/{catalog_name}/items/{item_id}"
474
+ query_params = {}
475
+ response = self._delete(url, params=query_params)
476
+ response.raise_for_status()
477
+ if (
478
+ response.status_code == 204
479
+ or not response.content
480
+ or not response.text.strip()
481
+ ):
482
+ return None
483
+ try:
484
+ return response.json()
485
+ except ValueError:
486
+ return None
487
+
488
+ def get_item_detail(self, catalog_name: str, item_id: str) -> dict[str, Any]:
489
+ """
490
+ List Catalog Item Details
491
+
492
+ Args:
493
+ catalog_name (string): catalog_name
494
+ item_id (string): item_id
495
+
496
+ Returns:
497
+ dict[str, Any]: Successful response
498
+
499
+ Raises:
500
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
501
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
502
+
503
+ Tags:
504
+ Catalogs > Catalog Items > Synchronous
505
+ """
506
+ if catalog_name is None:
507
+ raise ValueError("Missing required parameter 'catalog_name'.")
508
+ if item_id is None:
509
+ raise ValueError("Missing required parameter 'item_id'.")
510
+ url = f"{self.base_url}/catalogs/{catalog_name}/items/{item_id}"
511
+ query_params = {}
512
+ response = self._get(url, params=query_params)
513
+ response.raise_for_status()
514
+ if (
515
+ response.status_code == 204
516
+ or not response.content
517
+ or not response.text.strip()
518
+ ):
519
+ return None
520
+ try:
521
+ return response.json()
522
+ except ValueError:
523
+ return None
524
+
525
+ def update_catalog_item_by_id(
526
+ self,
527
+ catalog_name: str,
528
+ item_id: str,
529
+ items: list[dict[str, Any]] | None = None,
530
+ ) -> dict[str, Any]:
531
+ """
532
+ Edit Catalog Items
533
+
534
+ Args:
535
+ catalog_name (string): catalog_name
536
+ item_id (string): item_id
537
+ items (array): items Example: [{'Name': 'Restaurant', 'Loyalty_Program': False, 'Open_Time': '2021-09-03T09:03:19.967+00:00'}].
538
+
539
+ Returns:
540
+ dict[str, Any]: Successful response
541
+
542
+ Raises:
543
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
544
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
545
+
546
+ Tags:
547
+ Catalogs > Catalog Items > Synchronous
548
+ """
549
+ if catalog_name is None:
550
+ raise ValueError("Missing required parameter 'catalog_name'.")
551
+ if item_id is None:
552
+ raise ValueError("Missing required parameter 'item_id'.")
553
+ request_body_data = None
554
+ request_body_data = {
555
+ "items": items,
556
+ }
557
+ request_body_data = {
558
+ k: v for k, v in request_body_data.items() if v is not None
559
+ }
560
+ url = f"{self.base_url}/catalogs/{catalog_name}/items/{item_id}"
561
+ query_params = {}
562
+ response = self._patch(url, data=request_body_data, params=query_params)
563
+ response.raise_for_status()
564
+ if (
565
+ response.status_code == 204
566
+ or not response.content
567
+ or not response.text.strip()
568
+ ):
569
+ return None
570
+ try:
571
+ return response.json()
572
+ except ValueError:
573
+ return None
574
+
575
+ def add_catalog_item_by_id(
576
+ self,
577
+ catalog_name: str,
578
+ item_id: str,
579
+ items: list[dict[str, Any]] | None = None,
580
+ ) -> dict[str, Any]:
581
+ """
582
+ Create Catalog Item
583
+
584
+ Args:
585
+ catalog_name (string): catalog_name
586
+ item_id (string): item_id
587
+ items (array): items Example: [{'Name': 'Restaurant1', 'City': 'New York', 'Cuisine': 'American', 'Rating': 5, 'Loyalty_Program': True, 'Created_At': '2022-11-01T09:03:19.967+00:00'}].
588
+
589
+ Returns:
590
+ dict[str, Any]: Successful response
591
+
592
+ Raises:
593
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
594
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
595
+
596
+ Tags:
597
+ Catalogs > Catalog Items > Synchronous
598
+ """
599
+ if catalog_name is None:
600
+ raise ValueError("Missing required parameter 'catalog_name'.")
601
+ if item_id is None:
602
+ raise ValueError("Missing required parameter 'item_id'.")
603
+ request_body_data = None
604
+ request_body_data = {
605
+ "items": items,
606
+ }
607
+ request_body_data = {
608
+ k: v for k, v in request_body_data.items() if v is not None
609
+ }
610
+ url = f"{self.base_url}/catalogs/{catalog_name}/items/{item_id}"
611
+ query_params = {}
612
+ response = self._post(
613
+ url,
614
+ data=request_body_data,
615
+ params=query_params,
616
+ content_type="application/json",
617
+ )
618
+ response.raise_for_status()
619
+ if (
620
+ response.status_code == 204
621
+ or not response.content
622
+ or not response.text.strip()
623
+ ):
624
+ return None
625
+ try:
626
+ return response.json()
627
+ except ValueError:
628
+ return None
629
+
630
+ def update_catalog_item(
631
+ self,
632
+ catalog_name: str,
633
+ item_id: str,
634
+ items: list[dict[str, Any]] | None = None,
635
+ ) -> dict[str, Any]:
636
+ """
637
+ Update Catalog Item
638
+
639
+ Args:
640
+ catalog_name (string): catalog_name
641
+ item_id (string): item_id
642
+ items (array): items Example: [{'Name': 'Restaurant', 'Loyalty_Program': False, 'Location': {'Latitude': 33.6112, 'Longitude': -117.8711}, 'Open_Time': '2021-09-03T09:03:19.967+00:00'}].
643
+
644
+ Returns:
645
+ dict[str, Any]: Successful response
646
+
647
+ Raises:
648
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
649
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
650
+
651
+ Tags:
652
+ Catalogs > Catalog Items > Synchronous
653
+ """
654
+ if catalog_name is None:
655
+ raise ValueError("Missing required parameter 'catalog_name'.")
656
+ if item_id is None:
657
+ raise ValueError("Missing required parameter 'item_id'.")
658
+ request_body_data = None
659
+ request_body_data = {
660
+ "items": items,
661
+ }
662
+ request_body_data = {
663
+ k: v for k, v in request_body_data.items() if v is not None
664
+ }
665
+ url = f"{self.base_url}/catalogs/{catalog_name}/items/{item_id}"
666
+ query_params = {}
667
+ response = self._put(
668
+ url,
669
+ data=request_body_data,
670
+ params=query_params,
671
+ content_type="application/json",
672
+ )
673
+ response.raise_for_status()
674
+ if (
675
+ response.status_code == 204
676
+ or not response.content
677
+ or not response.text.strip()
678
+ ):
679
+ return None
680
+ try:
681
+ return response.json()
682
+ except ValueError:
683
+ return None
684
+
685
+ def list_hard_bounces(
686
+ self,
687
+ start_date: str | None = None,
688
+ end_date: str | None = None,
689
+ limit: int | None = None,
690
+ offset: int | None = None,
691
+ email: str | None = None,
692
+ ) -> dict[str, Any]:
693
+ """
694
+ Query Hard Bounced Emails
695
+
696
+ Args:
697
+ start_date (string): (Optional*) String in YYYY-MM-DD format Start date of the range to retrieve hard bounces, must be earlier than `end_date`. This is treated as midnight in UTC time by the API. *You must provide either an `email` or a `start_date`, and an `end_date`. Example: '2019-01-01'.
698
+ end_date (string): (Optional*) String in YYYY-MM-DD format String in YYYY-MM-DD format. End date of the range to retrieve hard bounces. This is treated as midnight in UTC time by the API. *You must provide either an `email` or a `start_date`, and an `end_date`. Example: '2019-02-01'.
699
+ limit (integer): (Optional) Integer Optional field to limit the number of results returned. Defaults to 100, maximum is 500. Example: '100'.
700
+ offset (integer): (Optional) Integer Optional beginning point in the list to retrieve from. Example: '1'.
701
+ email (string): (Optional*) String If provided, we will return whether or not the user has hard bounced. *You must provide either an `email` or a `start_date`, and an `end_date`. Example: 'example@braze.com'.
702
+
703
+ Returns:
704
+ dict[str, Any]: Successful response
705
+
706
+ Raises:
707
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
708
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
709
+
710
+ Tags:
711
+ Email Lists & Addresses
712
+ """
713
+ url = f"{self.base_url}/email/hard_bounces"
714
+ query_params = {
715
+ k: v
716
+ for k, v in [
717
+ ("start_date", start_date),
718
+ ("end_date", end_date),
719
+ ("limit", limit),
720
+ ("offset", offset),
721
+ ("email", email),
722
+ ]
723
+ if v is not None
724
+ }
725
+ response = self._get(url, params=query_params)
726
+ response.raise_for_status()
727
+ if (
728
+ response.status_code == 204
729
+ or not response.content
730
+ or not response.text.strip()
731
+ ):
732
+ return None
733
+ try:
734
+ return response.json()
735
+ except ValueError:
736
+ return None
737
+
738
+ def list_unsubscribes(
739
+ self,
740
+ start_date: str | None = None,
741
+ end_date: str | None = None,
742
+ limit: int | None = None,
743
+ offset: int | None = None,
744
+ sort_direction: str | None = None,
745
+ email: str | None = None,
746
+ ) -> dict[str, Any]:
747
+ """
748
+ Query List of Unsubscribed Email Addresses
749
+
750
+ Args:
751
+ start_date (string): (Optional*) String in YYYY-MM-DD format Start date of the range to retrieve unsubscribes, must be earlier than end_date. This is treated as midnight in UTC time by the API. Example: '2020-01-01'.
752
+ end_date (string): (Optional*) String in YYYY-MM-DD format End date of the range to retrieve unsubscribes. This is treated as midnight in UTC time by the API. Example: '2020-02-01'.
753
+ limit (integer): (Optional) Integer Optional field to limit the number of results returned. Limit must be greater than 1. Defaults to 100, maximum is 500. Example: '1'.
754
+ offset (integer): (Optional) Integer Optional beginning point in the list to retrieve from. Example: '1'.
755
+ sort_direction (string): (Optional) String Pass in the value `asc` to sort unsubscribes from oldest to newest. Pass in `desc` to sort from newest to oldest. If sort_direction is not included, the default order is newest to oldest. Example: 'desc'.
756
+ email (string): (Optional*) String If provided, we will return whether or not the user has unsubscribed. Example: 'example@braze.com'.
757
+
758
+ Returns:
759
+ dict[str, Any]: Successful response
760
+
761
+ Raises:
762
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
763
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
764
+
765
+ Tags:
766
+ Email Lists & Addresses
767
+ """
768
+ url = f"{self.base_url}/email/unsubscribes"
769
+ query_params = {
770
+ k: v
771
+ for k, v in [
772
+ ("start_date", start_date),
773
+ ("end_date", end_date),
774
+ ("limit", limit),
775
+ ("offset", offset),
776
+ ("sort_direction", sort_direction),
777
+ ("email", email),
778
+ ]
779
+ if v is not None
780
+ }
781
+ response = self._get(url, params=query_params)
782
+ response.raise_for_status()
783
+ if (
784
+ response.status_code == 204
785
+ or not response.content
786
+ or not response.text.strip()
787
+ ):
788
+ return None
789
+ try:
790
+ return response.json()
791
+ except ValueError:
792
+ return None
793
+
794
+ def post_email_status(
795
+ self, email: str | None = None, subscription_state: str | None = None
796
+ ) -> dict[str, Any]:
797
+ """
798
+ Change Email Subscription Status
799
+
800
+ Args:
801
+ email (string): email Example: 'example@braze.com'.
802
+ subscription_state (string): subscription_state Example: 'subscribed'.
803
+
804
+ Returns:
805
+ dict[str, Any]: Successful response
806
+
807
+ Raises:
808
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
809
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
810
+
811
+ Tags:
812
+ Email Lists & Addresses
813
+ """
814
+ request_body_data = None
815
+ request_body_data = {
816
+ "email": email,
817
+ "subscription_state": subscription_state,
818
+ }
819
+ request_body_data = {
820
+ k: v for k, v in request_body_data.items() if v is not None
821
+ }
822
+ url = f"{self.base_url}/email/status"
823
+ query_params = {}
824
+ response = self._post(
825
+ url,
826
+ data=request_body_data,
827
+ params=query_params,
828
+ content_type="application/json",
829
+ )
830
+ response.raise_for_status()
831
+ if (
832
+ response.status_code == 204
833
+ or not response.content
834
+ or not response.text.strip()
835
+ ):
836
+ return None
837
+ try:
838
+ return response.json()
839
+ except ValueError:
840
+ return None
841
+
842
+ def remove_bounced_email(self, email: str | None = None) -> dict[str, Any]:
843
+ """
844
+ Remove Hard Bounced Emails
845
+
846
+ Args:
847
+ email (string): email Example: 'example@braze.com'.
848
+
849
+ Returns:
850
+ dict[str, Any]: Successful response
851
+
852
+ Raises:
853
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
854
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
855
+
856
+ Tags:
857
+ Email Lists & Addresses
858
+ """
859
+ request_body_data = None
860
+ request_body_data = {
861
+ "email": email,
862
+ }
863
+ request_body_data = {
864
+ k: v for k, v in request_body_data.items() if v is not None
865
+ }
866
+ url = f"{self.base_url}/email/bounce/remove"
867
+ query_params = {}
868
+ response = self._post(
869
+ url,
870
+ data=request_body_data,
871
+ params=query_params,
872
+ content_type="application/json",
873
+ )
874
+ response.raise_for_status()
875
+ if (
876
+ response.status_code == 204
877
+ or not response.content
878
+ or not response.text.strip()
879
+ ):
880
+ return None
881
+ try:
882
+ return response.json()
883
+ except ValueError:
884
+ return None
885
+
886
+ def remove_email_spam(self, email: str | None = None) -> dict[str, Any]:
887
+ """
888
+ Remove Email Addresses from Spam List
889
+
890
+ Args:
891
+ email (string): email Example: 'example@braze.com'.
892
+
893
+ Returns:
894
+ dict[str, Any]: Successful response
895
+
896
+ Raises:
897
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
898
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
899
+
900
+ Tags:
901
+ Email Lists & Addresses
902
+ """
903
+ request_body_data = None
904
+ request_body_data = {
905
+ "email": email,
906
+ }
907
+ request_body_data = {
908
+ k: v for k, v in request_body_data.items() if v is not None
909
+ }
910
+ url = f"{self.base_url}/email/spam/remove"
911
+ query_params = {}
912
+ response = self._post(
913
+ url,
914
+ data=request_body_data,
915
+ params=query_params,
916
+ content_type="application/json",
917
+ )
918
+ response.raise_for_status()
919
+ if (
920
+ response.status_code == 204
921
+ or not response.content
922
+ or not response.text.strip()
923
+ ):
924
+ return None
925
+ try:
926
+ return response.json()
927
+ except ValueError:
928
+ return None
929
+
930
+ def add_email_to_blocklist(
931
+ self, email: list[str] | None = None
932
+ ) -> dict[str, Any]:
933
+ """
934
+ Blocklist Email Addresses
935
+
936
+ Args:
937
+ email (array): email Example: ['blocklist_email1', 'blocklist_email2'].
938
+
939
+ Returns:
940
+ dict[str, Any]: Successful response
941
+
942
+ Raises:
943
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
944
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
945
+
946
+ Tags:
947
+ Email Lists & Addresses
948
+ """
949
+ request_body_data = None
950
+ request_body_data = {
951
+ "email": email,
952
+ }
953
+ request_body_data = {
954
+ k: v for k, v in request_body_data.items() if v is not None
955
+ }
956
+ url = f"{self.base_url}/email/blocklist"
957
+ query_params = {}
958
+ response = self._post(
959
+ url,
960
+ data=request_body_data,
961
+ params=query_params,
962
+ content_type="application/json",
963
+ )
964
+ response.raise_for_status()
965
+ if (
966
+ response.status_code == 204
967
+ or not response.content
968
+ or not response.text.strip()
969
+ ):
970
+ return None
971
+ try:
972
+ return response.json()
973
+ except ValueError:
974
+ return None
975
+
976
+ def add_to_blacklist(self, email: list[str] | None = None) -> dict[str, Any]:
977
+ """
978
+ Blacklist Email Addresses
979
+
980
+ Args:
981
+ email (array): email Example: ['blacklist_email1', 'blacklist_email2'].
982
+
983
+ Returns:
984
+ dict[str, Any]: Successful response
985
+
986
+ Raises:
987
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
988
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
989
+
990
+ Tags:
991
+ Email Lists & Addresses
992
+ """
993
+ request_body_data = None
994
+ request_body_data = {
995
+ "email": email,
996
+ }
997
+ request_body_data = {
998
+ k: v for k, v in request_body_data.items() if v is not None
999
+ }
1000
+ url = f"{self.base_url}/email/blacklist"
1001
+ query_params = {}
1002
+ response = self._post(
1003
+ url,
1004
+ data=request_body_data,
1005
+ params=query_params,
1006
+ content_type="application/json",
1007
+ )
1008
+ response.raise_for_status()
1009
+ if (
1010
+ response.status_code == 204
1011
+ or not response.content
1012
+ or not response.text.strip()
1013
+ ):
1014
+ return None
1015
+ try:
1016
+ return response.json()
1017
+ except ValueError:
1018
+ return None
1019
+
1020
+ def get_campaign_data_series(
1021
+ self,
1022
+ campaign_id: str | None = None,
1023
+ length: int | None = None,
1024
+ ending_at: str | None = None,
1025
+ ) -> dict[str, Any]:
1026
+ """
1027
+ Export Campaign Analytics
1028
+
1029
+ Args:
1030
+ campaign_id (string): (Required) String See [campaign API identifier]( The `campaign_id` for API campaigns can be found at **Settings > Setup and Testing > API Keys** and the **Campaign Details** page within your dashboard, or you can use the [List campaigns endpoint]( Example: '{{campaign_identifier}}'.
1031
+ length (integer): (Required) Integer Max number of days before `ending_at` to include in the returned series. Must be between 1 and 100 (inclusive). Example: '7'.
1032
+ ending_at (string): (Optional) Datetime ([ISO 8601]( string) Date on which the data series should end. Defaults to time of the request. Example: '2020-06-28T23:59:59-5:00'.
1033
+
1034
+ Returns:
1035
+ dict[str, Any]: Successful response
1036
+
1037
+ Raises:
1038
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1039
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1040
+
1041
+ Tags:
1042
+ Export > Campaign
1043
+ """
1044
+ url = f"{self.base_url}/campaigns/data_series"
1045
+ query_params = {
1046
+ k: v
1047
+ for k, v in [
1048
+ ("campaign_id", campaign_id),
1049
+ ("length", length),
1050
+ ("ending_at", ending_at),
1051
+ ]
1052
+ if v is not None
1053
+ }
1054
+ response = self._get(url, params=query_params)
1055
+ response.raise_for_status()
1056
+ if (
1057
+ response.status_code == 204
1058
+ or not response.content
1059
+ or not response.text.strip()
1060
+ ):
1061
+ return None
1062
+ try:
1063
+ return response.json()
1064
+ except ValueError:
1065
+ return None
1066
+
1067
+ def get_campaign_details(self, campaign_id: str | None = None) -> dict[str, Any]:
1068
+ """
1069
+ Export Campaign Details
1070
+
1071
+ Args:
1072
+ campaign_id (string): (Required) String See [campaign API identifier]( The `campaign_id` for API campaigns can be found on the **Settings > Setup and Testing > API Keys** and the campaign details page within your dashboard, or you can use the [Campaign List Endpoint]( Example: '{{campaign_identifier}}'.
1073
+
1074
+ Returns:
1075
+ dict[str, Any]: Successful response
1076
+
1077
+ Raises:
1078
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1079
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1080
+
1081
+ Tags:
1082
+ Export > Campaign
1083
+ """
1084
+ url = f"{self.base_url}/campaigns/details"
1085
+ query_params = {
1086
+ k: v for k, v in [("campaign_id", campaign_id)] if v is not None
1087
+ }
1088
+ response = self._get(url, params=query_params)
1089
+ response.raise_for_status()
1090
+ if (
1091
+ response.status_code == 204
1092
+ or not response.content
1093
+ or not response.text.strip()
1094
+ ):
1095
+ return None
1096
+ try:
1097
+ return response.json()
1098
+ except ValueError:
1099
+ return None
1100
+
1101
+ def list_campaigns(
1102
+ self,
1103
+ page: int | None = None,
1104
+ include_archived: bool | None = None,
1105
+ sort_direction: str | None = None,
1106
+ last_edit_time_gt: str | None = None,
1107
+ ) -> dict[str, Any]:
1108
+ """
1109
+ Export Campaign List
1110
+
1111
+ Args:
1112
+ page (integer): (Optional) Integer The page of campaigns to return, defaults to 0 (returns the first set of up to 100).
1113
+ include_archived (boolean): (Optional) Boolean Whether or not to include archived campaigns, defaults to false.
1114
+ sort_direction (string): (Optional) String - Sort creation time from newest to oldest: pass in the value `desc`.
1115
+ - Sort creation time from oldest to newest: pass in the value `asc`. If `sort_direction` is not included, the default order is oldest to newest. Example: 'desc'.
1116
+ last_edit_time_gt (string): (Optional) Datetime ([ISO 8601]( string) Filters the results and only returns campaigns that were edited greater than the time provided till now. Format is `yyyy-MM-DDTHH:mm:ss`. Example: '2020-06-28T23:59:59-5:00'.
1117
+
1118
+ Returns:
1119
+ dict[str, Any]: Successful response
1120
+
1121
+ Raises:
1122
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1123
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1124
+
1125
+ Tags:
1126
+ Export > Campaign
1127
+ """
1128
+ url = f"{self.base_url}/campaigns/list"
1129
+ query_params = {
1130
+ k: v
1131
+ for k, v in [
1132
+ ("page", page),
1133
+ ("include_archived", include_archived),
1134
+ ("sort_direction", sort_direction),
1135
+ ("last_edit.time[gt]", last_edit_time_gt),
1136
+ ]
1137
+ if v is not None
1138
+ }
1139
+ response = self._get(url, params=query_params)
1140
+ response.raise_for_status()
1141
+ if (
1142
+ response.status_code == 204
1143
+ or not response.content
1144
+ or not response.text.strip()
1145
+ ):
1146
+ return None
1147
+ try:
1148
+ return response.json()
1149
+ except ValueError:
1150
+ return None
1151
+
1152
+ def get_send_data_series(
1153
+ self,
1154
+ campaign_id: str | None = None,
1155
+ send_id: str | None = None,
1156
+ length: int | None = None,
1157
+ ending_at: str | None = None,
1158
+ ) -> dict[str, Any]:
1159
+ """
1160
+ Export Send Analytics
1161
+
1162
+ Args:
1163
+ campaign_id (string): (Required) String See [Campaign API identifier]( Example: '{{campaign_identifier}}'.
1164
+ send_id (string): (Required) String See [Send API identifier]( Example: '{{send_identifier}}'.
1165
+ length (integer): (Required) Integer Max number of days before `ending_at` to include in the returned series. Must be between 1 and 100 (inclusive). Example: '30'.
1166
+ ending_at (string): (Optional) Datetime ([ISO 8601]( string) Date on which the data series should end. Defaults to time of the request. Example: '2014-12-10T23:59:59-05:00'.
1167
+
1168
+ Returns:
1169
+ dict[str, Any]: Successful response
1170
+
1171
+ Raises:
1172
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1173
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1174
+
1175
+ Tags:
1176
+ Export > Campaign
1177
+ """
1178
+ url = f"{self.base_url}/sends/data_series"
1179
+ query_params = {
1180
+ k: v
1181
+ for k, v in [
1182
+ ("campaign_id", campaign_id),
1183
+ ("send_id", send_id),
1184
+ ("length", length),
1185
+ ("ending_at", ending_at),
1186
+ ]
1187
+ if v is not None
1188
+ }
1189
+ response = self._get(url, params=query_params)
1190
+ response.raise_for_status()
1191
+ if (
1192
+ response.status_code == 204
1193
+ or not response.content
1194
+ or not response.text.strip()
1195
+ ):
1196
+ return None
1197
+ try:
1198
+ return response.json()
1199
+ except ValueError:
1200
+ return None
1201
+
1202
+ def get_canvas_data_series(
1203
+ self,
1204
+ canvas_id: str | None = None,
1205
+ ending_at: str | None = None,
1206
+ starting_at: str | None = None,
1207
+ length: int | None = None,
1208
+ include_variant_breakdown: bool | None = None,
1209
+ include_step_breakdown: bool | None = None,
1210
+ include_deleted_step_data: bool | None = None,
1211
+ ) -> dict[str, Any]:
1212
+ """
1213
+ Export Canvas Data Series Analytics
1214
+
1215
+ Args:
1216
+ canvas_id (string): (Required) String See [Canvas API Identifier]( Example: '{{canvas_id}}'.
1217
+ ending_at (string): (Required) Datetime ([ISO 8601]( string) Date on which the data export should end. Defaults to time of the request. Example: '2018-05-30T23:59:59-5:00'.
1218
+ starting_at (string): (Optional*) Datetime ([ISO 8601]( string) Date on which the data export should begin. *Either `length` or `starting_at` is required. Example: '2018-05-28T23:59:59-5:00'.
1219
+ length (integer): (Optional*) String Maximum number of days before `ending_at` to include in the returned series. Must be between 1 and 14 (inclusive). *Either `length` or `starting_at` is required. Example: '10'.
1220
+ include_variant_breakdown (boolean): (Optional) Boolean Whether or not to include variant stats (defaults to false). Example: 'True'.
1221
+ include_step_breakdown (boolean): (Optional) Boolean Whether or not to include step stats (defaults to false). Example: 'True'.
1222
+ include_deleted_step_data (boolean): (Optional) Boolean Whether or not to include step stats for deleted steps (defaults to false). Example: 'True'.
1223
+
1224
+ Returns:
1225
+ dict[str, Any]: Successful response
1226
+
1227
+ Raises:
1228
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1229
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1230
+
1231
+ Tags:
1232
+ Export > Canvas
1233
+ """
1234
+ url = f"{self.base_url}/canvas/data_series"
1235
+ query_params = {
1236
+ k: v
1237
+ for k, v in [
1238
+ ("canvas_id", canvas_id),
1239
+ ("ending_at", ending_at),
1240
+ ("starting_at", starting_at),
1241
+ ("length", length),
1242
+ ("include_variant_breakdown", include_variant_breakdown),
1243
+ ("include_step_breakdown", include_step_breakdown),
1244
+ ("include_deleted_step_data", include_deleted_step_data),
1245
+ ]
1246
+ if v is not None
1247
+ }
1248
+ response = self._get(url, params=query_params)
1249
+ response.raise_for_status()
1250
+ if (
1251
+ response.status_code == 204
1252
+ or not response.content
1253
+ or not response.text.strip()
1254
+ ):
1255
+ return None
1256
+ try:
1257
+ return response.json()
1258
+ except ValueError:
1259
+ return None
1260
+
1261
+ def fetch_canvas_data_summary(
1262
+ self,
1263
+ canvas_id: str | None = None,
1264
+ ending_at: str | None = None,
1265
+ starting_at: str | None = None,
1266
+ length: int | None = None,
1267
+ include_variant_breakdown: bool | None = None,
1268
+ include_step_breakdown: bool | None = None,
1269
+ include_deleted_step_data: bool | None = None,
1270
+ ) -> dict[str, Any]:
1271
+ """
1272
+ Export Canvas Data Analytics Summary
1273
+
1274
+ Args:
1275
+ canvas_id (string): (Required) String See [Canvas API identifier]( Example: '{{canvas_id}}'.
1276
+ ending_at (string): (Required) Datetime ([ISO 8601]( string)
1277
+ Date on which the data export should end. Defaults to time of the request Example: '2018-05-30T23:59:59-5:00'.
1278
+ starting_at (string): (Optional*) Datetime ([ISO 8601]( string) Date on which the data export should begin. *Either `length` or `starting_at` is required. Example: '2018-05-28T23:59:59-5:00'.
1279
+ length (integer): (Optional*) Integer Max number of days before `ending_at` to include in the returned series. Must be between 1 and 14 (inclusive). *Either `length` or `starting_at` is required. Example: '5'.
1280
+ include_variant_breakdown (boolean): (Optional) Boolean Whether or not to include variant stats (defaults to false). Example: 'True'.
1281
+ include_step_breakdown (boolean): (Optional) Boolean Whether or not to include step stats (defaults to false). Example: 'True'.
1282
+ include_deleted_step_data (boolean): (Optional) Boolean Whether or not to include step stats for deleted steps (defaults to false). Example: 'True'.
1283
+
1284
+ Returns:
1285
+ dict[str, Any]: Successful response
1286
+
1287
+ Raises:
1288
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1289
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1290
+
1291
+ Tags:
1292
+ Export > Canvas
1293
+ """
1294
+ url = f"{self.base_url}/canvas/data_summary"
1295
+ query_params = {
1296
+ k: v
1297
+ for k, v in [
1298
+ ("canvas_id", canvas_id),
1299
+ ("ending_at", ending_at),
1300
+ ("starting_at", starting_at),
1301
+ ("length", length),
1302
+ ("include_variant_breakdown", include_variant_breakdown),
1303
+ ("include_step_breakdown", include_step_breakdown),
1304
+ ("include_deleted_step_data", include_deleted_step_data),
1305
+ ]
1306
+ if v is not None
1307
+ }
1308
+ response = self._get(url, params=query_params)
1309
+ response.raise_for_status()
1310
+ if (
1311
+ response.status_code == 204
1312
+ or not response.content
1313
+ or not response.text.strip()
1314
+ ):
1315
+ return None
1316
+ try:
1317
+ return response.json()
1318
+ except ValueError:
1319
+ return None
1320
+
1321
+ def get_canvas_details(self, canvas_id: str | None = None) -> dict[str, Any]:
1322
+ """
1323
+ Export Canvas Details
1324
+
1325
+ Args:
1326
+ canvas_id (string): (Required) String See [Canvas API Identifier]( Example: '{{canvas_identifier}}'.
1327
+
1328
+ Returns:
1329
+ dict[str, Any]: Successful response
1330
+
1331
+ Raises:
1332
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1333
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1334
+
1335
+ Tags:
1336
+ Export > Canvas
1337
+ """
1338
+ url = f"{self.base_url}/canvas/details"
1339
+ query_params = {k: v for k, v in [("canvas_id", canvas_id)] if v is not None}
1340
+ response = self._get(url, params=query_params)
1341
+ response.raise_for_status()
1342
+ if (
1343
+ response.status_code == 204
1344
+ or not response.content
1345
+ or not response.text.strip()
1346
+ ):
1347
+ return None
1348
+ try:
1349
+ return response.json()
1350
+ except ValueError:
1351
+ return None
1352
+
1353
+ def list_canvas(
1354
+ self,
1355
+ page: int | None = None,
1356
+ include_archived: bool | None = None,
1357
+ sort_direction: str | None = None,
1358
+ last_edit_time_gt: str | None = None,
1359
+ ) -> dict[str, Any]:
1360
+ """
1361
+ Export Canvas List
1362
+
1363
+ Args:
1364
+ page (integer): (Optional) Integer The page of Canvases to return, defaults to `0` (returns the first set of up to 100). Example: '1'.
1365
+ include_archived (boolean): (Optional) Boolean Whether or not to include archived Canvases, defaults to `false`.
1366
+ sort_direction (string): (Optional) String - Sort creation time from newest to oldest: pass in the value `desc`.
1367
+ - Sort creation time from oldest to newest: pass in the value `asc`. If `sort_direction` is not included, the default order is oldest to newest. Example: 'desc'.
1368
+ last_edit_time_gt (string): (Optional) Datetime ([ISO 8601]( string) Filters the results and only returns Canvases that were edited greater than the time provided till now. Format is `yyyy-MM-DDTHH:mm:ss`. Example: '2020-06-28T23:59:59-5:00'.
1369
+
1370
+ Returns:
1371
+ dict[str, Any]: Successful response
1372
+
1373
+ Raises:
1374
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1375
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1376
+
1377
+ Tags:
1378
+ Export > Canvas
1379
+ """
1380
+ url = f"{self.base_url}/canvas/list"
1381
+ query_params = {
1382
+ k: v
1383
+ for k, v in [
1384
+ ("page", page),
1385
+ ("include_archived", include_archived),
1386
+ ("sort_direction", sort_direction),
1387
+ ("last_edit.time[gt]", last_edit_time_gt),
1388
+ ]
1389
+ if v is not None
1390
+ }
1391
+ response = self._get(url, params=query_params)
1392
+ response.raise_for_status()
1393
+ if (
1394
+ response.status_code == 204
1395
+ or not response.content
1396
+ or not response.text.strip()
1397
+ ):
1398
+ return None
1399
+ try:
1400
+ return response.json()
1401
+ except ValueError:
1402
+ return None
1403
+
1404
+ def list_events(self, page: int | None = None) -> dict[str, Any]:
1405
+ """
1406
+ Export Custom Events List
1407
+
1408
+ Args:
1409
+ page (integer): (Optional) Integer The page of event names to return, defaults to 0 (returns the first set of up to 250). Example: '3'.
1410
+
1411
+ Returns:
1412
+ dict[str, Any]: Successful response
1413
+
1414
+ Raises:
1415
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1416
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1417
+
1418
+ Tags:
1419
+ Export > Custom Events, important
1420
+ """
1421
+ url = f"{self.base_url}/events/list"
1422
+ query_params = {k: v for k, v in [("page", page)] if v is not None}
1423
+ response = self._get(url, params=query_params)
1424
+ response.raise_for_status()
1425
+ if (
1426
+ response.status_code == 204
1427
+ or not response.content
1428
+ or not response.text.strip()
1429
+ ):
1430
+ return None
1431
+ try:
1432
+ return response.json()
1433
+ except ValueError:
1434
+ return None
1435
+
1436
+ def fetch_event_series_data(
1437
+ self,
1438
+ event: str | None = None,
1439
+ length: int | None = None,
1440
+ unit: str | None = None,
1441
+ ending_at: str | None = None,
1442
+ app_id: str | None = None,
1443
+ segment_id: str | None = None,
1444
+ ) -> dict[str, Any]:
1445
+ """
1446
+ Export Custom Events Analytics
1447
+
1448
+ Args:
1449
+ event (string): (Required) String The name of the custom event for which to return analytics. Example: 'event_name'.
1450
+ length (integer): (Required) Integer Maximum number of units (days or hours) before `ending_at` to include in the returned series. Must be between 1 and 100 (inclusive). Example: '24'.
1451
+ unit (string): (Optional) String Unit of time between data points - can be `day` or `hour`, defaults to `day`. Example: 'hour'.
1452
+ ending_at (string): (Optional) Datetime ([ISO 8601]( string) Date on which the data series should end. Defaults to time of the request. Example: '2014-12-10T23:59:59-05:00'.
1453
+ app_id (string): (Optional) String App API identifier retrieved from **Settings > Setup and Testing > API Keys** to limit analytics to a specific app. Example: '{{app_identifier}}'.
1454
+ segment_id (string): (Optional) String See [Segment API identifier]( Segment ID indicating the analytics-enabled segment for which event analytics should be returned. Example: '{{segment_identifier}}'.
1455
+
1456
+ Returns:
1457
+ dict[str, Any]: Successful response
1458
+
1459
+ Raises:
1460
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1461
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1462
+
1463
+ Tags:
1464
+ Export > Custom Events
1465
+ """
1466
+ url = f"{self.base_url}/events/data_series"
1467
+ query_params = {
1468
+ k: v
1469
+ for k, v in [
1470
+ ("event", event),
1471
+ ("length", length),
1472
+ ("unit", unit),
1473
+ ("ending_at", ending_at),
1474
+ ("app_id", app_id),
1475
+ ("segment_id", segment_id),
1476
+ ]
1477
+ if v is not None
1478
+ }
1479
+ response = self._get(url, params=query_params)
1480
+ response.raise_for_status()
1481
+ if (
1482
+ response.status_code == 204
1483
+ or not response.content
1484
+ or not response.text.strip()
1485
+ ):
1486
+ return None
1487
+ try:
1488
+ return response.json()
1489
+ except ValueError:
1490
+ return None
1491
+
1492
+ def list_new_user_kpi_series(
1493
+ self,
1494
+ length: int | None = None,
1495
+ ending_at: str | None = None,
1496
+ app_id: str | None = None,
1497
+ ) -> dict[str, Any]:
1498
+ """
1499
+ Export Daily New Users by Date
1500
+
1501
+ Args:
1502
+ length (integer): (Required) Integer Maximum number of days before `ending_at` to include in the returned series. Must be between 1 and 100 (inclusive). Example: '14'.
1503
+ ending_at (string): (Optional) Datetime ([ISO 8601]( string) Date on which the data series should end. Defaults to time of the request. Example: '2018-06-28T23:59:59-5:00'.
1504
+ app_id (string): (Optional) String App API identifier retrieved from **Settings > Setup and Testing > API Keys**. If excluded, results for all apps in workspace will be returned. Example: '{{app_identifier}}'.
1505
+
1506
+ Returns:
1507
+ dict[str, Any]: Successful response
1508
+
1509
+ Raises:
1510
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1511
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1512
+
1513
+ Tags:
1514
+ Export > KPI
1515
+ """
1516
+ url = f"{self.base_url}/kpi/new_users/data_series"
1517
+ query_params = {
1518
+ k: v
1519
+ for k, v in [
1520
+ ("length", length),
1521
+ ("ending_at", ending_at),
1522
+ ("app_id", app_id),
1523
+ ]
1524
+ if v is not None
1525
+ }
1526
+ response = self._get(url, params=query_params)
1527
+ response.raise_for_status()
1528
+ if (
1529
+ response.status_code == 204
1530
+ or not response.content
1531
+ or not response.text.strip()
1532
+ ):
1533
+ return None
1534
+ try:
1535
+ return response.json()
1536
+ except ValueError:
1537
+ return None
1538
+
1539
+ def get_daily_active_users_series(
1540
+ self,
1541
+ length: int | None = None,
1542
+ ending_at: str | None = None,
1543
+ app_id: str | None = None,
1544
+ ) -> dict[str, Any]:
1545
+ """
1546
+ Export Daily Active Users by Date
1547
+
1548
+ Args:
1549
+ length (integer): (Required) Integer Maximum number of days before `ending_at` to include in the returned series. Must be between 1 and 100 (inclusive). Example: '10'.
1550
+ ending_at (string): (Optional) Datetime ([ISO 8601]( string)
1551
+ Date on which the data series should end. Defaults to time of the request. Example: '2018-06-28T23:59:59-5:00'.
1552
+ app_id (string): (Optional) String App API identifier retrieved from **Settings > Setup and Testing > API Keys**. If excluded, results for all apps in workspace will be returned. Example: '{{app_identifier}}'.
1553
+
1554
+ Returns:
1555
+ dict[str, Any]: Successful response
1556
+
1557
+ Raises:
1558
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1559
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1560
+
1561
+ Tags:
1562
+ Export > KPI
1563
+ """
1564
+ url = f"{self.base_url}/kpi/dau/data_series"
1565
+ query_params = {
1566
+ k: v
1567
+ for k, v in [
1568
+ ("length", length),
1569
+ ("ending_at", ending_at),
1570
+ ("app_id", app_id),
1571
+ ]
1572
+ if v is not None
1573
+ }
1574
+ response = self._get(url, params=query_params)
1575
+ response.raise_for_status()
1576
+ if (
1577
+ response.status_code == 204
1578
+ or not response.content
1579
+ or not response.text.strip()
1580
+ ):
1581
+ return None
1582
+ try:
1583
+ return response.json()
1584
+ except ValueError:
1585
+ return None
1586
+
1587
+ def get_kpimau_data_series(
1588
+ self,
1589
+ length: int | None = None,
1590
+ ending_at: str | None = None,
1591
+ app_id: str | None = None,
1592
+ ) -> dict[str, Any]:
1593
+ """
1594
+ Export Monthly Active Users for Last 30 Days
1595
+
1596
+ Args:
1597
+ length (integer): (Required) Integer Maximum number of days before `ending_at` to include in the returned series. Must be between 1 and 100 (inclusive). Example: '7'.
1598
+ ending_at (string): (Optional) Datetime ([ISO 8601]( string) Date on which the data series should end. Defaults to time of the request. Example: '2018-06-28T23:59:59-05:00'.
1599
+ app_id (string): (Optional) String App API identifier retrieved from **Settings > Setup and Testing > API Keys**. If excluded, results for all apps in workspace will be returned. Example: '{{app_identifier}}'.
1600
+
1601
+ Returns:
1602
+ dict[str, Any]: Successful response
1603
+
1604
+ Raises:
1605
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1606
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1607
+
1608
+ Tags:
1609
+ Export > KPI
1610
+ """
1611
+ url = f"{self.base_url}/kpi/mau/data_series"
1612
+ query_params = {
1613
+ k: v
1614
+ for k, v in [
1615
+ ("length", length),
1616
+ ("ending_at", ending_at),
1617
+ ("app_id", app_id),
1618
+ ]
1619
+ if v is not None
1620
+ }
1621
+ response = self._get(url, params=query_params)
1622
+ response.raise_for_status()
1623
+ if (
1624
+ response.status_code == 204
1625
+ or not response.content
1626
+ or not response.text.strip()
1627
+ ):
1628
+ return None
1629
+ try:
1630
+ return response.json()
1631
+ except ValueError:
1632
+ return None
1633
+
1634
+ def get_kpi_uninstalls_data_series(
1635
+ self,
1636
+ length: int | None = None,
1637
+ ending_at: str | None = None,
1638
+ app_id: str | None = None,
1639
+ ) -> dict[str, Any]:
1640
+ """
1641
+ Export KPIs for Daily App Uninstalls by Date
1642
+
1643
+ Args:
1644
+ length (integer): (Required) Integer Maximum number of days before `ending_at` to include in the returned series. Must be between 1 and 100 (inclusive). Example: '14'.
1645
+ ending_at (string): (Optional) Datetime ([ISO 8601]( string) Date on which the data series should end. Defaults to time of the request. Example: '2018-06-28T23:59:59-5:00'.
1646
+ app_id (string): (Optional) String App API identifier retrieved from **Settings > Setup and Testing > API Keys**. If excluded, results for all apps in workspace will be returned. Example: '{{app_identifier}}'.
1647
+
1648
+ Returns:
1649
+ dict[str, Any]: Successful response
1650
+
1651
+ Raises:
1652
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1653
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1654
+
1655
+ Tags:
1656
+ Export > KPI
1657
+ """
1658
+ url = f"{self.base_url}/kpi/uninstalls/data_series"
1659
+ query_params = {
1660
+ k: v
1661
+ for k, v in [
1662
+ ("length", length),
1663
+ ("ending_at", ending_at),
1664
+ ("app_id", app_id),
1665
+ ]
1666
+ if v is not None
1667
+ }
1668
+ response = self._get(url, params=query_params)
1669
+ response.raise_for_status()
1670
+ if (
1671
+ response.status_code == 204
1672
+ or not response.content
1673
+ or not response.text.strip()
1674
+ ):
1675
+ return None
1676
+ try:
1677
+ return response.json()
1678
+ except ValueError:
1679
+ return None
1680
+
1681
+ def get_feed_data_series(
1682
+ self,
1683
+ card_id: str | None = None,
1684
+ length: int | None = None,
1685
+ unit: str | None = None,
1686
+ ending_at: str | None = None,
1687
+ ) -> dict[str, Any]:
1688
+ """
1689
+ Export News Feed Card Analytics
1690
+
1691
+ Args:
1692
+ card_id (string): (Required) String See [Card API identifier]( The `card_id` for a given card can be found in the **Settings > Setup and Testing > API Keys** page and on the card details page within your dashboard, or you can use the [News Feed List Endpoint]( Example: '{{card_identifier}}'.
1693
+ length (integer): (Required) Integer Max number of units (days or hours) before `ending_at` to include in the returned series. Must be between 1 and 100 (inclusive). Example: '14'.
1694
+ unit (string): (Optional) String Unit of time between data points. Can be `day` or `hour`, defaults to `day`. Example: 'day'.
1695
+ ending_at (string): (Optional) Datetime ([ISO 8601]( string) Date on which the data series should end. Defaults to time of the request. Example: '2018-06-28T23:59:59-5:00'.
1696
+
1697
+ Returns:
1698
+ dict[str, Any]: Successful response
1699
+
1700
+ Raises:
1701
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1702
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1703
+
1704
+ Tags:
1705
+ Export > News Feed
1706
+ """
1707
+ url = f"{self.base_url}/feed/data_series"
1708
+ query_params = {
1709
+ k: v
1710
+ for k, v in [
1711
+ ("card_id", card_id),
1712
+ ("length", length),
1713
+ ("unit", unit),
1714
+ ("ending_at", ending_at),
1715
+ ]
1716
+ if v is not None
1717
+ }
1718
+ response = self._get(url, params=query_params)
1719
+ response.raise_for_status()
1720
+ if (
1721
+ response.status_code == 204
1722
+ or not response.content
1723
+ or not response.text.strip()
1724
+ ):
1725
+ return None
1726
+ try:
1727
+ return response.json()
1728
+ except ValueError:
1729
+ return None
1730
+
1731
+ def get_feed_details(self, card_id: str | None = None) -> dict[str, Any]:
1732
+ """
1733
+ Export News Feed Cards Details
1734
+
1735
+ Args:
1736
+ card_id (string): (Required) String See [Card API identifier]( The `card_id` for a given card can be found in the **Settings > Setup and Testing > API Keys** page and on the card details page within your dashboard, or you can use the [News Feed List Endpoint]( Example: '{{card_identifier}}'.
1737
+
1738
+ Returns:
1739
+ dict[str, Any]: Successful response
1740
+
1741
+ Raises:
1742
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1743
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1744
+
1745
+ Tags:
1746
+ Export > News Feed
1747
+ """
1748
+ url = f"{self.base_url}/feed/details"
1749
+ query_params = {k: v for k, v in [("card_id", card_id)] if v is not None}
1750
+ response = self._get(url, params=query_params)
1751
+ response.raise_for_status()
1752
+ if (
1753
+ response.status_code == 204
1754
+ or not response.content
1755
+ or not response.text.strip()
1756
+ ):
1757
+ return None
1758
+ try:
1759
+ return response.json()
1760
+ except ValueError:
1761
+ return None
1762
+
1763
+ def list_feed(
1764
+ self,
1765
+ page: int | None = None,
1766
+ include_archived: bool | None = None,
1767
+ sort_direction: str | None = None,
1768
+ ) -> dict[str, Any]:
1769
+ """
1770
+ Export News Feed Cards List
1771
+
1772
+ Args:
1773
+ page (integer): (Optional) Integer The page of cards to return, defaults to 0 (returns the first set of up to 100). Example: '1'.
1774
+ include_archived (boolean): (Optional) Boolean Whether or not to include archived cards, defaults to false. Example: 'True'.
1775
+ sort_direction (string): (Optional) String - Sort creation time from newest to oldest: pass in the value `desc`.
1776
+ - Sort creation time from oldest to newest: pass in the value `asc`. If `sort_direction` is not included, the default order is oldest to newest. Example: 'desc'.
1777
+
1778
+ Returns:
1779
+ dict[str, Any]: Successful response
1780
+
1781
+ Raises:
1782
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1783
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1784
+
1785
+ Tags:
1786
+ Export > News Feed
1787
+ """
1788
+ url = f"{self.base_url}/feed/list"
1789
+ query_params = {
1790
+ k: v
1791
+ for k, v in [
1792
+ ("page", page),
1793
+ ("include_archived", include_archived),
1794
+ ("sort_direction", sort_direction),
1795
+ ]
1796
+ if v is not None
1797
+ }
1798
+ response = self._get(url, params=query_params)
1799
+ response.raise_for_status()
1800
+ if (
1801
+ response.status_code == 204
1802
+ or not response.content
1803
+ or not response.text.strip()
1804
+ ):
1805
+ return None
1806
+ try:
1807
+ return response.json()
1808
+ except ValueError:
1809
+ return None
1810
+
1811
+ def list_products(self, page: int | None = None) -> dict[str, Any]:
1812
+ """
1813
+ Export Product IDs
1814
+
1815
+ Args:
1816
+ page (integer): (Optional) Integer The page of your product list that you would like to view. Example: '1'.
1817
+
1818
+ Returns:
1819
+ dict[str, Any]: Successful response
1820
+
1821
+ Raises:
1822
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1823
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1824
+
1825
+ Tags:
1826
+ Export > Purchases
1827
+ """
1828
+ url = f"{self.base_url}/purchases/product_list"
1829
+ query_params = {k: v for k, v in [("page", page)] if v is not None}
1830
+ response = self._get(url, params=query_params)
1831
+ response.raise_for_status()
1832
+ if (
1833
+ response.status_code == 204
1834
+ or not response.content
1835
+ or not response.text.strip()
1836
+ ):
1837
+ return None
1838
+ try:
1839
+ return response.json()
1840
+ except ValueError:
1841
+ return None
1842
+
1843
+ def get_purchase_quantity_series(
1844
+ self,
1845
+ ending_at: str | None = None,
1846
+ length: int | None = None,
1847
+ unit: int | None = None,
1848
+ app_id: str | None = None,
1849
+ product: str | None = None,
1850
+ ) -> dict[str, Any]:
1851
+ """
1852
+ Export Number of Purchases
1853
+
1854
+ Args:
1855
+ ending_at (string): (Optional) Datetime (ISO 8601 string)
1856
+ Date on which the data series should end. Defaults to time of the request. Example: '2018-06-28T23:59:59-5:00'.
1857
+ length (integer): (Required) Integer
1858
+ Maximum number of days before ending_at to include in the returned series. Must be between 1 and 100 (inclusive). Example: '100'.
1859
+ unit (integer): (Optional) String
1860
+ Unit of time between data points. Can be `day` or `hour`, defaults to `day`. Example: '14'.
1861
+ app_id (string): (Optional) String
1862
+ App API identifier retrieved from the Settings > Setup and Testing > API Keys to limit analytics to a specific app. Example: '{{app_identifier}}'.
1863
+ product (string): (Optional) String
1864
+ Name of product to filter response by. If excluded, results for all apps will be returned. Example: 'name'.
1865
+
1866
+ Returns:
1867
+ dict[str, Any]: Successful response
1868
+
1869
+ Raises:
1870
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1871
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1872
+
1873
+ Tags:
1874
+ Export > Purchases
1875
+ """
1876
+ url = f"{self.base_url}/purchases/quantity_series"
1877
+ query_params = {
1878
+ k: v
1879
+ for k, v in [
1880
+ ("ending_at", ending_at),
1881
+ ("length", length),
1882
+ ("unit", unit),
1883
+ ("app_id", app_id),
1884
+ ("product", product),
1885
+ ]
1886
+ if v is not None
1887
+ }
1888
+ response = self._get(url, params=query_params)
1889
+ response.raise_for_status()
1890
+ if (
1891
+ response.status_code == 204
1892
+ or not response.content
1893
+ or not response.text.strip()
1894
+ ):
1895
+ return None
1896
+ try:
1897
+ return response.json()
1898
+ except ValueError:
1899
+ return None
1900
+
1901
+ def get_purchases_revenue_series(
1902
+ self,
1903
+ ending_at: str | None = None,
1904
+ length: int | None = None,
1905
+ unit: int | None = None,
1906
+ app_id: str | None = None,
1907
+ product: str | None = None,
1908
+ ) -> dict[str, Any]:
1909
+ """
1910
+ Export Revenue Data by Time
1911
+
1912
+ Args:
1913
+ ending_at (string): (Optional) Datetime (ISO 8601 string)
1914
+ Date on which the data series should end. Defaults to time of the request. Example: '2018-06-28T23:59:59-5:00'.
1915
+ length (integer): (Required) Integer
1916
+ Maximum number of days before ending_at to include in the returned series. Must be between 1 and 100 (inclusive). Example: '100'.
1917
+ unit (integer): (Optional) String
1918
+ Unit of time between data points. Can be `day` or `hour`, defaults to `day`. Example: '14'.
1919
+ app_id (string): (Optional) String
1920
+ App API identifier retrieved from the Settings > Setup and Testing > API Keys to limit analytics to a specific app. Example: '{{app_identifier}}'.
1921
+ product (string): (Optional) String
1922
+ Name of product to filter response by. If excluded, results for all apps will be returned. Example: 'name'.
1923
+
1924
+ Returns:
1925
+ dict[str, Any]: Successful response
1926
+
1927
+ Raises:
1928
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1929
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1930
+
1931
+ Tags:
1932
+ Export > Purchases
1933
+ """
1934
+ url = f"{self.base_url}/purchases/revenue_series"
1935
+ query_params = {
1936
+ k: v
1937
+ for k, v in [
1938
+ ("ending_at", ending_at),
1939
+ ("length", length),
1940
+ ("unit", unit),
1941
+ ("app_id", app_id),
1942
+ ("product", product),
1943
+ ]
1944
+ if v is not None
1945
+ }
1946
+ response = self._get(url, params=query_params)
1947
+ response.raise_for_status()
1948
+ if (
1949
+ response.status_code == 204
1950
+ or not response.content
1951
+ or not response.text.strip()
1952
+ ):
1953
+ return None
1954
+ try:
1955
+ return response.json()
1956
+ except ValueError:
1957
+ return None
1958
+
1959
+ def list_segments(
1960
+ self, page: int | None = None, sort_direction: str | None = None
1961
+ ) -> dict[str, Any]:
1962
+ """
1963
+ Export Segment List
1964
+
1965
+ Args:
1966
+ page (integer): (Optional) Integer The page of segments to return, defaults to 0 (returns the first set of up to 100). Example: '1'.
1967
+ sort_direction (string): (Optional) String - Sort creation time from newest to oldest: pass in the value `desc`.
1968
+ - Sort creation time from oldest to newest: pass in the value `asc`. If `sort_direction` is not included, the default order is oldest to newest. Example: 'desc'.
1969
+
1970
+ Returns:
1971
+ dict[str, Any]: Successful response
1972
+
1973
+ Raises:
1974
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
1975
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
1976
+
1977
+ Tags:
1978
+ Export > Segment
1979
+ """
1980
+ url = f"{self.base_url}/segments/list"
1981
+ query_params = {
1982
+ k: v
1983
+ for k, v in [("page", page), ("sort_direction", sort_direction)]
1984
+ if v is not None
1985
+ }
1986
+ response = self._get(url, params=query_params)
1987
+ response.raise_for_status()
1988
+ if (
1989
+ response.status_code == 204
1990
+ or not response.content
1991
+ or not response.text.strip()
1992
+ ):
1993
+ return None
1994
+ try:
1995
+ return response.json()
1996
+ except ValueError:
1997
+ return None
1998
+
1999
+ def get_segments_data_series(
2000
+ self,
2001
+ segment_id: str | None = None,
2002
+ length: int | None = None,
2003
+ ending_at: str | None = None,
2004
+ ) -> dict[str, Any]:
2005
+ """
2006
+ Export Segment Analytics
2007
+
2008
+ Args:
2009
+ segment_id (string): (Required) String See [Segment API identifier]( The `segment_id` for a given segment can be found in your **Settings > Setup and Testing > API Keys.** within your Braze account or you can use the [Segment List Endpoint]( Example: '{{segment_identifier}}'.
2010
+ length (integer): (Required) Integer Max number of days before `ending_at` to include in the returned series - must be between 1 and 100 (inclusive). Example: '14'.
2011
+ ending_at (string): (Optional) Datetime ([ISO 8601]( string) Date on which the data series should end. Defaults to time of the request. Example: '2018-06-27T23:59:59-5:00'.
2012
+
2013
+ Returns:
2014
+ dict[str, Any]: Successful response
2015
+
2016
+ Raises:
2017
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2018
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2019
+
2020
+ Tags:
2021
+ Export > Segment
2022
+ """
2023
+ url = f"{self.base_url}/segments/data_series"
2024
+ query_params = {
2025
+ k: v
2026
+ for k, v in [
2027
+ ("segment_id", segment_id),
2028
+ ("length", length),
2029
+ ("ending_at", ending_at),
2030
+ ]
2031
+ if v is not None
2032
+ }
2033
+ response = self._get(url, params=query_params)
2034
+ response.raise_for_status()
2035
+ if (
2036
+ response.status_code == 204
2037
+ or not response.content
2038
+ or not response.text.strip()
2039
+ ):
2040
+ return None
2041
+ try:
2042
+ return response.json()
2043
+ except ValueError:
2044
+ return None
2045
+
2046
+ def get_segment_details(self, segment_id: str | None = None) -> dict[str, Any]:
2047
+ """
2048
+ Export Segment Details
2049
+
2050
+ Args:
2051
+ segment_id (string): (Required) String See [Segment API identifier]( The `segment_id` for a given segment can be found in your **Settings > Setup and Testing > API Keys** within your Braze account or you can use the [Segment List Endpoint]( Example: '{{segment_identifier}}'.
2052
+
2053
+ Returns:
2054
+ dict[str, Any]: Successful response
2055
+
2056
+ Raises:
2057
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2058
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2059
+
2060
+ Tags:
2061
+ Export > Segment
2062
+ """
2063
+ url = f"{self.base_url}/segments/details"
2064
+ query_params = {k: v for k, v in [("segment_id", segment_id)] if v is not None}
2065
+ response = self._get(url, params=query_params)
2066
+ response.raise_for_status()
2067
+ if (
2068
+ response.status_code == 204
2069
+ or not response.content
2070
+ or not response.text.strip()
2071
+ ):
2072
+ return None
2073
+ try:
2074
+ return response.json()
2075
+ except ValueError:
2076
+ return None
2077
+
2078
+ def get_sessions_data_series(
2079
+ self,
2080
+ length: int | None = None,
2081
+ unit: str | None = None,
2082
+ ending_at: str | None = None,
2083
+ app_id: str | None = None,
2084
+ segment_id: str | None = None,
2085
+ ) -> dict[str, Any]:
2086
+ """
2087
+ Export App Sessions by Time
2088
+
2089
+ Args:
2090
+ length (integer): (Required) Integer Max number of days before `ending_at` to include in the returned series - must be between 1 and 100 (inclusive). Example: '14'.
2091
+ unit (string): (Optional) String Unit of time between data points. Can be `day` or `hour`, defaults to `day`. Example: 'day'.
2092
+ ending_at (string): (Optional) Datetime (ISO 8601 string) Date on which the data series should end. Defaults to time of the request. Example: '2018-06-28T23:59:59-5:00'.
2093
+ app_id (string): (Optional) String App API identifier retrieved from the **Settings > Setup and Testing > API Keys** to limit analytics to a specific app. Example: '{{app_identifier}}'.
2094
+ segment_id (string): (Required) String See [Segment API identifier]( Segment ID indicating the analytics-enabled segment for which sessions should be returned. Example: '{{segment_identifier}}'.
2095
+
2096
+ Returns:
2097
+ dict[str, Any]: Successful response
2098
+
2099
+ Raises:
2100
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2101
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2102
+
2103
+ Tags:
2104
+ Export > Session Analytics
2105
+ """
2106
+ url = f"{self.base_url}/sessions/data_series"
2107
+ query_params = {
2108
+ k: v
2109
+ for k, v in [
2110
+ ("length", length),
2111
+ ("unit", unit),
2112
+ ("ending_at", ending_at),
2113
+ ("app_id", app_id),
2114
+ ("segment_id", segment_id),
2115
+ ]
2116
+ if v is not None
2117
+ }
2118
+ response = self._get(url, params=query_params)
2119
+ response.raise_for_status()
2120
+ if (
2121
+ response.status_code == 204
2122
+ or not response.content
2123
+ or not response.text.strip()
2124
+ ):
2125
+ return None
2126
+ try:
2127
+ return response.json()
2128
+ except ValueError:
2129
+ return None
2130
+
2131
+ def export_user_ids_by_post(
2132
+ self,
2133
+ external_ids: list[str] | None = None,
2134
+ user_aliases: list[dict[str, Any]] | None = None,
2135
+ device_id: str | None = None,
2136
+ braze_id: str | None = None,
2137
+ email_address: str | None = None,
2138
+ phone: str | None = None,
2139
+ fields_to_export: list[str] | None = None,
2140
+ ) -> dict[str, Any]:
2141
+ """
2142
+ Export User Profile by Identifier
2143
+
2144
+ Args:
2145
+ external_ids (array): external_ids Example: ['user_identifier1', 'user_identifier2'].
2146
+ user_aliases (array): user_aliases Example: [{'alias_name': 'example_alias', 'alias_label': 'example_label'}].
2147
+ device_id (string): device_id Example: '1234567'.
2148
+ braze_id (string): braze_id Example: 'braze_identifier'.
2149
+ email_address (string): email_address Example: 'example@braze.com'.
2150
+ phone (string): phone Example: '+11112223333'.
2151
+ fields_to_export (array): fields_to_export Example: ['first_name', 'email', 'purchases'].
2152
+
2153
+ Returns:
2154
+ dict[str, Any]: Successful response
2155
+
2156
+ Raises:
2157
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2158
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2159
+
2160
+ Tags:
2161
+ Export > Users
2162
+ """
2163
+ request_body_data = None
2164
+ request_body_data = {
2165
+ "external_ids": external_ids,
2166
+ "user_aliases": user_aliases,
2167
+ "device_id": device_id,
2168
+ "braze_id": braze_id,
2169
+ "email_address": email_address,
2170
+ "phone": phone,
2171
+ "fields_to_export": fields_to_export,
2172
+ }
2173
+ request_body_data = {
2174
+ k: v for k, v in request_body_data.items() if v is not None
2175
+ }
2176
+ url = f"{self.base_url}/users/export/ids"
2177
+ query_params = {}
2178
+ response = self._post(
2179
+ url,
2180
+ data=request_body_data,
2181
+ params=query_params,
2182
+ content_type="application/json",
2183
+ )
2184
+ response.raise_for_status()
2185
+ if (
2186
+ response.status_code == 204
2187
+ or not response.content
2188
+ or not response.text.strip()
2189
+ ):
2190
+ return None
2191
+ try:
2192
+ return response.json()
2193
+ except ValueError:
2194
+ return None
2195
+
2196
+ def export_users_by_segment_post(
2197
+ self,
2198
+ segment_id: str | None = None,
2199
+ callback_endpoint: str | None = None,
2200
+ fields_to_export: list[str] | None = None,
2201
+ output_format: str | None = None,
2202
+ ) -> dict[str, Any]:
2203
+ """
2204
+ Export User Profile by Segment
2205
+
2206
+ Args:
2207
+ segment_id (string): segment_id Example: 'segment_identifier'.
2208
+ callback_endpoint (string): callback_endpoint Example: 'example_endpoint'.
2209
+ fields_to_export (array): fields_to_export Example: ['first_name', 'email', 'purchases'].
2210
+ output_format (string): output_format Example: 'zip'.
2211
+
2212
+ Returns:
2213
+ dict[str, Any]: Successful response
2214
+
2215
+ Raises:
2216
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2217
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2218
+
2219
+ Tags:
2220
+ Export > Users
2221
+ """
2222
+ request_body_data = None
2223
+ request_body_data = {
2224
+ "segment_id": segment_id,
2225
+ "callback_endpoint": callback_endpoint,
2226
+ "fields_to_export": fields_to_export,
2227
+ "output_format": output_format,
2228
+ }
2229
+ request_body_data = {
2230
+ k: v for k, v in request_body_data.items() if v is not None
2231
+ }
2232
+ url = f"{self.base_url}/users/export/segment"
2233
+ query_params = {}
2234
+ response = self._post(
2235
+ url,
2236
+ data=request_body_data,
2237
+ params=query_params,
2238
+ content_type="application/json",
2239
+ )
2240
+ response.raise_for_status()
2241
+ if (
2242
+ response.status_code == 204
2243
+ or not response.content
2244
+ or not response.text.strip()
2245
+ ):
2246
+ return None
2247
+ try:
2248
+ return response.json()
2249
+ except ValueError:
2250
+ return None
2251
+
2252
+ def export_global_control_group_users(
2253
+ self,
2254
+ callback_endpoint: str | None = None,
2255
+ fields_to_export: list[str] | None = None,
2256
+ output_format: str | None = None,
2257
+ ) -> dict[str, Any]:
2258
+ """
2259
+ Export User Profile by Global Control Group
2260
+
2261
+ Args:
2262
+ callback_endpoint (string): callback_endpoint Example: ''.
2263
+ fields_to_export (array): fields_to_export Example: ['email', 'braze_id'].
2264
+ output_format (string): output_format Example: 'zip'.
2265
+
2266
+ Returns:
2267
+ dict[str, Any]: Successful response
2268
+
2269
+ Raises:
2270
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2271
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2272
+
2273
+ Tags:
2274
+ Export > Users
2275
+ """
2276
+ request_body_data = None
2277
+ request_body_data = {
2278
+ "callback_endpoint": callback_endpoint,
2279
+ "fields_to_export": fields_to_export,
2280
+ "output_format": output_format,
2281
+ }
2282
+ request_body_data = {
2283
+ k: v for k, v in request_body_data.items() if v is not None
2284
+ }
2285
+ url = f"{self.base_url}/users/export/global_control_group"
2286
+ query_params = {}
2287
+ response = self._post(
2288
+ url,
2289
+ data=request_body_data,
2290
+ params=query_params,
2291
+ content_type="application/json",
2292
+ )
2293
+ response.raise_for_status()
2294
+ if (
2295
+ response.status_code == 204
2296
+ or not response.content
2297
+ or not response.text.strip()
2298
+ ):
2299
+ return None
2300
+ try:
2301
+ return response.json()
2302
+ except ValueError:
2303
+ return None
2304
+
2305
+ def update_live_activity_message(
2306
+ self,
2307
+ app_id: str | None = None,
2308
+ activity_id: str | None = None,
2309
+ content_state: dict[str, Any] | None = None,
2310
+ end_activity: bool | None = None,
2311
+ dismissal_date: str | None = None,
2312
+ stale_date: str | None = None,
2313
+ notification: dict[str, Any] | None = None,
2314
+ ) -> dict[str, Any]:
2315
+ """
2316
+ Update Live Activity
2317
+
2318
+ Args:
2319
+ app_id (string): app_id Example: '{YOUR-APP-API-IDENTIFIER}'.
2320
+ activity_id (string): activity_id Example: 'live-activity-1'.
2321
+ content_state (object): content_state Example: {'teamOneScore': 2, 'teamTwoScore': 4}.
2322
+ end_activity (boolean): end_activity Example: False.
2323
+ dismissal_date (string): dismissal_date Example: '2023-02-28T00:00:00+0000'.
2324
+ stale_date (string): stale_date Example: '2023-02-27T16:55:49+0000'.
2325
+ notification (object): notification Example: {'alert': {'body': "It's halftime! Let's look at the scores", 'title': 'Halftime'}}.
2326
+
2327
+ Returns:
2328
+ dict[str, Any]: Successful response
2329
+
2330
+ Raises:
2331
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2332
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2333
+
2334
+ Tags:
2335
+ Messaging > Live Activities
2336
+ """
2337
+ request_body_data = None
2338
+ request_body_data = {
2339
+ "app_id": app_id,
2340
+ "activity_id": activity_id,
2341
+ "content_state": content_state,
2342
+ "end_activity": end_activity,
2343
+ "dismissal_date": dismissal_date,
2344
+ "stale_date": stale_date,
2345
+ "notification": notification,
2346
+ }
2347
+ request_body_data = {
2348
+ k: v for k, v in request_body_data.items() if v is not None
2349
+ }
2350
+ url = f"{self.base_url}/messages/live_activity/update"
2351
+ query_params = {}
2352
+ response = self._post(
2353
+ url,
2354
+ data=request_body_data,
2355
+ params=query_params,
2356
+ content_type="application/json",
2357
+ )
2358
+ response.raise_for_status()
2359
+ if (
2360
+ response.status_code == 204
2361
+ or not response.content
2362
+ or not response.text.strip()
2363
+ ):
2364
+ return None
2365
+ try:
2366
+ return response.json()
2367
+ except ValueError:
2368
+ return None
2369
+
2370
+ def list_scheduled_broadcasts(
2371
+ self, end_time: str | None = None
2372
+ ) -> dict[str, Any]:
2373
+ """
2374
+ List Upcoming Scheduled Campaigns and Canvases
2375
+
2376
+ Args:
2377
+ end_time (string): (Required) String in [ISO 8601]( format End date of the range to retrieve upcoming scheduled Campaigns and Canvases. This is treated as midnight in UTC time by the API. Example: '2018-09-01T00:00:00-04:00'.
2378
+
2379
+ Returns:
2380
+ dict[str, Any]: Successful response
2381
+
2382
+ Raises:
2383
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2384
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2385
+
2386
+ Tags:
2387
+ Messaging > Schedule Mesages
2388
+ """
2389
+ url = f"{self.base_url}/messages/scheduled_broadcasts"
2390
+ query_params = {k: v for k, v in [("end_time", end_time)] if v is not None}
2391
+ response = self._get(url, params=query_params)
2392
+ response.raise_for_status()
2393
+ if (
2394
+ response.status_code == 204
2395
+ or not response.content
2396
+ or not response.text.strip()
2397
+ ):
2398
+ return None
2399
+ try:
2400
+ return response.json()
2401
+ except ValueError:
2402
+ return None
2403
+
2404
+ def delete_scheduled_message(
2405
+ self, schedule_id: str | None = None
2406
+ ) -> dict[str, Any]:
2407
+ """
2408
+ Delete Scheduled Messages
2409
+
2410
+ Args:
2411
+ schedule_id (string): schedule_id Example: 'schedule_identifier'.
2412
+
2413
+ Returns:
2414
+ dict[str, Any]: Successful response
2415
+
2416
+ Raises:
2417
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2418
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2419
+
2420
+ Tags:
2421
+ Messaging > Schedule Mesages
2422
+ """
2423
+ request_body_data = None
2424
+ request_body_data = {
2425
+ "schedule_id": schedule_id,
2426
+ }
2427
+ request_body_data = {
2428
+ k: v for k, v in request_body_data.items() if v is not None
2429
+ }
2430
+ url = f"{self.base_url}/messages/schedule/delete"
2431
+ query_params = {}
2432
+ response = self._post(
2433
+ url,
2434
+ data=request_body_data,
2435
+ params=query_params,
2436
+ content_type="application/json",
2437
+ )
2438
+ response.raise_for_status()
2439
+ if (
2440
+ response.status_code == 204
2441
+ or not response.content
2442
+ or not response.text.strip()
2443
+ ):
2444
+ return None
2445
+ try:
2446
+ return response.json()
2447
+ except ValueError:
2448
+ return None
2449
+
2450
+ def schedule_delete_canvas_trigger(
2451
+ self, canvas_id: str | None = None, schedule_id: str | None = None
2452
+ ) -> dict[str, Any]:
2453
+ """
2454
+ Delete Scheduled API-Triggered Canvases
2455
+
2456
+ Args:
2457
+ canvas_id (string): canvas_id Example: 'canvas_identifier'.
2458
+ schedule_id (string): schedule_id Example: 'schedule_identifier'.
2459
+
2460
+ Returns:
2461
+ dict[str, Any]: Successful response
2462
+
2463
+ Raises:
2464
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2465
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2466
+
2467
+ Tags:
2468
+ Messaging > Schedule Mesages
2469
+ """
2470
+ request_body_data = None
2471
+ request_body_data = {
2472
+ "canvas_id": canvas_id,
2473
+ "schedule_id": schedule_id,
2474
+ }
2475
+ request_body_data = {
2476
+ k: v for k, v in request_body_data.items() if v is not None
2477
+ }
2478
+ url = f"{self.base_url}/canvas/trigger/schedule/delete"
2479
+ query_params = {}
2480
+ response = self._post(
2481
+ url,
2482
+ data=request_body_data,
2483
+ params=query_params,
2484
+ content_type="application/json",
2485
+ )
2486
+ response.raise_for_status()
2487
+ if (
2488
+ response.status_code == 204
2489
+ or not response.content
2490
+ or not response.text.strip()
2491
+ ):
2492
+ return None
2493
+ try:
2494
+ return response.json()
2495
+ except ValueError:
2496
+ return None
2497
+
2498
+ def delete_campaign_schedule(
2499
+ self, campaign_id: str | None = None, schedule_id: str | None = None
2500
+ ) -> dict[str, Any]:
2501
+ """
2502
+ Delete Scheduled API Triggered Campaigns
2503
+
2504
+ Args:
2505
+ campaign_id (string): campaign_id Example: 'campaign_identifier'.
2506
+ schedule_id (string): schedule_id Example: 'schedule_identifier'.
2507
+
2508
+ Returns:
2509
+ dict[str, Any]: Successful response
2510
+
2511
+ Raises:
2512
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2513
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2514
+
2515
+ Tags:
2516
+ Messaging > Schedule Mesages
2517
+ """
2518
+ request_body_data = None
2519
+ request_body_data = {
2520
+ "campaign_id": campaign_id,
2521
+ "schedule_id": schedule_id,
2522
+ }
2523
+ request_body_data = {
2524
+ k: v for k, v in request_body_data.items() if v is not None
2525
+ }
2526
+ url = f"{self.base_url}/campaigns/trigger/schedule/delete"
2527
+ query_params = {}
2528
+ response = self._post(
2529
+ url,
2530
+ data=request_body_data,
2531
+ params=query_params,
2532
+ content_type="application/json",
2533
+ )
2534
+ response.raise_for_status()
2535
+ if (
2536
+ response.status_code == 204
2537
+ or not response.content
2538
+ or not response.text.strip()
2539
+ ):
2540
+ return None
2541
+ try:
2542
+ return response.json()
2543
+ except ValueError:
2544
+ return None
2545
+
2546
+ def create_scheduled_message(
2547
+ self,
2548
+ broadcast: bool | None = None,
2549
+ external_user_ids: str | None = None,
2550
+ user_aliases: dict[str, Any] | None = None,
2551
+ segment_id: str | None = None,
2552
+ audience: dict[str, Any] | None = None,
2553
+ campaign_id: str | None = None,
2554
+ send_id: str | None = None,
2555
+ override_messaging_limits: bool | None = None,
2556
+ recipient_subscription_state: str | None = None,
2557
+ schedule: dict[str, Any] | None = None,
2558
+ messages: dict[str, Any] | None = None,
2559
+ ) -> dict[str, Any]:
2560
+ """
2561
+ Create Scheduled Messages
2562
+
2563
+ Args:
2564
+ broadcast (boolean): broadcast Example: False.
2565
+ external_user_ids (string): external_user_ids Example: 'external_user_identifiers'.
2566
+ user_aliases (object): user_aliases Example: {'alias_name': 'example_name', 'alias_label': 'example_label'}.
2567
+ segment_id (string): segment_id Example: 'segment_identifiers'.
2568
+ audience (object): audience Example: {'AND': [{'custom_attribute': {'custom_attribute_name': 'eye_color', 'comparison': 'equals', 'value': 'blue'}}, {'custom_attribute': {'custom_attribute_name': 'favorite_foods', 'comparison': 'includes_value', 'value': 'pizza'}}, {'OR': [{'custom_attribute': {'custom_attribute_name': 'last_purchase_time', 'comparison': 'less_than_x_days_ago', 'value': 2}}, {'push_subscription_status': {'comparison': 'is', 'value': 'opted_in'}}]}, {'email_subscription_status': {'comparison': 'is_not', 'value': 'subscribed'}}, {'last_used_app': {'comparison': 'after', 'value': '2019-07-22T13:17:55+0000'}}]}.
2569
+ campaign_id (string): campaign_id Example: 'campaign_identifier'.
2570
+ send_id (string): send_id Example: 'send_identifier'.
2571
+ override_messaging_limits (boolean): override_messaging_limits Example: False.
2572
+ recipient_subscription_state (string): recipient_subscription_state Example: 'subscribed'.
2573
+ schedule (object): schedule Example: {'time': '', 'in_local_time': True, 'at_optimal_time': True}.
2574
+ messages (object): messages Example: {'apple_push': {}, 'android_push': {}, 'windows_push': {}, 'windows8_push': {}, 'kindle_push': {}, 'web_push': {}, 'email': {}, 'webhook': {}, 'content_card': {}}.
2575
+
2576
+ Returns:
2577
+ dict[str, Any]: Successful response
2578
+
2579
+ Raises:
2580
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2581
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2582
+
2583
+ Tags:
2584
+ Messaging > Schedule Mesages
2585
+ """
2586
+ request_body_data = None
2587
+ request_body_data = {
2588
+ "broadcast": broadcast,
2589
+ "external_user_ids": external_user_ids,
2590
+ "user_aliases": user_aliases,
2591
+ "segment_id": segment_id,
2592
+ "audience": audience,
2593
+ "campaign_id": campaign_id,
2594
+ "send_id": send_id,
2595
+ "override_messaging_limits": override_messaging_limits,
2596
+ "recipient_subscription_state": recipient_subscription_state,
2597
+ "schedule": schedule,
2598
+ "messages": messages,
2599
+ }
2600
+ request_body_data = {
2601
+ k: v for k, v in request_body_data.items() if v is not None
2602
+ }
2603
+ url = f"{self.base_url}/messages/schedule/create"
2604
+ query_params = {}
2605
+ response = self._post(
2606
+ url,
2607
+ data=request_body_data,
2608
+ params=query_params,
2609
+ content_type="application/json",
2610
+ )
2611
+ response.raise_for_status()
2612
+ if (
2613
+ response.status_code == 204
2614
+ or not response.content
2615
+ or not response.text.strip()
2616
+ ):
2617
+ return None
2618
+ try:
2619
+ return response.json()
2620
+ except ValueError:
2621
+ return None
2622
+
2623
+ def create_schedule(
2624
+ self,
2625
+ campaign_id: str | None = None,
2626
+ send_id: str | None = None,
2627
+ recipients: list[dict[str, Any]] | None = None,
2628
+ audience: dict[str, Any] | None = None,
2629
+ broadcast: bool | None = None,
2630
+ trigger_properties: dict[str, Any] | None = None,
2631
+ schedule: dict[str, Any] | None = None,
2632
+ ) -> dict[str, Any]:
2633
+ """
2634
+ Schedule API Triggered Campaigns
2635
+
2636
+ Args:
2637
+ campaign_id (string): campaign_id Example: 'campaign_identifier'.
2638
+ send_id (string): send_id Example: 'send_identifier'.
2639
+ recipients (array): recipients Example: [{'user_alias': 'example_alias', 'external_user_id': 'external_user_identifier', 'trigger_properties': {}}].
2640
+ audience (object): audience Example: {'AND': [{'custom_attribute': {'custom_attribute_name': 'eye_color', 'comparison': 'equals', 'value': 'blue'}}, {'custom_attribute': {'custom_attribute_name': 'favorite_foods', 'comparison': 'includes_value', 'value': 'pizza'}}, {'OR': [{'custom_attribute': {'custom_attribute_name': 'last_purchase_time', 'comparison': 'less_than_x_days_ago', 'value': 2}}, {'push_subscription_status': {'comparison': 'is', 'value': 'opted_in'}}]}, {'email_subscription_status': {'comparison': 'is_not', 'value': 'subscribed'}}, {'last_used_app': {'comparison': 'after', 'value': '2019-07-22T13:17:55+0000'}}]}.
2641
+ broadcast (boolean): broadcast Example: False.
2642
+ trigger_properties (object): trigger_properties Example: {}.
2643
+ schedule (object): schedule Example: {'time': '', 'in_local_time': False, 'at_optimal_time': False}.
2644
+
2645
+ Returns:
2646
+ dict[str, Any]: Successful response
2647
+
2648
+ Raises:
2649
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2650
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2651
+
2652
+ Tags:
2653
+ Messaging > Schedule Mesages
2654
+ """
2655
+ request_body_data = None
2656
+ request_body_data = {
2657
+ "campaign_id": campaign_id,
2658
+ "send_id": send_id,
2659
+ "recipients": recipients,
2660
+ "audience": audience,
2661
+ "broadcast": broadcast,
2662
+ "trigger_properties": trigger_properties,
2663
+ "schedule": schedule,
2664
+ }
2665
+ request_body_data = {
2666
+ k: v for k, v in request_body_data.items() if v is not None
2667
+ }
2668
+ url = f"{self.base_url}/campaigns/trigger/schedule/create"
2669
+ query_params = {}
2670
+ response = self._post(
2671
+ url,
2672
+ data=request_body_data,
2673
+ params=query_params,
2674
+ content_type="application/json",
2675
+ )
2676
+ response.raise_for_status()
2677
+ if (
2678
+ response.status_code == 204
2679
+ or not response.content
2680
+ or not response.text.strip()
2681
+ ):
2682
+ return None
2683
+ try:
2684
+ return response.json()
2685
+ except ValueError:
2686
+ return None
2687
+
2688
+ def create_schedule_trigger(
2689
+ self,
2690
+ canvas_id: str | None = None,
2691
+ recipients: list[dict[str, Any]] | None = None,
2692
+ audience: dict[str, Any] | None = None,
2693
+ broadcast: bool | None = None,
2694
+ canvas_entry_properties: dict[str, Any] | None = None,
2695
+ schedule: dict[str, Any] | None = None,
2696
+ ) -> dict[str, Any]:
2697
+ """
2698
+ Schedule API Triggered Canvases
2699
+
2700
+ Args:
2701
+ canvas_id (string): canvas_id Example: 'canvas_identifier'.
2702
+ recipients (array): recipients Example: [{'user_alias': 'example_alias', 'external_user_id': 'external_user_identifier', 'trigger_properties': {}, 'canvas_entry_properties': {}}].
2703
+ audience (object): audience Example: {'AND': [{'custom_attribute': {'custom_attribute_name': 'eye_color', 'comparison': 'equals', 'value': 'blue'}}, {'custom_attribute': {'custom_attribute_name': 'favorite_foods', 'comparison': 'includes_value', 'value': 'pizza'}}, {'OR': [{'custom_attribute': {'custom_attribute_name': 'last_purchase_time', 'comparison': 'less_than_x_days_ago', 'value': 2}}, {'push_subscription_status': {'comparison': 'is', 'value': 'opted_in'}}]}, {'email_subscription_status': {'comparison': 'is_not', 'value': 'subscribed'}}, {'last_used_app': {'comparison': 'after', 'value': '2019-07-22T13:17:55+0000'}}]}.
2704
+ broadcast (boolean): broadcast Example: False.
2705
+ canvas_entry_properties (object): canvas_entry_properties Example: {}.
2706
+ schedule (object): schedule Example: {'time': '', 'in_local_time': False, 'at_optimal_time': False}.
2707
+
2708
+ Returns:
2709
+ dict[str, Any]: Successful response
2710
+
2711
+ Raises:
2712
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2713
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2714
+
2715
+ Tags:
2716
+ Messaging > Schedule Mesages
2717
+ """
2718
+ request_body_data = None
2719
+ request_body_data = {
2720
+ "canvas_id": canvas_id,
2721
+ "recipients": recipients,
2722
+ "audience": audience,
2723
+ "broadcast": broadcast,
2724
+ "canvas_entry_properties": canvas_entry_properties,
2725
+ "schedule": schedule,
2726
+ }
2727
+ request_body_data = {
2728
+ k: v for k, v in request_body_data.items() if v is not None
2729
+ }
2730
+ url = f"{self.base_url}/canvas/trigger/schedule/create"
2731
+ query_params = {}
2732
+ response = self._post(
2733
+ url,
2734
+ data=request_body_data,
2735
+ params=query_params,
2736
+ content_type="application/json",
2737
+ )
2738
+ response.raise_for_status()
2739
+ if (
2740
+ response.status_code == 204
2741
+ or not response.content
2742
+ or not response.text.strip()
2743
+ ):
2744
+ return None
2745
+ try:
2746
+ return response.json()
2747
+ except ValueError:
2748
+ return None
2749
+
2750
+ def schedule_message_update(
2751
+ self,
2752
+ schedule_id: str | None = None,
2753
+ schedule: dict[str, Any] | None = None,
2754
+ messages: dict[str, Any] | None = None,
2755
+ ) -> dict[str, Any]:
2756
+ """
2757
+ Update Scheduled Messages
2758
+
2759
+ Args:
2760
+ schedule_id (string): schedule_id Example: 'schedule_identifier'.
2761
+ schedule (object): schedule Example: {'time': '2017-05-24T20:30:36Z'}.
2762
+ messages (object): messages Example: {'apple_push': {'alert': 'Updated Message!', 'badge': 1}, 'android_push': {'title': 'Updated title!', 'alert': 'Updated message!'}, 'sms': {'subscription_group_id': 'subscription_group_identifier', 'message_variation_id': 'message_variation_identifier', 'body': 'This is my SMS body.', 'app_id': 'app_identifier'}}.
2763
+
2764
+ Returns:
2765
+ dict[str, Any]: Successful response
2766
+
2767
+ Raises:
2768
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2769
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2770
+
2771
+ Tags:
2772
+ Messaging > Schedule Mesages
2773
+ """
2774
+ request_body_data = None
2775
+ request_body_data = {
2776
+ "schedule_id": schedule_id,
2777
+ "schedule": schedule,
2778
+ "messages": messages,
2779
+ }
2780
+ request_body_data = {
2781
+ k: v for k, v in request_body_data.items() if v is not None
2782
+ }
2783
+ url = f"{self.base_url}/messages/schedule/update"
2784
+ query_params = {}
2785
+ response = self._post(
2786
+ url,
2787
+ data=request_body_data,
2788
+ params=query_params,
2789
+ content_type="application/json",
2790
+ )
2791
+ response.raise_for_status()
2792
+ if (
2793
+ response.status_code == 204
2794
+ or not response.content
2795
+ or not response.text.strip()
2796
+ ):
2797
+ return None
2798
+ try:
2799
+ return response.json()
2800
+ except ValueError:
2801
+ return None
2802
+
2803
+ def update_campaign_trigger_schedule(
2804
+ self,
2805
+ campaign_id: str | None = None,
2806
+ schedule_id: str | None = None,
2807
+ schedule: dict[str, Any] | None = None,
2808
+ ) -> dict[str, Any]:
2809
+ """
2810
+ Update Scheduled API Triggered Campaigns
2811
+
2812
+ Args:
2813
+ campaign_id (string): campaign_id Example: 'campaign_identifier'.
2814
+ schedule_id (string): schedule_id Example: 'schedule_identifier'.
2815
+ schedule (object): schedule Example: {'time': '2017-05-24T21:30:00Z', 'in_local_time': True}.
2816
+
2817
+ Returns:
2818
+ dict[str, Any]: Successful response
2819
+
2820
+ Raises:
2821
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2822
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2823
+
2824
+ Tags:
2825
+ Messaging > Schedule Mesages
2826
+ """
2827
+ request_body_data = None
2828
+ request_body_data = {
2829
+ "campaign_id": campaign_id,
2830
+ "schedule_id": schedule_id,
2831
+ "schedule": schedule,
2832
+ }
2833
+ request_body_data = {
2834
+ k: v for k, v in request_body_data.items() if v is not None
2835
+ }
2836
+ url = f"{self.base_url}/campaigns/trigger/schedule/update"
2837
+ query_params = {}
2838
+ response = self._post(
2839
+ url,
2840
+ data=request_body_data,
2841
+ params=query_params,
2842
+ content_type="application/json",
2843
+ )
2844
+ response.raise_for_status()
2845
+ if (
2846
+ response.status_code == 204
2847
+ or not response.content
2848
+ or not response.text.strip()
2849
+ ):
2850
+ return None
2851
+ try:
2852
+ return response.json()
2853
+ except ValueError:
2854
+ return None
2855
+
2856
+ def update_canvas_trigger_schedule(
2857
+ self,
2858
+ canvas_id: str | None = None,
2859
+ schedule_id: str | None = None,
2860
+ schedule: dict[str, Any] | None = None,
2861
+ ) -> dict[str, Any]:
2862
+ """
2863
+ Update Scheduled API Triggered Canvases
2864
+
2865
+ Args:
2866
+ canvas_id (string): canvas_id Example: 'canvas_identifier'.
2867
+ schedule_id (string): schedule_id Example: 'schedule_identifier'.
2868
+ schedule (object): schedule Example: {'time': '2017-05-24T21:30:00Z', 'in_local_time': True}.
2869
+
2870
+ Returns:
2871
+ dict[str, Any]: Successful response
2872
+
2873
+ Raises:
2874
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2875
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2876
+
2877
+ Tags:
2878
+ Messaging > Schedule Mesages
2879
+ """
2880
+ request_body_data = None
2881
+ request_body_data = {
2882
+ "canvas_id": canvas_id,
2883
+ "schedule_id": schedule_id,
2884
+ "schedule": schedule,
2885
+ }
2886
+ request_body_data = {
2887
+ k: v for k, v in request_body_data.items() if v is not None
2888
+ }
2889
+ url = f"{self.base_url}/canvas/trigger/schedule/update"
2890
+ query_params = {}
2891
+ response = self._post(
2892
+ url,
2893
+ data=request_body_data,
2894
+ params=query_params,
2895
+ content_type="application/json",
2896
+ )
2897
+ response.raise_for_status()
2898
+ if (
2899
+ response.status_code == 204
2900
+ or not response.content
2901
+ or not response.text.strip()
2902
+ ):
2903
+ return None
2904
+ try:
2905
+ return response.json()
2906
+ except ValueError:
2907
+ return None
2908
+
2909
+ def create_send_by_id(
2910
+ self, campaign_id: str | None = None, send_id: str | None = None
2911
+ ) -> dict[str, Any]:
2912
+ """
2913
+ Create Send IDs For Message Send Tracking
2914
+
2915
+ Args:
2916
+ campaign_id (string): campaign_id Example: 'campaign_identifier'.
2917
+ send_id (string): send_id Example: 'send_identifier'.
2918
+
2919
+ Returns:
2920
+ dict[str, Any]: Successful response
2921
+
2922
+ Raises:
2923
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2924
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2925
+
2926
+ Tags:
2927
+ Messaging > Send Messages
2928
+ """
2929
+ request_body_data = None
2930
+ request_body_data = {
2931
+ "campaign_id": campaign_id,
2932
+ "send_id": send_id,
2933
+ }
2934
+ request_body_data = {
2935
+ k: v for k, v in request_body_data.items() if v is not None
2936
+ }
2937
+ url = f"{self.base_url}/sends/id/create"
2938
+ query_params = {}
2939
+ response = self._post(
2940
+ url,
2941
+ data=request_body_data,
2942
+ params=query_params,
2943
+ content_type="application/json",
2944
+ )
2945
+ response.raise_for_status()
2946
+ if (
2947
+ response.status_code == 204
2948
+ or not response.content
2949
+ or not response.text.strip()
2950
+ ):
2951
+ return None
2952
+ try:
2953
+ return response.json()
2954
+ except ValueError:
2955
+ return None
2956
+
2957
+ def send_message(
2958
+ self,
2959
+ broadcast: str | None = None,
2960
+ external_user_ids: str | None = None,
2961
+ user_aliases: dict[str, Any] | None = None,
2962
+ segment_id: str | None = None,
2963
+ audience: dict[str, Any] | None = None,
2964
+ campaign_id: str | None = None,
2965
+ send_id: str | None = None,
2966
+ override_frequency_capping: str | None = None,
2967
+ recipient_subscription_state: str | None = None,
2968
+ messages: dict[str, Any] | None = None,
2969
+ ) -> dict[str, Any]:
2970
+ """
2971
+ Send Messages Immediately via API Only
2972
+
2973
+ Args:
2974
+ broadcast (string): broadcast Example: 'false'.
2975
+ external_user_ids (string): external_user_ids Example: 'external_user_identifiers'.
2976
+ user_aliases (object): user_aliases Example: {'alias_name': 'example_name', 'alias_label': 'example_label'}.
2977
+ segment_id (string): segment_id Example: 'segment_identifier'.
2978
+ audience (object): audience Example: {'AND': [{'custom_attribute': {'custom_attribute_name': 'eye_color', 'comparison': 'equals', 'value': 'blue'}}, {'custom_attribute': {'custom_attribute_name': 'favorite_foods', 'comparison': 'includes_value', 'value': 'pizza'}}, {'OR': [{'custom_attribute': {'custom_attribute_name': 'last_purchase_time', 'comparison': 'less_than_x_days_ago', 'value': 2}}, {'push_subscription_status': {'comparison': 'is', 'value': 'opted_in'}}]}, {'email_subscription_status': {'comparison': 'is_not', 'value': 'subscribed'}}, {'last_used_app': {'comparison': 'after', 'value': '2019-07-22T13:17:55+0000'}}]}.
2979
+ campaign_id (string): campaign_id Example: 'campaign_identifier'.
2980
+ send_id (string): send_id Example: 'send_identifier'.
2981
+ override_frequency_capping (string): override_frequency_capping Example: 'false'.
2982
+ recipient_subscription_state (string): recipient_subscription_state Example: 'all'.
2983
+ messages (object): messages Example: {'android_push': '(optional, Android Push Object)', 'apple_push': '(optional, Apple Push Object)', 'content_card': '(optional, Content Card Object)', 'email': '(optional, Email Object)', 'kindle_push': '(optional, Kindle/FireOS Push Object)', 'web_push': '(optional, Web Push Object)', 'windows_phone8_push': '(optional, Windows Phone 8 Push Object)', 'windows_universal_push': '(optional, Windows Universal Push Object)'}.
2984
+
2985
+ Returns:
2986
+ dict[str, Any]: Successful response
2987
+
2988
+ Raises:
2989
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
2990
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
2991
+
2992
+ Tags:
2993
+ Messaging > Send Messages
2994
+ """
2995
+ request_body_data = None
2996
+ request_body_data = {
2997
+ "broadcast": broadcast,
2998
+ "external_user_ids": external_user_ids,
2999
+ "user_aliases": user_aliases,
3000
+ "segment_id": segment_id,
3001
+ "audience": audience,
3002
+ "campaign_id": campaign_id,
3003
+ "send_id": send_id,
3004
+ "override_frequency_capping": override_frequency_capping,
3005
+ "recipient_subscription_state": recipient_subscription_state,
3006
+ "messages": messages,
3007
+ }
3008
+ request_body_data = {
3009
+ k: v for k, v in request_body_data.items() if v is not None
3010
+ }
3011
+ url = f"{self.base_url}/messages/send"
3012
+ query_params = {}
3013
+ response = self._post(
3014
+ url,
3015
+ data=request_body_data,
3016
+ params=query_params,
3017
+ content_type="application/json",
3018
+ )
3019
+ response.raise_for_status()
3020
+ if (
3021
+ response.status_code == 204
3022
+ or not response.content
3023
+ or not response.text.strip()
3024
+ ):
3025
+ return None
3026
+ try:
3027
+ return response.json()
3028
+ except ValueError:
3029
+ return None
3030
+
3031
+ def send_campaign_transactional(
3032
+ self,
3033
+ campaign_id: str,
3034
+ external_send_id: str | None = None,
3035
+ trigger_properties: dict[str, Any] | None = None,
3036
+ recipient: list[dict[str, Any]] | None = None,
3037
+ ) -> dict[str, Any]:
3038
+ """
3039
+ Send Transactional Email via API Triggered Delivery
3040
+
3041
+ Args:
3042
+ campaign_id (string): campaign_id
3043
+ external_send_id (string): external_send_id Example: 'YOUR_BASE64_COMPATIBLE_ID'.
3044
+ trigger_properties (object): trigger_properties Example: {'example_string_property': 'YOUR_EXAMPLE_STRING', 'example_integer_property': 'YOUR_EXAMPLE_INTEGER'}.
3045
+ recipient (array): recipient Example: [{'external_user_id': 'TARGETED_USER_ID_STRING'}].
3046
+
3047
+ Returns:
3048
+ dict[str, Any]: Successful response
3049
+
3050
+ Raises:
3051
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3052
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3053
+
3054
+ Tags:
3055
+ Messaging > Send Messages
3056
+ """
3057
+ if campaign_id is None:
3058
+ raise ValueError("Missing required parameter 'campaign_id'.")
3059
+ request_body_data = None
3060
+ request_body_data = {
3061
+ "external_send_id": external_send_id,
3062
+ "trigger_properties": trigger_properties,
3063
+ "recipient": recipient,
3064
+ }
3065
+ request_body_data = {
3066
+ k: v for k, v in request_body_data.items() if v is not None
3067
+ }
3068
+ url = f"{self.base_url}/transactional/v1/campaigns/{campaign_id}/send"
3069
+ query_params = {}
3070
+ response = self._post(
3071
+ url,
3072
+ data=request_body_data,
3073
+ params=query_params,
3074
+ content_type="application/json",
3075
+ )
3076
+ response.raise_for_status()
3077
+ if (
3078
+ response.status_code == 204
3079
+ or not response.content
3080
+ or not response.text.strip()
3081
+ ):
3082
+ return None
3083
+ try:
3084
+ return response.json()
3085
+ except ValueError:
3086
+ return None
3087
+
3088
+ def send_campaign_trigger(
3089
+ self,
3090
+ campaign_id: str | None = None,
3091
+ send_id: str | None = None,
3092
+ trigger_properties: dict[str, Any] | None = None,
3093
+ broadcast: bool | None = None,
3094
+ audience: dict[str, Any] | None = None,
3095
+ recipients: list[dict[str, Any]] | None = None,
3096
+ ) -> dict[str, Any]:
3097
+ """
3098
+ Send Campaign Messages via API Triggered Delivery
3099
+
3100
+ Args:
3101
+ campaign_id (string): campaign_id Example: 'campaign_identifier'.
3102
+ send_id (string): send_id Example: 'send_identifier'.
3103
+ trigger_properties (object): trigger_properties Example: {}.
3104
+ broadcast (boolean): broadcast Example: False.
3105
+ audience (object): audience Example: {'AND': [{'custom_attribute': {'custom_attribute_name': 'eye_color', 'comparison': 'equals', 'value': 'blue'}}, {'custom_attribute': {'custom_attribute_name': 'favorite_foods', 'comparison': 'includes_value', 'value': 'pizza'}}, {'OR': [{'custom_attribute': {'custom_attribute_name': 'last_purchase_time', 'comparison': 'less_than_x_days_ago', 'value': 2}}, {'push_subscription_status': {'comparison': 'is', 'value': 'opted_in'}}]}, {'email_subscription_status': {'comparison': 'is_not', 'value': 'subscribed'}}, {'last_used_app': {'comparison': 'after', 'value': '2019-07-22T13:17:55+0000'}}]}.
3106
+ recipients (array): recipients Example: [{'user_alias': {'alias_name': 'example_name', 'alias_label': 'example_label'}, 'external_user_id': 'external_user_identifier', 'trigger_properties': {}, 'send_to_existing_only': True, 'attributes': {'first_name': 'Alex'}}].
3107
+
3108
+ Returns:
3109
+ dict[str, Any]: Successful response
3110
+
3111
+ Raises:
3112
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3113
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3114
+
3115
+ Tags:
3116
+ Messaging > Send Messages
3117
+ """
3118
+ request_body_data = None
3119
+ request_body_data = {
3120
+ "campaign_id": campaign_id,
3121
+ "send_id": send_id,
3122
+ "trigger_properties": trigger_properties,
3123
+ "broadcast": broadcast,
3124
+ "audience": audience,
3125
+ "recipients": recipients,
3126
+ }
3127
+ request_body_data = {
3128
+ k: v for k, v in request_body_data.items() if v is not None
3129
+ }
3130
+ url = f"{self.base_url}/campaigns/trigger/send"
3131
+ query_params = {}
3132
+ response = self._post(
3133
+ url,
3134
+ data=request_body_data,
3135
+ params=query_params,
3136
+ content_type="application/json",
3137
+ )
3138
+ response.raise_for_status()
3139
+ if (
3140
+ response.status_code == 204
3141
+ or not response.content
3142
+ or not response.text.strip()
3143
+ ):
3144
+ return None
3145
+ try:
3146
+ return response.json()
3147
+ except ValueError:
3148
+ return None
3149
+
3150
+ def send_canvas_trigger_post(
3151
+ self,
3152
+ canvas_id: str | None = None,
3153
+ canvas_entry_properties: dict[str, Any] | None = None,
3154
+ broadcast: bool | None = None,
3155
+ audience: dict[str, Any] | None = None,
3156
+ recipients: list[dict[str, Any]] | None = None,
3157
+ ) -> dict[str, Any]:
3158
+ """
3159
+ Send Canvas Messages via API Triggered Delivery
3160
+
3161
+ Args:
3162
+ canvas_id (string): canvas_id Example: 'canvas_identifier'.
3163
+ canvas_entry_properties (object): canvas_entry_properties Example: {'product_name': 'shoes', 'product_price': 79.99}.
3164
+ broadcast (boolean): broadcast Example: False.
3165
+ audience (object): audience Example: {'AND': [{'custom_attribute': {'custom_attribute_name': 'eye_color', 'comparison': 'equals', 'value': 'blue'}}, {'custom_attribute': {'custom_attribute_name': 'favorite_foods', 'comparison': 'includes_value', 'value': 'pizza'}}, {'OR': [{'custom_attribute': {'custom_attribute_name': 'last_purchase_time', 'comparison': 'less_than_x_days_ago', 'value': 2}}, {'push_subscription_status': {'comparison': 'is', 'value': 'opted_in'}}]}, {'email_subscription_status': {'comparison': 'is_not', 'value': 'subscribed'}}, {'last_used_app': {'comparison': 'after', 'value': '2019-07-22T13:17:55+0000'}}]}.
3166
+ recipients (array): recipients Example: [{'user_alias': {'alias_name': 'example_name', 'alias_label': 'example_label'}, 'external_user_id': 'user_identifier', 'trigger_properties': {}, 'canvas_entry_properties': '', 'send_to_existing_only': True, 'attributes': {'first_name': 'Alex'}}].
3167
+
3168
+ Returns:
3169
+ dict[str, Any]: Successful response
3170
+
3171
+ Raises:
3172
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3173
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3174
+
3175
+ Tags:
3176
+ Messaging > Send Messages
3177
+ """
3178
+ request_body_data = None
3179
+ request_body_data = {
3180
+ "canvas_id": canvas_id,
3181
+ "canvas_entry_properties": canvas_entry_properties,
3182
+ "broadcast": broadcast,
3183
+ "audience": audience,
3184
+ "recipients": recipients,
3185
+ }
3186
+ request_body_data = {
3187
+ k: v for k, v in request_body_data.items() if v is not None
3188
+ }
3189
+ url = f"{self.base_url}/canvas/trigger/send"
3190
+ query_params = {}
3191
+ response = self._post(
3192
+ url,
3193
+ data=request_body_data,
3194
+ params=query_params,
3195
+ content_type="application/json",
3196
+ )
3197
+ response.raise_for_status()
3198
+ if (
3199
+ response.status_code == 204
3200
+ or not response.content
3201
+ or not response.text.strip()
3202
+ ):
3203
+ return None
3204
+ try:
3205
+ return response.json()
3206
+ except ValueError:
3207
+ return None
3208
+
3209
+ def get_preference_center_url_by_user_id(
3210
+ self,
3211
+ PreferenceCenterExternalID: str,
3212
+ UserID: str,
3213
+ preference_center_api_id: str | None = None,
3214
+ external_id: str | None = None,
3215
+ ) -> dict[str, Any]:
3216
+ """
3217
+ Generate Preference Center URL
3218
+
3219
+ Args:
3220
+ PreferenceCenterExternalID (string): PreferenceCenterExternalID
3221
+ UserID (string): UserID
3222
+ preference_center_api_id (string): Identifies the unique API ID for the preference center resource, used to specify which preference center instance to query. Example: '{{preference_center_api_id}}'.
3223
+ external_id (string): (Required) String Example: '{{external_id}}'.
3224
+
3225
+ Returns:
3226
+ dict[str, Any]: Successful response
3227
+
3228
+ Raises:
3229
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3230
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3231
+
3232
+ Tags:
3233
+ Preference Center
3234
+ """
3235
+ if PreferenceCenterExternalID is None:
3236
+ raise ValueError("Missing required parameter 'PreferenceCenterExternalID'.")
3237
+ if UserID is None:
3238
+ raise ValueError("Missing required parameter 'UserID'.")
3239
+ url = f"{self.base_url}/preference_center_v1/{PreferenceCenterExternalID}/url/{UserID}"
3240
+ query_params = {
3241
+ k: v
3242
+ for k, v in [
3243
+ ("preference_center_api_id", preference_center_api_id),
3244
+ ("external_id", external_id),
3245
+ ]
3246
+ if v is not None
3247
+ }
3248
+ response = self._get(url, params=query_params)
3249
+ response.raise_for_status()
3250
+ if (
3251
+ response.status_code == 204
3252
+ or not response.content
3253
+ or not response.text.strip()
3254
+ ):
3255
+ return None
3256
+ try:
3257
+ return response.json()
3258
+ except ValueError:
3259
+ return None
3260
+
3261
+ def list_preferences(self) -> dict[str, Any]:
3262
+ """
3263
+ List Preference Centers
3264
+
3265
+ Returns:
3266
+ dict[str, Any]: Successful response
3267
+
3268
+ Raises:
3269
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3270
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3271
+
3272
+ Tags:
3273
+ Preference Center
3274
+ """
3275
+ url = f"{self.base_url}/preference_center/v1/list"
3276
+ query_params = {}
3277
+ response = self._get(url, params=query_params)
3278
+ response.raise_for_status()
3279
+ if (
3280
+ response.status_code == 204
3281
+ or not response.content
3282
+ or not response.text.strip()
3283
+ ):
3284
+ return None
3285
+ try:
3286
+ return response.json()
3287
+ except ValueError:
3288
+ return None
3289
+
3290
+ def get_preference_center_by_id(
3291
+ self, PreferenceCenterExternalID: str
3292
+ ) -> dict[str, Any]:
3293
+ """
3294
+ View Details for Preference Center
3295
+
3296
+ Args:
3297
+ PreferenceCenterExternalID (string): PreferenceCenterExternalID
3298
+
3299
+ Returns:
3300
+ dict[str, Any]: Successful response
3301
+
3302
+ Raises:
3303
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3304
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3305
+
3306
+ Tags:
3307
+ Preference Center
3308
+ """
3309
+ if PreferenceCenterExternalID is None:
3310
+ raise ValueError("Missing required parameter 'PreferenceCenterExternalID'.")
3311
+ url = f"{self.base_url}/preference_center/v1/{PreferenceCenterExternalID}"
3312
+ query_params = {}
3313
+ response = self._get(url, params=query_params)
3314
+ response.raise_for_status()
3315
+ if (
3316
+ response.status_code == 204
3317
+ or not response.content
3318
+ or not response.text.strip()
3319
+ ):
3320
+ return None
3321
+ try:
3322
+ return response.json()
3323
+ except ValueError:
3324
+ return None
3325
+
3326
+ def update_preference_center_by_id(
3327
+ self,
3328
+ PreferenceCenterExternalID: str,
3329
+ external_send_id: str | None = None,
3330
+ trigger_properties: dict[str, Any] | None = None,
3331
+ recipient: list[dict[str, Any]] | None = None,
3332
+ ) -> dict[str, Any]:
3333
+ """
3334
+ Update Preference Center
3335
+
3336
+ Args:
3337
+ PreferenceCenterExternalID (string): PreferenceCenterExternalID
3338
+ external_send_id (string): external_send_id Example: 'YOUR_BASE64_COMPATIBLE_ID'.
3339
+ trigger_properties (object): trigger_properties Example: {'example_string_property': 'YOUR_EXAMPLE_STRING', 'example_integer_property': 'YOUR_EXAMPLE_INTEGER'}.
3340
+ recipient (array): recipient Example: [{'external_user_id': 'TARGETED_USER_ID_STRING'}].
3341
+
3342
+ Returns:
3343
+ dict[str, Any]: Successful response
3344
+
3345
+ Raises:
3346
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3347
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3348
+
3349
+ Tags:
3350
+ Preference Center
3351
+ """
3352
+ if PreferenceCenterExternalID is None:
3353
+ raise ValueError("Missing required parameter 'PreferenceCenterExternalID'.")
3354
+ request_body_data = None
3355
+ request_body_data = {
3356
+ "external_send_id": external_send_id,
3357
+ "trigger_properties": trigger_properties,
3358
+ "recipient": recipient,
3359
+ }
3360
+ request_body_data = {
3361
+ k: v for k, v in request_body_data.items() if v is not None
3362
+ }
3363
+ url = f"{self.base_url}/preference_center/v1/{PreferenceCenterExternalID}"
3364
+ query_params = {}
3365
+ response = self._put(
3366
+ url,
3367
+ data=request_body_data,
3368
+ params=query_params,
3369
+ content_type="application/json",
3370
+ )
3371
+ response.raise_for_status()
3372
+ if (
3373
+ response.status_code == 204
3374
+ or not response.content
3375
+ or not response.text.strip()
3376
+ ):
3377
+ return None
3378
+ try:
3379
+ return response.json()
3380
+ except ValueError:
3381
+ return None
3382
+
3383
+ def create_preference_center_entry(
3384
+ self,
3385
+ name: str | None = None,
3386
+ preference_center_title: str | None = None,
3387
+ preference_center_page_html: str | None = None,
3388
+ confirmation_page_html: str | None = None,
3389
+ state: str | None = None,
3390
+ options: dict[str, Any] | None = None,
3391
+ ) -> dict[str, Any]:
3392
+ """
3393
+ Create Preference Center
3394
+
3395
+ Args:
3396
+ name (string): name Example: 'string'.
3397
+ preference_center_title (string): preference_center_title Example: 'string'.
3398
+ preference_center_page_html (string): preference_center_page_html Example: 'string'.
3399
+ confirmation_page_html (string): confirmation_page_html Example: 'string'.
3400
+ state (string): state Example: 'active'.
3401
+ options (object): options Example: {'meta-viewport-content': 'string'}.
3402
+
3403
+ Returns:
3404
+ dict[str, Any]: Successful response
3405
+
3406
+ Raises:
3407
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3408
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3409
+
3410
+ Tags:
3411
+ Preference Center
3412
+ """
3413
+ request_body_data = None
3414
+ request_body_data = {
3415
+ "name": name,
3416
+ "preference_center_title": preference_center_title,
3417
+ "preference_center_page_html": preference_center_page_html,
3418
+ "confirmation_page_html": confirmation_page_html,
3419
+ "state": state,
3420
+ "options": options,
3421
+ }
3422
+ request_body_data = {
3423
+ k: v for k, v in request_body_data.items() if v is not None
3424
+ }
3425
+ url = f"{self.base_url}/preference_center/v1"
3426
+ query_params = {}
3427
+ response = self._post(
3428
+ url,
3429
+ data=request_body_data,
3430
+ params=query_params,
3431
+ content_type="application/json",
3432
+ )
3433
+ response.raise_for_status()
3434
+ if (
3435
+ response.status_code == 204
3436
+ or not response.content
3437
+ or not response.text.strip()
3438
+ ):
3439
+ return None
3440
+ try:
3441
+ return response.json()
3442
+ except ValueError:
3443
+ return None
3444
+
3445
+ def delete_user_by_id(self, id: str) -> dict[str, Any]:
3446
+ """
3447
+ Remove Dashboard User Account
3448
+
3449
+ Args:
3450
+ id (string): id
3451
+
3452
+ Returns:
3453
+ dict[str, Any]: Successful response
3454
+
3455
+ Raises:
3456
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3457
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3458
+
3459
+ Tags:
3460
+ SCIM
3461
+ """
3462
+ if id is None:
3463
+ raise ValueError("Missing required parameter 'id'.")
3464
+ url = f"{self.base_url}/scim/v2/Users/{id}"
3465
+ query_params = {}
3466
+ response = self._delete(url, params=query_params)
3467
+ response.raise_for_status()
3468
+ if (
3469
+ response.status_code == 204
3470
+ or not response.content
3471
+ or not response.text.strip()
3472
+ ):
3473
+ return None
3474
+ try:
3475
+ return response.json()
3476
+ except ValueError:
3477
+ return None
3478
+
3479
+ def get_user_by_id(self, id: str) -> dict[str, Any]:
3480
+ """
3481
+ Look Up an Existing Dashboard User Account
3482
+
3483
+ Args:
3484
+ id (string): id
3485
+
3486
+ Returns:
3487
+ dict[str, Any]: Successful response
3488
+
3489
+ Raises:
3490
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3491
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3492
+
3493
+ Tags:
3494
+ SCIM
3495
+ """
3496
+ if id is None:
3497
+ raise ValueError("Missing required parameter 'id'.")
3498
+ url = f"{self.base_url}/scim/v2/Users/{id}"
3499
+ query_params = {}
3500
+ response = self._get(url, params=query_params)
3501
+ response.raise_for_status()
3502
+ if (
3503
+ response.status_code == 204
3504
+ or not response.content
3505
+ or not response.text.strip()
3506
+ ):
3507
+ return None
3508
+ try:
3509
+ return response.json()
3510
+ except ValueError:
3511
+ return None
3512
+
3513
+ def update_user_by_id(
3514
+ self,
3515
+ id: str,
3516
+ schemas: list[str] | None = None,
3517
+ name: dict[str, Any] | None = None,
3518
+ department: str | None = None,
3519
+ permissions: dict[str, Any] | None = None,
3520
+ ) -> dict[str, Any]:
3521
+ """
3522
+ Update Dashboard User Account
3523
+
3524
+ Args:
3525
+ id (string): id
3526
+ schemas (array): schemas Example: ['urn:ietf:params:scim:schemas:core:2.0:User'].
3527
+ name (object): name Example: {'givenName': 'Test', 'familyName': 'User'}.
3528
+ department (string): department Example: 'finance'.
3529
+ permissions (object): permissions Example: {'companyPermissions': ['manage_company_settings'], 'appGroup': [{'appGroupName': 'Test App Group', 'appGroupPermissions': ['basic_access', 'send_campaigns_canvases'], 'team': [{'teamName': 'Test Team', 'teamPermissions': ['admin']}]}]}.
3530
+
3531
+ Returns:
3532
+ dict[str, Any]: Successful response
3533
+
3534
+ Raises:
3535
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3536
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3537
+
3538
+ Tags:
3539
+ SCIM
3540
+ """
3541
+ if id is None:
3542
+ raise ValueError("Missing required parameter 'id'.")
3543
+ request_body_data = None
3544
+ request_body_data = {
3545
+ "schemas": schemas,
3546
+ "name": name,
3547
+ "department": department,
3548
+ "permissions": permissions,
3549
+ }
3550
+ request_body_data = {
3551
+ k: v for k, v in request_body_data.items() if v is not None
3552
+ }
3553
+ url = f"{self.base_url}/scim/v2/Users/{id}"
3554
+ query_params = {}
3555
+ response = self._put(
3556
+ url,
3557
+ data=request_body_data,
3558
+ params=query_params,
3559
+ content_type="application/json",
3560
+ )
3561
+ response.raise_for_status()
3562
+ if (
3563
+ response.status_code == 204
3564
+ or not response.content
3565
+ or not response.text.strip()
3566
+ ):
3567
+ return None
3568
+ try:
3569
+ return response.json()
3570
+ except ValueError:
3571
+ return None
3572
+
3573
+ def list_users(self, filter: str | None = None) -> dict[str, Any]:
3574
+ """
3575
+ Search Existing Dashboard User by Email
3576
+
3577
+ Args:
3578
+ filter (string): A string parameter used to filter the results of the GET operation by specifying conditions for user attributes, such as `userName`, `externalId`, or name fields. Example: '{userName@example.com}'.
3579
+
3580
+ Returns:
3581
+ dict[str, Any]: Successful response
3582
+
3583
+ Raises:
3584
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3585
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3586
+
3587
+ Tags:
3588
+ SCIM, important
3589
+ """
3590
+ url = f"{self.base_url}/scim/v2/Users"
3591
+ query_params = {k: v for k, v in [("filter", filter)] if v is not None}
3592
+ response = self._get(url, params=query_params)
3593
+ response.raise_for_status()
3594
+ if (
3595
+ response.status_code == 204
3596
+ or not response.content
3597
+ or not response.text.strip()
3598
+ ):
3599
+ return None
3600
+ try:
3601
+ return response.json()
3602
+ except ValueError:
3603
+ return None
3604
+
3605
+ def create_user(
3606
+ self,
3607
+ schemas: list[str] | None = None,
3608
+ userName: str | None = None,
3609
+ name: dict[str, Any] | None = None,
3610
+ department: str | None = None,
3611
+ permissions: dict[str, Any] | None = None,
3612
+ ) -> dict[str, Any]:
3613
+ """
3614
+ Create New Dashboard User Account
3615
+
3616
+ Args:
3617
+ schemas (array): schemas Example: ['urn:ietf:params:scim:schemas:core:2.0:User'].
3618
+ userName (string): userName Example: 'user@test.com'.
3619
+ name (object): name Example: {'givenName': 'Test', 'familyName': 'User'}.
3620
+ department (string): department Example: 'finance'.
3621
+ permissions (object): permissions Example: {'companyPermissions': ['manage_company_settings'], 'appGroup': [{'appGroupName': 'Test App Group', 'appGroupPermissions': ['basic_access', 'send_campaigns_canvases'], 'team': [{'teamName': 'Test Team', 'teamPermissions': ['basic_access', 'export_user_data']}]}]}.
3622
+
3623
+ Returns:
3624
+ dict[str, Any]: Successful response
3625
+
3626
+ Raises:
3627
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3628
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3629
+
3630
+ Tags:
3631
+ SCIM, important
3632
+ """
3633
+ request_body_data = None
3634
+ request_body_data = {
3635
+ "schemas": schemas,
3636
+ "userName": userName,
3637
+ "name": name,
3638
+ "department": department,
3639
+ "permissions": permissions,
3640
+ }
3641
+ request_body_data = {
3642
+ k: v for k, v in request_body_data.items() if v is not None
3643
+ }
3644
+ url = f"{self.base_url}/scim/v2/Users"
3645
+ query_params = {}
3646
+ response = self._post(
3647
+ url,
3648
+ data=request_body_data,
3649
+ params=query_params,
3650
+ content_type="application/json",
3651
+ )
3652
+ response.raise_for_status()
3653
+ if (
3654
+ response.status_code == 204
3655
+ or not response.content
3656
+ or not response.text.strip()
3657
+ ):
3658
+ return None
3659
+ try:
3660
+ return response.json()
3661
+ except ValueError:
3662
+ return None
3663
+
3664
+ def list_invalid_phone_numbers(
3665
+ self,
3666
+ start_date: str | None = None,
3667
+ end_date: str | None = None,
3668
+ limit: int | None = None,
3669
+ offset: int | None = None,
3670
+ phone_numbers: int | None = None,
3671
+ ) -> dict[str, Any]:
3672
+ """
3673
+ Query Invalid Phone Numbers
3674
+
3675
+ Args:
3676
+ start_date (string): (Optional*) String in YYYY-MM-DD format Start date of the range to retrieve invalid phone numbers, must be earlier than `end_date`. This is treated as midnight in UTC time by the API. Example: '2018-09-01'.
3677
+ end_date (string): (Optional*) String in YYYY-MM-DD format End date of the range to retrieve invalid phone numbers. This is treated as midnight in UTC time by the API. Example: '2018-09-01'.
3678
+ limit (integer): (Optional) Integer
3679
+ Optional field to limit the number of results returned. Defaults to 100, maximum is 500. Example: '100'.
3680
+ offset (integer): (Optional) Integer
3681
+ Optional beginning point in the list to retrieve from. Example: '1'.
3682
+ phone_numbers (integer): (Optional*) Array of Strings in e.164 format
3683
+ If provided, we will return the phone number if it has been found to be invalid. Example: '12345678901'.
3684
+
3685
+ Returns:
3686
+ dict[str, Any]: Successful response
3687
+
3688
+ Raises:
3689
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3690
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3691
+
3692
+ Tags:
3693
+ SMS
3694
+ """
3695
+ url = f"{self.base_url}/sms/invalid_phone_numbers"
3696
+ query_params = {
3697
+ k: v
3698
+ for k, v in [
3699
+ ("start_date", start_date),
3700
+ ("end_date", end_date),
3701
+ ("limit", limit),
3702
+ ("offset", offset),
3703
+ ("phone_numbers", phone_numbers),
3704
+ ]
3705
+ if v is not None
3706
+ }
3707
+ response = self._get(url, params=query_params)
3708
+ response.raise_for_status()
3709
+ if (
3710
+ response.status_code == 204
3711
+ or not response.content
3712
+ or not response.text.strip()
3713
+ ):
3714
+ return None
3715
+ try:
3716
+ return response.json()
3717
+ except ValueError:
3718
+ return None
3719
+
3720
+ def remove_invalid_phone_numbers(
3721
+ self, phone_numbers: list[str] | None = None
3722
+ ) -> dict[str, Any]:
3723
+ """
3724
+ Remove Invalid Phone Numbers
3725
+
3726
+ Args:
3727
+ phone_numbers (array): phone_numbers Example: ['12183095514', '14255551212'].
3728
+
3729
+ Returns:
3730
+ dict[str, Any]: Successful response
3731
+
3732
+ Raises:
3733
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3734
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3735
+
3736
+ Tags:
3737
+ SMS
3738
+ """
3739
+ request_body_data = None
3740
+ request_body_data = {
3741
+ "phone_numbers": phone_numbers,
3742
+ }
3743
+ request_body_data = {
3744
+ k: v for k, v in request_body_data.items() if v is not None
3745
+ }
3746
+ url = f"{self.base_url}/sms/invalid_phone_numbers/remove"
3747
+ query_params = {}
3748
+ response = self._post(
3749
+ url,
3750
+ data=request_body_data,
3751
+ params=query_params,
3752
+ content_type="application/json",
3753
+ )
3754
+ response.raise_for_status()
3755
+ if (
3756
+ response.status_code == 204
3757
+ or not response.content
3758
+ or not response.text.strip()
3759
+ ):
3760
+ return None
3761
+ try:
3762
+ return response.json()
3763
+ except ValueError:
3764
+ return None
3765
+
3766
+ def get_subscription_status(
3767
+ self,
3768
+ subscription_group_id: str | None = None,
3769
+ external_id: str | None = None,
3770
+ phone: str | None = None,
3771
+ ) -> dict[str, Any]:
3772
+ """
3773
+ List User's Subscription Group Status - SMS
3774
+
3775
+ Args:
3776
+ subscription_group_id (string): (Required) String The `id` of your subscription group. Example: '{{subscription_group_id}}'.
3777
+ external_id (string): (Required*) String The `external_id` of the user (must include at least one and at most 50 `external_ids`). When both an `external_id` and `phone` are submitted, only the external_id(s) provided will be applied to the result query. Example: '{{external_identifier}}'.
3778
+ phone (string): (Required*) String in [E.164]( format The phone number of the user (must include at least one phone number and at most 50 phone numbers). Example: '+11112223333'.
3779
+
3780
+ Returns:
3781
+ dict[str, Any]: Successful response
3782
+
3783
+ Raises:
3784
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3785
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3786
+
3787
+ Tags:
3788
+ Subscription Groups > SMS and WhatsApp
3789
+ """
3790
+ url = f"{self.base_url}/subscription/status/get"
3791
+ query_params = {
3792
+ k: v
3793
+ for k, v in [
3794
+ ("subscription_group_id", subscription_group_id),
3795
+ ("external_id", external_id),
3796
+ ("phone", phone),
3797
+ ]
3798
+ if v is not None
3799
+ }
3800
+ response = self._get(url, params=query_params)
3801
+ response.raise_for_status()
3802
+ if (
3803
+ response.status_code == 204
3804
+ or not response.content
3805
+ or not response.text.strip()
3806
+ ):
3807
+ return None
3808
+ try:
3809
+ return response.json()
3810
+ except ValueError:
3811
+ return None
3812
+
3813
+ def get_subscription_user_status(
3814
+ self,
3815
+ external_id: str | None = None,
3816
+ limit: int | None = None,
3817
+ offset: int | None = None,
3818
+ phone: str | None = None,
3819
+ ) -> dict[str, Any]:
3820
+ """
3821
+ List User's Subscription Group - SMS
3822
+
3823
+ Args:
3824
+ external_id (string): (Required*) String The `external_id` of the user (must include at least one and at most 50 `external_ids`). Example: '{{external_id}}'.
3825
+ limit (integer): (Optional) Integer The limit on the maximum number of results returned. Default (and max) limit is 100. Example: '100'.
3826
+ offset (integer): (Optional) Integer Number of templates to skip before returning the rest of the templates that fit the search criteria. Example: '1'.
3827
+ phone (string): (Required*) String in [E.164]( format The phone number of the user. Must include at least one phone number (with a max of 50). Example: '+11112223333'.
3828
+
3829
+ Returns:
3830
+ dict[str, Any]: Successful response
3831
+
3832
+ Raises:
3833
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3834
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3835
+
3836
+ Tags:
3837
+ Subscription Groups > SMS and WhatsApp
3838
+ """
3839
+ url = f"{self.base_url}/subscription/user/status"
3840
+ query_params = {
3841
+ k: v
3842
+ for k, v in [
3843
+ ("external_id", external_id),
3844
+ ("limit", limit),
3845
+ ("offset", offset),
3846
+ ("phone", phone),
3847
+ ]
3848
+ if v is not None
3849
+ }
3850
+ response = self._get(url, params=query_params)
3851
+ response.raise_for_status()
3852
+ if (
3853
+ response.status_code == 204
3854
+ or not response.content
3855
+ or not response.text.strip()
3856
+ ):
3857
+ return None
3858
+ try:
3859
+ return response.json()
3860
+ except ValueError:
3861
+ return None
3862
+
3863
+ def set_subscription_status(
3864
+ self,
3865
+ subscription_group_id: str | None = None,
3866
+ subscription_state: str | None = None,
3867
+ external_id: str | None = None,
3868
+ phone: list[str] | None = None,
3869
+ ) -> dict[str, Any]:
3870
+ """
3871
+ Update User's Subscription Group Status - SMS
3872
+
3873
+ Args:
3874
+ subscription_group_id (string): subscription_group_id Example: 'subscription_group_identifier'.
3875
+ subscription_state (string): subscription_state Example: 'unsubscribed'.
3876
+ external_id (string): external_id Example: 'external_identifier'.
3877
+ phone (array): phone Example: ['+12223334444', '+11112223333'].
3878
+
3879
+ Returns:
3880
+ dict[str, Any]: Successful response
3881
+
3882
+ Raises:
3883
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3884
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3885
+
3886
+ Tags:
3887
+ Subscription Groups > SMS and WhatsApp
3888
+ """
3889
+ request_body_data = None
3890
+ request_body_data = {
3891
+ "subscription_group_id": subscription_group_id,
3892
+ "subscription_state": subscription_state,
3893
+ "external_id": external_id,
3894
+ "phone": phone,
3895
+ }
3896
+ request_body_data = {
3897
+ k: v for k, v in request_body_data.items() if v is not None
3898
+ }
3899
+ url = f"{self.base_url}/subscription/status/set"
3900
+ query_params = {}
3901
+ response = self._post(
3902
+ url,
3903
+ data=request_body_data,
3904
+ params=query_params,
3905
+ content_type="application/json",
3906
+ )
3907
+ response.raise_for_status()
3908
+ if (
3909
+ response.status_code == 204
3910
+ or not response.content
3911
+ or not response.text.strip()
3912
+ ):
3913
+ return None
3914
+ try:
3915
+ return response.json()
3916
+ except ValueError:
3917
+ return None
3918
+
3919
+ def set_subscription_status_post(
3920
+ self, subscription_groups: list[dict[str, Any]] | None = None
3921
+ ) -> dict[str, Any]:
3922
+ """
3923
+ Update User's Subscription Group Status V2
3924
+
3925
+ Args:
3926
+ subscription_groups (array): subscription_groups Example: [{'subscription_group_id': 'subscription_group_identifier', 'subscription_state': 'subscribed', 'emails': ['example1@email.com', 'example2@email.com']}].
3927
+
3928
+ Returns:
3929
+ dict[str, Any]: Successful response
3930
+
3931
+ Raises:
3932
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3933
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3934
+
3935
+ Tags:
3936
+ Subscription Groups > SMS and WhatsApp
3937
+ """
3938
+ request_body_data = None
3939
+ request_body_data = {
3940
+ "subscription_groups": subscription_groups,
3941
+ }
3942
+ request_body_data = {
3943
+ k: v for k, v in request_body_data.items() if v is not None
3944
+ }
3945
+ url = f"{self.base_url}/v2/subscription/status/set"
3946
+ query_params = {}
3947
+ response = self._post(
3948
+ url,
3949
+ data=request_body_data,
3950
+ params=query_params,
3951
+ content_type="application/json",
3952
+ )
3953
+ response.raise_for_status()
3954
+ if (
3955
+ response.status_code == 204
3956
+ or not response.content
3957
+ or not response.text.strip()
3958
+ ):
3959
+ return None
3960
+ try:
3961
+ return response.json()
3962
+ except ValueError:
3963
+ return None
3964
+
3965
+ def list_content_blocks(
3966
+ self,
3967
+ modified_after: str | None = None,
3968
+ modified_before: str | None = None,
3969
+ limit: int | None = None,
3970
+ offset: int | None = None,
3971
+ ) -> dict[str, Any]:
3972
+ """
3973
+ List Available Content Blocks
3974
+
3975
+ Args:
3976
+ modified_after (string): (Optional) String in [ISO 8601]( Retrieve only content blocks updated at or after the given time. Example: '2020-01-01T01:01:01.000000'.
3977
+ modified_before (string): (Optional) String in [ISO 8601]( Retrieve only content blocks updated at or before the given time. Example: '2020-02-01T01:01:01.000000'.
3978
+ limit (integer): (Optional) Positive Number Maximum number of content blocks to retrieve. Default to 100 if not provided, with a maximum acceptable value of 1000. Example: '100'.
3979
+ offset (integer): (Optional) Positive Number Number of content blocks to skip before returning rest of the templates that fit the search criteria. Example: '1'.
3980
+
3981
+ Returns:
3982
+ dict[str, Any]: Successful response
3983
+
3984
+ Raises:
3985
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
3986
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
3987
+
3988
+ Tags:
3989
+ Templates > Content Blocks
3990
+ """
3991
+ url = f"{self.base_url}/content_blocks/list"
3992
+ query_params = {
3993
+ k: v
3994
+ for k, v in [
3995
+ ("modified_after", modified_after),
3996
+ ("modified_before", modified_before),
3997
+ ("limit", limit),
3998
+ ("offset", offset),
3999
+ ]
4000
+ if v is not None
4001
+ }
4002
+ response = self._get(url, params=query_params)
4003
+ response.raise_for_status()
4004
+ if (
4005
+ response.status_code == 204
4006
+ or not response.content
4007
+ or not response.text.strip()
4008
+ ):
4009
+ return None
4010
+ try:
4011
+ return response.json()
4012
+ except ValueError:
4013
+ return None
4014
+
4015
+ def get_info_content_block(
4016
+ self,
4017
+ content_block_id: str | None = None,
4018
+ include_inclusion_data: bool | None = None,
4019
+ ) -> dict[str, Any]:
4020
+ """
4021
+ See Content Block Information
4022
+
4023
+ Args:
4024
+ content_block_id (string): (Required) String The content block identifier. You can find this by either listing content block information through an API call or going to **Settings > Setup and Testing > API Keys**, then scrolling to the bottom and searching for your content block API identifier. Example: '{{content_block_id}}'.
4025
+ include_inclusion_data (boolean): (Optional) Boolean When set to `true`, the API returns back the Message Variation API identifier of campaigns and Canvases where this content block is included, to be used in subsequent calls. The results exclude archived or deleted Campaigns or Canvases.
4026
+
4027
+ Returns:
4028
+ dict[str, Any]: Successful response
4029
+
4030
+ Raises:
4031
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
4032
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
4033
+
4034
+ Tags:
4035
+ Templates > Content Blocks
4036
+ """
4037
+ url = f"{self.base_url}/content_blocks/info"
4038
+ query_params = {
4039
+ k: v
4040
+ for k, v in [
4041
+ ("content_block_id", content_block_id),
4042
+ ("include_inclusion_data", include_inclusion_data),
4043
+ ]
4044
+ if v is not None
4045
+ }
4046
+ response = self._get(url, params=query_params)
4047
+ response.raise_for_status()
4048
+ if (
4049
+ response.status_code == 204
4050
+ or not response.content
4051
+ or not response.text.strip()
4052
+ ):
4053
+ return None
4054
+ try:
4055
+ return response.json()
4056
+ except ValueError:
4057
+ return None
4058
+
4059
+ def create_content_block(
4060
+ self,
4061
+ name: str | None = None,
4062
+ description: str | None = None,
4063
+ content: str | None = None,
4064
+ state: str | None = None,
4065
+ tags: list[str] | None = None,
4066
+ ) -> dict[str, Any]:
4067
+ """
4068
+ Create Content Block
4069
+
4070
+ Args:
4071
+ name (string): name Example: 'content_block'.
4072
+ description (string): description Example: 'This is my content block'.
4073
+ content (string): content Example: 'HTML content within block'.
4074
+ state (string): state Example: 'draft'.
4075
+ tags (array): tags Example: ['marketing'].
4076
+
4077
+ Returns:
4078
+ dict[str, Any]: Successful response
4079
+
4080
+ Raises:
4081
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
4082
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
4083
+
4084
+ Tags:
4085
+ Templates > Content Blocks, important
4086
+ """
4087
+ request_body_data = None
4088
+ request_body_data = {
4089
+ "name": name,
4090
+ "description": description,
4091
+ "content": content,
4092
+ "state": state,
4093
+ "tags": tags,
4094
+ }
4095
+ request_body_data = {
4096
+ k: v for k, v in request_body_data.items() if v is not None
4097
+ }
4098
+ url = f"{self.base_url}/content_blocks/create"
4099
+ query_params = {}
4100
+ response = self._post(
4101
+ url,
4102
+ data=request_body_data,
4103
+ params=query_params,
4104
+ content_type="application/json",
4105
+ )
4106
+ response.raise_for_status()
4107
+ if (
4108
+ response.status_code == 204
4109
+ or not response.content
4110
+ or not response.text.strip()
4111
+ ):
4112
+ return None
4113
+ try:
4114
+ return response.json()
4115
+ except ValueError:
4116
+ return None
4117
+
4118
+ def update_content_block(
4119
+ self,
4120
+ content_block_id: str | None = None,
4121
+ name: str | None = None,
4122
+ description: str | None = None,
4123
+ content: str | None = None,
4124
+ state: str | None = None,
4125
+ tags: list[str] | None = None,
4126
+ ) -> dict[str, Any]:
4127
+ """
4128
+ Update Content Block
4129
+
4130
+ Args:
4131
+ content_block_id (string): content_block_id Example: 'content_block_id'.
4132
+ name (string): name Example: 'content_block'.
4133
+ description (string): description Example: 'This is my content block'.
4134
+ content (string): content Example: 'HTML or text content within block'.
4135
+ state (string): state Example: 'draft'.
4136
+ tags (array): tags Example: ['marketing'].
4137
+
4138
+ Returns:
4139
+ dict[str, Any]: Successful response
4140
+
4141
+ Raises:
4142
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
4143
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
4144
+
4145
+ Tags:
4146
+ Templates > Content Blocks
4147
+ """
4148
+ request_body_data = None
4149
+ request_body_data = {
4150
+ "content_block_id": content_block_id,
4151
+ "name": name,
4152
+ "description": description,
4153
+ "content": content,
4154
+ "state": state,
4155
+ "tags": tags,
4156
+ }
4157
+ request_body_data = {
4158
+ k: v for k, v in request_body_data.items() if v is not None
4159
+ }
4160
+ url = f"{self.base_url}/content_blocks/update"
4161
+ query_params = {}
4162
+ response = self._post(
4163
+ url,
4164
+ data=request_body_data,
4165
+ params=query_params,
4166
+ content_type="application/json",
4167
+ )
4168
+ response.raise_for_status()
4169
+ if (
4170
+ response.status_code == 204
4171
+ or not response.content
4172
+ or not response.text.strip()
4173
+ ):
4174
+ return None
4175
+ try:
4176
+ return response.json()
4177
+ except ValueError:
4178
+ return None
4179
+
4180
+ def list_email_templates(
4181
+ self,
4182
+ modified_after: str | None = None,
4183
+ modified_before: str | None = None,
4184
+ limit: int | None = None,
4185
+ offset: int | None = None,
4186
+ ) -> dict[str, Any]:
4187
+ """
4188
+ List Available Email Templates
4189
+
4190
+ Args:
4191
+ modified_after (string): (Optional) String in [ISO 8601]( Retrieve only templates updated at or after the given time. Example: '2020-01-01T01:01:01.000000'.
4192
+ modified_before (string): (Optional) String in [ISO 8601]( Retrieve only templates updated at or before the given time. Example: '2020-02-01T01:01:01.000000'.
4193
+ limit (integer): (Optional) Positive Number Maximum number of templates to retrieve. Default to 100 if not provided, with a maximum acceptable value of 1000. Example: '1'.
4194
+ offset (integer): (Optional) Positive Number Number of templates to skip before returning rest of the templates that fit the search criteria.
4195
+
4196
+ Returns:
4197
+ dict[str, Any]: Successful response
4198
+
4199
+ Raises:
4200
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
4201
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
4202
+
4203
+ Tags:
4204
+ Templates > Email Templates
4205
+ """
4206
+ url = f"{self.base_url}/templates/email/list"
4207
+ query_params = {
4208
+ k: v
4209
+ for k, v in [
4210
+ ("modified_after", modified_after),
4211
+ ("modified_before", modified_before),
4212
+ ("limit", limit),
4213
+ ("offset", offset),
4214
+ ]
4215
+ if v is not None
4216
+ }
4217
+ response = self._get(url, params=query_params)
4218
+ response.raise_for_status()
4219
+ if (
4220
+ response.status_code == 204
4221
+ or not response.content
4222
+ or not response.text.strip()
4223
+ ):
4224
+ return None
4225
+ try:
4226
+ return response.json()
4227
+ except ValueError:
4228
+ return None
4229
+
4230
+ def get_email_template_info(
4231
+ self, email_template_id: str | None = None
4232
+ ) -> dict[str, Any]:
4233
+ """
4234
+ See Email Template Information
4235
+
4236
+ Args:
4237
+ email_template_id (string): (Required) String See [email template's API identifier]( Example: '{{email_template_id}}'.
4238
+
4239
+ Returns:
4240
+ dict[str, Any]: Successful response
4241
+
4242
+ Raises:
4243
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
4244
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
4245
+
4246
+ Tags:
4247
+ Templates > Email Templates
4248
+ """
4249
+ url = f"{self.base_url}/templates/email/info"
4250
+ query_params = {
4251
+ k: v for k, v in [("email_template_id", email_template_id)] if v is not None
4252
+ }
4253
+ response = self._get(url, params=query_params)
4254
+ response.raise_for_status()
4255
+ if (
4256
+ response.status_code == 204
4257
+ or not response.content
4258
+ or not response.text.strip()
4259
+ ):
4260
+ return None
4261
+ try:
4262
+ return response.json()
4263
+ except ValueError:
4264
+ return None
4265
+
4266
+ def create_email_template(
4267
+ self,
4268
+ template_name: str | None = None,
4269
+ subject: str | None = None,
4270
+ body: str | None = None,
4271
+ plaintext_body: str | None = None,
4272
+ preheader: str | None = None,
4273
+ tags: list[str] | None = None,
4274
+ ) -> dict[str, Any]:
4275
+ """
4276
+ Create Email Template
4277
+
4278
+ Args:
4279
+ template_name (string): template_name Example: 'email_template_name'.
4280
+ subject (string): subject Example: 'Welcome to my email template!'.
4281
+ body (string): body Example: 'This is the text within my email body and https://www.braze.com/ here is a link to Braze.com.'.
4282
+ plaintext_body (string): plaintext_body Example: 'This is the text within my email body and here is a link to https://www.braze.com/.'.
4283
+ preheader (string): preheader Example: 'My preheader is pretty cool.'.
4284
+ tags (array): tags Example: ['Tag1', 'Tag2'].
4285
+
4286
+ Returns:
4287
+ dict[str, Any]: Successful response
4288
+
4289
+ Raises:
4290
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
4291
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
4292
+
4293
+ Tags:
4294
+ Templates > Email Templates
4295
+ """
4296
+ request_body_data = None
4297
+ request_body_data = {
4298
+ "template_name": template_name,
4299
+ "subject": subject,
4300
+ "body": body,
4301
+ "plaintext_body": plaintext_body,
4302
+ "preheader": preheader,
4303
+ "tags": tags,
4304
+ }
4305
+ request_body_data = {
4306
+ k: v for k, v in request_body_data.items() if v is not None
4307
+ }
4308
+ url = f"{self.base_url}/templates/email/create"
4309
+ query_params = {}
4310
+ response = self._post(
4311
+ url,
4312
+ data=request_body_data,
4313
+ params=query_params,
4314
+ content_type="application/json",
4315
+ )
4316
+ response.raise_for_status()
4317
+ if (
4318
+ response.status_code == 204
4319
+ or not response.content
4320
+ or not response.text.strip()
4321
+ ):
4322
+ return None
4323
+ try:
4324
+ return response.json()
4325
+ except ValueError:
4326
+ return None
4327
+
4328
+ def rename_external_id(
4329
+ self, external_id_renames: list[dict[str, Any]] | None = None
4330
+ ) -> dict[str, Any]:
4331
+ """
4332
+ Rename External ID
4333
+
4334
+ Args:
4335
+ external_id_renames (array): external_id_renames Example: [{'current_external_id': 'existing_external_id', 'new_external_id': 'new_external_id'}].
4336
+
4337
+ Returns:
4338
+ dict[str, Any]: Successful response
4339
+
4340
+ Raises:
4341
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
4342
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
4343
+
4344
+ Tags:
4345
+ User Data > External ID Migration
4346
+ """
4347
+ request_body_data = None
4348
+ request_body_data = {
4349
+ "external_id_renames": external_id_renames,
4350
+ }
4351
+ request_body_data = {
4352
+ k: v for k, v in request_body_data.items() if v is not None
4353
+ }
4354
+ url = f"{self.base_url}/users/external_ids/rename"
4355
+ query_params = {}
4356
+ response = self._post(
4357
+ url,
4358
+ data=request_body_data,
4359
+ params=query_params,
4360
+ content_type="application/json",
4361
+ )
4362
+ response.raise_for_status()
4363
+ if (
4364
+ response.status_code == 204
4365
+ or not response.content
4366
+ or not response.text.strip()
4367
+ ):
4368
+ return None
4369
+ try:
4370
+ return response.json()
4371
+ except ValueError:
4372
+ return None
4373
+
4374
+ def remove_external_id(
4375
+ self, external_ids: list[str] | None = None
4376
+ ) -> dict[str, Any]:
4377
+ """
4378
+ Remove External ID
4379
+
4380
+ Args:
4381
+ external_ids (array): external_ids Example: ['existing_deprecated_external_id_string'].
4382
+
4383
+ Returns:
4384
+ dict[str, Any]: Successful response
4385
+
4386
+ Raises:
4387
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
4388
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
4389
+
4390
+ Tags:
4391
+ User Data > External ID Migration
4392
+ """
4393
+ request_body_data = None
4394
+ request_body_data = {
4395
+ "external_ids": external_ids,
4396
+ }
4397
+ request_body_data = {
4398
+ k: v for k, v in request_body_data.items() if v is not None
4399
+ }
4400
+ url = f"{self.base_url}/users/external_ids/remove"
4401
+ query_params = {}
4402
+ response = self._post(
4403
+ url,
4404
+ data=request_body_data,
4405
+ params=query_params,
4406
+ content_type="application/json",
4407
+ )
4408
+ response.raise_for_status()
4409
+ if (
4410
+ response.status_code == 204
4411
+ or not response.content
4412
+ or not response.text.strip()
4413
+ ):
4414
+ return None
4415
+ try:
4416
+ return response.json()
4417
+ except ValueError:
4418
+ return None
4419
+
4420
+ def update_user_alias(
4421
+ self, alias_updates: list[dict[str, Any]] | None = None
4422
+ ) -> dict[str, Any]:
4423
+ """
4424
+ Update User Alias
4425
+
4426
+ Args:
4427
+ alias_updates (array): alias_updates Example: [{'alias_label': 'example_alias_label', 'old_alias_name': 'example_old_alias_name', 'new_alias_name': 'example_new_alias_name'}].
4428
+
4429
+ Returns:
4430
+ dict[str, Any]: Successful response
4431
+
4432
+ Raises:
4433
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
4434
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
4435
+
4436
+ Tags:
4437
+ User Data
4438
+ """
4439
+ request_body_data = None
4440
+ request_body_data = {
4441
+ "alias_updates": alias_updates,
4442
+ }
4443
+ request_body_data = {
4444
+ k: v for k, v in request_body_data.items() if v is not None
4445
+ }
4446
+ url = f"{self.base_url}/users/alias/update"
4447
+ query_params = {}
4448
+ response = self._post(
4449
+ url,
4450
+ data=request_body_data,
4451
+ params=query_params,
4452
+ content_type="application/json",
4453
+ )
4454
+ response.raise_for_status()
4455
+ if (
4456
+ response.status_code == 204
4457
+ or not response.content
4458
+ or not response.text.strip()
4459
+ ):
4460
+ return None
4461
+ try:
4462
+ return response.json()
4463
+ except ValueError:
4464
+ return None
4465
+
4466
+ def create_user_alias_new(
4467
+ self, user_aliases: list[dict[str, Any]] | None = None
4468
+ ) -> dict[str, Any]:
4469
+ """
4470
+ Create New User Aliases
4471
+
4472
+ Args:
4473
+ user_aliases (array): user_aliases Example: [{'external_id': 'external_identifier', 'alias_name': 'example_name', 'alias_label': 'example_label'}].
4474
+
4475
+ Returns:
4476
+ dict[str, Any]: Successful response
4477
+
4478
+ Raises:
4479
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
4480
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
4481
+
4482
+ Tags:
4483
+ User Data
4484
+ """
4485
+ request_body_data = None
4486
+ request_body_data = {
4487
+ "user_aliases": user_aliases,
4488
+ }
4489
+ request_body_data = {
4490
+ k: v for k, v in request_body_data.items() if v is not None
4491
+ }
4492
+ url = f"{self.base_url}/users/alias/new"
4493
+ query_params = {}
4494
+ response = self._post(
4495
+ url,
4496
+ data=request_body_data,
4497
+ params=query_params,
4498
+ content_type="application/json",
4499
+ )
4500
+ response.raise_for_status()
4501
+ if (
4502
+ response.status_code == 204
4503
+ or not response.content
4504
+ or not response.text.strip()
4505
+ ):
4506
+ return None
4507
+ try:
4508
+ return response.json()
4509
+ except ValueError:
4510
+ return None
4511
+
4512
+ def delete_user(
4513
+ self,
4514
+ external_ids: list[str] | None = None,
4515
+ braze_ids: list[str] | None = None,
4516
+ user_aliases: list[dict[str, Any]] | None = None,
4517
+ ) -> dict[str, Any]:
4518
+ """
4519
+ Delete Users
4520
+
4521
+ Args:
4522
+ external_ids (array): external_ids Example: ['external_identifier1', 'external_identifier2'].
4523
+ braze_ids (array): braze_ids Example: ['braze_identifier1', 'braze_identifier2'].
4524
+ user_aliases (array): user_aliases Example: [{'alias_name': 'user_alias1', 'alias_label': 'alias_label1'}, {'alias_name': 'user_alias2', 'alias_label': 'alias_label2'}].
4525
+
4526
+ Returns:
4527
+ dict[str, Any]: Successful response
4528
+
4529
+ Raises:
4530
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
4531
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
4532
+
4533
+ Tags:
4534
+ User Data
4535
+ """
4536
+ request_body_data = None
4537
+ request_body_data = {
4538
+ "external_ids": external_ids,
4539
+ "braze_ids": braze_ids,
4540
+ "user_aliases": user_aliases,
4541
+ }
4542
+ request_body_data = {
4543
+ k: v for k, v in request_body_data.items() if v is not None
4544
+ }
4545
+ url = f"{self.base_url}/users/delete"
4546
+ query_params = {}
4547
+ response = self._post(
4548
+ url,
4549
+ data=request_body_data,
4550
+ params=query_params,
4551
+ content_type="application/json",
4552
+ )
4553
+ response.raise_for_status()
4554
+ if (
4555
+ response.status_code == 204
4556
+ or not response.content
4557
+ or not response.text.strip()
4558
+ ):
4559
+ return None
4560
+ try:
4561
+ return response.json()
4562
+ except ValueError:
4563
+ return None
4564
+
4565
+ def identify_user(
4566
+ self, aliases_to_identify: list[dict[str, Any]] | None = None
4567
+ ) -> dict[str, Any]:
4568
+ """
4569
+ Identify Users
4570
+
4571
+ Args:
4572
+ aliases_to_identify (array): aliases_to_identify Example: [{'external_id': 'external_identifier', 'user_alias': {'alias_name': 'example_alias', 'alias_label': 'example_label'}}].
4573
+
4574
+ Returns:
4575
+ dict[str, Any]: Successful response
4576
+
4577
+ Raises:
4578
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
4579
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
4580
+
4581
+ Tags:
4582
+ User Data
4583
+ """
4584
+ request_body_data = None
4585
+ request_body_data = {
4586
+ "aliases_to_identify": aliases_to_identify,
4587
+ }
4588
+ request_body_data = {
4589
+ k: v for k, v in request_body_data.items() if v is not None
4590
+ }
4591
+ url = f"{self.base_url}/users/identify"
4592
+ query_params = {}
4593
+ response = self._post(
4594
+ url,
4595
+ data=request_body_data,
4596
+ params=query_params,
4597
+ content_type="application/json",
4598
+ )
4599
+ response.raise_for_status()
4600
+ if (
4601
+ response.status_code == 204
4602
+ or not response.content
4603
+ or not response.text.strip()
4604
+ ):
4605
+ return None
4606
+ try:
4607
+ return response.json()
4608
+ except ValueError:
4609
+ return None
4610
+
4611
+ def merge_users_post(
4612
+ self, merge_updates: list[dict[str, Any]] | None = None
4613
+ ) -> dict[str, Any]:
4614
+ """
4615
+ Merge Users
4616
+
4617
+ Args:
4618
+ merge_updates (array): merge_updates Example: [{'identifier_to_merge': {'external_id': 'old-user1'}, 'identifier_to_keep': {'external_id': 'current-user1'}}, {'identifier_to_merge': {'user_alias': {'alias_name': 'old-user2@example.com', 'alias_label': 'email'}}, 'identifier_to_keep': {'user_alias': {'alias_name': 'current-user2@example.com', 'alias_label': 'email'}}}].
4619
+
4620
+ Returns:
4621
+ dict[str, Any]: Successful response
4622
+
4623
+ Raises:
4624
+ HTTPError: Raised when the API request fails (e.g., non-2XX status code).
4625
+ JSONDecodeError: Raised if the response body cannot be parsed as JSON.
4626
+
4627
+ Tags:
4628
+ User Data
4629
+ """
4630
+ request_body_data = None
4631
+ request_body_data = {
4632
+ "merge_updates": merge_updates,
4633
+ }
4634
+ request_body_data = {
4635
+ k: v for k, v in request_body_data.items() if v is not None
4636
+ }
4637
+ url = f"{self.base_url}/users/merge"
4638
+ query_params = {}
4639
+ response = self._post(
4640
+ url,
4641
+ data=request_body_data,
4642
+ params=query_params,
4643
+ content_type="application/json",
4644
+ )
4645
+ response.raise_for_status()
4646
+ if (
4647
+ response.status_code == 204
4648
+ or not response.content
4649
+ or not response.text.strip()
4650
+ ):
4651
+ return None
4652
+ try:
4653
+ return response.json()
4654
+ except ValueError:
4655
+ return None
4656
+
4657
+ def list_tools(self):
4658
+ return [
4659
+ self.update_email_template,
4660
+ self.track_user_activity,
4661
+ self.delete_catalog_by_name,
4662
+ self.list_catalogs,
4663
+ self.create_catalog,
4664
+ self.delete_catalog_item,
4665
+ self.edit_catalog_item,
4666
+ self.create_catalog_item,
4667
+ self.update_catalog_items,
4668
+ self.list_catalog_items,
4669
+ self.delete_catalog_item_by_id,
4670
+ self.get_item_detail,
4671
+ self.update_catalog_item_by_id,
4672
+ self.add_catalog_item_by_id,
4673
+ self.update_catalog_item,
4674
+ self.list_hard_bounces,
4675
+ self.list_unsubscribes,
4676
+ self.post_email_status,
4677
+ self.remove_bounced_email,
4678
+ self.remove_email_spam,
4679
+ self.add_email_to_blocklist,
4680
+ self.add_to_blacklist,
4681
+ self.get_campaign_data_series,
4682
+ self.get_campaign_details,
4683
+ self.list_campaigns,
4684
+ self.get_send_data_series,
4685
+ self.get_canvas_data_series,
4686
+ self.fetch_canvas_data_summary,
4687
+ self.get_canvas_details,
4688
+ self.list_canvas,
4689
+ self.list_events,
4690
+ self.fetch_event_series_data,
4691
+ self.list_new_user_kpi_series,
4692
+ self.get_daily_active_users_series,
4693
+ self.get_kpimau_data_series,
4694
+ self.get_kpi_uninstalls_data_series,
4695
+ self.get_feed_data_series,
4696
+ self.get_feed_details,
4697
+ self.list_feed,
4698
+ self.list_products,
4699
+ self.get_purchase_quantity_series,
4700
+ self.get_purchases_revenue_series,
4701
+ self.list_segments,
4702
+ self.get_segments_data_series,
4703
+ self.get_segment_details,
4704
+ self.get_sessions_data_series,
4705
+ self.export_user_ids_by_post,
4706
+ self.export_users_by_segment_post,
4707
+ self.export_global_control_group_users,
4708
+ self.update_live_activity_message,
4709
+ self.list_scheduled_broadcasts,
4710
+ self.delete_scheduled_message,
4711
+ self.schedule_delete_canvas_trigger,
4712
+ self.delete_campaign_schedule,
4713
+ self.create_scheduled_message,
4714
+ self.create_schedule,
4715
+ self.create_schedule_trigger,
4716
+ self.schedule_message_update,
4717
+ self.update_campaign_trigger_schedule,
4718
+ self.update_canvas_trigger_schedule,
4719
+ self.create_send_by_id,
4720
+ self.send_message,
4721
+ self.send_campaign_transactional,
4722
+ self.send_campaign_trigger,
4723
+ self.send_canvas_trigger_post,
4724
+ self.get_preference_center_url_by_user_id,
4725
+ self.list_preferences,
4726
+ self.get_preference_center_by_id,
4727
+ self.update_preference_center_by_id,
4728
+ self.create_preference_center_entry,
4729
+ self.delete_user_by_id,
4730
+ self.get_user_by_id,
4731
+ self.update_user_by_id,
4732
+ self.list_users,
4733
+ self.create_user,
4734
+ self.list_invalid_phone_numbers,
4735
+ self.remove_invalid_phone_numbers,
4736
+ self.get_subscription_status,
4737
+ self.get_subscription_user_status,
4738
+ self.set_subscription_status,
4739
+ self.set_subscription_status_post,
4740
+ self.list_content_blocks,
4741
+ self.get_info_content_block,
4742
+ self.create_content_block,
4743
+ self.update_content_block,
4744
+ self.list_email_templates,
4745
+ self.get_email_template_info,
4746
+ self.create_email_template,
4747
+ self.rename_external_id,
4748
+ self.remove_external_id,
4749
+ self.update_user_alias,
4750
+ self.create_user_alias_new,
4751
+ self.delete_user,
4752
+ self.identify_user,
4753
+ self.merge_users_post,
4754
+ ]