TouchQuill REST API

Machine-readable: /api/v1/openapi.json (OpenAPI 3.0). Authorization: Authorization: Bearer <token>. Errors: {"error":{"code","message"}}. Stable operations change only by addition within /api/v1.

server

GET/internalLanding page (HTML) linking the admin panel, API docs and health
GET/admininternalAdmin panel (single HTML page; it calls the admin API with a token)
GET/healthstableLiveness with version and uptime (old address) deprecated since 2026-10-11, sunset Fri, 01 Oct 2027 00:00:00 GMT; use /api/v1/health
GET/healthzstableProcess is alive (always 200, no details)
GET/readyzstableReady for traffic: metadata store answers, data directory writable, no maintenance (503 with a reason otherwise)
GET/api/v1/healthstableLiveness with version and uptime
GET/api/v1/openapi.jsonstableThis specification (OpenAPI 3.0)
GET/api/v1/docsstableHuman-readable list of endpoints (HTML, no external assets)
GET/metricsexperimentalPrometheus metrics · needs admin.server

updates

GET/updates/v1/{path}internalOrganisation update mirror: signed manifest and packages (ADR-0018)

auth

POST/api/v1/loginstableLog in with a password (and 2FA code) - returns a session token tqs_*
GET/api/v1/mestableUser and role of the token · needs repo.read

admin

GET/api/v1/admin/usersinternalAccounts with roles and token expiry · needs admin.users
POST/api/v1/admin/usersinternalCreate an account (password by default; technical: token with ttl, scopes, repos) · needs admin.users
DELETE/api/v1/admin/users/{name}internalRemove an account · needs admin.users
POST/api/v1/admin/users/{name}/passwdinternalSet a password · needs admin.users
POST/api/v1/admin/users/{name}/tokeninternalRotate the token of a technical account (optional ttl) · needs admin.users
POST/api/v1/admin/users/{name}/roleinternalChange the role · needs admin.users
POST/api/v1/admin/users/{name}/logoutinternalEnd all sessions of the account · needs admin.users
GET/api/v1/admin/rolesinternalRoles and their permissions · needs admin.roles
POST/api/v1/admin/rolesinternalCreate or change a custom role · needs admin.roles
DELETE/api/v1/admin/roles/{name}internalRemove a custom role · needs admin.roles
POST/api/v1/admin/users/{name}/custom-roleinternalAssign a custom role · needs admin.roles
POST/api/v1/admin/users/{name}/grantinternalGrant or revoke single permissions · needs admin.users
GET/api/v1/admin/protectionsinternalPath protections (read/write restrictions) · needs admin.roles
PUT/api/v1/admin/protectionsinternalReplace path protections · needs admin.roles
GET/api/v1/admin/patsinternalPersonal access tokens with scopes and expiry · needs admin.users
POST/api/v1/admin/patsinternalIssue a PAT {name, user, scopes, ttl?, repos?} - the token is shown once · needs admin.users
POST/api/v1/admin/scribe/rebuildinternalAsk the server to rebuild a repository's Scribe index (in the background) · query: repo · needs admin.server
GET/api/v1/admin/maintenanceinternalMaintenance mode state · needs admin.server
POST/api/v1/admin/maintenanceinternalTurn maintenance mode on {reason} · needs admin.server
DELETE/api/v1/admin/maintenanceinternalTurn maintenance mode off · needs admin.server
DELETE/api/v1/admin/pats/{name}internalRevoke a PAT · needs admin.users
GET/api/v1/admin/auditinternalAudit log entries · query: limit, event, user, denied, before, since_ms, until_ms, resource, channel, repo, outcome · needs admin.audit
GET/api/v1/admin/telemetryinternalClient timings and errors (ADR-0019) · query: days · needs admin.audit
GET/api/v1/admin/audit/verifyinternalVerify the audit hash chain · needs admin.audit
GET/api/v1/admin/audit/{id}internalOne audit entry (seq or au-*) with verified: hash, signature and link to the previous entry · needs admin.audit
GET/api/v1/admin/config/validateinternalCheck server.toml, ci.toml and users.toml: errors per file, warnings, settings that need a restart · needs admin.server
POST/api/v1/admin/config/reloadinternalCheck the configuration and apply what works without a restart (422 and nothing applied on errors) · needs admin.server
GET/api/v1/admin/statusinternalServer status for the dashboard · needs admin.server

repos

GET/api/v1/reposstableRepositories visible to the caller · needs repo.read
GET/api/v1/repos/{repo}stableOne repository: channels, abandoned ones, default channel and its head · needs repo.read

channels

GET/api/v1/repos/{repo}/channelsstableChannels with type and parent, plus abandoned ones · needs repo.read
GET/api/v1/repos/{repo}/channels/{channel}stableOne channel (name percent-encoded, task%2Fx): type, parent, state, owner, ticket, head, locks, open conflicts, review gate · needs repo.read

revisions

GET/api/v1/repos/{repo}/changes/{change_id}stableA logical change (ch-*): current revision with files and earlier materializations · needs repo.read
GET/api/v1/repos/{repo}/revisionsstableRevisions of a channel, newest first, cursor pagination · query: limit, page_token, channel · needs repo.read
GET/api/v1/repos/{repo}/revisions/{rev}stableOne revision (number without rev:, or ch-*) with its files · needs repo.read
GET/api/v1/repos/{repo}/revisions/{rev}/flagsexperimentalBuild flags of a revision and whether it is stable · needs repo.read

ugs

GET/ugs/api/latestexternalUnrealGameSync metadata protocol version ({version: 2})
GET/ugs/api/metadataexternalUGS/Horde build metadata of changes · query: stream, minchange, maxchange, change, project, sequence · needs repo.read
POST/ugs/api/metadataexternalUGS UpdateMetadataRequest: sync, vote, comment, badges (badges need build-flag.set) · needs repo.read

browse

GET/api/v1/repos/{repo}/tree/{rev}experimentalAll files at a revision (HEAD, number or commit hash) with size and blob hash · needs repo.read
GET/api/v1/repos/{repo}/file/{rev}experimentalFile content at a revision (text preview) · query: path · needs repo.read
GET/api/v1/repos/{repo}/filediff/{rev}experimentalDiff of one file against the parent commit or base · query: path, base · needs repo.read
GET/api/v1/repos/{repo}/diff/{rev}experimentalFiles changed by a revision against the parent commit or base · query: base · needs repo.read
GET/api/v1/repos/{repo}/raw/{rev}stableRaw bytes of a file (application/octet-stream), outside the request limit · query: path · needs repo.read

locks

GET/api/v1/repos/{repo}/locksstableLocks of a channel with queue, requests and disputes · query: channel · needs repo.read
POST/api/v1/repos/{repo}/locksstableAcquire a lock {path, channel?} · needs lock.acquire
DELETE/api/v1/repos/{repo}/locks/{path}stableRelease a lock (the path is percent-encoded) · query: channel · needs lock.acquire

conflicts

GET/api/v1/repos/{repo}/conflictsstableConflict records · query: channel · needs repo.read
GET/api/v1/repos/{repo}/conflicts/{id}stableFull conflict record · needs repo.read
POST/api/v1/repos/{repo}/conflicts/{id}/assignexperimentalAssign a conflict record kept on the server to a person or role:<role> ({to, message?}) · needs conflict.assign

review

GET/api/v1/repos/{repo}/reviewexperimentalReview comments, verdicts, gate and the pending review request of a channel · query: channel · needs repo.read
POST/api/v1/repos/{repo}/reviewexperimentalAdd a review comment · needs repo.read
POST/api/v1/repos/{repo}/review/verdictexperimentalApprove or request changes (not on your own change) · needs review.verdict

shelves

GET/api/v1/repos/{repo}/shelvesstableShelves visible to the caller · query: channel · needs repo.read
GET/api/v1/repos/{repo}/shelves/{id}stableShelf record with files · needs repo.read
GET/api/v1/repos/{repo}/shelves/{id}/rawexperimentalBytes of a shelved file · query: path · needs repo.read

webhooks

GET/api/v1/repos/{repo}/webhooksstableWebhook subscriptions · needs webhook.manage
POST/api/v1/repos/{repo}/webhooksstableSubscribe {url, events, channels?, secret?, kind?} - HMAC-SHA256 signed deliveries · needs webhook.manage
DELETE/api/v1/repos/{repo}/webhooks/{id}stableDelete a subscription · needs webhook.manage
GET/api/v1/repos/{repo}/webhooks/{id}/deliveriesstableDelivery attempts of a subscription · needs webhook.manage
POST/api/v1/repos/{repo}/webhooks/{id}/redeliver/{seq}stableDeliver an event again · needs webhook.manage

events

GET/api/v1/repos/{repo}/eventsstableServer-sent events with id: and Last-Event-ID resume · query: types, events, channels, last_event_id · needs repo.read

notifications

GET/api/v1/repos/{repo}/notify/prefsstableNotification preferences of the caller · needs repo.read
PUT/api/v1/repos/{repo}/notify/prefsstableSet notification preferences of the caller · needs repo.read
POST/api/v1/repos/{repo}/notify/testexperimentalTest notification for the caller {event?, email?}: the event template in the account language with example data goes to the inbox (and e-mail) · needs repo.read

scribe

GET/api/v1/repos/{repo}/scribe/symbolsstableSymbols of a file (also Blueprints) · query: path, rev · needs scribe.read
GET/api/v1/repos/{repo}/scribe/blamestableHistory of a symbol across renames and moves · query: symbol · needs scribe.read
GET/api/v1/repos/{repo}/scribe/traceexperimentalFull lineage of a symbol · query: symbol · needs scribe.read
POST/api/v1/repos/{repo}/scribe/linkexperimentalLink two symbols by hand {newer, older} (resolves Ambiguous) · needs repo.write
DELETE/api/v1/repos/{repo}/scribe/linkexperimentalRemove a manual link · query: symbol · needs repo.write
GET/api/v1/repos/{repo}/scribe/searchexperimentalFind symbols by name (exact, prefix, substring; case-insensitive) · query: q, kind, lang, path, rev · needs scribe.read
GET/api/v1/repos/{repo}/scribe/usagesexperimentalWhere a symbol or asset is used (code and Blueprint nodes) · query: symbol, rev · needs scribe.read
GET/api/v1/repos/{repo}/scribe/timelineexperimentalNames, files and authors of a symbol over time · query: symbol · needs scribe.read
GET/api/v1/repos/{repo}/scribe/diffexperimentalSemantic diff of two revisions: symbols added, removed, changed, renamed, moved · query: from, to, path · needs scribe.read
GET/api/v1/repos/{repo}/scribe/annotateexperimentalPer-symbol blame of a file · query: path, rev · needs scribe.read
GET/api/v1/repos/{repo}/scribe/relationsexperimentalTyped links of a symbol (must-sync, derived-from, replaces, depends-on) · query: symbol · needs scribe.read
GET/api/v1/repos/{repo}/scribe/notesexperimentalNotes attached to a symbol · query: symbol · needs scribe.read
POST/api/v1/repos/{repo}/scribe/notesexperimentalAttach a note to a symbol {symbol, tag, note} · needs repo.write
DELETE/api/v1/repos/{repo}/scribe/notesexperimentalRemove a note · query: symbol, tag · needs repo.write

commits

PUT/api/v1/repos/{repo}/blobsstableUpload file bytes (up to 1 GiB) for a server-side commit · query: path · needs repo.write
POST/api/v1/repos/{repo}/commitsstableServer-side commit from uploaded blobs {channel, message, changes, deletes} · needs repo.write