DoskaDocs
Docs / Integrations

REST API

Doska REST API v1 for CI and scripts: update diagrams from code, import and check infrastructure, publish Markdown docs from git.

The REST API lets CI pipelines and scripts keep Doska in sync with your repositories: push diagram code to a board, rebuild an infrastructure diagram after terraform apply, check a hand-drawn diagram for drift, and publish a folder of Markdown files as documents. Changes go through the live board, so anyone who has it open sees them at once.

Authentication

Every request needs an API token in the Authorization header:

bash
curl -s https://getdoska.top/api/v1/boards/$BOARD_ID/diagrams \
  -H "Authorization: Bearer $DOSKA_TOKEN"

Create a token in Settings and API tokens → Access tokens → Create token. A token belongs to one organization, can be limited to some projects, and has a level: read, comment or edit. It never has more rights than its owner, so an edit token still can't change a board where you are a viewer. The details are on the Claude and MCP page.

Tokens work only for /api/v1/* and MCP. Any other address answers 403 with the code token_forbidden. Requests and responses are JSON.

Board and project IDs are in the address bar: https://getdoska.top/b/<boardId> and https://getdoska.top/p/<projectId>.

Diagrams

A diagramId is your own stable name for a diagram on a board: Latin letters, digits, - and _, up to 64 characters. For example, architecture.

Create or update a diagram

PUT /api/v1/boards/:boardId/diagrams/:diagramId · token level edit, board role Editor

Creates the diagram if it doesn't exist, or applies the new code to the existing one with the same rules as the Apply button in the code editor: manual positions and styles are kept.

bash
jq -Rs '{source: ., name: "Architecture"}' docs/architecture.mmd | \
  curl -fsS -X PUT "https://getdoska.top/api/v1/boards/$BOARD_ID/diagrams/architecture" \
    -H "Authorization: Bearer $DOSKA_TOKEN" -H "Content-Type: application/json" --data-binary @-
FieldTypeDescription
sourcestringDiagram code: Mermaid (flowchart, architecture-beta, sequenceDiagram), D2 or nwdiag. The language is detected automatically
namestring, optionalDisplay name, up to 120 characters
relayoutboolean, default falseLay out the whole diagram again, discarding manual positions

Response: 201 when the diagram was created, 200 when it was updated.

json
{
  "ok": true,
  "created": false,
  "summary": { "nodesAdded": 1, "nodesUpdated": 0, "nodesRemoved": 0, "edgesAdded": 1, "edgesUpdated": 0,
               "edgesRemoved": 0, "groupsAdded": 0, "groupsUpdated": 0, "groupsRemoved": 0,
               "moved": 0, "overridesKept": 0, "detached": 0 },
  "diagnostics": []
}

If the code has errors, the answer is 422 and the board is not changed:

json
{
  "error": "The diagram code has errors — the board was not changed",
  "code": "invalid_diagram",
  "diagnostics": [{ "line": 2, "col": 6, "severity": "error", "message": "Unclosed node shape \"api\": expected \"]\"" }]
}

Read diagrams

GET /api/v1/boards/:boardId/diagrams · token level read

json
[{ "id": "architecture", "name": "Architecture", "appliedAt": 1761480000000, "hasUnappliedChanges": false }]

GET /api/v1/boards/:boardId/diagrams/:diagramId · token level read

Returns { id, name, source, draft, appliedAt, revisions }. source is the last applied code, draft is what is in the code editor now, and revisions is the number of saved revisions.

Delete a diagram

DELETE /api/v1/boards/:boardId/diagrams/:diagramId · token level edit, board role Editor

Removes the diagram and all its elements from the board. Response: { "ok": true }.

Validate code

POST /api/v1/diagrams/validate · any token

Checks code without touching a board. Handy in a pre-commit hook.

bash
jq -Rs '{source: .}' docs/architecture.mmd | \
  curl -fsS -X POST https://getdoska.top/api/v1/diagrams/validate \
    -H "Authorization: Bearer $DOSKA_TOKEN" -H "Content-Type: application/json" --data-binary @-

Response: { ok, diagnostics, stats: { nodes, edges, subgraphs } }; stats is null when the code is invalid.

Infrastructure

Build diagrams from Terraform (terraform show -json or a state file), Kubernetes manifests (including helm template output) or docker-compose files. What ends up on the board is described in Infrastructure.

The request body takes either content with the file text, or files: [{ name, content }] for several files. detail is "overview" (default) or "detailed". The file type is detected automatically; up to 25 MB per file. Only names, types and relations are stored, never attribute values.

Import

POST /api/v1/boards/:boardId/infra/import · token level edit, board role Editor

Builds or updates the diagram (ID infra-<source> unless you pass diagramId; name is optional) and keeps the import on the board for drift checks.

bash
terraform show -json > state.json
jq -Rs '{content: .}' state.json | \
  curl -fsS -X POST "https://getdoska.top/api/v1/boards/$BOARD_ID/infra/import" \
    -H "Authorization: Bearer $DOSKA_TOKEN" -H "Content-Type: application/json" --data-binary @-
json
{ "ok": true, "source": "terraform", "diagramId": "infra-terraform",
  "summary": { "nodesAdded": 12, "…": 0 }, "warnings": [],
  "drift": { "inSync": true, "bound": 13, "total": 13, "missing": [], "gone": [], "missingLinks": [], "extraLinks": [] } }

Check for drift

POST /api/v1/boards/:boardId/infra/check · token level edit, board role Editor

Compares the board with the file and keeps the file as the reference; the diagram itself isn't changed. With notify: true, a comment is posted on the board when it is out of date. The same comment is not posted twice in a row.

Response: { ok, source, warnings, drift, commentThreadId }. In drift:

FieldMeaning
inSynctrue when there are no differences
missingReal resources not on the board: [{ id, name, kind }]
goneBoard elements bound to resources that no longer exist: [{ elementId, resource, label }]
missingLinksConnections not on the board: [{ from, to, kind }]
extraLinksConnections on the board that aren't in the infrastructure: [{ connectorId, from, to }]

To fail a CI step when the board is out of date, pipe the response to jq -e '.drift.inSync'.

List imports

GET /api/v1/boards/:boardId/infra · token level read

Every import on the board with its current drift: [{ source, importedAt, by, detail, diagramId, drift }].

Docs from git

POST /api/v1/projects/:projectId/docs/sync · token level edit, project role Editor

CI sends the Markdown files of a repository folder, and each file becomes a document in the project.

json
{
  "repo": "acme/payments",
  "ref": "main",
  "sha": "abc1234",
  "fileUrl": "https://github.com/acme/payments/blob/main/docs/{path}",
  "folder": "Docs",
  "prune": false,
  "files": [{ "path": "adr/0001-kafka.md", "markdown": "# Use Kafka\n…" }]
}
  • A document is matched by repo and path. New files create documents, changed files update them (the previous text stays in version history), unchanged files are left alone.
  • The title comes from title: in front matter, then the first # heading, then the file name. Subdirectories become folders inside folder.
  • Relative links between files point to the matching documents.
  • With prune: true, documents of this repo whose files are gone are deleted.
  • Limits: up to 500 files, 1 MB per file and 8 MB in total.

Response: { created, updated, unchanged, removed, docs: [{ path, id, url, status }] }.

The server also hosts a ready-made script with no dependencies (Node 18+). In GitHub Actions it picks up the repository, branch and commit from the environment:

bash
curl -fsSL https://getdoska.top/docs-sync.mjs -o docs-sync.mjs
DOSKA_TOKEN=dsk_… node docs-sync.mjs --project <projectId> --dir docs --folder Docs

A ready workflow with your project ID is in the app: open the project, click Create → Docs from git….

Example: GitHub Actions

yaml
name: Sync diagrams
on:
  push:
    paths: ['docs/diagrams/**.mmd']
jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Push diagrams to Doska
        env:
          DOSKA_BOARD: ${{ vars.DOSKA_BOARD }}
          DOSKA_TOKEN: ${{ secrets.DOSKA_TOKEN }}
        run: |
          for f in docs/diagrams/*.mmd; do
            id=$(basename "$f" .mmd)
            jq -Rs --arg n "$id" '{source: ., name: $n}' "$f" | \
              curl -fsS -X PUT "https://getdoska.top/api/v1/boards/$DOSKA_BOARD/diagrams/$id" \
                -H "Authorization: Bearer $DOSKA_TOKEN" -H "Content-Type: application/json" --data-binary @-
          done

GitLab CI uses the same curl command in script:.

Errors

Errors come as JSON with an HTTP status:

json
{ "error": "Board not found", "code": "not_found" }
StatusCodeWhen
400bad_request, invalid_infrastructure, duplicate_pathThe request body or file can't be used
401unauthorizedNo token, or the token is revoked, expired or disabled by the organization
403forbidden, token_forbiddenThe token level or your role is too low, or the address isn't part of the API
404not_foundThe board or project doesn't exist or the token can't see it
413too_largeThe request is too large
422invalid_diagramThe diagram code has errors; nothing was changed
429rate_limitedToo many requests; try again in a minute

A board you can't access answers 404, not 403, so the API doesn't reveal that it exists. Messages are in the token owner's interface language; send X-Doska-Locale: en or ru to choose.

Rate limits

  • Up to 600 requests per minute from one address.
  • Infrastructure import and check, and docs sync: up to 30 requests per minute each.
  • Diagram code up to 200 KB, 2,000 nodes and 5,000 edges.