linq-python 0.1.0__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 (139) hide show
  1. linq/__init__.py +102 -0
  2. linq/_base_client.py +2149 -0
  3. linq/_client.py +2479 -0
  4. linq/_compat.py +226 -0
  5. linq/_constants.py +14 -0
  6. linq/_exceptions.py +108 -0
  7. linq/_files.py +123 -0
  8. linq/_models.py +878 -0
  9. linq/_qs.py +153 -0
  10. linq/_resource.py +43 -0
  11. linq/_response.py +833 -0
  12. linq/_streaming.py +338 -0
  13. linq/_types.py +271 -0
  14. linq/_utils/__init__.py +65 -0
  15. linq/_utils/_compat.py +45 -0
  16. linq/_utils/_datetime_parse.py +136 -0
  17. linq/_utils/_json.py +35 -0
  18. linq/_utils/_logs.py +25 -0
  19. linq/_utils/_path.py +127 -0
  20. linq/_utils/_proxy.py +65 -0
  21. linq/_utils/_reflection.py +42 -0
  22. linq/_utils/_resources_proxy.py +24 -0
  23. linq/_utils/_streams.py +12 -0
  24. linq/_utils/_sync.py +58 -0
  25. linq/_utils/_transform.py +457 -0
  26. linq/_utils/_typing.py +156 -0
  27. linq/_utils/_utils.py +421 -0
  28. linq/_version.py +4 -0
  29. linq/lib/.keep +4 -0
  30. linq/pagination.py +95 -0
  31. linq/py.typed +0 -0
  32. linq/resources/__init__.py +134 -0
  33. linq/resources/attachments.py +589 -0
  34. linq/resources/capability.py +297 -0
  35. linq/resources/chats/__init__.py +61 -0
  36. linq/resources/chats/chats.py +1492 -0
  37. linq/resources/chats/messages.py +416 -0
  38. linq/resources/chats/participants.py +322 -0
  39. linq/resources/chats/typing.py +299 -0
  40. linq/resources/contact_card.py +472 -0
  41. linq/resources/messages.py +686 -0
  42. linq/resources/phone_numbers.py +163 -0
  43. linq/resources/phonenumbers.py +165 -0
  44. linq/resources/webhook_events.py +319 -0
  45. linq/resources/webhook_subscriptions.py +776 -0
  46. linq/resources/webhooks.py +34 -0
  47. linq/types/__init__.py +90 -0
  48. linq/types/attachment_create_params.py +42 -0
  49. linq/types/attachment_create_response.py +44 -0
  50. linq/types/attachment_retrieve_response.py +55 -0
  51. linq/types/capability_check_RCS_params.py +20 -0
  52. linq/types/capability_check_i_message_params.py +20 -0
  53. linq/types/chat.py +44 -0
  54. linq/types/chat_create_params.py +33 -0
  55. linq/types/chat_create_response.py +44 -0
  56. linq/types/chat_created_webhook_event.py +87 -0
  57. linq/types/chat_group_icon_update_failed_webhook_event.py +65 -0
  58. linq/types/chat_group_icon_updated_webhook_event.py +66 -0
  59. linq/types/chat_group_name_update_failed_webhook_event.py +65 -0
  60. linq/types/chat_group_name_updated_webhook_event.py +66 -0
  61. linq/types/chat_leave_chat_response.py +15 -0
  62. linq/types/chat_list_chats_params.py +36 -0
  63. linq/types/chat_send_voicememo_params.py +23 -0
  64. linq/types/chat_send_voicememo_response.py +79 -0
  65. linq/types/chat_typing_indicator_started_webhook_event.py +52 -0
  66. linq/types/chat_typing_indicator_stopped_webhook_event.py +52 -0
  67. linq/types/chat_update_params.py +15 -0
  68. linq/types/chat_update_response.py +13 -0
  69. linq/types/chats/__init__.py +12 -0
  70. linq/types/chats/message_list_params.py +15 -0
  71. linq/types/chats/message_send_params.py +18 -0
  72. linq/types/chats/message_send_response.py +16 -0
  73. linq/types/chats/participant_add_params.py +12 -0
  74. linq/types/chats/participant_add_response.py +15 -0
  75. linq/types/chats/participant_remove_params.py +12 -0
  76. linq/types/chats/participant_remove_response.py +15 -0
  77. linq/types/chats/sent_message.py +69 -0
  78. linq/types/contact_card_create_params.py +24 -0
  79. linq/types/contact_card_retrieve_params.py +15 -0
  80. linq/types/contact_card_retrieve_response.py +23 -0
  81. linq/types/contact_card_update_params.py +21 -0
  82. linq/types/events_webhook_event.py +50 -0
  83. linq/types/handle_check_response.py +13 -0
  84. linq/types/link_part_param.py +22 -0
  85. linq/types/media_part_param.py +54 -0
  86. linq/types/message.py +87 -0
  87. linq/types/message_add_reaction_params.py +32 -0
  88. linq/types/message_add_reaction_response.py +15 -0
  89. linq/types/message_content_param.py +82 -0
  90. linq/types/message_delivered_webhook_event.py +65 -0
  91. linq/types/message_edited_webhook_event.py +100 -0
  92. linq/types/message_effect.py +23 -0
  93. linq/types/message_effect_param.py +22 -0
  94. linq/types/message_event_v2.py +116 -0
  95. linq/types/message_failed_webhook_event.py +72 -0
  96. linq/types/message_list_messages_thread_params.py +18 -0
  97. linq/types/message_read_webhook_event.py +65 -0
  98. linq/types/message_received_webhook_event.py +65 -0
  99. linq/types/message_sent_webhook_event.py +65 -0
  100. linq/types/message_update_params.py +15 -0
  101. linq/types/participant_added_webhook_event.py +66 -0
  102. linq/types/participant_removed_webhook_event.py +66 -0
  103. linq/types/phone_number_list_response.py +20 -0
  104. linq/types/phone_number_status_updated_webhook_event.py +82 -0
  105. linq/types/phonenumber_list_response.py +39 -0
  106. linq/types/reaction_added_webhook_event.py +46 -0
  107. linq/types/reaction_event_base.py +85 -0
  108. linq/types/reaction_removed_webhook_event.py +46 -0
  109. linq/types/reply_to.py +21 -0
  110. linq/types/reply_to_param.py +21 -0
  111. linq/types/schemas_media_part_response.py +29 -0
  112. linq/types/schemas_message_effect.py +18 -0
  113. linq/types/schemas_text_part_response.py +22 -0
  114. linq/types/set_contact_card.py +24 -0
  115. linq/types/shared/__init__.py +9 -0
  116. linq/types/shared/chat_handle.py +33 -0
  117. linq/types/shared/media_part_response.py +34 -0
  118. linq/types/shared/reaction.py +56 -0
  119. linq/types/shared/reaction_type.py +7 -0
  120. linq/types/shared/service_type.py +7 -0
  121. linq/types/shared/text_decoration.py +23 -0
  122. linq/types/shared/text_part_response.py +26 -0
  123. linq/types/shared_params/__init__.py +5 -0
  124. linq/types/shared_params/reaction_type.py +9 -0
  125. linq/types/shared_params/service_type.py +9 -0
  126. linq/types/shared_params/text_decoration.py +23 -0
  127. linq/types/supported_content_type.py +60 -0
  128. linq/types/text_part_param.py +44 -0
  129. linq/types/webhook_event_list_response.py +17 -0
  130. linq/types/webhook_event_type.py +33 -0
  131. linq/types/webhook_subscription.py +35 -0
  132. linq/types/webhook_subscription_create_params.py +27 -0
  133. linq/types/webhook_subscription_create_response.py +46 -0
  134. linq/types/webhook_subscription_list_response.py +13 -0
  135. linq/types/webhook_subscription_update_params.py +30 -0
  136. linq_python-0.1.0.dist-info/METADATA +572 -0
  137. linq_python-0.1.0.dist-info/RECORD +139 -0
  138. linq_python-0.1.0.dist-info/WHEEL +4 -0
  139. linq_python-0.1.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,589 @@
1
+ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
+
3
+ from __future__ import annotations
4
+
5
+ import httpx
6
+
7
+ from ..types import SupportedContentType, attachment_create_params
8
+ from .._types import Body, Query, Headers, NotGiven, not_given
9
+ from .._utils import path_template, maybe_transform, async_maybe_transform
10
+ from .._compat import cached_property
11
+ from .._resource import SyncAPIResource, AsyncAPIResource
12
+ from .._response import (
13
+ to_raw_response_wrapper,
14
+ to_streamed_response_wrapper,
15
+ async_to_raw_response_wrapper,
16
+ async_to_streamed_response_wrapper,
17
+ )
18
+ from .._base_client import make_request_options
19
+ from ..types.supported_content_type import SupportedContentType
20
+ from ..types.attachment_create_response import AttachmentCreateResponse
21
+ from ..types.attachment_retrieve_response import AttachmentRetrieveResponse
22
+
23
+ __all__ = ["AttachmentsResource", "AsyncAttachmentsResource"]
24
+
25
+
26
+ class AttachmentsResource(SyncAPIResource):
27
+ """
28
+ Send files (images, videos, documents, audio) with messages by providing a URL in a media part.
29
+ Pre-uploading via `POST /v3/attachments` is **optional** and only needed for specific optimization scenarios.
30
+
31
+ ## Sending Media via URL (up to 10MB)
32
+
33
+ Provide a publicly accessible HTTPS URL with a [supported media type](#supported-file-types) in the `url` field of a media part.
34
+
35
+ ```json
36
+ {
37
+ "parts": [
38
+ { "type": "media", "url": "https://your-cdn.com/images/photo.jpg" }
39
+ ]
40
+ }
41
+ ```
42
+
43
+ This works with any URL you already host — no pre-upload step required. **Maximum file size: 10MB.**
44
+
45
+ ## Pre-Upload (required for files over 10MB)
46
+
47
+ Use `POST /v3/attachments` when you want to:
48
+ - **Send files larger than 10MB** (up to 100MB) — URL-based downloads are limited to 10MB
49
+ - **Send the same file to many recipients** — upload once, reuse the `attachment_id` without re-downloading each time
50
+ - **Reduce message send latency** — the file is already stored, so sending is faster
51
+
52
+ **How it works:**
53
+ 1. `POST /v3/attachments` with file metadata → returns a presigned `upload_url` (valid for **15 minutes**) and a permanent `attachment_id`
54
+ 2. PUT the raw file bytes to the `upload_url` with the `required_headers` (no JSON or multipart — just the binary content)
55
+ 3. Reference the `attachment_id` in your media part when sending messages (no expiration)
56
+
57
+ **Key difference:** When you provide an external `url`, we download and process the file on every send.
58
+ When you use a pre-uploaded `attachment_id`, the file is already stored — so repeated sends skip the download step entirely.
59
+
60
+ ## Domain Allowlisting
61
+
62
+ Attachment URLs in API responses are served from `cdn.linqapp.com`. This includes:
63
+ - `url` fields in media and voice memo message parts
64
+ - `download_url` fields in attachment and upload response objects
65
+
66
+ If your application enforces domain allowlists (e.g., for SSRF protection), add:
67
+
68
+ ```
69
+ cdn.linqapp.com
70
+ ```
71
+
72
+ ## Supported File Types
73
+
74
+ - **Images:** JPEG, PNG, GIF, HEIC, HEIF, TIFF, BMP
75
+ - **Videos:** MP4, MOV, M4V
76
+ - **Audio:** M4A, AAC, MP3, WAV, AIFF, CAF, AMR
77
+ - **Documents:** PDF, TXT, RTF, CSV, Office formats, ZIP
78
+ - **Contact & Calendar:** VCF, ICS
79
+
80
+ ## Audio: Attachment vs Voice Memo
81
+
82
+ Audio files sent as media parts appear as **downloadable file attachments** in iMessage.
83
+ To send audio as an **iMessage voice memo bubble** (with native inline playback UI),
84
+ use the dedicated `POST /v3/chats/{chatId}/voicememo` endpoint instead.
85
+
86
+ ## File Size Limits
87
+
88
+ - **URL-based (`url` field):** 10MB maximum
89
+ - **Pre-upload (`attachment_id`):** 100MB maximum
90
+ """
91
+
92
+ @cached_property
93
+ def with_raw_response(self) -> AttachmentsResourceWithRawResponse:
94
+ """
95
+ This property can be used as a prefix for any HTTP method call to return
96
+ the raw response object instead of the parsed content.
97
+
98
+ For more information, see https://www.github.com/linq-team/linq-python#accessing-raw-response-data-eg-headers
99
+ """
100
+ return AttachmentsResourceWithRawResponse(self)
101
+
102
+ @cached_property
103
+ def with_streaming_response(self) -> AttachmentsResourceWithStreamingResponse:
104
+ """
105
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
106
+
107
+ For more information, see https://www.github.com/linq-team/linq-python#with_streaming_response
108
+ """
109
+ return AttachmentsResourceWithStreamingResponse(self)
110
+
111
+ def create(
112
+ self,
113
+ *,
114
+ content_type: SupportedContentType,
115
+ filename: str,
116
+ size_bytes: int,
117
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
118
+ # The extra values given here take precedence over values defined on the client or passed to this method.
119
+ extra_headers: Headers | None = None,
120
+ extra_query: Query | None = None,
121
+ extra_body: Body | None = None,
122
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
123
+ ) -> AttachmentCreateResponse:
124
+ """
125
+ **This endpoint is optional.** You can send media by simply providing a URL in
126
+ your message's media part — no pre-upload required. Use this endpoint only when
127
+ you want to upload a file ahead of time for reuse or latency optimization.
128
+
129
+ Returns a presigned upload URL and a permanent `attachment_id` you can reference
130
+ in future messages.
131
+
132
+ ## Step 1: Request an upload URL
133
+
134
+ Call this endpoint with file metadata:
135
+
136
+ ```json
137
+ POST /v3/attachments
138
+ {
139
+ "filename": "photo.jpg",
140
+ "content_type": "image/jpeg",
141
+ "size_bytes": 1024000
142
+ }
143
+ ```
144
+
145
+ The response includes an `upload_url` (valid for 15 minutes) and a permanent
146
+ `attachment_id`.
147
+
148
+ ## Step 2: Upload the file
149
+
150
+ Make a PUT request to the `upload_url` with the raw file bytes as the request
151
+ body. You **must** include all headers from `required_headers` exactly as
152
+ returned — the presigned URL is signed with these values and S3 will reject the
153
+ upload if they don't match.
154
+
155
+ The request body is the binary file content — **not** JSON, **not** multipart
156
+ form data. The file must equal `size_bytes` bytes (the value you declared in
157
+ step 1).
158
+
159
+ ```bash
160
+ curl -X PUT "<upload_url from step 1>" \\
161
+ -H "Content-Type: image/jpeg" \\
162
+ -H "Content-Length: 1024000" \\
163
+ --data-binary @photo.jpg
164
+ ```
165
+
166
+ ## Step 3: Send a message with the attachment
167
+
168
+ Reference the `attachment_id` in a media part. The ID never expires — use it in
169
+ as many messages as you want.
170
+
171
+ ```json
172
+ POST /v3/chats
173
+ {
174
+ "from": "+15559876543",
175
+ "to": ["+15551234567"],
176
+ "message": {
177
+ "parts": [
178
+ { "type": "media", "attachment_id": "<attachment_id from step 1>" }
179
+ ]
180
+ }
181
+ }
182
+ ```
183
+
184
+ ## When to use this instead of a URL in the media part
185
+
186
+ - Sending the same file to multiple recipients (avoids re-downloading each time)
187
+ - Large files where you want to separate upload from message send
188
+ - Latency-sensitive sends where the file should already be stored
189
+
190
+ If you just need to send a file once, skip all of this and pass a `url` directly
191
+ in the media part instead.
192
+
193
+ **File Size Limit:** 100MB
194
+
195
+ **Unsupported Types:** WebP, SVG, FLAC, OGG, and executable files are explicitly
196
+ rejected.
197
+
198
+ Args:
199
+ content_type: Supported MIME types for file attachments and media URLs.
200
+
201
+ **Images:** image/jpeg, image/png, image/gif, image/heic, image/heif,
202
+ image/tiff, image/bmp
203
+
204
+ **Videos:** video/mp4, video/quicktime, video/mpeg, video/3gpp
205
+
206
+ **Audio:** audio/mpeg, audio/mp4, audio/x-m4a, audio/x-caf, audio/wav,
207
+ audio/aiff, audio/aac, audio/amr
208
+
209
+ **Documents:** application/pdf, text/plain, text/markdown, text/vcard, text/rtf,
210
+ text/csv, text/html, text/calendar, application/msword,
211
+ application/vnd.openxmlformats-officedocument.wordprocessingml.document,
212
+ application/vnd.ms-excel,
213
+ application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,
214
+ application/vnd.ms-powerpoint,
215
+ application/vnd.openxmlformats-officedocument.presentationml.presentation,
216
+ application/vnd.apple.pages, application/vnd.apple.numbers,
217
+ application/vnd.apple.keynote, application/epub+zip, application/zip
218
+
219
+ **Unsupported:** WebP, SVG, FLAC, OGG, and executable files are explicitly
220
+ rejected.
221
+
222
+ filename: Name of the file to upload
223
+
224
+ size_bytes: Size of the file in bytes (max 100MB)
225
+
226
+ extra_headers: Send extra headers
227
+
228
+ extra_query: Add additional query parameters to the request
229
+
230
+ extra_body: Add additional JSON properties to the request
231
+
232
+ timeout: Override the client-level default timeout for this request, in seconds
233
+ """
234
+ return self._post(
235
+ "/v3/attachments",
236
+ body=maybe_transform(
237
+ {
238
+ "content_type": content_type,
239
+ "filename": filename,
240
+ "size_bytes": size_bytes,
241
+ },
242
+ attachment_create_params.AttachmentCreateParams,
243
+ ),
244
+ options=make_request_options(
245
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
246
+ ),
247
+ cast_to=AttachmentCreateResponse,
248
+ )
249
+
250
+ def retrieve(
251
+ self,
252
+ attachment_id: str,
253
+ *,
254
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
255
+ # The extra values given here take precedence over values defined on the client or passed to this method.
256
+ extra_headers: Headers | None = None,
257
+ extra_query: Query | None = None,
258
+ extra_body: Body | None = None,
259
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
260
+ ) -> AttachmentRetrieveResponse:
261
+ """
262
+ Retrieve metadata for a specific attachment including its status, file
263
+ information, and URLs for downloading.
264
+
265
+ Args:
266
+ extra_headers: Send extra headers
267
+
268
+ extra_query: Add additional query parameters to the request
269
+
270
+ extra_body: Add additional JSON properties to the request
271
+
272
+ timeout: Override the client-level default timeout for this request, in seconds
273
+ """
274
+ if not attachment_id:
275
+ raise ValueError(f"Expected a non-empty value for `attachment_id` but received {attachment_id!r}")
276
+ return self._get(
277
+ path_template("/v3/attachments/{attachment_id}", attachment_id=attachment_id),
278
+ options=make_request_options(
279
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
280
+ ),
281
+ cast_to=AttachmentRetrieveResponse,
282
+ )
283
+
284
+
285
+ class AsyncAttachmentsResource(AsyncAPIResource):
286
+ """
287
+ Send files (images, videos, documents, audio) with messages by providing a URL in a media part.
288
+ Pre-uploading via `POST /v3/attachments` is **optional** and only needed for specific optimization scenarios.
289
+
290
+ ## Sending Media via URL (up to 10MB)
291
+
292
+ Provide a publicly accessible HTTPS URL with a [supported media type](#supported-file-types) in the `url` field of a media part.
293
+
294
+ ```json
295
+ {
296
+ "parts": [
297
+ { "type": "media", "url": "https://your-cdn.com/images/photo.jpg" }
298
+ ]
299
+ }
300
+ ```
301
+
302
+ This works with any URL you already host — no pre-upload step required. **Maximum file size: 10MB.**
303
+
304
+ ## Pre-Upload (required for files over 10MB)
305
+
306
+ Use `POST /v3/attachments` when you want to:
307
+ - **Send files larger than 10MB** (up to 100MB) — URL-based downloads are limited to 10MB
308
+ - **Send the same file to many recipients** — upload once, reuse the `attachment_id` without re-downloading each time
309
+ - **Reduce message send latency** — the file is already stored, so sending is faster
310
+
311
+ **How it works:**
312
+ 1. `POST /v3/attachments` with file metadata → returns a presigned `upload_url` (valid for **15 minutes**) and a permanent `attachment_id`
313
+ 2. PUT the raw file bytes to the `upload_url` with the `required_headers` (no JSON or multipart — just the binary content)
314
+ 3. Reference the `attachment_id` in your media part when sending messages (no expiration)
315
+
316
+ **Key difference:** When you provide an external `url`, we download and process the file on every send.
317
+ When you use a pre-uploaded `attachment_id`, the file is already stored — so repeated sends skip the download step entirely.
318
+
319
+ ## Domain Allowlisting
320
+
321
+ Attachment URLs in API responses are served from `cdn.linqapp.com`. This includes:
322
+ - `url` fields in media and voice memo message parts
323
+ - `download_url` fields in attachment and upload response objects
324
+
325
+ If your application enforces domain allowlists (e.g., for SSRF protection), add:
326
+
327
+ ```
328
+ cdn.linqapp.com
329
+ ```
330
+
331
+ ## Supported File Types
332
+
333
+ - **Images:** JPEG, PNG, GIF, HEIC, HEIF, TIFF, BMP
334
+ - **Videos:** MP4, MOV, M4V
335
+ - **Audio:** M4A, AAC, MP3, WAV, AIFF, CAF, AMR
336
+ - **Documents:** PDF, TXT, RTF, CSV, Office formats, ZIP
337
+ - **Contact & Calendar:** VCF, ICS
338
+
339
+ ## Audio: Attachment vs Voice Memo
340
+
341
+ Audio files sent as media parts appear as **downloadable file attachments** in iMessage.
342
+ To send audio as an **iMessage voice memo bubble** (with native inline playback UI),
343
+ use the dedicated `POST /v3/chats/{chatId}/voicememo` endpoint instead.
344
+
345
+ ## File Size Limits
346
+
347
+ - **URL-based (`url` field):** 10MB maximum
348
+ - **Pre-upload (`attachment_id`):** 100MB maximum
349
+ """
350
+
351
+ @cached_property
352
+ def with_raw_response(self) -> AsyncAttachmentsResourceWithRawResponse:
353
+ """
354
+ This property can be used as a prefix for any HTTP method call to return
355
+ the raw response object instead of the parsed content.
356
+
357
+ For more information, see https://www.github.com/linq-team/linq-python#accessing-raw-response-data-eg-headers
358
+ """
359
+ return AsyncAttachmentsResourceWithRawResponse(self)
360
+
361
+ @cached_property
362
+ def with_streaming_response(self) -> AsyncAttachmentsResourceWithStreamingResponse:
363
+ """
364
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
365
+
366
+ For more information, see https://www.github.com/linq-team/linq-python#with_streaming_response
367
+ """
368
+ return AsyncAttachmentsResourceWithStreamingResponse(self)
369
+
370
+ async def create(
371
+ self,
372
+ *,
373
+ content_type: SupportedContentType,
374
+ filename: str,
375
+ size_bytes: int,
376
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
377
+ # The extra values given here take precedence over values defined on the client or passed to this method.
378
+ extra_headers: Headers | None = None,
379
+ extra_query: Query | None = None,
380
+ extra_body: Body | None = None,
381
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
382
+ ) -> AttachmentCreateResponse:
383
+ """
384
+ **This endpoint is optional.** You can send media by simply providing a URL in
385
+ your message's media part — no pre-upload required. Use this endpoint only when
386
+ you want to upload a file ahead of time for reuse or latency optimization.
387
+
388
+ Returns a presigned upload URL and a permanent `attachment_id` you can reference
389
+ in future messages.
390
+
391
+ ## Step 1: Request an upload URL
392
+
393
+ Call this endpoint with file metadata:
394
+
395
+ ```json
396
+ POST /v3/attachments
397
+ {
398
+ "filename": "photo.jpg",
399
+ "content_type": "image/jpeg",
400
+ "size_bytes": 1024000
401
+ }
402
+ ```
403
+
404
+ The response includes an `upload_url` (valid for 15 minutes) and a permanent
405
+ `attachment_id`.
406
+
407
+ ## Step 2: Upload the file
408
+
409
+ Make a PUT request to the `upload_url` with the raw file bytes as the request
410
+ body. You **must** include all headers from `required_headers` exactly as
411
+ returned — the presigned URL is signed with these values and S3 will reject the
412
+ upload if they don't match.
413
+
414
+ The request body is the binary file content — **not** JSON, **not** multipart
415
+ form data. The file must equal `size_bytes` bytes (the value you declared in
416
+ step 1).
417
+
418
+ ```bash
419
+ curl -X PUT "<upload_url from step 1>" \\
420
+ -H "Content-Type: image/jpeg" \\
421
+ -H "Content-Length: 1024000" \\
422
+ --data-binary @photo.jpg
423
+ ```
424
+
425
+ ## Step 3: Send a message with the attachment
426
+
427
+ Reference the `attachment_id` in a media part. The ID never expires — use it in
428
+ as many messages as you want.
429
+
430
+ ```json
431
+ POST /v3/chats
432
+ {
433
+ "from": "+15559876543",
434
+ "to": ["+15551234567"],
435
+ "message": {
436
+ "parts": [
437
+ { "type": "media", "attachment_id": "<attachment_id from step 1>" }
438
+ ]
439
+ }
440
+ }
441
+ ```
442
+
443
+ ## When to use this instead of a URL in the media part
444
+
445
+ - Sending the same file to multiple recipients (avoids re-downloading each time)
446
+ - Large files where you want to separate upload from message send
447
+ - Latency-sensitive sends where the file should already be stored
448
+
449
+ If you just need to send a file once, skip all of this and pass a `url` directly
450
+ in the media part instead.
451
+
452
+ **File Size Limit:** 100MB
453
+
454
+ **Unsupported Types:** WebP, SVG, FLAC, OGG, and executable files are explicitly
455
+ rejected.
456
+
457
+ Args:
458
+ content_type: Supported MIME types for file attachments and media URLs.
459
+
460
+ **Images:** image/jpeg, image/png, image/gif, image/heic, image/heif,
461
+ image/tiff, image/bmp
462
+
463
+ **Videos:** video/mp4, video/quicktime, video/mpeg, video/3gpp
464
+
465
+ **Audio:** audio/mpeg, audio/mp4, audio/x-m4a, audio/x-caf, audio/wav,
466
+ audio/aiff, audio/aac, audio/amr
467
+
468
+ **Documents:** application/pdf, text/plain, text/markdown, text/vcard, text/rtf,
469
+ text/csv, text/html, text/calendar, application/msword,
470
+ application/vnd.openxmlformats-officedocument.wordprocessingml.document,
471
+ application/vnd.ms-excel,
472
+ application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,
473
+ application/vnd.ms-powerpoint,
474
+ application/vnd.openxmlformats-officedocument.presentationml.presentation,
475
+ application/vnd.apple.pages, application/vnd.apple.numbers,
476
+ application/vnd.apple.keynote, application/epub+zip, application/zip
477
+
478
+ **Unsupported:** WebP, SVG, FLAC, OGG, and executable files are explicitly
479
+ rejected.
480
+
481
+ filename: Name of the file to upload
482
+
483
+ size_bytes: Size of the file in bytes (max 100MB)
484
+
485
+ extra_headers: Send extra headers
486
+
487
+ extra_query: Add additional query parameters to the request
488
+
489
+ extra_body: Add additional JSON properties to the request
490
+
491
+ timeout: Override the client-level default timeout for this request, in seconds
492
+ """
493
+ return await self._post(
494
+ "/v3/attachments",
495
+ body=await async_maybe_transform(
496
+ {
497
+ "content_type": content_type,
498
+ "filename": filename,
499
+ "size_bytes": size_bytes,
500
+ },
501
+ attachment_create_params.AttachmentCreateParams,
502
+ ),
503
+ options=make_request_options(
504
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
505
+ ),
506
+ cast_to=AttachmentCreateResponse,
507
+ )
508
+
509
+ async def retrieve(
510
+ self,
511
+ attachment_id: str,
512
+ *,
513
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
514
+ # The extra values given here take precedence over values defined on the client or passed to this method.
515
+ extra_headers: Headers | None = None,
516
+ extra_query: Query | None = None,
517
+ extra_body: Body | None = None,
518
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
519
+ ) -> AttachmentRetrieveResponse:
520
+ """
521
+ Retrieve metadata for a specific attachment including its status, file
522
+ information, and URLs for downloading.
523
+
524
+ Args:
525
+ extra_headers: Send extra headers
526
+
527
+ extra_query: Add additional query parameters to the request
528
+
529
+ extra_body: Add additional JSON properties to the request
530
+
531
+ timeout: Override the client-level default timeout for this request, in seconds
532
+ """
533
+ if not attachment_id:
534
+ raise ValueError(f"Expected a non-empty value for `attachment_id` but received {attachment_id!r}")
535
+ return await self._get(
536
+ path_template("/v3/attachments/{attachment_id}", attachment_id=attachment_id),
537
+ options=make_request_options(
538
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
539
+ ),
540
+ cast_to=AttachmentRetrieveResponse,
541
+ )
542
+
543
+
544
+ class AttachmentsResourceWithRawResponse:
545
+ def __init__(self, attachments: AttachmentsResource) -> None:
546
+ self._attachments = attachments
547
+
548
+ self.create = to_raw_response_wrapper(
549
+ attachments.create,
550
+ )
551
+ self.retrieve = to_raw_response_wrapper(
552
+ attachments.retrieve,
553
+ )
554
+
555
+
556
+ class AsyncAttachmentsResourceWithRawResponse:
557
+ def __init__(self, attachments: AsyncAttachmentsResource) -> None:
558
+ self._attachments = attachments
559
+
560
+ self.create = async_to_raw_response_wrapper(
561
+ attachments.create,
562
+ )
563
+ self.retrieve = async_to_raw_response_wrapper(
564
+ attachments.retrieve,
565
+ )
566
+
567
+
568
+ class AttachmentsResourceWithStreamingResponse:
569
+ def __init__(self, attachments: AttachmentsResource) -> None:
570
+ self._attachments = attachments
571
+
572
+ self.create = to_streamed_response_wrapper(
573
+ attachments.create,
574
+ )
575
+ self.retrieve = to_streamed_response_wrapper(
576
+ attachments.retrieve,
577
+ )
578
+
579
+
580
+ class AsyncAttachmentsResourceWithStreamingResponse:
581
+ def __init__(self, attachments: AsyncAttachmentsResource) -> None:
582
+ self._attachments = attachments
583
+
584
+ self.create = async_to_streamed_response_wrapper(
585
+ attachments.create,
586
+ )
587
+ self.retrieve = async_to_streamed_response_wrapper(
588
+ attachments.retrieve,
589
+ )