Overview
The ticket API lets your own systems file a card onto a TraceItX board directly —
a failing CI run, a cron job, a Slack bot, anything that isn't a human clicking
around the dashboard. It's v1: fields may be added to requests and
responses without notice, but nothing documented on this page will change meaning
or be removed within v1.
Get a token
Tokens are managed from Settings → API tokens → Create in the dashboard — an organisation admin role is required for every token operation (create, list, rename/re-scope, revoke); a non-admin following this path will get a permission error. Each token has:
- A name. Up to 80 characters. This is what appears as the ticket's
author in TraceItX — on the card and in activity history — so name it after the
system that's using it (
ci-bot,support-triage), not a person. It does not appear in @mentions: a token is deliberately left out of the mention list, since there's no one behind it to notify. - All projects, or selected projects. A token can reach every project in the organisation, or a specific list you choose when creating it. Narrowing to only the projects a given integration actually needs limits the blast radius if that token ever leaks — a CI job that only files tickets against one project has no business holding a token that can reach every other one too.
An API token is not an SDK key. An SDK key ships inside your application — a web bundle or a decompiled binary yields it — which is why the ingest endpoint it authenticates only ever accepts reports and can't be used to read or change anything. An API token can create tickets in your projects (v1 has no update endpoint — a token can't modify a ticket after creating it). Never embed an API token inside an application you ship; it belongs in CI secrets or a server environment, not in a client.
Authenticate
Send the token as a bearer token on every request:
Authorization: Bearer txx_api_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Any problem with the credential — missing, malformed, unknown, or revoked —
returns 401 with { "error": "invalid_api_token" },
deliberately without saying which: telling a caller a token is "revoked" rather
than simply "invalid" would confirm the token once existed. Revoking a token takes
effect immediately.
Create a ticket
POST /api/v1/tickets curl -X POST https://traceitx.com/api/v1/tickets \
-H "Authorization: Bearer $TRACEITX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title": "Checkout crashes on iOS 18"}' Fields
| Field | Type | Notes |
|---|---|---|
title | string, required | 1–200 characters. |
description | string | Optional. Up to 20,000 characters. |
projectId | uuid | Defaults to the token's only reachable project; required once the token reaches more than one. |
boardId | uuid | Defaults to the project's first board. |
columnId | uuid | Defaults to the board's leftmost column. |
priority | string | One of none, low, medium, high. Defaults to none. |
assigneeUserId | uuid, nullable | Must be a member of the organisation. |
agentRepositoryId | uuid, nullable | Must be a repository already bound to the project. |
startsAt | string, nullable | YYYY-MM-DD. |
dueAt | string, nullable | YYYY-MM-DD. |
projectId, boardId, and columnId resolve in
order: if you don't name a project, the token must reach exactly one — the
request fails once it reaches more than one, rather than guessing. If you don't
name a board, TraceItX uses the resolved project's first board. If you don't name
a column, TraceItX uses that board's leftmost column.
assigneeUserId names the org's AI agent, TraceItX enqueues an
autonomous run against the ticket — the same behaviour as assigning a card to the
agent from the dashboard — which consumes credits and may open a pull request.
This is intentional: it's what makes agentRepositoryId useful, since
that field selects which bound repository the run works against. If you only want
a ticket to appear on the board, don't set assigneeUserId to the
agent.
On success, the API returns 201 with:
{
"id": "<uuid>",
"title": "Checkout crashes on iOS 18",
"projectId": "<uuid>",
"boardId": "<uuid>",
"columnId": "<uuid>",
"createdAt": "<ISO 8601>",
"url": "<dashboard deep link>"
} url is a deep link straight to the new card in the dashboard — print it in CI output so a person can click through to it.
Idempotency
A CI job that retries after a timeout must not file the same ticket twice. Send an
Idempotency-Key and a repeat with the same key returns the original
ticket unchanged and creates nothing new:
-H "Idempotency-Key: ci-run-${GITHUB_RUN_ID}"
Keys are scoped to the token — the same key used by two different tokens is two
different keys. Use a key that is unique per ticket you intend to create — deriving
it from something already unique to the run, like the ci-run-${GITHUB_RUN_ID}
example above, is the natural approach. Don't reuse a key expecting it to have
expired: reusing one replays the original ticket rather than creating a new one.
Errors
| Status | Error | Meaning |
|---|---|---|
400 | invalid_input | Body failed validation, including an unrecognised field. |
400 | project_required | The token reaches more than one project; name one. |
400 | invalid_date_range | startsAt is after dueAt. |
400 | not_a_member | assigneeUserId is not a member of the organisation. |
400 | invalid_agent_repository | agentRepositoryId is not a repository bound to the project. |
400 | invalid_idempotency_key | Empty, or longer than 255 characters. |
401 | invalid_api_token | Missing, malformed, unknown, or revoked token. |
403 | insufficient_scope | The token lacks tickets:write. |
404 | project_not_found | No such project, or the token cannot reach it. |
404 | board_not_found | No such board, or it belongs to another project. |
404 | column_not_found | No such column, or it belongs to another board. |
429 | — | Over 60 requests/minute for this token. |
project_not_found deliberately covers both "does not exist" and "not
yours" — the same response either way, on purpose, so a token can't be used to map
an organisation it has no access to by comparing error codes.
Limits
| Limit | Value |
|---|---|
| Rate limit (per token) | 60 requests / minute |
| Attachments | Not supported in v1 |
Versioning
Within /api/v1: fields may be added to requests and responses without
notice; existing fields will not be removed or change meaning. Don't validate
responses against a strict shape that rejects unknown fields — a client that does
will break on a purely additive change.