Members
Read the workspace roster and resolve people to user ids. Never guess a userId — resolve names/emails first, then pass the id to assignee writes.
List members
Section titled “List members”List the workspace’s assignable members. Returns { members: [{ userId, name, email, role, editableProjectKeys? }], total, truncated }; userId is what create_issue/set_assignees/add_assignee require. role is admin/manager/member, or guest for an external guest editor — a guest carries editableProjectKeys (e.g. ["ENG"]) and can ONLY be assigned to issues in those projects (assignment elsewhere is rejected). View-only guests and deactivated members are excluded (assignable nowhere). The list is name-sorted and capped at 250 — truncated: true means the workspace exceeds the cap (use resolve_member to find a specific person instead of paging).
GET /v1/workspaces/{workspaceId}/members
curl -H "Authorization: Bearer $DOTBY_TOKEN" \ "https://api.dotby.app/v1/workspaces/acme/members"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.
Resolve member
Section titled “Resolve member”Resolve a person by name or email to their userId(s), best match first. Use this to turn “assign it to José” into an assignee id without paging the whole roster. Matching ignores accents, punctuation, and case; searches only assignable members (view-only guests and deactivated members excluded); returns { matches: [{ userId, name, email, role, editableProjectKeys? }], total, truncated }, up to limit (default 5) candidates. A match with role: "guest" is an external guest editor assignable ONLY in the projects listed in editableProjectKeys. Empty matches means no match — but if truncated is true the roster overflowed the 250 cap, so refine the query rather than concluding the person is absent. Never guess a userId.
GET /v1/workspaces/{workspaceId}/members/resolve
curl -H "Authorization: Bearer $DOTBY_TOKEN" \ "https://api.dotby.app/v1/workspaces/acme/members/resolve?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.
Errors
Section titled “Errors”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_requiredmeans 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: sameIdempotency-Key, different body. Mint a new key.429—rate_limited: back off for the number of seconds inRetry-After, then retry.400—validation_failed: the request shape is wrong. Fix the request; retrying unchanged will fail again.