Developers
REST API
Use API tokens to read and change projects, issues, comments, members and channels from scripts and integrations.
Deckbell has a REST API for scripts, internal tools and integrations. It works with JSON over HTTPS, and every request uses an API token that belongs to you and one workspace.
- Base URL:
https://api.deckbell.com/api/v1 - OpenAPI description: api.deckbell.com/api/v1/openapi.yaml (import it into Postman, Insomnia or a code generator)
To be told about changes as they happen instead of polling, use webhooks. To use Deckbell from an AI assistant, see the MCP server.
Create an API token
- Open Settings → API tokens (in the Workspace group).
- Choose New token, give it a name you'll recognize (for example "Zapier" or "CI"), and tick what it may do. Each area (projects, issues, comments, chat, members) has Read and Write; write includes read.
- Pick when it expires, or Never.
- Copy the token (it starts with
dkb_). It's shown only once; Deckbell keeps only a fingerprint of it.
A token acts as you: it can never do more than your role in the workspace allows, even with every scope. It works in that one workspace only, and stops working if you leave the workspace or are deactivated.
The token list shows when each token was last used. Revoke a token you no longer need, or if it leaks; anything using it stops working right away. Workspace owners and admins also see everyone else's tokens and can revoke them. Creating and revoking tokens is recorded in the audit log.
Make a request
Send the token in the Authorization header:
curl https://api.deckbell.com/api/v1/issues?assignee=me \
-H "Authorization: Bearer dkb_your_token"
Create an issue:
curl https://api.deckbell.com/api/v1/issues \
-H "Authorization: Bearer dkb_your_token" \
-H "Content-Type: application/json" \
-d '{"project": "WEB", "title": "Checkout button is broken", "priority": "high", "labels": ["Bug"], "state": "Todo"}'
Statuses, labels and priorities can be given by name (case doesn't matter),
and people by their member id or "me".
Endpoints
| Endpoint | What it does | Scope |
|---|---|---|
GET /me | The person, workspace and scopes of the token | any |
GET /projects, GET /projects/{key} | List projects, get one | projects:read |
POST /projects, PATCH /projects/{key} | Create or edit a project | projects:write |
GET /projects/{key}/states | A project's statuses (board columns) | projects:read or issues:read |
GET /projects/{key}/labels, POST …/labels | List or add labels | read / projects:write |
GET /issues | List and search issues (filters below) | issues:read |
POST /issues | Create an issue | issues:write |
GET /issues/{id} | One issue, by key (WEB-42) or id | issues:read |
PATCH /issues/{id} | Change title, description, status, priority, assignee, labels, estimate, or archive it | issues:write |
DELETE /issues/{id} | Delete an issue for good | issues:write |
GET /issues/{id}/comments, POST …/comments | Read or add comments | comments:read / comments:write |
GET /members | People in the workspace and their roles | members:read |
GET /channels, GET /channels/{channel} | Channels you're in | chat:read |
GET /channels/{channel}/messages, POST …/messages | Read or post messages | chat:read / chat:write |
Projects can be referred to by key (WEB), slug or id, and channels by name
(general) or id. Direct messages aren't available through the API.
Filtering issues
GET /issues takes any of these query parameters (several values are
comma-separated):
project: project key, slug or idstate: status name or id, e.g.In Progressstate_category:backlog,unstarted,started,completed,canceledassignee: a member id,me,none, oragent:<id>label,priority(none,urgent,high,medium,low)q: text in the title or descriptionupdated_since,created_since: an ISO 8601 date-timeinclude_archived=trueto include archived issuessort:-updated_at(default),updated_at,created_at,-created_at,priority
Pagination
Lists return a page of results and a cursor for the next one:
{
"data": [ … ],
"pagination": { "next_cursor": "eyJpZCI6…", "has_more": true, "limit": 25 }
}
Pass cursor=<next_cursor> to get the next page, and limit (1 to 100) to
change the page size.
Errors
Errors always have the same shape, with a stable code:
{
"error": {
"code": "validation_failed",
"message": "The title field is required.",
"details": { "errors": { "title": ["The title field is required."] } }
}
}
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthenticated | No token, or it's invalid, expired or revoked |
| 403 | insufficient_scope | The token lacks a scope (details.required_scope says which) |
| 403 | forbidden | Your role doesn't allow this |
| 404 | not_found | It doesn't exist in this workspace |
| 422 | validation_failed | Something in the request is wrong (details.errors per field) |
| 402 | plan_limit | Your plan's limit is reached (for example the Free plan's issue limit) |
| 429 | rate_limited | Too many requests; wait Retry-After seconds |
Rate limits
Each token may make a number of requests per minute, by your workspace's
plan: 60 on Free, 300 on Pro, 600 on Business and 1,200 on Enterprise. Every
response has X-RateLimit-Limit and X-RateLimit-Remaining headers. Calls
from the MCP server count towards the same limit.
Plans and permissions
The API is available on every plan. Your plan's limits apply just as in the app (for example, the Free plan's number of projects and issues), and so does your role: a token made by someone who can't create projects can't create them either. Assigning an issue to an AI agent through the API starts the agent, as it does in the app.