Tasks API¶
The TasksAPI client exposes the task-detail read endpoint added in v0.4.0 and, since 0.10.0,
the three write endpoints: create, edit and delete (the first write group opened by ADR 0001).
Resource grouping¶
The endpoint is grouped under client.tasks (D-v0.4-1), even though a task belongs to a post.
This mirrors the M16 decision to give attachments their own resource group rather than folding
into PostsAPI.
Usage¶
from pynteracta.client import InteractaClient
with InteractaClient(base_url="https://tenant.example.com", credentials=...) as client:
task = client.tasks.get(7001)
print(task.id, task.title, task.state)
print(task.description_plain_text)
# Sub-tasks and reminders (typed via …1 siblings)
for st in task.sub_tasks:
print(st.id, st.description, st.state)
for r in task.reminders:
print(r.id, r.value, r.range)
# Capabilities
if task.capabilities and task.capabilities.can_modify:
print("task is editable")
# Rich-text delta and survey data — reachable only via .raw (D-v0.4-4)
print(task.raw.descriptionDelta)
print(task.raw.surveyData)
# Optimistic-concurrency token, needed by edit()
print(task.occ_token)
Writing tasks¶
create(), edit() and delete() mirror the read API: explicit snake_case keyword arguments
for every field of the request DTO, a *_raw() variant for callers holding a pre-built DTO, and a
facade over the server response. Only the fields you pass are sent; the request body is built
in camelCase from the non-None arguments.
from datetime import datetime
from zoneinfo import ZoneInfo
from pynteracta.client import InteractaClient
from pynteracta.exceptions import ConcurrencyError
with InteractaClient(base_url="https://tenant.example.com", credentials=...) as client:
created = client.tasks.create(
21269,
title="Prepare the quarterly report",
priority=2,
assignee_user_id=1042,
watcher_user_ids=[1042, 1099],
expiration=datetime(2026, 12, 31, 18, 0, tzinfo=ZoneInfo("Europe/Rome")),
client_uid="report-2026-q4",
)
print(created.task_id, created.next_occ_token, created.task.title)
# Edit: read first, pass the concurrency token explicitly, and send back every field that
# must survive (the server clears what is missing: see "Omitted fields" below)
task = client.tasks.get(created.task_id)
try:
edited = client.tasks.edit(
task.id,
task.occ_token,
title="Prepare the Q4 report",
priority=task.priority,
expiration=datetime(2026, 12, 31, 18, 0, tzinfo=ZoneInfo("Europe/Rome")),
assignee_user_id=1042,
)
except ConcurrencyError:
# the task changed after we read it: re-read and decide — the library never retries
raise
print(edited.next_occ_token)
post_id = client.tasks.delete(created.task_id)
TaskWriteResult¶
create() and edit() return a TaskWriteResult: task_id, next_occ_token (the token to
pass to the next edit()), task (the task data after the write, typed TaskDetailDTO1),
capabilities, and .raw (the generated CreateTaskResponseDTO / EditTaskResponseDTO).
delete() returns the id of the post that contained the task.
Concurrency: occ_token¶
edit() takes the occ_token read with get() (Task.occ_token). If the task changed in the
meantime the server answers 409, mapped to ConcurrencyError. The library does not re-read
and retry: that decision belongs to the caller (ADR 0001, non-negotiable rule "no automatic
retries towards Interacta"). The same holds for timeouts and network errors on writes: one request
per call, the outcome stays unknown until you check.
Expiration¶
expiration must be a timezone-aware datetime; a naive one raises ValueError before any
request. With an IANA zone (ZoneInfo) the local time and the zone name are sent
({"datetime": "2026-12-31T18:00:00", "timezone": "Europe/Rome"}); with a fixed offset the value
is converted to UTC and sent with "timezone": "UTC".
Omitted fields in edit(): the server replaces the task¶
Fields you do not pass are not sent, and the server treats the request as a replacement, not a
patch (verified against a tenant, spec 02): title, description, expiration, priority, the
assignee and sub_tasks that are missing from the request are cleared. Watchers and
attachments are the exception: they are changed only through the add_* / remove_* arguments.
attachments (create) and add_attachments (edit) accept files just uploaded with
client.attachments.upload() (an UploadedAttachment) as well as references the server already
knows (InputTaskAttachmentDTO). See Uploading files.
Pass every field you want to keep
Read the task first and send back what must survive. The CLI tasks edit does this for you;
the library does not, so that a call stays one explicit request. Sub-tasks sent back with their
id are re-created by the server with new ids.
The same tenant also enforces fields the Swagger does not mark as required, on both create()
and edit(): an assignee (assignee_user_id or assignee_group_id; without one the server
answers 400 on the field assignee, raised as ValidationError) and an expiration (without
one the server answers 500, raised as ServerError). Every sub-task needs a non-zero state.
When the mapped message is not enough, the server's detail is in exc.response_body.
The server returns expiration as {"zonedDatetime": "2026-12-31T18:00:00+01:00",
"localDatetime": "2026-12-31T18:00:00", "timezone": "Europe/Rome"}.
state vs currentWorkflowState¶
Task.state is an integer lifecycle code (open/closed etc.) — the recommended field to display
and filter on. Task.current_workflow_state is the post's workflow-state DTO
(PostWorkflowDefinitionStateDTO) and represents the post-level workflow, not the task lifecycle.
Both are exposed on the facade; the CLI default table shows state (Q-v0.4-3).
Description and survey data¶
Per D-v0.4-4, the facade surfaces description_plain_text (curated scalar). The Quill
rich-text JSON (descriptionDelta) and survey payloads (surveyData,
surveyDataCommentsInfo) are left on .raw — surveyData is an untyped object → object map
with no DTO, making .raw the only faithful surface.
API Reference¶
pynteracta.api.tasks.TasksAPI
¶
Bases: ResourceClient
Client for the tasks endpoints: one read, plus create, edit and delete (spec 02).
get(task_id)
¶
GET /communication/tasks/data/task-detail-by-id/{taskId}.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
task_id
|
int
|
The task ID to fetch. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
A |
Task
|
class: |
create(post_id, *, title=None, description_delta=None, description_plain_text=None, expiration=None, priority=None, sub_tasks=None, assignee_user_id=None, assignee_group_id=None, attachments=None, watcher_user_ids=None, watcher_group_ids=None, client_uid=None)
¶
POST /communication/tasks/manage/create-task/{postId}.
Il corpo contiene solo i campi passati, in camelCase. expiration deve avere un fuso
orario (ValueError altrimenti, prima di qualunque chiamata). Una sola richiesta: un
errore del server o di rete risale al chiamante, mai un nuovo tentativo.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
post_id
|
int
|
Il post a cui il task appartiene. |
required |
title
|
str | None
|
Titolo del task. |
None
|
description_delta
|
str | None
|
Descrizione in formato Quill delta (JSON). |
None
|
description_plain_text
|
str | None
|
Descrizione in testo semplice. |
None
|
expiration
|
datetime | None
|
Scadenza, |
None
|
priority
|
int | None
|
Priorità (intero del tenant). |
None
|
sub_tasks
|
WriteItems
|
Sub-task, nella forma di |
None
|
assignee_user_id
|
int | None
|
Utente assegnatario. |
None
|
assignee_group_id
|
int | None
|
Gruppo assegnatario. |
None
|
attachments
|
WriteItems
|
Allegati: :class: |
None
|
watcher_user_ids
|
list[int] | None
|
Utenti osservatori. |
None
|
watcher_group_ids
|
list[int] | None
|
Gruppi osservatori. |
None
|
client_uid
|
str | None
|
Identificativo scelto dal chiamante. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
Un |
TaskWriteResult
|
class: |
TaskWriteResult
|
|
create_raw(post_id, req)
¶
Come :meth:create, da un CreateTaskRequestDTO già costruito.
edit(task_id, occ_token, *, title=None, description_delta=None, description_plain_text=None, expiration=None, priority=None, sub_tasks=None, assignee_user_id=None, assignee_group_id=None, add_attachments=None, remove_attachment_ids=None, add_watcher_user_ids=None, remove_watcher_user_ids=None, add_watcher_group_ids=None, remove_watcher_group_ids=None)
¶
PUT /communication/tasks/manage/edit-task/{taskId}/{occToken}.
occ_token è il token di concorrenza letto con :meth:get (Task.occ_token): se il
task è cambiato nel frattempo il server risponde 409 e viene sollevata
:class:~pynteracta.exceptions.ConcurrencyError; la libreria non rilegge e non riprova.
Il corpo contiene solo i campi passati; l'effetto sui campi omessi è deciso dal server.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
task_id
|
int
|
Il task da modificare. |
required |
occ_token
|
int
|
Token di concorrenza ottimistica del task letto. |
required |
title
|
str | None
|
Titolo. |
None
|
description_delta
|
str | None
|
Descrizione in formato Quill delta (JSON). |
None
|
description_plain_text
|
str | None
|
Descrizione in testo semplice. |
None
|
expiration
|
datetime | None
|
Scadenza, |
None
|
priority
|
int | None
|
Priorità. |
None
|
sub_tasks
|
WriteItems
|
Sub-task, nella forma di |
None
|
assignee_user_id
|
int | None
|
Utente assegnatario. |
None
|
assignee_group_id
|
int | None
|
Gruppo assegnatario. |
None
|
add_attachments
|
WriteItems
|
Allegati da aggiungere: |
None
|
remove_attachment_ids
|
list[int] | None
|
Allegati da togliere. |
None
|
add_watcher_user_ids
|
list[int] | None
|
Utenti osservatori da aggiungere. |
None
|
remove_watcher_user_ids
|
list[int] | None
|
Utenti osservatori da togliere. |
None
|
add_watcher_group_ids
|
list[int] | None
|
Gruppi osservatori da aggiungere. |
None
|
remove_watcher_group_ids
|
list[int] | None
|
Gruppi osservatori da togliere. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
Un |
TaskWriteResult
|
class: |
TaskWriteResult
|
token per la modifica successiva. |
edit_raw(task_id, occ_token, req)
¶
Come :meth:edit, da un EditTaskRequestDTO già costruito.
delete(task_id)
¶
DELETE /communication/tasks/manage/delete-task/{taskId}.
Returns:
| Type | Description |
|---|---|
int | None
|
L'id del post che conteneva il task ( |
int | None
|
restituisce. |
Facade Reference¶
pynteracta.models.facade.tasks.Task
¶
Narrow facade over :class:~generated.GetTaskDetailResponseDTO.
Nested TaskCapabilitiesDTO, SubTaskDTO, and TaskReminderDTO are generated as
RootModel[Any] stubs; this facade re-validates them against their typed …1 siblings.
descriptionDelta (Quill rich-text JSON), surveyData, and surveyDataCommentsInfo
are left on .raw per D-v0.4-4.
Attributes:
| Name | Type | Description |
|---|---|---|
raw |
The underlying generated DTO; access additional fields via this escape hatch. |
Source code in src/pynteracta/models/facade/tasks.py
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 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 | |
capabilities
property
¶
Typed capabilities facade.
occ_token
property
¶
Token di concorrenza ottimistica, da passare a TasksAPI.edit.
reminders
property
¶
Re-validate each opaque TaskReminderDTO stub into :class:TaskReminder.
state
property
¶
Task lifecycle state (integer code). Use .raw.currentWorkflowState for the post
workflow state DTO.
sub_tasks
property
¶
Re-validate each opaque SubTaskDTO stub into :class:SubTask.
pynteracta.models.facade.tasks.TaskWriteResult
¶
Façade sulla risposta di create ed edit di un task.
taskData e capabilities sono stub RootModel nei modelli generati: la façade li
rivalida nelle varianti tipizzate TaskDetailDTO1 e TaskCapabilitiesDTO1.
Attributes:
| Name | Type | Description |
|---|---|---|
raw |
Il DTO generato sottostante ( |
Source code in src/pynteracta/models/facade/tasks.py
capabilities
property
¶
Capabilities sul task dopo la scrittura.
next_occ_token
property
¶
Token di concorrenza da usare per la modifica successiva.
task
property
¶
Dati del task dopo la scrittura, tipizzati.
task_id
property
¶
Id del task: dalla risposta di creazione, altrimenti dai dati del task.
from_create(data)
classmethod
¶
Parse the response of create-task.
from_edit(data)
classmethod
¶
pynteracta.models.facade.tasks.TaskCapabilities
¶
Thin facade over :class:~generated.TaskCapabilitiesDTO1.
Attributes:
| Name | Type | Description |
|---|---|---|
raw |
The underlying typed DTO. |
Source code in src/pynteracta/models/facade/tasks.py
pynteracta.models.facade.tasks.SubTask
¶
Thin facade over :class:~generated.SubTaskDTO1.
Attributes:
| Name | Type | Description |
|---|---|---|
raw |
The underlying typed DTO. |
Source code in src/pynteracta/models/facade/tasks.py
pynteracta.models.facade.tasks.TaskReminder
¶
Thin facade over :class:~generated.TaskReminderDTO1.
Attributes:
| Name | Type | Description |
|---|---|---|
raw |
The underlying typed DTO. |