REST API

Scripts, integrations and other tools outside Jira can read and change TreeCraft hierarchies through the app's REST API. This page is for the developers who build them. It covers turning the API on, getting a token, the scopes, every endpoint, and the rules every call follows.

On this page

What the API is for

The API lets a program do what a person does on the app's pages, as that person. For example, it can:

  • list the hierarchies someone can open, and read their rows;
  • keep a hierarchy in step with another tool, by adding, moving and removing rows;
  • create, rename, archive or delete hierarchies;
  • read a hierarchy's rules and the saved views.

Every call acts as the person who authorized it, with the same checks as the app's own pages:

A row never shows a work item the caller can't see in Jira. The API gives work item ids, not work item fields: read the work items themselves from Jira's own REST API with the same token, so Jira's permissions apply there too.

This is version 1, in beta. The API is built on Forge app REST APIs, which Atlassian offers as a Preview. Atlassian may change them at shorter notice than usual, so the API stays in beta until they are generally available.

It runs on Atlassian

Calls go through Atlassian's API gateway to the app, which runs on Atlassian's cloud like the rest of TreeCraft. The app sends no data outside Atlassian. What the API keeps, such as the record of a retried call, stays in the app's storage on Atlassian with the rest of the site's data. With the API on, TreeCraft is still built to Atlassian's Runs on Atlassian requirements.

The gateway checks the token and its scopes before the call reaches the app. A token without the scope a route needs never reaches TreeCraft.

Turn the API on

Two switches must be on for a call to reach the app. Both belong to the site, and turning off either one stops every call at once.

The first version of TreeCraft with the API is a major update of the app. A site admin approves that update once before the API is available.

Atlassian's switch

Atlassian's switch is off by default. A site admin or an organization admin turns it on:

  1. Go to Atlassian Administration and select your organization.
  2. Under Apps, go to Sites and select the site where TreeCraft is installed.
  3. Select Connected apps, find TreeCraft, and select View app details.
  4. On the Details tab, turn on App REST APIs.

TreeCraft's switch

TreeCraft's own switch is on by default. Jira admins and app admins find it in the app's settings, in Jira administration under Apps: select REST API in the Access group. The page has:

  • Allow calls to this app's REST API on this site, the switch. A change reaches every call within a minute. While it is off, every call answers 403 API_TURNED_OFF.
  • Base URL, both forms, filled in for your site, each with a copy button.
  • Identifiers: the app id, the environment id and the cloud id.
  • Scopes: the three scopes and what each one allows.

Get an access token

The API takes an OAuth 2.0 (3LO) access token. A token belongs to one person, and every call made with it acts as that person. Only members of the site where TreeCraft is installed can set up the integration.

  1. Open the Atlassian Developer Console. Select Create, then OAuth 2.0 integration, and give it a name.
  2. Under Permissions, select Add Marketplace or custom app. Pick your site, then TreeCraft, then the scopes your integration needs. Pick only those.
  3. Also add the Jira scope read:forge-app:jira. Every call to an app's REST API needs it.
  4. Under Authorization, set a callback URL. The console then shows an authorization URL.
  5. Check that the URL's scope parameter lists the TreeCraft scopes and read:forge-app:jira. Add offline_access to get a refresh token. Add any missing scope by hand, separated by %20.
  6. Open the URL, pick the site and select Accept. Atlassian sends you to the callback URL with a code.
  7. Exchange the code for a token, as shown below.

An authorization URL that asks for the read scope looks like this:

https://auth.atlassian.com/authorize?audience=api.atlassian.com&client_id=YOUR_CLIENT_ID&scope=read%3Ahierarchy%3Acustom%20read%3Aforge-app%3Ajira%20offline_access&redirect_uri=YOUR_CALLBACK&state=RANDOM&response_type=code&prompt=consent

Exchange the code for a token like this:

curl -s -X POST https://auth.atlassian.com/oauth/token \
  -H 'Content-Type: application/json' \
  -d '{"grant_type":"authorization_code","client_id":"YOUR_CLIENT_ID","client_secret":"YOUR_CLIENT_SECRET","code":"THE_CODE","redirect_uri":"YOUR_CALLBACK"}'

The answer holds access_token, which is short-lived, and refresh_token if you asked for offline_access. To get a new access token, send the refresh token in place of the code:

curl -s -X POST https://auth.atlassian.com/oauth/token \
  -H 'Content-Type: application/json' \
  -d '{"grant_type":"refresh_token","client_id":"YOUR_CLIENT_ID","client_secret":"YOUR_CLIENT_SECRET","refresh_token":"THE_REFRESH_TOKEN"}'

Send the token on every call, in the Authorization header:

curl -s "$BASE/v1/hierarchies" -H "Authorization: Bearer $TOKEN" -H 'Accept: application/json'

If the token lacks the scope a route needs, Atlassian's gateway refuses the call with 401 Unauthorized; scope does not match.

Base URL

Two forms of base URL reach the same API:

https://api.atlassian.com/svc/jira/<cloud-id>/apps/<app-id>_<environment-id>
https://<your-site>.atlassian.net/gateway/api/svc/jira/apps/<app-id>_<environment-id>

The parts in angle brackets are placeholders. Your own values are on TreeCraft's REST API page, which shows both URLs filled in, ready to copy.

Part Where to find it
cloud-id The Identifiers on TreeCraft's REST API page. You can also open https://<your-site>.atlassian.net/_edge/tenant_info, or call GET https://api.atlassian.com/oauth/token/accessible-resources with a token, which lists the sites it may reach with their ids.
app-id The Identifiers on TreeCraft's REST API page.
environment-id The Identifiers on TreeCraft's REST API page.
your-site Your site's address, as in your-site.atlassian.net.

Once Atlassian's switch is on, Atlassian Administration also shows the base URL under App REST APIs.

The examples on this page use two shell variables:

BASE='https://api.atlassian.com/svc/jira/<cloud-id>/apps/<app-id>_<environment-id>'
TOKEN='<access-token>'

Scopes

TreeCraft has three scopes. Each endpoint needs exactly one of them.

Scope Lets the integration
read:hierarchy:custom Read the hierarchies the person can open: their details, rows and rules, and the views the person can use. Changes nothing.
write:hierarchy:custom Add work items and folders, and move or remove rows, in hierarchies the person can edit. Changes no Jira work item.
manage:hierarchy:custom Create hierarchies, and rename, label, archive, restore or delete those the person controls.

A scope never gives more than the person has. An integration that changes rows usually asks for read:hierarchy:custom too, so it can read what it changes. Every call also needs the Jira scope read:forge-app:jira.

Endpoints

Every path starts with the version, /v1. {id} is a hierarchy id and {viewId} a view id. The level is the person's access level on the hierarchy. Every call also needs App access to let the person use the app.

Method Path Scope TreeCraft permission
GET /v1/hierarchies read:hierarchy:custom Lists only hierarchies where the person has View or more
POST /v1/hierarchies manage:hierarchy:custom App access lets the person create hierarchies
GET /v1/hierarchies/{id} read:hierarchy:custom View
PATCH /v1/hierarchies/{id} manage:hierarchy:custom Control
DELETE /v1/hierarchies/{id} manage:hierarchy:custom Control
GET /v1/hierarchies/{id}/rows read:hierarchy:custom View
POST /v1/hierarchies/{id}/rows/batch write:hierarchy:custom Edit, and Automate to move or remove rules
GET /v1/hierarchies/{id}/rules read:hierarchy:custom Automate
GET /v1/views read:hierarchy:custom None on a hierarchy: the person's own views and the shared views they may use
GET /v1/views/{viewId} read:hierarchy:custom None on a hierarchy: one of the person's own views, or a shared view they may use

A hierarchy the person can't open answers 404, the same as one that doesn't exist. A level that is too low answers 403.

List hierarchies

GET /v1/hierarchies · Scope: read:hierarchy:custom · Needs: View on each hierarchy listed

Lists the hierarchies the person can open, ordered by id, one page at a time.

Parameter In Description
limit query 1 to 500. Default 100.
cursor query The nextCursor of the previous page.
includeArchived query true to include archived hierarchies. Default false.
label query Only hierarchies with this label, in any case.
curl -s "$BASE/v1/hierarchies?limit=2" -H "Authorization: Bearer $TOKEN"
{
  "hierarchies": [
    { "id": 12, "name": "Release plan", "description": "", "ownerAccountId": "5b10ac8d82e05b22cc7d4ef5", "access": "control",
      "archived": false, "version": 48, "labels": ["Planning"], "favorite": true, "searchable": false },
    { "id": 15, "name": "Support backlog", "description": "Open requests by team", "ownerAccountId": "5b10ac8d82e05b22cc7d4ef5",
      "access": "view", "archived": false, "version": 7, "labels": [], "favorite": false, "searchable": true }
  ],
  "nextCursor": "aDoxNQ"
}

Each hierarchy has these fields:

Field Meaning
id The hierarchy's id.
name, description Its name and description.
ownerAccountId The owner's Atlassian account id.
access The person's own level on it: view, edit, automate or control.
archived true if it is archived.
version Goes up with every change to its rows.
labels Its labels.
favorite true if it is one of the person's favorites.
searchable true if its work items can be found with Jira search.

Create a hierarchy

POST /v1/hierarchies · Scope: manage:hierarchy:custom · Needs: App access lets the person create hierarchies

Creates a hierarchy. The person becomes its owner, with Control, and it is one of their favorites. Like any new hierarchy, it starts private.

Field In Description
name body Required. Up to 255 characters.
description body Up to 20,000 characters.
Idempotency-Key header Optional. See Idempotency.
curl -s -X POST "$BASE/v1/hierarchies" -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' -H 'Idempotency-Key: create-release-plan-1' \
  -d '{"name":"Release plan","description":"Everything planned for the next release"}'

Answers 201 with the new hierarchy:

{ "id": 21, "name": "Release plan", "description": "Everything planned for the next release", "ownerAccountId": "5b10ac8d82e05b22cc7d4ef5",
  "access": "control", "archived": false, "version": 0, "labels": [], "favorite": true, "searchable": false }

Get a hierarchy

GET /v1/hierarchies/{id} · Scope: read:hierarchy:custom · Needs: View

Reads one hierarchy's details. This call is cheap, so it is a good way to check version before reading the rows again.

Parameter In Description
id path The hierarchy's id.
curl -s "$BASE/v1/hierarchies/12" -H "Authorization: Bearer $TOKEN"

Answers 200 with the hierarchy, with the same fields as in the list:

{ "id": 12, "name": "Release plan", "description": "", "ownerAccountId": "5b10ac8d82e05b22cc7d4ef5", "access": "control",
  "archived": false, "version": 48, "labels": ["Planning"], "favorite": true, "searchable": false }

Change a hierarchy

PATCH /v1/hierarchies/{id} · Scope: manage:hierarchy:custom · Needs: Control

Renames, describes, labels, archives or restores a hierarchy. Give at least one field.

The fields are applied one after another, as in the app. So a 400 for a bad name or description can come after the labels of the same request were already changed. Where that matters, send one field at a time.

Field In Description
id path The hierarchy's id.
name body Up to 255 characters.
description body Up to 20,000 characters.
labels body Up to 10 labels, each up to 40 characters. Replaces the current labels.
archived body true archives the hierarchy, false restores it.
Idempotency-Key header Optional. See Idempotency.
curl -s -X PATCH "$BASE/v1/hierarchies/12" -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' -d '{"name":"Release plan 2027","labels":["Planning","2027"]}'

Answers 200 with the hierarchy as it is now:

{ "id": 12, "name": "Release plan 2027", "description": "", "ownerAccountId": "5b10ac8d82e05b22cc7d4ef5", "access": "control",
  "archived": false, "version": 48, "labels": ["Planning", "2027"], "favorite": true, "searchable": false }

Delete a hierarchy

DELETE /v1/hierarchies/{id} · Scope: manage:hierarchy:custom · Needs: Control

Deletes the hierarchy with its rows, rules and write-backs. The Jira work items are not changed. This can't be undone.

Parameter In Description
id path The hierarchy's id.
Idempotency-Key header Optional. See Idempotency.
curl -s -X DELETE "$BASE/v1/hierarchies/12" -H "Authorization: Bearer $TOKEN"

Answers 204 with no body.

Read rows

GET /v1/hierarchies/{id}/rows · Scope: read:hierarchy:custom · Needs: View

Reads the tree, or the part below one row. Rows come in the order the grid shows them with nothing sorted: each row, then the rows below it.

Parameter In Description
id path The hierarchy's id.
under query A row id. Only the rows below that row.
depth query Levels below the start, 1 to 64. Default 64. 1 gives only the top level, or only the children of under.
limit query 1 to 5,000. Default 1,000.
cursor query The nextCursor of the previous page.
curl -s "$BASE/v1/hierarchies/12/rows?depth=2&limit=5000" -H "Authorization: Bearer $TOKEN"
{
  "hierarchyId": 12,
  "version": 48,
  "building": false,
  "limitsReached": [],
  "rows": [
    { "id": 4711, "parentId": null, "level": 1, "kind": "issue", "byRule": false, "hasChildren": true, "issueId": "10001" },
    { "id": 4712, "parentId": 4711, "level": 2, "kind": "folder", "byRule": false, "hasChildren": false, "folderId": "7", "name": "Next quarter" },
    { "id": 4713, "parentId": 4711, "level": 2, "kind": "restricted", "byRule": false, "hasChildren": true },
    { "id": 4800, "parentId": null, "level": 1, "kind": "group", "byRule": true, "hasChildren": true, "groupId": "status:3", "label": "In Progress" }
  ],
  "nextCursor": null
}

Every row has these fields:

Field Meaning
id The row's id.
parentId The row above it, or null at the top level.
level 1 is directly below the start.
kind What the row shows (see the next table).
byRule true if a rule placed the row. The rule decides where it goes.
hasChildren true if rows sit below it. Read them later with under.

Then, by kind:

kind Fields
issue issueId. Read the work item itself from Jira's REST API with your own token.
folder folderId, name.
planningItem planningItemId, name, estimateHours, ownerAccountId.
memo memoId, text (in wiki markup), revision.
group groupId, label.
rule ruleId. Only people with Automate see rule rows.
restricted Nothing else. A work item the person can't see, placed by hand above rows they can see. See What the API never shows.

The answer also has:

  • version: the hierarchy's version when the page was read.
  • building: true while the rules' output is being rebuilt. Read again shortly for the newest rows.
  • limitsReached: the rule limits that cut the rules' output, as the app's notice names them.

Each page reads the tree again, so ask for large pages. A hierarchy of 20,000 rows takes 4 calls of 5,000.

Change rows

POST /v1/hierarchies/{id}/rows/batch · Scope: write:hierarchy:custom · Needs: Edit, and Automate to move or remove rules

Adds, moves and removes rows in one batch. The app checks the whole batch first, then writes it as one change, or not at all. It is the same change, with the same checks, as editing in the app.

Field In Description
id path The hierarchy's id.
changes body Required. 1 to 200 changes, applied in order.
Idempotency-Key header Optional. See Idempotency.

Each change has an action:

action Fields
add items: each one is {"issueId": "10001"}, {"folderId": "7"} for an existing folder, or {"folderName": "New folder"} for a new folder the app makes for you. parentId: the row to add under (null or left out: the top level). afterId: the sibling to add after (null or left out: first).
move rowIds, parentId, afterId.
remove rowIds. keepChildren: true moves the rows below each removed row up to its place. By default they are removed with it.
curl -s -X POST "$BASE/v1/hierarchies/12/rows/batch" -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' -H 'Idempotency-Key: sync-2026-10-24-0900' \
  -d '{"changes":[
        {"action":"add","parentId":null,"afterId":4711,"items":[{"issueId":"10001"},{"folderName":"Next quarter"}]},
        {"action":"move","rowIds":[4712],"parentId":4800,"afterId":null},
        {"action":"remove","rowIds":[4713],"keepChildren":true}]}'
{
  "hierarchyId": 12,
  "version": 49,
  "added": [
    { "changeIndex": 0, "rowId": 6620417819, "kind": "issue", "issueId": "10001" },
    { "changeIndex": 0, "rowId": 2299815532, "kind": "folder", "folderId": "8" }
  ],
  "removedRowIds": [4713]
}

added lists the new rows, with the index of the change that added each one. The app chooses new row ids. removedRowIds lists only rows the person could see.

  • The person must be able to see every row the batch names, the rows above it, and every work item it adds. Otherwise the batch answers 403 and changes nothing.
  • A row that no longer exists answers 409 CONFLICT.
  • A batch holds at most 200 changes, 2,000 rows and 50 new folders.
  • A hierarchy holds at most 20,000 work items.
  • Rows the person can't see below a removed row stay where they were, as in the app.
  • New folders named by folderName are made before the change is written. If the batch is refused, they are deleted again.
  • Changes inside the rules' output need the hierarchy's setting for it. See Changes inside rule output.
  • A hierarchy with rules rebuilds their output afterwards, in the background.

List rules

GET /v1/hierarchies/{id}/rules · Scope: read:hierarchy:custom · Needs: Automate

Lists the hierarchy's rules in tree order, with their settings. It needs Automate, as rule settings do in the app.

Parameter In Description
id path The hierarchy's id.
curl -s "$BASE/v1/hierarchies/12/rules" -H "Authorization: Bearer $TOKEN"
{
  "hierarchyId": 12,
  "version": 48,
  "building": false,
  "limitsReached": [],
  "rules": [
    { "ruleId": "31", "rowId": 4800, "parentId": null, "position": 0, "type": "insertJql", "settings": { "type": "insertJql", "jql": "project = REL" } }
  ]
}

Each rule has its ruleId, its rowId in the tree, its parentId, its position among its siblings (from 0), its type, and its settings as the app keeps them. Later versions may add fields to settings.

List views

GET /v1/views · Scope: read:hierarchy:custom · Needs: no level on a hierarchy

Lists all of the person's own views and up to 100 shared views they may use.

Parameter In Description
search query Narrows the shared views by name. Up to 100 characters.
curl -s "$BASE/v1/views?search=release" -H "Authorization: Bearer $TOKEN"
{
  "views": [
    { "id": 4, "name": "Release columns", "mine": true, "shared": true, "editable": true,
      "columns": [ { "id": "c1", "type": "field", "field": "status" } ], "wrap": false }
  ],
  "moreShared": false
}

mine is true for the person's own views, shared for views shared with others, and editable when the person may change the view in the app. columns lists its columns in order, as the app keeps them. moreShared is true when more shared views exist than were listed: search by name to find them.

Get a view

GET /v1/views/{viewId} · Scope: read:hierarchy:custom · Needs: no level on a hierarchy

Reads one view: one of the person's own, or a shared view they may use. Any other view answers 404.

Parameter In Description
viewId path The view's id.
curl -s "$BASE/v1/views/4" -H "Authorization: Bearer $TOKEN"
{ "id": 4, "name": "Release columns", "mine": true, "shared": true, "editable": true,
  "columns": [ { "id": "c1", "type": "field", "field": "status" } ], "wrap": false }

What the API never shows

  • Work items the person can't see in Jira. Rows that rules placed and that the person can't see are left out, with everything below them. A work item placed by hand that the person can't see shows as a restricted row only where it holds rows they can see. That row says nothing about the work item. This holds for everyone, app admins included.
  • Work item fields. The API gives work item ids. Read the work items from Jira's REST API with the same token.
  • Email addresses. People appear by Atlassian account id only.
  • Rules and their settings, to people without Automate on the hierarchy.

Errors

Every error has the same shape:

{ "error": { "status": 409, "code": "CONFLICT", "message": "row no longer exists" } }
Status Code Meaning and what to do
400 INVALID_REQUEST A parameter or the body is wrong. The message says which.
401 UNAUTHENTICATED The call came without a person's account, or the account the call acts as in Jira could not be confirmed. Use a person's 3LO token.
401 IDENTITY_MISMATCH Atlassian named more than one account or Jira site for the call, or Jira named another account for the token. Get a new token.
401 REAUTHORIZE The person must allow the app again: they open TreeCraft in Jira once and allow access.
403 FORBIDDEN The person's level on the hierarchy, App access or the Automation permissions don't allow it. The message says which.
403 API_TURNED_OFF An admin turned TreeCraft's switch off for this site. See Turn the API on.
403 JIRA_REFUSED Jira refused a request the app made as the person. Jira's own message follows. When Jira refuses a request the app makes as itself, the answer is 500 INTERNAL instead, without Jira's words.
404 NOT_FOUND No such hierarchy, row or view, or one the person can't see.
409 CONFLICT A row changed since you read it. Read again, then retry.
409 CURSOR_STALE The row a page continues from is gone. Read from the first page again.
409 IDEMPOTENCY_IN_PROGRESS A call with the same Idempotency-Key is still running. Wait retryAfterSeconds, then retry with the same key.
409 IDEMPOTENCY_UNFINISHED A call with the same Idempotency-Key ended without an answer, after it may have changed something. Read the hierarchy to see whether the change took effect. If it didn't, use a new key. Retrying with this key answers the same.
422 IDEMPOTENCY_KEY_REUSED The Idempotency-Key was used for a different request. Use a new key.
429 RATE_LIMITED Past the API's rate limits. Wait retryAfterSeconds.
429 JIRA_BUSY Jira is limiting the app's requests on this site. Wait retryAfterSeconds.
500 INTERNAL Something went wrong in the app. Retry. If it goes on, contact support with the time of the call.
502 JIRA_ERROR Jira failed to answer, or could not be reached as the person (a network error, a timeout, Atlassian's platform failing the request). Retry after retryAfterSeconds.
503 BUSY The hierarchy or the app's database is busy. Retry after retryAfterSeconds.
503 UPDATING The app is applying an update. Retry in a minute.

429, 502 and 503 answers, and 409 IDEMPOTENCY_IN_PROGRESS, carry retryAfterSeconds in the body and a Retry-After header, both in seconds.

A token without the scope a route needs is refused by Atlassian's gateway, before the app, with 401 Unauthorized; scope does not match. That answer doesn't have the shape above.

Paging

Lists answer one page and a nextCursor. Pass it back as cursor to get the next page, until nextCursor is null. Cursors are opaque: don't build or change them.

List Default page Largest page
GET /v1/hierarchies 100 hierarchies 500
GET /v1/hierarchies/{id}/rows 1,000 rows 5,000

If the row a page continues from is gone, the answer is 409 CURSOR_STALE. Start again from the first page.

Rate limits

Limit Value
Requests per person 120 a minute
Requests per site, all callers together 1,000 a minute
Changes in one batch 200, with 2,000 rows and 50 new folders
Request body 800 kB

Past a limit, the answer is 429 RATE_LIMITED with retryAfterSeconds. Atlassian applies its own rate limits to app REST APIs on top of these.

Each call also runs on your site's copy of the app. What it asks Jira counts against the app's hourly allowance of Jira API points on your site, which the app's pages share. Reading rows costs about the same as opening the hierarchy in the app. To keep the cost low:

  • read with large pages;
  • check a hierarchy's version with GET /v1/hierarchies/{id}, and read its rows again only when it changed;
  • don't poll more often than you need.

Idempotency

POST, PATCH and DELETE take an optional Idempotency-Key header: 1 to 64 letters, digits, - and _. It makes a retry safe.

  • The same key with the same request within 24 hours answers the first answer again, with the header Idempotent-Replayed: true. Nothing is done twice.
  • The same key with a different request answers 422 IDEMPOTENCY_KEY_REUSED.
  • The same key while the first call is still running answers 409 IDEMPOTENCY_IN_PROGRESS with Retry-After. Wait, then retry with the same key.
  • A first try that failed with 401, 429 or a 5xx before it changed anything keeps nothing, so a retry with the same key runs it. After a 401, retry once the person has signed in or allowed the app again.
  • A first try that failed after it changed something keeps its key. A retry with that key answers 409 IDEMPOTENCY_IN_PROGRESS for the first minute, then 409 IDEMPOTENCY_UNFINISHED: the first try ended without an answer. Read the hierarchy to see whether the change took effect. If it didn't, use a new key.
  • A replay is the person's own first answer to that request, sent as it was. It is not checked against their access again.

Use a new key for each change you mean to make, and the same key to retry that change. Without a key, a retried POST may do its work twice: a second hierarchy, or rows added twice.

Versioning

  • Paths carry the version: /v1. Within v1, changes only add things: new fields, optional parameters and new endpoints. Ignore fields you don't know.
  • A change that would break callers makes /v2. v1 keeps working for at least 12 months after v2 is released. In that time, its answers carry Deprecation and Sunset headers.
  • The scopes keep their meaning. A new scope means each integration asks its people to consent again.

Changelog

Version Date Change
1.0.0-beta October 2026 First version, in beta: hierarchies (list, get, create, change, delete), rows (read, batch changes), rules (list) and views (list, get).

Planned next, in no promised order: computed column values for a view, work item keys in rows, rule changes, memos and planning items, history and tree queries.

Questions about the app? Write to info@plugincraft.ca.