Aller au contenu

Tasks

Ce contenu n’est pas encore disponible dans votre langue.

Tasks are issues in the API. Address a task by its KEY-N identifier (e.g. ENG-42) or by id — on reads AND writes. Create tasks under a project (see Projects) or in bulk with the batch endpoint at the bottom of this page.

Search issues across a workspace by title or exact KEY-N identifier. Returns up to 20 board rows (id, identifier KEY-N, title, state, assignees).

GET /v1/workspaces/{workspaceId}/issues/search

Terminal window
curl -H "Authorization: Bearer $DOTBY_TOKEN" \
"https://api.dotby.app/v1/workspaces/acme/issues/search?query=onboarding"

Response: a list envelope { data, has_more, next_cursor }. While has_more is true, pass next_cursor back as cursor to get the next page.

Get one issue by its identifier (KEY-N, e.g. “ENG-42”). Compact by default: id, identifier, title, state, priority, assigneeIds, startDate, dueDate, plus commentCount/subIssueCount/relationCount/attachmentCount. Heavy sections load only via include: “description” (plain text — an issue description can be huge, so it is never returned unless asked), “labels”, “comments”, “relations”, “subIssues”, “attachments” (file metadata + a short-lived signed download url per file — fetch it promptly, it expires in ~15 minutes; to view an image, request this and fetch the url), “fields” (resolved custom-property values: fieldId, name, kind, raw value, displayValue). “whiteboards” (first 4 description embeds with gated structured content; follow list_whiteboards with issueId and nextCursor for more). Including “description” also returns whiteboardIds for discovery. Unknown include keys are ignored.

GET /v1/workspaces/{workspaceId}/issues/{identifier}

Terminal window
curl -H "Authorization: Bearer $DOTBY_TOKEN" \
"https://api.dotby.app/v1/workspaces/acme/issues/ENG-42"

Response: the resulting object as JSON.

Get the canonical, workspace-scoped web URL for one Task. Returns its stable raw id, current KEY-N identifier, and absolute URL. An old KEY-N retained as an alias after moving the Task resolves to the Task’s current identifier and URL.

GET /v1/workspaces/{workspaceId}/issues/{identifier}/url

Terminal window
curl -H "Authorization: Bearer $DOTBY_TOKEN" \
"https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/url"

Response: the resulting object as JSON.

Filter and page issues across a workspace — the way to NARROW instead of dumping. All filters are optional; multiple VALUES within one filter would be OR (v1 takes single values), and DIFFERENT filters are AND-ed; absent = no constraint. Index-backed filters: projectId, assigneeUserId, creatorUserId, labelId, cycleId, moduleId. Status by dotby’s five workflow buckets (backlog|unstarted|started|completed|canceled) or an exact stateId. Post-filters (best combined with an index-backed filter or a project scope): priority (0-4), typeId, includeArchived (default false). Index-backed date ranges (ms epoch, inclusive): dueFrom/dueTo (on due date), completedFrom/completedTo (on completion time) — a range only matches issues that HAVE that date. Pagination: limit (default 25, max 100), opaque cursor (page until nextCursor is null to get everything), desc (default true); order is “created” (default) or “due” (pages by due date via its index). Note that when you filter by assigneeUserId or labelId, “created” orders by when that assignment/label was added, not when the issue was created (that filter drives the read). A low count with a non-null nextCursor does NOT mean few matches — post-filters can thin a page, so keep paging until nextCursor is null. Rows are COMPACT by default (id, identifier, title, state, priority, assigneeIds, startDate, dueDate); fields:“full” adds labels/module/cycle/type/assignee-names, and include:[“description”,“labels”] adds those per row (description is plain text; comments/relations/sub-issues/attachments are get_issue-only). Response: { issues, nextCursor, count }.

GET /v1/workspaces/{workspaceId}/issues

Terminal window
curl -H "Authorization: Bearer $DOTBY_TOKEN" \
"https://api.dotby.app/v1/workspaces/acme/issues?limit=25"

Response: a list envelope { data, has_more, next_cursor }. While has_more is true, pass next_cursor back as cursor to get the next page.

List the current user’s issues in a workspace: assigned to them, created by them, or subscribed to.

GET /v1/workspaces/{workspaceId}/issues/mine

Terminal window
curl -H "Authorization: Bearer $DOTBY_TOKEN" \
"https://api.dotby.app/v1/workspaces/acme/issues/mine?tab=assigned"

Response: a list envelope { data, has_more, next_cursor }. While has_more is true, pass next_cursor back as cursor to get the next page.

List the sub-issues (children) of an issue.

GET /v1/workspaces/{workspaceId}/issues/{issueId}/sub-issues

Terminal window
curl -H "Authorization: Bearer $DOTBY_TOKEN" \
"https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/sub-issues"

Response: a list envelope { data, has_more, next_cursor }. While has_more is true, pass next_cursor back as cursor to get the next page.

List the comments on an issue, oldest first.

GET /v1/workspaces/{workspaceId}/issues/{issueId}/comments

Terminal window
curl -H "Authorization: Bearer $DOTBY_TOKEN" \
"https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/comments"

Response: a list envelope { data, has_more, next_cursor }. While has_more is true, pass next_cursor back as cursor to get the next page.

Add a comment to a Task. body is always Markdown, converted and validated as rich text by the server; no format flag or TipTap JSON is needed. @mentions notify. Optionally reply to a comment.

POST /v1/workspaces/{workspaceId}/issues/{issueId}/comments

Terminal window
curl -X POST "https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/comments" \
-H "Authorization: Bearer $DOTBY_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"body":"Plain text content."}'

Response: the resulting object as JSON.

List the relations from an issue (blocks / blocked_by / relates / duplicate).

GET /v1/workspaces/{workspaceId}/issues/{issueId}/relations

Terminal window
curl -H "Authorization: Bearer $DOTBY_TOKEN" \
"https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/relations"

Response: a list envelope { data, has_more, next_cursor }. While has_more is true, pass next_cursor back as cursor to get the next page.

Create a relation from one issue to another.

POST /v1/workspaces/{workspaceId}/issues/{issueId}/relations

Terminal window
curl -X POST "https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/relations" \
-H "Authorization: Bearer $DOTBY_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"relatedIssueId":"ENG-7","type":"blocks"}'

Response: the resulting object as JSON.

Remove a relation between two issues. Pass the same (issueId, relatedIssueId, type) you’d give to link_issues; idempotent — a no-op when the relation isn’t there.

DELETE /v1/workspaces/{workspaceId}/issues/{issueId}/relations

Terminal window
curl -X DELETE -H "Authorization: Bearer $DOTBY_TOKEN" \
"https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/relations?relatedIssueId=ENG-7&type=blocks"

Response: the resulting object as JSON.

List an issue’s curated links to internal surfaces (page / whiteboard / ERD) and external URLs.

GET /v1/workspaces/{workspaceId}/issues/{issueId}/links

Terminal window
curl -H "Authorization: Bearer $DOTBY_TOKEN" \
"https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/links"

Response: a list envelope { data, has_more, next_cursor }. While has_more is true, pass next_cursor back as cursor to get the next page.

Add a curated link from an issue to an internal surface (kind “page” / “whiteboard” / “erd”, with targetId = that item’s id) or an external URL (kind “url”, with targetId = the http(s) URL). Idempotent per (kind, targetId). Optional label overrides the display text.

POST /v1/workspaces/{workspaceId}/issues/{issueId}/links

Terminal window
curl -X POST "https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/links" \
-H "Authorization: Bearer $DOTBY_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"kind":"url","targetId":"https://example.com/spec"}'

Response: the resulting object as JSON.

Remove a curated link from an issue by its (kind, targetId) — the same pair you passed to add_link. Idempotent.

DELETE /v1/workspaces/{workspaceId}/issues/{issueId}/links

Terminal window
curl -X DELETE -H "Authorization: Bearer $DOTBY_TOKEN" \
"https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/links?kind=url&targetId=https%3A%2F%2Fexample.com%2Fspec"

Response: the resulting object as JSON.

Update a Task’s fields. description is always Markdown, converted and validated as rich text by the server; no format flag or TipTap JSON is needed. Only pass the fields to change. An empty description clears it; omitting it leaves it unchanged.

PATCH /v1/workspaces/{workspaceId}/issues/{issueId}

Terminal window
curl -X PATCH "https://api.dotby.app/v1/workspaces/acme/issues/ENG-42" \
-H "Authorization: Bearer $DOTBY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"Ship the onboarding flow"}'

Response: the resulting object as JSON.

Permanently delete an issue and its comments/relations/attachments. Irreversible.

DELETE /v1/workspaces/{workspaceId}/issues/{issueId}

Terminal window
curl -X DELETE -H "Authorization: Bearer $DOTBY_TOKEN" \
"https://api.dotby.app/v1/workspaces/acme/issues/ENG-42"

Response: the resulting object as JSON.

Add a top-level task to another project without duplicating it. The task keeps one title, description, comments, attachments, subtasks, relations, and dates; the added project gets its own board column, ordering, assignees, and planning slots. Current assignees are copied by default, then remain project-specific. The caller must be a non-guest member of both projects. This is idempotent: an existing project membership is returned unchanged.

POST /v1/workspaces/{workspaceId}/issues/{issueId}/projects

Terminal window
curl -X POST "https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/projects" \
-H "Authorization: Bearer $DOTBY_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"projectId":"ENG"}'

Response: the resulting object as JSON.

Remove a task from one added project without deleting the shared task. A non-guest member of either the task’s home project or the target project may recall or eject an existing membership. With access to both projects, this is idempotent: an already-absent membership returns removed: false.

DELETE /v1/workspaces/{workspaceId}/issues/{issueId}/projects/{projectId}

Terminal window
curl -X DELETE -H "Authorization: Bearer $DOTBY_TOKEN" \
"https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/projects/ENG"

Response: the resulting object as JSON.

Set or clear ONE custom-property value on an issue (Spec 109). value is {“kind”: <the field’s kind>, “value”: …} — text/url → string; number → number; date → ms epoch number; checkbox → boolean; select → array of option ids; member → array of user ids — or null to clear. Kinds/options/members are validated server-side; member values obey the same assignability rules as assignees.

PATCH /v1/workspaces/{workspaceId}/issues/{issueId}/fields

Terminal window
curl -X PATCH "https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/fields" \
-H "Authorization: Bearer $DOTBY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"fieldId":"FIELD_ID","value":{"kind":"text","value":"Blue"}}'

Response: the resulting object as JSON.

Move an issue to a workflow state (board column) and/or reorder it.

POST /v1/workspaces/{workspaceId}/issues/{issueId}/move

Terminal window
curl -X POST "https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/move" \
-H "Authorization: Bearer $DOTBY_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"stateId":"STATE_ID"}'

Response: the resulting object as JSON.

Replace an issue’s entire assignee set (pass [] to clear).

PATCH /v1/workspaces/{workspaceId}/issues/{issueId}/assignees

Terminal window
curl -X PATCH "https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/assignees" \
-H "Authorization: Bearer $DOTBY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"userIds":["USER_ID"]}'

Response: the resulting object as JSON.

Add one assignee to an issue (idempotent).

POST /v1/workspaces/{workspaceId}/issues/{issueId}/assignees

Terminal window
curl -X POST "https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/assignees" \
-H "Authorization: Bearer $DOTBY_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"userId":"USER_ID"}'

Response: the resulting object as JSON.

Remove one assignee from an issue.

DELETE /v1/workspaces/{workspaceId}/issues/{issueId}/assignees/{userId}

Terminal window
curl -X DELETE -H "Authorization: Bearer $DOTBY_TOKEN" \
"https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/assignees/USER_ID"

Response: the resulting object as JSON.

Add a label to an issue (idempotent).

POST /v1/workspaces/{workspaceId}/issues/{issueId}/labels

Terminal window
curl -X POST "https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/labels" \
-H "Authorization: Bearer $DOTBY_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"labelId":"LABEL_ID"}'

Response: the resulting object as JSON.

Remove a label from an issue.

DELETE /v1/workspaces/{workspaceId}/issues/{issueId}/labels/{labelId}

Terminal window
curl -X DELETE -H "Authorization: Bearer $DOTBY_TOKEN" \
"https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/labels/LABEL_ID"

Response: the resulting object as JSON.

Nest an existing issue under another as a sub-issue — this is how you make one task a subtask of another. Both issues must be in the SAME workspace; re-parents the child if it already had a parent (the change is global). Rejects self-nesting and cycles. (To create a NEW issue already nested, pass parentIssueId to create_issue instead. PATCH update_issue does not accept a parent field.)

POST /v1/workspaces/{workspaceId}/issues/{parentIssueId}/sub-issues

Terminal window
curl -X POST "https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/sub-issues" \
-H "Authorization: Bearer $DOTBY_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"childIssueId":"ENG-43"}'

Response: the resulting object as JSON.

Detach a sub-issue from its parent. The issue stays alive as a top-level issue — only its parent link is cleared, it is never deleted. Idempotent when it has no parent.

DELETE /v1/workspaces/{workspaceId}/issues/{childIssueId}/parent

Terminal window
curl -X DELETE -H "Authorization: Bearer $DOTBY_TOKEN" \
"https://api.dotby.app/v1/workspaces/acme/issues/ENG-43/parent"

Response: the resulting object as JSON.

Archive an issue (soft delete — reversible in the app).

POST /v1/workspaces/{workspaceId}/issues/{issueId}/archive

Terminal window
curl -X POST "https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/archive" \
-H "Authorization: Bearer $DOTBY_TOKEN" \
-H "Idempotency-Key: $(uuidgen)"

Response: the resulting object as JSON.

Attach a SMALL file you already hold (a screenshot, a short document) to a task, passing its bytes inline as base64. data accepts bare base64 or a full data: URI. Limited to 1MB — MCP clients corrupt larger base64 in tool arguments, so for anything bigger (or any file on disk) use create_attachment_upload + register_attachment instead. Allowed: images, video, audio, text, PDF, Office/OpenDocument, zip, json, rtf — executables are rejected. Pass commentId to attach inside a comment rather than on the task itself. Read it back later with read_attachment.

POST /v1/workspaces/{workspaceId}/issues/{issueId}/attachments

Terminal window
curl -X POST "https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/attachments" \
-H "Authorization: Bearer $DOTBY_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"fileName":"screenshot.png","contentType":"image/png","data":"iVBORw0KGgoAAA..."}'

Response: the resulting object as JSON.

Step 1 of 2 for a file of ANY size up to 25MB (the path to use for anything on disk, and for anything over 1MB). Returns { url, key }: PUT the raw bytes to url with a native HTTP client (e.g. curl -X PUT --upload-file <path> "<url>"), then call register_attachment with the same key to finish. The upload URL is short-lived — use it promptly. contentType and size are checked here and re-verified against the real uploaded object at register time, so they must be accurate.

POST /v1/workspaces/{workspaceId}/issues/{issueId}/attachments/upload-url

Terminal window
curl -X POST "https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/attachments/upload-url" \
-H "Authorization: Bearer $DOTBY_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"contentType":"image/png","size":4096}'

Response: the resulting object as JSON.

Step 2 of 2: finish an upload started with create_attachment_upload, after the bytes have been PUT to the returned url. Pass the same key. The real object’s size and type are verified here — a mismatched or disallowed file is rejected and deleted. Pass commentId to attach inside a comment rather than on the task itself.

POST /v1/workspaces/{workspaceId}/issues/{issueId}/attachments/register

Terminal window
curl -X POST "https://api.dotby.app/v1/workspaces/acme/issues/ENG-42/attachments/register" \
-H "Authorization: Bearer $DOTBY_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"key":"ENG","fileName":"screenshot.png","contentType":"image/png","size":4096}'

Response: the resulting object as JSON.

Create up to 100 issues in one call with PER-ITEM results under HTTP 200 — one bad item never poisons the rest. Body: { projectId (id or KEY), items: [{title, description?, …create_issue fields}], plus shared defaults (stateId, priority, assigneeUserIds, labelIds) applied to every item. Task descriptions are always Markdown, converted and validated by the server. Legacy descriptionFormat values at batch or item level are ignored. Honors Idempotency-Key for the whole batch. Response: { succeeded: [{index, …}], failed: [{index, problem}] }.

POST /v1/workspaces/{workspaceId}/issues/batch

Terminal window
curl -X POST "https://api.dotby.app/v1/workspaces/acme/issues/batch" \
-H "Authorization: Bearer $DOTBY_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"projectId":"ENG","items":[{"title":"First task"},{"title":"Second task"}]}'

Response: HTTP 200 with PER-ITEM results { succeeded: [{index, …}], failed: [{index, problem}] } — one bad item never fails the rest. Check failed even on 200.

Every error is an RFC 9457 application/problem+json body with a machine-stable code. Branch on the code, not the message:

  • 401 — unauthenticated / invalid_token: the bearer token is missing, expired, or revoked. Re-authenticate; do not retry as-is.
  • 403 — insufficient_scope / forbidden / upgrade_required: the token works but may not do this. upgrade_required means the workspace is not on Pro.
  • 404 — not_found_or_forbidden: the resource does not exist for this token. Never probe for existence.
  • 409 — idempotency_conflict: same Idempotency-Key, different body. Mint a new key.
  • 429 — rate_limited: back off for the number of seconds in Retry-After, then retry.
  • 400 — validation_failed: the request shape is wrong. Fix the request; retrying unchanged will fail again.