Developers
Everything the dashboard does, your code can do.
A REST API and an MCP server over the same workspace: send data, ask with citations, run procedures, read cameras.
Quick start
Three calls
Create a key in the dashboard under Settings → Developers. Then send something and ask about it.
# 1. send a reading (IRF) curl https://YOUR-IRRIS/api/v1/ingest \ -H "Authorization: Bearer $IRRIS_KEY" -H "Content-Type: application/json" \ -d '{"type":"reading","source":"line-3/plc","subject":"asset:press-7", "data":{"value":182.4,"unit":"C"}}' # 2. send a manual curl https://YOUR-IRRIS/api/v1/ingest/file -H "Authorization: Bearer $IRRIS_KEY" -F file=@press7-manual.pdf # 3. ask curl https://YOUR-IRRIS/api/v1/ask \ -H "Authorization: Bearer $IRRIS_KEY" -H "Content-Type: application/json" \ -d '{"message":"Is press 7 within its platen limits?"}' → {"reply": "No. It read 182.4 C [1], above the 180 C hold limit on p. 14 of the manual [2].", "sources": [{"n":1,"title":"…"},{"n":2,"title":"press7-manual.pdf","page":14}], "conversation_id": "…"}
Authentication
One key per integration
Keys start with irr_ and belong to one workspace. Send Authorization: Bearer irr_… or X-API-Key: irr_…. Clients that can only take a URL may add ?key=irr_…, but a key in a URL can end up in logs. Keys are shown once; delete one to revoke it.
Send data
Any data, one standard
Records follow the Irris Record Format. Send IRF when you can, and anything else as it is.
| Call | What it takes |
|---|---|
| POST /api/v1/ingest | One IRF record, a list, or {"records": [...]}. Up to 10,000 per call. Same source + id updates. |
| POST /api/v1/ingest?type=work_order&source=erp | Any other JSON. Each object becomes one record of that type. |
| Content-Type: application/x-ndjson | One record per line, for streams and big batches. |
| POST /api/v1/ingest/file | PDF, Word, Excel, CSV, JSON, Markdown, text, images (multipart file). PDFs keep page numbers for citations. |
| POST /api/v1/hooks/{secret} | A webhook made in Data → Webhooks, for systems that can only POST. No key needed: the secret is in the URL. |
| Postgres | Connect in Data → Databases. Irris syncs the tables you pick and runs read-only queries live. Use a read-only database user. |
Ask
Questions in, cited answers out
POST /api/v1/ask with {"message", "conversation_id"?, "camera_id"?, "run_id"?, "stream"?}. Irris searches your records and documents, queries connected databases, looks through cameras and starts procedures on her own. Every fact in the reply carries a [n] that matches sources. With "stream": true the reply is Server-Sent Events: tool for each step, then done.
Procedures
SOPs that check themselves
A procedure is a list of steps. A step can say what correct looks like on camera (check) and the range a reading must fall in. A run walks through it: each step is checked through the camera or marked by hand, out-of-range readings fail, and the finished run writes a batch_record.
Calls
| POST /api/v1/procedures | Create |
| POST /api/v1/runs | {"procedure_id", "camera_id"?, "label"?} |
| POST /api/v1/runs/{id}/check | {} checks through the camera; {"result": "pass", "reading": {"value": 180, "unit": "C"}} marks it by hand |
| POST /api/v1/runs/{id}/back · /stop | Move back a step, or stop |
{
"name": "Mould change, tool T-12",
"steps": [
{ "instruction": "Lock out the press",
"check": "red LOTO tag on the main isolator" },
{ "instruction": "Check the platen temperature",
"check": "the controller display is readable",
"reading": { "label": "platen", "min": 175,
"max": 185, "unit": "C" } },
{ "instruction": "Fit the mould",
"check": "all four clamps closed",
"caution": "two people to lift" }
]
}
Cameras
A phone, or the cameras you have
| POST /api/v1/cameras {"kind": "phone"} | Returns a pairing link. Open it on any phone: it streams its back camera to Irris. No account on the phone. |
| POST /api/v1/cameras {"kind": "url", "url"} | An HTTP snapshot URL, an MJPEG stream, or RTSP (with OpenCV on the server). Irris grabs a frame when it needs one. |
| POST /api/v1/cam/frame?t={token} | Push your own JPEG frames for a paired camera, from any device or script. |
| GET /api/v1/cameras/{id}/frame.jpg | The latest frame. |
| POST /api/v1/cameras/{id}/look | {"question"} → {"say", "status", "reading"} |
MCP
Give your AI agents your operation
Streamable HTTP at /mcp, stateless, JSON responses. Tools: ask, ingest, search, records, databases, sql, look, cameras, procedures, start_run, run_status, check_step, remember. Resources: irris://irf (the standard) and irris://workspace.
// Claude Desktop, Cursor, any MCP client
{
"mcpServers": {
"irris": {
"type": "http",
"url": "https://YOUR-IRRIS/mcp",
"headers": { "Authorization": "Bearer irr_…" }
}
}
}
# Claude Code claude mcp add --transport http irris \ https://YOUR-IRRIS/mcp \ --header "Authorization: Bearer $IRRIS_KEY" # clients that only take a URL https://YOUR-IRRIS/mcp?key=irr_…
Models
Bring your own models
Irris reasons with any OpenAI-compatible chat API that supports tool calling, and sees with any OpenAI-compatible API that takes images: Ollama or vLLM on your own GPU, or a hosted provider. Set them per workspace in Settings → Models. Keys are stored encrypted and never returned. Irris never pools workspaces or trains anything shared on your data. What reaches a hosted model follows that provider's terms, so run both models on your own GPU to keep everything in-house.
Reference
Every endpoint
The full OpenAPI reference, with every field, is at /api/docs (spec: /api/v1/openapi.json). A guide for LLMs is at /llms.txt.
Building an agent? Give it /api/v1/openapi.json and /llms.txt, not this page. Every error carries a code and a next_action; creates take an Idempotency-Key; GET /api/v1/changes?cursor= is a feed of everything that changed; GET /api/v1/status/{kind}/{id} says why anything is stuck and what unblocks it; webhooks are signed with HMAC-SHA256.