REST API

Truke KF exposes a small REST/JSON API under /api. With it you can read an item, run a full-text search, walk the relations between items, and create or update items and their related objects (events, actions, components, and so on) — everything the web interface does with the item store, from a script or an integration.

The API carries exactly your own access: a request made with your token sees the same items you would see in the browser, no more. See authentication & access for how identity and access labels work.

Interactive documentation

The full specification is browsable and testable in your browser:

AddressWhat it is
/api/docsSwagger UI — try every endpoint interactively
/api/openapi.yamlthe raw OpenAPI 3.0 document

Open /api/docs, click Authorize, paste a token (below), and you can call any endpoint directly from the page.

Authentication

Every data endpoint requires a personal access token sent as a bearer credential:

Authorization: Bearer 

Only /api/health, /api/docs and /api/openapi.yaml are public — everything else returns 401 without a valid token.

Create a token (you must be logged in). The plaintext is shown once — store it immediately, it cannot be retrieved later:

curl -X POST https://kf.example.com/auth/tokens \
  -d name=my-script -d ttl=720h
# {"id":"a1b2c3d4","token":"f0e1d2…"}

name is a label for your own reference; ttl is an optional lifetime (for example 720h for 30 days) — omit it for a token that never expires. Revoke a token with POST /auth/tokens/{id}/revoke. See access tokens for the full details.

How long is a token valid? As long as you decide. Unlike the browser

session (which expires after a fixed period, 24 hours by default), an API

token has no default and no maximum lifetime — it lives for exactly the ttl

you set at creation, or forever if you omit it. Once issued, the only way to end

it early is to revoke it.

ttl must use Go duration units — h (hours), m (minutes), s (seconds); for

example 720h, not 30d. A value KF cannot parse is treated as no expiry, so

a typo like 30d silently produces a token that never expires.

Conventions

  • All request and response bodies are JSON; send Content-Type: application/json on POST and PUT.
  • An item is identified by its id (or uid). Items also have an optional human code (an SKU or x0 number) and a space-separated list of tags.
  • Every item has a class: m (module), i (item), e (event), a (action), t (type). The class controls how an item behaves and how it is shown.
  • Errors are returned as { "error": "…" } with an appropriate HTTP status (400 invalid input, 401 no/invalid token, 404 not found).

Endpoints

Method & pathPurpose
GET /api/healthLiveness check (public, no token)
GET /api/search?q=…Full-text (BM25) search
POST /api/itemsCreate an item
GET /api/items/{id}Get an item by id
PUT /api/items/{id}Update an item
GET /api/items/by-code/{code}Get an item by its code (SKU / x0)
GET /api/items/by-tag/{tag}List items carrying a tag
GET /api/items/{id}/pathBreadcrumb path of an item
GET /api/items/{id}/{relation}List related items
POST /api/items/{id}/{relation}Create and link a related item

GET /api/search?q=pump+failure

Full-text search over all items, in BM25 rank order (best match first). The query uses FTS5 syntax: plain keywords, "exact phrases", prefix* wildcards, and the boolean operators AND / OR / NOT.

curl -G https://kf.example.com/api/search \
  --data-urlencode "q=pump AND (seal OR bearing)" \
  -H "Authorization: Bearer $TOKEN"

Each result is a compact reference:

[
  { "id": "3k9", "title": "Pump seal leak", "type": "e", "link": "/3k9" }
]

Read an item

GET /api/items/{id} returns the full item:

{
  "id": "3k9",
  "uid": "…",
  "title": "Centrifugal pump",
  "class": "i",
  "code": "PMP-100",
  "tags": "critical rotating",
  "parent": "1a2",
  "doc": "Markdown body of the item…"
}

You can also fetch by code (GET /api/items/by-code/PMP-100) or list every item carrying a tag (GET /api/items/by-tag/critical). GET /api/items/{id}/path returns the breadcrumb trail:

{ "id": "3k9", "path": "Home / Machine / Pump" }

GET /api/items/{id}/{relation} lists the items linked to an item by a given relation. {relation} is one of:

RelationDirectionWhat it lists
eventsdownfailure modes / problems annotated on the item
componentsdownsub-parts (bill of materials)
actionsdowncorrective / preventive actions
outputsdownexpected outcomes
instancesdownitems that draw from this one as a type
sidebardownsidebar navigation elements
causesupcauses leading to this event
typesuptypes this item learns from
curl https://kf.example.com/api/items/3k9/events \
  -H "Authorization: Bearer $TOKEN"

Create and update items

Create an item with POST /api/items. Only title is required; class,

code, tags, doc and parent are optional:

curl -X POST https://kf.example.com/api/items \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"Centrifugal pump","class":"i","code":"PMP-100","tags":"critical"}'

The response is the created item (HTTP 201), including its new id.

Update with PUT /api/items/{id}. Only the fields you send (title, doc,

code, tags) are changed; anything omitted is left as it was.

POST /api/items/{id}/{relation} creates a new item of the class implied by the relation and links it to {id} in one step. For example, to annotate a failure event on a component:

curl -X POST https://kf.example.com/api/items/3k9/events \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"Seal leak under load"}'

The down relations (events, components, actions, outputs, instances,

sidebar) attach the new item below {id}; the up relations (causes,

types) attach it above. The body is the same NewItem shape as

POST /api/items, but class and parent are ignored — the relation decides both.

A minimal session

export TOKEN=f0e1d2…

# find an item
curl -G https://kf.example.com/api/search --data-urlencode "q=pump" \
  -H "Authorization: Bearer $TOKEN"

# read it
curl https://kf.example.com/api/items/3k9 -H "Authorization: Bearer $TOKEN"

# annotate a failure event on it
curl -X POST https://kf.example.com/api/items/3k9/events \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"title":"Bearing seizure"}'