0.x — pre-release, no compatibility promise yet.What this means
Python SDK
What this is: tasksmate, a typed client generated from the same contract as this site.
When you need it: any Python that talks to TasksMate — scripts, services, notebooks.
from tasksmate import TasksMate
tm = TasksMate(token="tm_live_…") # or set TASKSMATE_TOKEN and call TasksMate()for task in tm.tasks.list(org_id="O0020"): # every task, page after page print(task.task_id, task.status, task.title)tm.views.rows("V123456").to_dataframe() # a saved view as a pandas DataFrame- Token: mint it in TasksMate → Developers → Tokens (it is shown once).
- OAuth apps: the authorization flow (
/oauth/authorize,/oauth/token,/.well-known/*) is not wrapped here — run it with any OAuth 2.1 library; the access token it returns is a token like any other:TasksMate(token=…). - Reach: a token belongs to one organization and carries scopes (
tasks:read,tasks:write,projects:read, …); each method's docstring names the scope it needs. - Try it:
examples/quickstart.pyruns a full round trip — create, conditional update, filtered list, DataFrame, delete — and leaves nothing behind.
Install
Section titled “Install”pip install tasksmate # the client (Python 3.10+)pip install "tasksmate[pandas]" # + DataFramespip install "tasksmate[cli]" # + the `tm` command lineNot on PyPI yet: until the first release, install from a checkout — pip install -e ".[pandas,cli]" — or from a
built wheel (python -m build, then pip install "dist/tasksmate-<version>-py3-none-any.whl[pandas]").
Lists and pagination
Section titled “Lists and pagination”Every list returns a Page: .data (this page), .next_cursor, and iteration over every item, following the
cursor until it is None (a page may be short, or even empty, while more follow — iteration handles it).
page = tm.tasks.list(org_id="O0020", filter={"status": ["in_progress", "blocked"], "search": "invoice"}, sort_by="due_date", limit=200)page.data, page.next_cursor # the first pagefor task in page: ... # all of themfor p in page.pages(): ... # page by pagepage.envelope # the full response model (some lists carry sums beside `data`)filter={key: value} becomes filter[key]=value (a list is comma-joined); an unknown key raises ValueError
naming the allowed ones. The grammar — keys, sorts, limits — is the API's
list grammar.
Errors
Section titled “Errors”Every API error is application/problem+json, and every problem type is its own exception, all subclasses of
tasksmate.TasksMateError (itself an APIError) with .status, .type, .title, .detail, .request_id,
.errors:
from tasksmate import InsufficientScopeError, NotFoundError, PreconditionFailedError, TasksMateError
try: tm.tasks.update("T123456", {"status": "completed"})except InsufficientScopeError as exc: print("this token needs", exc.required_scope) # e.g. tasks:writeexcept NotFoundError: ...except TasksMateError as exc: print(exc.status, exc.detail, "— quote request_id", exc.request_id)| Status | Exceptions |
|---|---|
| 400 | BadRequestError · InvalidParameterError · IdempotencyKeyInvalidError |
| 401 | AuthenticationError · TokenInvalidError · TokenExpiredError · TokenRevokedError |
| 403 | ForbiddenError · InsufficientScopeError · TestTokenReadOnlyError · TokenPolicyError (also 422) |
| 404 · 409 · 412 | NotFoundError · ConflictError (IdempotencyKeyInFlightError) · PreconditionFailedError |
| 422 | UnprocessableEntityError · ValidationError · IdempotencyKeyReusedError · UrlRefusedError |
| 429 · 5xx | RateLimitedError (.retry_after) · InternalError |
| — | APIConnectionError / APITimeoutError (no HTTP answer) · ResponseValidationError (a 2xx this SDK version cannot read — upgrade) |
pandas
Section titled “pandas”tm.tasks.list(org_id="O0020").to_dataframe() # every page; to_dataframe(all_pages=False) for onetm.views.rows("V123456").to_dataframe()One row per item, with the API's own field names:
- a nested object becomes dotted columns (
type_data.severity); - a list of scalars becomes one comma-separated string (
tags→"api, backend"); *_atcolumns are timezone-aware datetimes,*_datecolumnsdatetime.date(missing →None).
Needs the pandas extra — without it you get an ImportError saying so.
Webhooks
Section titled “Webhooks”from tasksmate import webhooks
def receive(headers, raw_body: bytes): if not webhooks.verify(SECRET, headers, raw_body): # the RAW body, not re-serialized JSON return 400 event = webhooks.parse(raw_body) # WebhookEvent: .id .type_ .org_id .data.resource_id … ... # dedupe on event.id — delivery is at-least-once return 200verify implements the Standard Webhooks recipe TasksMate signs with:
- Signature:
v1,HMAC-SHA256 overid.timestamp.body, keyed by the base64-decoded part of thewhsec_…secret. - Replay window: timestamps more than
toleranceseconds (300) away are refused. - Rotation, both ways: during the 24 h after a secret rotation TasksMate sends two signatures, and you may pass
both secrets —
verify([new, old], …)— while you switch over. - Errors:
raise_on_failure=TrueraisesWebhookVerificationErrorwith the reason instead of returningFalse.
Every method, generated per resource: the API reference shows each operation’s Python call.