Ownware
Inspectora · API

Inspectora API, as shipped in the download

Inspectora — API, webhooks and the agent door

Everything here runs on your own server. Nothing is proxied, and no request leaves your network unless you point it somewhere.

Authentication

Mint a key in the app: API & agents → API keys. Send it as a bearer token:

Authorization: Bearer ink_...

Each key has a scope:

ScopeWhat it can do
Read and writeEverything the key's user could do in the browser.
Read onlyGET, HEAD and OPTIONS. Anything else is refused with 403 forbidden at the door — not per route, because the route that forgets is the one that leaks.

A key can never exceed its user's role. A read key belonging to an admin still cannot write.

Endpoints

MethodPathWhat it does
GET/api/pingVerify a key; returns its scope.
GET/api/matrixThe whole board: every asset against every inspection type, with each cell's state and next-due date.
GET/api/attentionFailed, expired, never recorded and expiring — worst first. `?state=failed\expired\none\expiring`.
GET/api/subjectsThe register of assets.
GET/api/subjects/{id}One asset and what is on file for it.
GET/api/requirementsThe inspection types tracked, with their interval in months.
GET/api/recordsRecords, newest first. ?subject_id= ?requirement_id=
POST/api/recordsRecord an inspection and its result.
GET/api/openapi.jsonOpenAPI 3 description of all of the above.
GET/healthzLiveness, no key required.

Record an inspection

curl -X POST https://inspectora.example.com/api/records \
  -H "Authorization: Bearer ink_xxxx" -H "Content-Type: application/json" \
  -d '{"subject_id": 4, "requirement_id": 2, "achieved_on": "2026-08-01", "result": "fail", "note": "Nozzle cracked"}'

result is pass (the default when you leave it out), pass_remarks or fail; anything else is refused. A fail is recorded with no next-due date (expires_on is null and never_expires is false), and the asset's cell reads failed in /api/matrix and /api/attention until a later pass is recorded. A pass with remarks is a pass; put the remarks in note.

You cannot set the next-due date. It is computed from the inspection type's own interval, because a client that could choose its own due date would make the whole register meaningless. The same call refuses, with a sentence, when:

  • the date is in the future, or is not a real date;
  • the inspection type does not apply to that asset's class;
  • the asset or the inspection type is archived, or does not exist.
  • the result is not pass, pass_remarks or fail.

These are the same refusals the board shows and the MCP tool returns, because all four doors call one function.

Webhooks

record.created fires whenever an inspection is recorded, from any door. Configure receivers under API & agents. One delivery attempt per event, with a log — that is a log, not a retry queue.

Limits, honestly

  • List endpoints cap at 500 rows. This is a compliance register for one organisation, not a warehouse.
  • There is no endpoint that creates an asset, an inspection type or a schedule. Those are deliberate screens with their own guards; the API is for reading the register and recording inspections.
  • No endpoint issues a certificate. Inspectora does not issue certificates — see the hand-off below.

The certificate hand-off

GET /export/certora-recipients.csv emits exactly name,course,email, one row per asset whose check is currently in date. Those three header names are [Certora](../29-certora)'s recipient-import contract; import the file there and issue from it.

It is a file hand-off on purpose: no request leaves this box, and Inspectora never learns whether a certificate was issued. If you want that link automated, drive Certora's own API with this file.


MCP — the agent door

Inspectora speaks the Model Context Protocol at POST /mcp, so Claude, ChatGPT agents, n8n's AI nodes or your own code can use the register rather than merely read it. It is the same product underneath: the same bearer key, the same roles, and the same due-date engine. An agent cannot do anything its key's user could not do in the browser — and it cannot compute a due date, ever.

Transport is streamable HTTP, stateless: one JSON-RPC 2.0 request in, one JSON response out.

Connect it to an assistant

Mint the key in the app first: API & agents → API keys. Choose Read only when the assistant should answer questions but never change anything — the endpoint then lists only the read tools and refuses the rest by name, so a careless prompt cannot write. Full access behaves as before.

Every client needs the same three facts, and nothing in the handshake is vendor-specific:

The addresshttps://inspectora.example.com/mcp
The keyheader Authorization: Bearer ink_xxxx
The transportMCP over streamable HTTP, stateless

Claude — one command, or the same URL and header as a custom connector in the desktop and web apps:

claude mcp add --transport http inspectora https://inspectora.example.com/mcp \
  --header "Authorization: Bearer ink_xxxx"

ChatGPT and the OpenAI API — one entry in the Responses API's tools array (in ChatGPT itself, the same URL and key go in as a connector):

{
  "type": "mcp",
  "server_label": "inspectora",
  "server_url": "https://inspectora.example.com/mcp",
  "authorization": "ink_xxxx",
  "require_approval": "never"
}

Own Your AI reads a list of servers in this shape:

{
  "mcpServers": [
    { "id": "inspectora", "name": "Inspectora", "url": "https://inspectora.example.com/mcp",
      "token": "ink_xxxx", "enabled": true }
  ]
}

**Every other client spells the same three facts differently — copy the shape from its own documentation, not from here.** VS Code is the clearest example of why: its configuration reference (read 6 September 2026) puts servers in .vscode/mcp.json under a "servers" object — *"an object that maps server names to their configurations"* — not an mcpServers array. Pasted as-is, the block above will not load there. The id, the URL and the token are what travel; the JSON around them belongs to whichever client you are configuring.

A local model, n8n, or your own code — n8n's MCP Client node takes the URL and the same Authorization: Bearer header; a model running on your own machine reaches it through any MCP client, so nothing leaves your network at all. Writing it yourself is one POST of JSON-RPC 2.0:

curl -X POST https://inspectora.example.com/mcp \
  -H "Authorization: Bearer ink_xxxx" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Any client that speaks MCP's streamable-HTTP transport works, including ones that do not exist yet: Inspectora implements the protocol, not an integration with a particular vendor.

Tools

ToolReads or writesWhat it is for
matrixreadsThe whole board, with coverage.
attentionreadsWhat is overdue, never done or due soon — the list to work down.
subject_detailreadsOne asset: what is on file and what is missing.
requirementsreadsThe inspection types and how long each is good for.
record_completionwritesRecord a check on an asset on a date, with its result: pass (default), pass_remarks or fail.

Every read tool is annotated readOnly, which is what makes a read-scoped key see only those four. A read key calling record_completion by name gets a refusal naming the tool, not a silent failure.

← Back to Inspectora · Manual · Quickstart · Test run

Affiliate program
Recommend tools people own — earn 35% on every sale. 90-day tracking, instant delivery, payouts by Lemon Squeezy.
Become an affiliate →