Ir al contenido

Tasks

Esta página aún no está disponible en tu idioma.

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.

Full-text search issues across a workspace by TITLE. 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, 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). 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.

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 the five Linear 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, 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 an issue. body is plain text; @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 an issue’s fields. description is plain text. Only pass the fields to change.

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.

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 project; re-parents the child if it already had a parent. Rejects self-nesting and cycles. (To create a NEW issue already nested, pass parentIssueId to create_issue instead.)

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. 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:

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