REST API #
The REST API is how a program with no MCP client, such as a script or a CI job, works a tzTrack space over HTTPS. It takes the same token as the MCP server at https://tztrack.ai/mcp, admits you at the same level, and applies the same rules. It also makes acts the MCP server's tools do not, such as land, check, and configure. Read this page when your caller speaks plain HTTP rather than MCP.
Requests and answers #
Every call is a POST to https://tztrack.turnzero.ai/v1/<act>, such as /v1/list. The body is one JSON object: the act's request, as the table in the section The acts lists it, with space beside it. An empty body counts as {}.
Leave space out where your account owns or is a member of one space: that space is the default. Where it holds several, name one by its id. The project's setting file holds the id a project works in.
A body is at most 65,536 bytes. submit and comment carry images, so their bound is 3,145,728 bytes.
A call that works answers 200 and a JSON object with three members:
space, the id of the space the act worked;act, the act's name;result, the act's own answer, as the table lists it.
A call that fails answers an error status and a JSON object with two members: error, the refusal's name, and detail, one sentence on what to do next. Branch on error, never on detail, since the sentence can change. A refused call changes nothing.
The token #
Send a tzTrack token in the authorization header as Bearer <token>. It is the token Turn Zero signs for tzTrack, the same token an AI tool holds after you sign in.
A script or a CI job gets its token one of two ways. It can mint one with the action mint_token, the grant tztrack, and a label you give, from your account's own signed-in session on Turn Zero Cloud. The mint answers a token claim line, which you run in a terminal of your own, so the value never passes through the chat. Mint a token gives the steps. Or it can sign in by itself with a code you allow in a browser, the device sign-in, naming https://tztrack.ai/mcp as the resource.
Sign in from a script gives every answer of the device sign-in. The Quick start gives both ways step by step. Keep the token as a secret, as you keep a password. The REST API verifies it as it verifies the token an AI tool holds after sign-in.
Any other credential is refused credential_refused, a token for another Turn Zero product among them. A call with no authorization header is refused credential_required. Both answers carry a www-authenticate header naming where the sign-in starts.
In a space of your own you hold the owner's level, and every act works. In a space shared with you, you hold the level its owner gave you: report, contribute, or owner. An act past your level is refused grant_required.
The acts #
The table names each act, the lowest level that makes it, the members its request takes, and what result holds. key, where an act takes it, is your own idempotency key: repeat a write with the same key and it is made once. A write is recorded under your account and your token's label, whatever actor a body names.
A member that names an issue takes its number, as 12 or "#12", or its id, as the MCP tools take it. Those members are issue, a settle's target, a relate's target other than an arising_from reference, and follow's repeat_of.
| Act | Level | Request | result |
|---|---|---|---|
submit |
report | origin, kind, title; where you have them, text, impact, workaround, proposed_resolution, seen_in, evidence, evidence_basis, restricted, component, problem_key, attachments, amends, withdraws, key; from contribute, requirements, labels, and priority, each refused grant_required below it |
report, issue, outcome, candidates, masked, personal_removed |
follow |
report | report, repeat_of, key |
report, issue, outcome |
list |
report | the filters state, outcome, kind, component, path, requirement, label, priority, level, alarm, origin, waiting_for, claimed_by, plan, reporter, proposed, related, since; order, limit, cursor |
issues, cursor |
search |
report | query; the filters state, kind, component; limit, cursor |
issues, cursor |
read |
report | issue |
issue, reports, links, history, comments, relations, landings, checks, proposals |
attachment |
contribute | id, one image's id as a report or a comment lists it |
type, the image's media type, and bytes, its bytes in base64url |
update |
contribute | issue, fields, key |
issue, mentioned |
comment |
contribute | issue, text, attachments, key |
comment, issue, mentioned |
relate |
contribute | issue, type, target, withdraw, key |
issue, relation |
next |
contribute | role, branch, component, paths, plan, key |
issue, check, secret, packet |
give_back |
contribute | issue, check, secret, reason, key |
issue |
wait |
contribute | issue, waiting_for, resolution, key |
issue |
cache |
contribute | since for a refresh |
link, expires_at, space, since, count, numbers, gone |
land |
owner | issue, commit, trailer, test, proof, remainder, component, key |
landing, issue |
deploy |
owner | line, version, order, commit, environment, live, withdrawn, key |
build |
ship |
owner | build, landings, key |
build, shipped |
check |
owner | check, covers, result, builds, cause, component, evidence, withdraw, key |
check, issue, outcome |
settle |
owner | issue, outcome, target, resolution, fixed_in, key |
issue, related_open |
reopen |
owner | issue, key |
issue |
unmerge |
owner | issue, key |
issue |
configure |
owner | components, lines, credential_forms, personal_forms, machinery, main_paths, constants |
configuration |
export |
owner | limit, cursor |
issues, comments, signals, asks, landings, builds, checks, cursor |
count |
owner | the filters of list, exclude_label, group_by |
total, groups |
rates |
owner | since, until, grain, component, kind, label, exclude_label |
since, until, grain, steps, time_to_close |
read_space |
owner | nothing | space, counts, configuration, sampled_merges, pass_runs |
The form of each member is the contract's: Issue Tracking gives every member's type, bounds, and meaning, and every answer member's.
What differs from the contract #
A few members are set for you, and a few are bounded, each refused where the body passes the bound.
Set for you, whatever the body says:
- A write's actor is your account and your token's label, written as an agent.
- A filing's
evidence_basisisclaimedwhere the body names none. - Below the owner's level, a filing's
originisfield.
Refused where the body passes the bound:
- An
evidence_basisother thanclaimedis refusedinvalid_request. So is aseen_inentry other than{ line, version, environment }with a repository commit as its version. - A body that names
relayed_levelis refusedinvalid_request. Your level in the space decides which restricted issues your filings join. - A
waiting_forofperson:<account>names the space's owner or one of its members, and any other account is refusedinvalid_request. - Below the owner's level, an
updatethat lowersrestrictedor namesalarmis refusedgrant_required. Arelateof the typearising_fromwhosetargetis an issue's number, such as#7, is refusedinvalid_requestthere too. configuretakes the members the table lists. Amongconstantsit takesreport_text_retention_days,lift_reports,lift_window_days,lift_account_max, andrank_trial_weight, and refuses every other,model_budgetamong them.- A
configurethat setsmachinery.passestotrueon a space with no model budget sets the budget to 200 in the same call. A budget already set stands.
Every other act of the contract, such as mint, revoke, or delete_space, is refused grant_required, whatever your level. Turn Zero Cloud makes those acts for you, and sharing a space and creating one are its own: the MCP server's share and create_issue_space tools carry them.
Refusals #
A refusal names itself in error. Refusals gives each one's status, cause, and remedy, from credential_required to rate_limited.
Two answers are no refusal of an act. A path that names no act answers 404 not_found, whatever the method: check the act's spelling against the table. A request to an act's path that is no POST answers 405 method_not_allowed, with an allow header naming POST.
An example #
This lists the open issues of your one space with curl, the token in the variable TZTRACK_TOKEN:
curl -s -X POST https://tztrack.turnzero.ai/v1/list -H "authorization: Bearer $TZTRACK_TOKEN" -H "content-type: application/json" -d '{"state": "open", "limit": 20}'
The answer holds the space's id as space, list as act, and the page of issues with its cursor as result. To raise an issue in a named space:
curl -s -X POST https://tztrack.turnzero.ai/v1/submit -H "authorization: Bearer $TZTRACK_TOKEN" -H "content-type: application/json" -d '{"space": "<id>", "origin": "workspace", "kind": "bug", "title": "The nightly build fails on the login test", "text": "Seen on three runs since Monday."}'
Any HTTP client works the same way: a POST, the authorization header, and one JSON object.
Related #
- The tools lists the MCP server's tools, which make some of the same acts, under the same rules.
- Refusals lists every refusal with its remedy.
- Sharing a space explains the levels a member works at.
- The setting file gives the file that holds a project's space id.