Overview
The AssetBlue API turns messy field evidence into an inspectable diagnosis. You send the asset and whatever you have — natural-language evidence (symptoms, diagnostics, maintenance actions), structured sensor readings, photos, HMI screenshots, voice notes — and AssetBlue reasons through failure physics and your engineering knowledge graph to a ranked root cause and the next best test.
The API is skill-based. Each endpoint runs one complete reliability skill and returns its result — the flagship is RCA (the diagnosis lifecycle), and alongside it are what-if (the boiler binary for boilers, an operating-envelope assessment for transformers) and knowledge Q&A (see Skill endpoints). It is REST over HTTPS, returns JSON, and uses standard verbs and status codes. Every response is evidence-linked and traceable, so a recommendation never arrives without its reasoning. There is deliberately no endpoint into the knowledge base itself — the KB stays behind the skills.
- Base URL
https://dev.assetblue.ai/v1 - Content type
application/jsonfor all request and response bodies - Evidence kinds each
evidence[]item issymptom,diagnostic, oraction— all plain language - Structured readings send sensor / SCADA / instrument data as
readings[]for charts, thresholds, and trend reasoning - Multimodal input attach images, audio, and HMI captures by reference on any evidence or reading
Authentication
Authenticate every request with a secret API key in the Authorization header as a bearer token. Keys are scoped per environment.
Authorization: Bearer ab_live_8f2c9d4a1b6e…
Use ab_test_… keys against the sandbox and ab_live_… keys in production. Never expose a secret key in client-side code or a mobile bundle — proxy requests through your own backend. Rotate keys from the console at any time.
Quickstart
Create your first diagnosis in one call over plain HTTP. Pass ?wait=true to block until reasoning settles and get the leading hypothesis and next best test back directly; omit it to get a diagnosis you can poll.
curl -X POST 'https://dev.assetblue.ai/v1/diagnoses?wait=true' \
-H 'Authorization: Bearer ab_live_8f2c…' \
-H 'Content-Type: application/json' \
-d '{
"asset": { "id": "TX-4021", "type": "transformer" },
"evidence": [
{ "kind": "symptom", "text": "Top-oil temperature climbing over the last week at unchanged load" },
{ "kind": "action", "text": "Cooler-bank fans serviced last month, no change in the top-oil trend" }
],
"readings": [
{ "metric": "top_oil_temp", "value": 82.4, "unit": "C" },
{ "metric": "acetylene", "value": 4.7, "unit": "ppm" }
]
}'
The response carries the ranked leading_hypothesis and the single next_best_test. See GET /diagnoses/{id} for the full shape.
The diagnosis lifecycle
A diagnosis moves through four states. You can act on it at any point, and a human always signs off before it becomes a finalized RCA.
Submitted
Evidence received; reasoning starts.
Reasoned
Ranked hypotheses and the next best test.
Validated
An engineer confirms or overrides.
Finalized
Audit-ready RCA and asset memory.
Statuses surface as status on the diagnosis object: submitted, reasoning, reasoned, validated, finalized. Poll GET /diagnoses/{id} to follow the state, or pass ?wait=true on create/validate to block until reasoning settles.
Endpoints
Six endpoints cover the full lifecycle: create, retrieve, enrich, validate, report, and recall. Paths are relative to the base URL.
Start a diagnosis from any combination of evidence. Returns immediately with a diagnosis in the reasoning state.
| Field | Type | Description |
|---|---|---|
| asset | object | Asset id and type.required |
| evidence | array | One or more natural-language evidence items. Each is { kind, text, at?, attachments? } where kind is one of symptom (what was observed), diagnostic (an engineer’s interpretation of a test or instrument), or action (a maintenance action that was performed). text is free-form prose — no metric/unit schema. Optional at ISO-8601 timestamp; optional attachments array of upload ids / URLs scoped to that item.required |
| readings | array | Structured sensor / SCADA / instrument readings as { metric, value, unit, at? }. Send these in parallel with evidence[] — they drive charts, threshold comparisons, and trend reasoning. Engineers don’t have to interpret them in prose; AssetBlue will. |
| attachments | array | Top-level images, audio, or HMI captures that aren’t tied to a specific evidence item — by URL or upload id. |
{
"asset": { "id": "TX-4021", "type": "transformer" },
"evidence": [
{
"kind": "symptom",
"text": "Top-oil temperature climbing over the last week at unchanged load; Buchholz alarmed once overnight",
"at": "2026-06-04T13:47Z"
},
{
"kind": "diagnostic",
"text": "Latest DGA shows acetylene with rising ethylene — a high-energy internal fault signature",
"at": "2026-06-04T13:55Z",
"attachments": ["upl_2Hk…"]
},
{
"kind": "action",
"text": "Cooler-bank fans serviced last month — no change in the top-oil trend",
"at": "2026-06-03T09:00Z"
}
],
"readings": [
{ "metric": "top_oil_temp", "value": 82.4, "unit": "C", "at": "2026-06-04T13:55Z" },
{ "metric": "acetylene", "value": 4.7, "unit": "ppm", "at": "2026-06-04T13:55Z" }
]
}
{
"id": "dg_3Qa9kR2xVb",
"status": "reasoning",
"asset": { "id": "TX-4021", "type": "transformer" },
"created_at": "2026-06-04T14:18:07Z"
}
Retrieve the current reasoning state: ranked hypotheses, the evidence weighed for and against each, and the single next test that best discriminates the cause.
{
"id": "dg_3Qa9kR2xVb",
"status": "reasoned",
"leading_hypothesis": {
"mechanism": "internal_arcing.high_energy_discharge",
"confidence": 0.86,
"evidence_for": [
{ "claim": "Acetylene present with rising ethylene — high-energy fault signature", "source": "dga" },
{ "claim": "Top-oil rise decoupled from load", "source": "thermal" }
],
"evidence_against": [
{ "claim": "No gas accumulation in the Buchholz relay on inspection", "source": "field_note" }
]
},
"next_best_test": {
"action": "Repeat DGA at 48 h and run a Duval triangle on the trend",
"expected_confidence": 0.97
}
}
Append one or more evidence items to an in-flight diagnosis — same shape as the evidence array on POST /v1/diagnoses. AssetBlue re-reasons and returns the updated diagnosis with revised confidence. To answer a clarifying question AssetBlue raised, set in_reply_to to its question_id.
| Field | Type | Description |
|---|---|---|
| kind | string | One of symptom, diagnostic, or action.required |
| text | string | Plain-language description.required |
| at | string | ISO-8601 timestamp the evidence applies to. Defaults to now. |
| attachments | array | Upload ids or URLs scoped to this evidence item. |
| in_reply_to | string | A question_id from a clarifying question AssetBlue raised, if this evidence answers it. |
{
"kind": "diagnostic",
"text": "Repeat DGA at 48 h: acetylene up to 21 ppm; Duval places it in D2 (high-energy arcing)",
"at": "2026-06-04T15:02Z",
"attachments": ["upl_9Wq…"]
}
Record a named engineer's decision. No work order is issued without sign-off. decision is confirm or override; on confirm a final reasoning pass emits the formal RCA and the diagnosis moves to finalized (fetch it via GET /rca), on override the note is recorded and the diagnosis stays validated. Returns the updated diagnosis object. Pass ?wait=true to block until the finalize pass completes.
{
"decision": "confirm",
"engineer_name": "R. Okafor",
"engineer_email": "r.okafor@example.com",
"note": "DGA trend confirms high-energy arcing. De-energize and schedule an internal inspection."
}
Fetch the formal root-cause report: the confirmed root cause, causal chain, key evidence, eliminated causes, recommended actions with owners and due dates, confidence progression, and referenced standards. Finalizes on demand — if the diagnosis has no report yet, this runs the finalize reasoning pass inline and returns the result, so create → evidence → GET /rca works without an explicit /validate call (/validate remains the way to record engineer sign-off). Default response is JSON; pass ?format=pdf to download the same report as a formatted PDF (application/pdf).
Your onboarded assets — the same register the web app shows, scoped to the account that created the API key. Use it to discover the asset ids (plus manufacturer/model context) to feed into /v1/diagnoses and /v1/whatif without re-entering them.
{
"assets": [
{
"id": "seed-tx-bhel-220",
"name": "GT-1 — BHEL 160 MVA 220/66 kV",
"asset_type": "transformer",
"manufacturer": "BHEL",
"model_number": "220/66 kV, 50, 100 & 160 MVA POWER TRANSFORMER",
"envelope_rows": 6
}
],
"count": 1
}
Recall an asset’s accumulated memory: prior evidence (symptoms, diagnostics, and maintenance actions), confirmed mechanisms, corrective actions, and recurrence patterns. Every new diagnosis starts from this intelligence, not a blank form.
Skill endpoints
The API is skill-based: every endpoint runs one complete reliability skill and returns its result. There is no endpoint into the knowledge base — no search, no traversal, no raw reads. The RCA lifecycle above is one skill; three more are below. All use the same Bearer-key auth, are scoped to your key, and scrub third-party source names from responses.
The assets we support right now: boiler and transformer. This endpoint lists them, which skills each can run, and the state of its binary. Every asset_type you send must be one of these — anything else is a 400, never a silent default. Availability is live: what-if works for both off the knowledge base; the boiler binary is an extra engine for boilers, and the transformer binary is not built yet — it’s on the way.
{
"supported": ["boiler", "transformer"],
"asset_types": [
{ "asset_type": "boiler", "label": "Boiler", "supported": true,
"skills": {
"rca": { "available": true },
"whatif": { "available": true, "engines": { "envelope_assessment": true, "boiler_binary": true } },
"knowledge": { "available": true } },
"binary": { "name": "boiler_binary", "available": true, "status": "available" } },
{ "asset_type": "transformer", "label": "Transformer", "supported": true,
"skills": {
"rca": { "available": true },
"whatif": { "available": true, "engines": { "envelope_assessment": true, "transformer_binary": false } },
"knowledge": { "available": true } },
// the transformer binary is not built yet
"binary": { "name": "transformer_binary", "available": false, "status": "on_the_way" } }
]
}
Look up the manufacturers and models you can address on a skill call. This is the catalog index — names only. It is a lookup, not a directory dump: manufacturers need a q (2+ chars), models are always scoped to one manufacturer, results are capped with a truncated flag, and there is no offset/cursor to walk. The knowledge itself — envelopes, mechanisms, diagnostics, documents — is never returned here; it stays behind the skills.
| Field | Type | Description |
|---|---|---|
| asset_type | string | boiler | transformer.required |
| q | string | manufacturers: required, 2+ chars. models: optional narrowing. |
| manufacturer | string | models only — required. There is no global model listing.required |
{ "asset_type": "boiler", "q": "bhel" }
{
"asset_type": "boiler", "q": "bhel",
"manufacturers": [ { "manufacturer": "Bharat Heavy Electricals Limited", "models": 12 } ],
"returned": 1, "truncated": false
}
{ "asset_type": "boiler", "manufacturer": "Bharat Heavy Electricals Limited" }
// → { "models": ["200/210 MW Subcritical …", …], "returned": 12, "truncated": false }
What a what-if run accepts, keyed by asset_type — every family in one response, so there is no discriminator to pass (asset_type is only ever a body field on POST). Each asset type reports whatif.available (true for both — it runs off the knowledge base), its accepted inputs, and its engines: envelope_assessment (always available, no binary) plus the binary — boiler_binary (live, with its primitives/controls/mechanisms) or transformer_binary (on_the_way).
One what-if endpoint for every asset. The engine is chosen by the asset’s family (inferred from asset, or set asset_type explicitly) — there is no per-asset-type path. A boiler runs the boiler binary; a transformer is assessed against its operating envelope. The response carries asset_type and engine so you know which result shape you got. Boiler runs are synchronous (a few seconds); transformer assessments honour ?wait (default true returns the result; false returns a job to poll at GET /whatif/{id}).
Transformer: its what-if works today (knowledge base). Only the transformer binary is on the way — so primitive is the one input it doesn’t take, and sending it returns 501 Not Implemented saying so rather than quietly running something else.
| Field | Type | Description |
|---|---|---|
| asset_type | string | boiler | transformer — selects the engine.required |
| asset | object | { manufacturer, model } — needed for a transformer (to pull its envelope); optional label for a boiler. |
| change | string | Natural language description of the change. Any asset type; no binary needed. |
| primitive | string | Boiler only, optional — runs the boiler binary. steady | cycling | load_ramp | chemistry_excursion | fuel_switch | tube_leak, with params / controls / horizon. See capabilities. |
| proposed | object | Structured conditions, e.g. { "load_pct": 115, "top_oil_C": 95, "duration": "6h" }. Any asset type. |
{
"asset_type": "boiler",
"asset": { "model": "200/210 MW subcritical" },
"primitive": "chemistry_excursion",
"params": { "species": "pH_low", "value": 8.2, "duration": "72h" },
"horizon": "90d"
}
{
"asset_type": "boiler",
"asset": { "manufacturer": "BHEL", "model": "200/210 MW subcritical" },
"change": "two-shift the unit daily for the next quarter"
}
// …or structured conditions, on any asset type:
{
"asset_type": "transformer",
"asset": { "manufacturer": "ABB", "model": "TrafoStar 400" },
"proposed": { "load_pct": 118, "top_oil_C": 98, "duration": "6h" }
}
{
"id": "wif_73a7fdbdad",
"skill": "whatif",
"status": "done",
"result": {
"asset_type": "boiler",
"engine": "boiler_binary",
"prognosis": { "governing_mechanism": { "name": "Hydrogen damage" }, "failure_risk_pct": 12.0, "remaining_life_days": 540 },
"final_state_token": "…"
}
}
A transformer result instead carries "engine": "envelope_assessment" with an assessment (headroom, risks, go/caution/no-go) and envelopes_considered.
Recall a stored what-if run by id (scoped to your key). GET /v1/whatif lists your recent runs. For a transformer run started with ?wait=false, poll here until status is done.
Knowledge Q&A. Answer a technical reliability question, grounded in the knowledge base and scrubbed of source names. Default ?wait=true returns the answer directly; ?wait=false returns a job to poll at GET /v1/answers/{id}.
| Field | Type | Description |
|---|---|---|
| question | string | The technical question, in plain language.required |
| asset_type | string | boiler or transformer — which corpus to draw from. Inferred from asset if omitted. |
| asset | object | Optional context, e.g. { manufacturer, model, asset_type }. |
{
"question": "What causes waterwall tube hydrogen damage and how is it detected?",
"asset_type": "boiler"
}
{
"id": "ans_1b7c9d0e2f",
"skill": "knowledge_answer",
"status": "done",
"result": {
"answer": "## Causes … (markdown, no source names)",
"grounded": true,
"asset_type": "boiler",
"sources_considered": 8
}
}
Using the API
The API is plain REST over HTTPS — no SDK required. Send a Bearer key and a JSON body from any language. Here is the same call in a few common clients.
import requests
r = requests.post(
"https://dev.assetblue.ai/v1/answers?wait=true",
headers={"Authorization": "Bearer ab_live_8f2c…"},
json={"question": "What causes waterwall tube hydrogen damage?", "asset_type": "boiler"},
timeout=60,
)
print(r.json()["result"]["answer"])
const r = await fetch("https://dev.assetblue.ai/v1/answers?wait=true", {
method: "POST",
headers: {
"Authorization": "Bearer ab_live_8f2c…",
"Content-Type": "application/json",
},
body: JSON.stringify({ question: "What causes waterwall tube hydrogen damage?", asset_type: "boiler" }),
});
const { result } = await r.json();
console.log(result.answer);
Every example on this page is a plain request you can run with curl or any HTTP client — copy a request body, add your Bearer key, and go. Never expose a secret key in client-side code; proxy through your own backend.
Errors & limits
AssetBlue uses conventional HTTP status codes and returns a structured error body.
{
"error": {
"type": "invalid_request",
"code": "missing_field",
"message": "asset.id is required",
"param": "asset.id"
}
}
| 400 · 422 | Malformed or invalid request body. |
| 401 | Missing or invalid API key. |
| 404 | No such diagnosis or asset. |
| 429 | Rate limit exceeded. Default 600 req/min; reasoning jobs are async and uncapped. |
| 5xx | Transient server error. Retry idempotently with backoff. |
Send an Idempotency-Key header on writes to safely retry without creating duplicate diagnoses.