Attachments API¶
The AttachmentsAPI client reads attachments (list, detail, visibility) and uploads new files
that can then be attached to posts, comments and tasks.
Resource grouping¶
All three endpoints are grouped under client.attachments regardless of their URL prefix.
In particular, get() calls communication/posts/data/attachment-detail-by-id/{id} — a
posts/data/ URL — but logically belongs to the attachments resource group (D-v0.3-1).
Usage¶
from pynteracta.client import InteractaClient
with InteractaClient(base_url="https://tenant.example.com", credentials=...) as client:
# List all attachments for a post (first page)
page = client.attachments.list_for_post(21269)
for att in page.items_typed:
print(att.id, att.name, att.content_mime_type)
# Iterate all pages lazily
for att in client.attachments.iterate_for_post(21269, page_size=20):
print(att.id, att.name)
# Fetch a single attachment with parent-post info
detail = client.attachments.get(3001)
print(detail.name, detail.post.id if detail.post else None)
# Check which attachment IDs are visible
visibility = client.attachments.check_visibility([3001, 3002, 3099])
print(visibility.ids) # only visible IDs
Uploading files¶
Interacta uploads a file in two steps: the API returns a temporary storage URL with a signed
upload policy, then the file is sent there as a multipart POST form. upload() does both and
returns an UploadedAttachment (content_ref, name, mime_type, temporary_download_url,
.raw), which the write methods of posts, comments and tasks accept directly.
from pathlib import Path
from pynteracta.client import InteractaClient
with InteractaClient(base_url="https://tenant.example.com", credentials=...) as client:
report = client.attachments.upload(Path("report.pdf")) # name and MIME from the file
data = client.attachments.upload(b"a,b\n1,2\n", name="data.csv") # bytes need a name
client.posts.create(79, title="Q4 report", attachments=[report, data])
# a new version of an existing attachment (id 9466)
v2 = client.attachments.upload(Path("report-v2.pdf"))
client.posts.edit_attachments(21269, update=[v2.as_version_of(9466)])
upload(file, *, name=None, mime_type=None)accepts aPathor a path string (read in streaming and closed by the library),bytes, or a binary file object you opened (left open). Withbytesor a file objectnameis required. The MIME type is guessed from the name's extension (application/octet-streamwhen unknown) unlessmime_typeis given. A missing path, a directory or a missing name raise before any request.UploadedAttachmentgoes wherever a write accepts attachments (attachments,add_attachments,add) and is sent as{"name", "contentRef"};as_version_of(id)gives{"attachmentId", "contentRef", "name"}forupdate_attachments/update. The server applies the new name to the new version (verified against a tenant). Dicts and DTOs already accepted keep working, also mixed with uploaded files.upload(..., downloadable=False)marks the file as not downloadable. The flag never goes to the storage: theUploadedAttachmentcarries it and adds"downloadable"to the dicts ofas_write_input()andas_version_of(), only when you set it (omitted, the server default is downloadable). On the test tenant the flag is stored on post attachments (custom and event posts:create,edit,copy,edit_attachments) and read back asPostAttachment.downloadable. On comments and tasks the server has no such field and rejects the write with400"Unrecognized field downloadable": upload files for comments and tasks without the flag. In the CLI pass it in the attachments of--json.
from pathlib import Path
from pynteracta.client import InteractaClient
with InteractaClient(base_url="https://tenant.example.com", credentials=...) as client:
contract = client.attachments.upload(Path("contract.pdf"), downloadable=False)
client.posts.create(79, title="Contract", attachments=[contract])
request_upload_url()performs only the first step and returns anUploadTicket(content_ref,upload_url,form_params,temporary_download_url), for callers that upload the file with another tool.
Errors and retries. Each step sends one request and never retries. A storage response
other than 2xx (expired policy, file too large) raises UploadError with status_code,
response_body (the storage's XML, as is), the redacted request_url and file_name; a timeout
or network error raises TransportError, with an unknown outcome. timeout_seconds applies to
each network operation of the upload, not to its total duration: raise it for large files.
Secrets. The storage request never carries the Interacta token. It goes through hooks and
the audit log with its URL and status only: neither the file content nor the policy fields are
ever logged, even with audit_log_bodies. The policy and signature fields and the
Signature of signed URLs are redacted everywhere (see Audit Logging).
Temporary content links¶
PostAttachment and AttachmentDetail expose temporaryContent*Link properties
(temporary_content_view_link, temporary_content_download_link, etc.). These are
short-lived signed URLs returned by the API; they are not shown in the default CLI table
(D-v0.3-3a) but are accessible via --full, --fields, or --export in the CLI and
directly on the facade object in Python.
Filter surface for list_for_post¶
Curated explicit kwargs: types, entity_types, mime_types, mime_type_category,
order_by, order_desc.
Valid order_by values: 'name', 'mimeType', 'size', 'creatorUserId',
'creationTimestamp', 'entityType'.
Niche filters (aiSupportedFilter, postFilePickerFieldId, wfScreenFilePickerFieldId,
language) are reachable only via the list_for_post_raw(req) escape hatch.
API Reference¶
pynteracta.api.attachments.AttachmentsAPI
¶
Bases: ResourceClient
Client degli allegati: elenco, dettaglio e visibilità; upload di nuovi file (spec 04).
list_for_post(post_id, *, page_token=None, page_size=None, types=None, entity_types=None, mime_types=None, mime_type_category=None, order_by=None, order_desc=None)
¶
POST /communication/attachments/data/posts/{postId}/attachments-list.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
post_id
|
int
|
The post whose attachments to list. |
required |
page_token
|
str | None
|
Pagination cursor from a previous response. |
None
|
page_size
|
int | None
|
Maximum items per page. |
None
|
types
|
list[int] | None
|
Filter by attachment type (1=STORAGE, 2=DRIVE). |
None
|
entity_types
|
list[int] | None
|
Filter by entity type (1=POST, 2=TASK, 3=COMMENT, 4=POST_FILE_PICKER, 5=SCREEN_FILE_PICKER). |
None
|
mime_types
|
list[str] | None
|
Filter by MIME type strings. |
None
|
mime_type_category
|
str | None
|
Filter by MIME category ( |
None
|
order_by
|
str | None
|
Sort field. Valid values: |
None
|
order_desc
|
bool | None
|
|
None
|
list_for_post_raw(post_id, req)
¶
POST attachment list with a pre-built request DTO (escape hatch).
iterate_for_post(post_id, *, page_size=None, types=None, entity_types=None, mime_types=None, mime_type_category=None, order_by=None, order_desc=None)
¶
Lazy iterator over all pages of :meth:list_for_post.
get(attachment_id)
¶
GET /communication/posts/data/attachment-detail-by-id/{attachmentId}.
Note: this endpoint lives under the posts/data/ URL prefix but belongs to the
attachments resource group (D-v0.3-1).
check_visibility(attachment_ids)
¶
POST /communication/attachments/data/check-visibility.
check_visibility_raw(req)
¶
POST check-visibility with a pre-built request DTO (escape hatch).
upload(file, *, name=None, mime_type=None, downloadable=None)
¶
Carica un file nello storage temporaneo del tenant, in due passi.
Prima chiede l'URL con :meth:request_upload_url, poi invia il file con un form
multipart POST firmato, senza token Interacta. Il risultato si passa agli allegati
dei metodi di scrittura di post, commenti e task. Una sola richiesta per passo: un
errore risale al chiamante, mai un nuovo tentativo.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
UploadSource
|
Un percorso ( |
required |
name
|
str | None
|
Nome del file; da un percorso è il nome del file, con |
None
|
mime_type
|
str | None
|
MIME del file; se manca è dedotto dall'estensione del nome
( |
None
|
downloadable
|
bool | None
|
Se l'allegato sarà scaricabile. Non va allo storage: il risultato lo
porta negli allegati delle scritture ( |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
Un |
UploadedAttachment
|
class: |
UploadedAttachment
|
|
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
Il percorso non esiste (nessuna richiesta parte). |
IsADirectoryError
|
Il percorso è una cartella (nessuna richiesta parte). |
ValueError
|
|
UploadError
|
Lo storage ha risposto con un errore. |
TransportError
|
Timeout o errore di rete: l'esito è sconosciuto. |
request_upload_url()
¶
POST /core/storage/upload-new-attachment: il primo passo dell'upload.
Una sola richiesta, senza corpo. Il risultato porta l'URL dello storage, i campi della
policy firmata e il content_ref; serve a chi carica il file con altri strumenti,
altrimenti :meth:upload fa entrambi i passi.
Facade Reference¶
pynteracta.models.facade.attachments.PostAttachment
¶
Narrow facade over :class:~generated.ListPostAttachmentsElementDTOModel.
Attributes:
| Name | Type | Description |
|---|---|---|
raw |
The underlying generated DTO; access additional fields via this escape hatch. |
Source code in src/pynteracta/models/facade/attachments.py
from_dict(data)
classmethod
¶
Parse from a raw API response dict element.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
dict
|
A single item dict from the |
required |
Returns:
| Type | Description |
|---|---|
PostAttachment
|
A new :class: |
Source code in src/pynteracta/models/facade/attachments.py
pynteracta.models.facade.attachments.PostAttachmentList
¶
Narrow facade over :class:~generated.ListPostAttachmentsResponseDTO.
The items list holds :class:~generated.ListPostAttachmentsElementDTO objects, which are
generated as RootModel[Any] stubs. Call :meth:items_typed to re-validate each item
against the fully-typed :class:~generated.ListPostAttachmentsElementDTOModel.
Attributes:
| Name | Type | Description |
|---|---|---|
raw |
The underlying generated DTO; access additional fields via this escape hatch. |
Source code in src/pynteracta/models/facade/attachments.py
items_typed
property
¶
Re-validate each opaque list item into :class:PostAttachment.
Returns:
| Type | Description |
|---|---|
list[PostAttachment]
|
List of :class: |
from_dict(data)
classmethod
¶
Parse from a raw API response dict.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
dict
|
Parsed JSON response body. |
required |
Returns:
| Type | Description |
|---|---|
PostAttachmentList
|
A new :class: |
Source code in src/pynteracta/models/facade/attachments.py
pynteracta.models.facade.attachments.AttachmentDetail
¶
Narrow facade over :class:~generated.GetPostAttachmentDetailResponseDTO.
attachmentData is typed as PostAttachmentDataDTO (a RootModel[Any] stub) in the
generated code; we re-validate it against the typed sibling
:class:~generated.PostAttachmentDataDTO1.
Attributes:
| Name | Type | Description |
|---|---|---|
raw |
The underlying generated DTO; access additional fields via this escape hatch. |
Source code in src/pynteracta/models/facade/attachments.py
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | |
attachment_data
property
¶
Typed attachment data DTO.
post
property
¶
Parent post base info (typed variant of the RootModel stub).
from_dict(data)
classmethod
¶
Parse from a raw API response dict.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
dict
|
Parsed JSON response body. |
required |
Returns:
| Type | Description |
|---|---|
AttachmentDetail
|
A new :class: |
Source code in src/pynteracta/models/facade/attachments.py
pynteracta.models.facade.attachments.AttachmentVisibility
¶
Thin facade over :class:~generated.CheckVisibilityResponseDTO.
Returns which attachment IDs are visible to the current user.
Kept separate from the v0.2 :class:~pynteracta.models.facade.posts.VisibilityResult.
Attributes:
| Name | Type | Description |
|---|---|---|
raw |
The underlying generated DTO; access additional fields via this escape hatch. |
Source code in src/pynteracta/models/facade/attachments.py
ids
property
¶
List of visible attachment IDs.
from_dict(data)
classmethod
¶
Parse from a raw API response dict.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
dict
|
Parsed JSON response body. |
required |
Returns:
| Type | Description |
|---|---|
AttachmentVisibility
|
A new :class: |
Source code in src/pynteracta/models/facade/attachments.py
pynteracta.models.facade.attachments.UploadedAttachment
¶
Un file caricato nello storage temporaneo, pronto da allegare (spec 04).
Si passa direttamente agli attachments (o add_attachments, add) dei metodi di
scrittura di post, commenti e task, che lo inviano come {name, contentRef}; per caricare
una nuova versione di un allegato esistente si usa :meth:as_version_of. Con
downloadable indicato (spec 09) i due riferimenti portano anche "downloadable", che il
server prevede negli allegati dei post custom ed evento; senza, decide il server (default
scaricabile).
Attributes:
| Name | Type | Description |
|---|---|---|
raw |
Il |
Source code in src/pynteracta/models/facade/attachments.py
content_ref
property
¶
Riferimento del file nello storage.
downloadable
property
¶
Se l'allegato sarà scaricabile; None se non indicato al caricamento.
mime_type
property
¶
MIME con cui il file è stato caricato.
name
property
¶
Nome con cui il file è stato caricato.
temporary_download_url
property
¶
URL firmato da cui rileggere il file caricato.
as_version_of(attachment_id)
¶
Il riferimento come nuova versione dell'allegato attachment_id.
Va in update_attachments (o update di edit_attachments); porta
downloadable se indicato.
Source code in src/pynteracta/models/facade/attachments.py
as_write_input()
¶
Il riferimento da allegare: {"name", "contentRef"}, con downloadable se dato.
pynteracta.models.facade.attachments.UploadTicket
¶
Façade sulla risposta di core/storage/upload-new-attachment (spec 04).
È il primo passo dell'upload: il riferimento del file nello storage temporaneo, l'URL a cui caricarlo e i campi della policy firmata da inviare nel form multipart.
Attributes:
| Name | Type | Description |
|---|---|---|
raw |
Il |
Source code in src/pynteracta/models/facade/attachments.py
content_ref
property
¶
Riferimento del file nello storage, da passare nelle scritture come contentRef.
form_params
property
¶
Campi della policy firmata, da inviare prima del file (una copia: {} se assenti).
Contengono credenziali temporanee: non vanno loggati.
temporary_download_url
property
¶
URL firmato da cui rileggere il file caricato, finché la firma non scade.
upload_url
property
¶
URL dello storage a cui inviare il form multipart.
from_dict(data)
classmethod
¶
Legge la risposta di upload-new-attachment.
pynteracta.exceptions.UploadError
¶
Bases: InteractaError
Lo storage ha rifiutato il caricamento di un file (risposta non 2xx, spec 04).
response_body è il corpo della risposta dello storage così com'è (di solito XML);
request_url è l'URL di storage redatto; request_id è assente. file_name è il nome
del file che non è stato caricato. Timeout ed errori di rete restano :class:TransportError.