Reference

API reference.

A stable, versioned HTTP API for interpreting and analyzing PLC projects.

v1.0.0OpenAPI 3.1.0

The PLCs.ai API provides plain-language interpretation, troubleshooting, and analysis of Allen-Bradley and Siemens projects — behind a versioned, externally-authenticated HTTP surface.

Authentication. Every request carries an API key as a bearer token: Authorization: Bearer plck_live_…. A key resolves its organization from the credential itself — there is no organization in the URL. Mint, scope, and revoke keys from Settings → API Keys in the app.

Idempotency. Every write accepts (and requires) an Idempotency-Key header so a retry never creates a duplicate billable unit.

Errors. Every error uses one envelope with a human userMessage, a suggestedAction, and an isRetryable flag. Every response — success or error — carries a unique request-id header; quote it in support requests.

Permissions. A key carries a set of scopes. Each endpoint documents the scope it requires.

Download the OpenAPI 3.1 spec (YAML) — the same file the SDKs use.

Base URL

ServerDescription
https://app.plcs.ai/api/v1Production

Authentication

An API key minted from Settings → API Keys, sent as Authorization: Bearer plck_live_….

Authenticated health check

get/health

Confirms the API is reachable and your credential resolves an organization. Returns the resolved organizationId and actorType.

Responses

StatusDescription
200The credential resolved an organization.
401No valid credential, or the key was revoked.

Response · 200

FieldTypeDescription
status requiredconst "ok"
Always ok
organizationId requiredstring
actorType requiredstring enum
Values: api_key embed_token
json
{
  "status": "ok",
  "organizationId": "string",
  "actorType": "api_key"
}

Every 4xx/5xx uses the standard error envelope and carries a request-id header.

Interpret a prompt against a project

post/projects/{id}/interpret

The headline capability: a prompt in, a cited interpretation out, over the existing assistant. Two response modes off one endpoint:

  • mode: "sync" (default) — a blocking JSON body { answer, citations, usage }.
  • mode: "stream" — a Server-Sent Events stream (status / token / citations / done / error). See the Streaming guide.

Requires the ai_explain permission.

Parameters

NameInTypeDescription
id requiredpathstringThe project id.
Idempotency-Key requiredheaderstringA unique key (e.g. a UUID) for this write. Retrying with the same key and body replays the original result without double-billing.

Request body required

FieldTypeDescription
prompt requiredstringThe question to ask about the project.
modestring enumsync returns a blocking JSON body. stream returns an SSE stream.
Values: sync stream · Default sync
include_citationsbooleanWhether to include source citations in the response.
Default true
json
{
  "prompt": "What conditions must be true for the main conveyor to start?",
  "mode": "sync",
  "include_citations": true
}

Responses

StatusDescription
200For mode: "sync", the cited interpretation. For mode: "stream", an text/event-stream of SSE events (see the Streaming guide).
400The request was malformed.
401No valid credential, or the key was revoked.
403The key lacks the permission (or project scope) this endpoint needs.
404The resource was not found, or is not visible to this key's org.
409A request with this Idempotency-Key is still being processed.
422This Idempotency-Key was already used with a different body.
429Per-key rate limit exceeded.

Response · 200

FieldTypeDescription
answer requiredstring
citations requiredarray<string>Source identifiers backing the answer.
usage requiredobjectToken counts for this call. Informational only — not a bill.
usage.input_tokensinteger
usage.output_tokensinteger
json
{
  "answer": "string",
  "citations": [
    "string"
  ],
  "usage": {
    "input_tokens": 0,
    "output_tokens": 0
  }
}

Every 4xx/5xx uses the standard error envelope and carries a request-id header.

Generate or modify PLC code (proposal)

post/projects/{id}/generate

Ask the assistant to PRODUCE or MODIFY PLC logic and get back a reviewable proposal. Proposes, never deploys: the response is generated routine(s) / SCL text with inline insertion directives — it creates NO version. To persist a proposal, commit it as a new version with POST /projects/{id}/versions (requires the separate code_write scope). Requires the ai_generate permission.

Two response modes off one endpoint:

  • mode: "sync" (default) — a blocking JSON body { generated_code, code_blocks, citations, usage }.
  • mode: "stream" — a Server-Sent Events stream (status / token / citations / done / error). See the Streaming guide.

generated_code is the assistant's full markdown response (prose + fenced `ladder / `st / `scl blocks + inline directives such as INSERT_RUNG_AFTER / MARK_DELETE); code_blocks is those fenced blocks lifted out for programmatic use.

Parameters

NameInTypeDescription
id requiredpathstringThe project id.
Idempotency-Key requiredheaderstringA unique key (e.g. a UUID) for this write. Retrying with the same key and body replays the original result without double-billing.

Request body required

FieldTypeDescription
prompt requiredstringWhat to generate or change (e.g. "Add a 5-second start-up delay timer").
targetobjectOptional hint for which program/routine to target. Folded into the prompt as guidance; the assistant decides the final placement.
target.programstring
target.routinestring
modestring enumsync returns a blocking JSON body. stream returns an SSE stream.
Values: sync stream · Default sync
include_citationsbooleanWhether to include source citations in the response.
Default true
json
{
  "prompt": "Add a 5-second start-up delay timer before the conveyor enables.",
  "target": {
    "program": "MainProgram",
    "routine": "ConveyorControl"
  },
  "mode": "sync",
  "include_citations": true
}

Responses

StatusDescription
200For mode: "sync", the generated proposal. For mode: "stream", a text/event-stream of SSE events (see the Streaming guide).
400The request was malformed.
401No valid credential, or the key was revoked.
402The organization reached its self-set API spend limit for the period and chose to pause. An owner/admin can raise the limit or enable overage billing in Settings → Spending Controls.
403The key lacks the permission (or project scope) this endpoint needs.
404The resource was not found, or is not visible to this key's org.
409A request with this Idempotency-Key is still being processed.
422This Idempotency-Key was already used with a different body.
429Per-key rate limit exceeded.

Response · 200

FieldTypeDescription
generated_code requiredstringThe assistant's full proposal: prose + fenced code blocks + inline insertion directives. The same text the in-app editor parses. This is a PROPOSAL — it creates no version.
code_blocks requiredarray<object>Fenced code blocks lifted from generated_code for programmatic use.
citations requiredarray<string>Source identifiers backing the proposal.
usage requiredobjectToken counts for this call. Informational only — not a bill.
usage.input_tokensinteger
usage.output_tokensinteger
json
{
  "generated_code": "string",
  "code_blocks": [
    {
      "language": "string",
      "content": "string"
    }
  ],
  "citations": [
    "string"
  ],
  "usage": {
    "input_tokens": 0,
    "output_tokens": 0
  }
}

Every 4xx/5xx uses the standard error envelope and carries a request-id header.

Create a troubleshooting thread

post/projects/{id}/conversations

Open a stateful multi-turn thread scoped to a project. Append turns with POST /conversations/{cid}/messages. Requires ai_explain.

Parameters

NameInTypeDescription
id requiredpathstringThe project id.
Idempotency-Key requiredheaderstringA unique key (e.g. a UUID) for this write. Retrying with the same key and body replays the original result without double-billing.

Request body

FieldTypeDescription
namestringOptional human label for the thread.
json
{
  "name": "string"
}

Responses

StatusDescription
201The created thread.
400The request was malformed.
401No valid credential, or the key was revoked.
403The key lacks the permission (or project scope) this endpoint needs.
404The resource was not found, or is not visible to this key's org.
409A request with this Idempotency-Key is still being processed.
422This Idempotency-Key was already used with a different body.
429Per-key rate limit exceeded.

Response · 201

FieldTypeDescription
conversationId requiredstring
projectId requiredstring
json
{
  "conversationId": "string",
  "projectId": "string"
}

Every 4xx/5xx uses the standard error envelope and carries a request-id header.

Append a turn to a thread

post/conversations/{cid}/messages

Run one interpret turn inside an existing thread. The thread's prior history is loaded automatically. Requires ai_explain.

Parameters

NameInTypeDescription
cid requiredpathstringThe conversation (thread) id.
Idempotency-Key requiredheaderstringA unique key (e.g. a UUID) for this write. Retrying with the same key and body replays the original result without double-billing.

Request body required

FieldTypeDescription
prompt requiredstring
include_citationsboolean
Default true
json
{
  "prompt": "string",
  "include_citations": true
}

Responses

StatusDescription
200The assistant's answer for this turn.
400The request was malformed.
401No valid credential, or the key was revoked.
403The key lacks the permission (or project scope) this endpoint needs.
404The resource was not found, or is not visible to this key's org.
409A request with this Idempotency-Key is still being processed.
422This Idempotency-Key was already used with a different body.
429Per-key rate limit exceeded.

Response · 200

FieldTypeDescription
conversationId requiredstring
answer requiredstring
citations requiredarray<string>
usage requiredobjectToken counts for this call. Informational only — not a bill.
usage.input_tokensinteger
usage.output_tokensinteger
json
{
  "conversationId": "string",
  "answer": "string",
  "citations": [
    "string"
  ],
  "usage": {
    "input_tokens": 0,
    "output_tokens": 0
  }
}

Every 4xx/5xx uses the standard error envelope and carries a request-id header.

Start an async analysis job

post/projects/{id}/analyses

Kick off an analysis run (dead code, missing handshakes, cycle-time) and return a job id immediately. Poll GET /analyses/{analysisId} for status and results. Requires analysis_tab.

Parameters

NameInTypeDescription
id requiredpathstringThe project id.
Idempotency-Key requiredheaderstringA unique key (e.g. a UUID) for this write. Retrying with the same key and body replays the original result without double-billing.

Responses

StatusDescription
202The analysis job was started (or joined an in-flight run).
401No valid credential, or the key was revoked.
403The key lacks the permission (or project scope) this endpoint needs.
404The resource was not found, or is not visible to this key's org.
409A request with this Idempotency-Key is still being processed.
422This Idempotency-Key was already used with a different body.
429Per-key rate limit exceeded.

Response · 202

FieldTypeDescription
analysisId requiredstring
status requiredstring enum
Values: queued running complete error
json
{
  "analysisId": "string",
  "status": "queued"
}

Every 4xx/5xx uses the standard error envelope and carries a request-id header.

Poll an analysis job

get/analyses/{analysisId}

Return the current status of an analysis job. While running, the response carries a status of queued/running plus a message with poll guidance — never an empty 200. When complete, results is populated; when error, errors is populated. Requires analysis_tab.

Parameters

NameInTypeDescription
analysisId requiredpathstringThe analysis job id returned by startAnalysis.

Responses

StatusDescription
200The analysis job status (and results when complete).
401No valid credential, or the key was revoked.
403The key lacks the permission (or project scope) this endpoint needs.
404The resource was not found, or is not visible to this key's org.
429Per-key rate limit exceeded.

Response · 200

FieldTypeDescription
analysisId requiredstring
status requiredstring enum
Values: queued running complete error
messagestringPresent while queued/running — poll-interval guidance.
resultsobjectPresent when status is complete.
errorsobjectPresent when status is error.
json
{
  "analysisId": "string",
  "status": "queued",
  "message": "string",
  "results": null,
  "errors": null
}

Every 4xx/5xx uses the standard error envelope and carries a request-id header.

Export the project to its vendor PLC file

post/projects/{id}/exports/plc

Start an async export of the project's current committed version to its native vendor format (Rockwell .L5X or a Siemens TIA .zip). Returns a job id immediately; poll GET /exports/{exportId} for status, then GET the download_url when complete. Exports the current version as-is (no edits). Requires export_plc.

Parameters

NameInTypeDescription
id requiredpathstringThe project id.
Idempotency-Key requiredheaderstringA unique key (e.g. a UUID) for this write. Retrying with the same key and body replays the original result without double-billing.

Responses

StatusDescription
202The export job was started.
401No valid credential, or the key was revoked.
403The key lacks the permission (or project scope) this endpoint needs.
404The resource was not found, or is not visible to this key's org.
409A request with this Idempotency-Key is still being processed.
422This Idempotency-Key was already used with a different body.
429Per-key rate limit exceeded.

Response · 202

FieldTypeDescription
exportId requiredstring
status requiredstring enum
Values: pending running complete error
json
{
  "exportId": "string",
  "status": "pending"
}

Every 4xx/5xx uses the standard error envelope and carries a request-id header.

Render a PDF report for the project

post/projects/{id}/exports/pdf

Start an async render of a PDF documentation report for the project's current committed version. The report is assembled server-side from the parsed structure + analysis results (a "report-only" PDF; it does not include in-app chat history). Returns a job id immediately; poll GET /exports/{exportId} then GET the download_url. Requires export_pdf.

Parameters

NameInTypeDescription
id requiredpathstringThe project id.
Idempotency-Key requiredheaderstringA unique key (e.g. a UUID) for this write. Retrying with the same key and body replays the original result without double-billing.

Responses

StatusDescription
202The export job was started.
401No valid credential, or the key was revoked.
403The key lacks the permission (or project scope) this endpoint needs.
404The resource was not found, or is not visible to this key's org.
409A request with this Idempotency-Key is still being processed.
422This Idempotency-Key was already used with a different body.
429Per-key rate limit exceeded.

Response · 202

FieldTypeDescription
exportId requiredstring
status requiredstring enum
Values: pending running complete error
json
{
  "exportId": "string",
  "status": "pending"
}

Every 4xx/5xx uses the standard error envelope and carries a request-id header.

Poll an export job

get/exports/{exportId}

Return the current status of an export job. While pending/running the response carries a message with poll guidance. When complete, download_url (a relative /exports/{id}/download path) and filename are populated; when error, error carries a short reason. Gated on the export's matching permission (export_plc / export_pdf).

Parameters

NameInTypeDescription
exportId requiredpathstringThe export job id returned by startPlcExport / startPdfExport.

Responses

StatusDescription
200The export job status (and download_url when complete).
401No valid credential, or the key was revoked.
403The key lacks the permission (or project scope) this endpoint needs.
404The resource was not found, or is not visible to this key's org.
429Per-key rate limit exceeded.

Response · 200

FieldTypeDescription
exportId requiredstring
kind requiredstring enum
Values: plc pdf
status requiredstring enum
Values: pending running complete error
download_urlstringPresent only when status is complete. A relative path.
filenamestringSuggested download filename (present when complete).
errorstringShort failure reason (present when status is error).
messagestringPoll guidance (present while pending/running).
json
{
  "exportId": "string",
  "kind": "plc",
  "status": "pending",
  "download_url": "string",
  "filename": "string",
  "error": "string",
  "message": "string"
}

Every 4xx/5xx uses the standard error envelope and carries a request-id header.

Download a completed export artifact

get/exports/{exportId}/download

Stream the finished artifact (L5X / Siemens ZIP / PDF) for a complete export job, with the right Content-Type and a Content-Disposition filename. Gated on the export's matching permission and scope.

Parameters

NameInTypeDescription
exportId requiredpathstringThe export job id returned by startPlcExport / startPdfExport.

Responses

StatusDescription
200The export artifact bytes.
400The request was malformed.
401No valid credential, or the key was revoked.
403The key lacks the permission (or project scope) this endpoint needs.
404The resource was not found, or is not visible to this key's org.
429Per-key rate limit exceeded.

Every 4xx/5xx uses the standard error envelope and carries a request-id header.

List projects

get/projects

Enumerate the organization's active projects, most-recently-touched first. Requires only a valid key (no extra permission) — an ai_explain-only operator key still needs to discover which projects exist. Results are filtered to the key's project scope. Returns identity-level metadata only; read source via GET /projects/{id}/source.

Parameters

NameInTypeDescription
team_idquerystringRestrict to a single team.
limitqueryintegerPage size (default 50, max 200).
cursorquerystringOpaque cursor from a previous response's next_cursor.

Responses

StatusDescription
200A page of projects.
400The request was malformed.
401No valid credential, or the key was revoked.
429Per-key rate limit exceeded.

Response · 200

FieldTypeDescription
projects requiredarray<object>
next_cursor requiredstringPass as ?cursor= to fetch the next page; null on the last page.
json
{
  "projects": [
    {
      "project_id": "string",
      "identity_id": "string",
      "name": "string",
      "vendor": "allen-bradley",
      "file_type": "string",
      "current_version_id": "string",
      "updated_at": "2026-05-31T18:15:00.000Z"
    }
  ],
  "next_cursor": "string"
}

Every 4xx/5xx uses the standard error envelope and carries a request-id header.

Ingest an L5X / Siemens export

post/projects

Upload an L5X (Rockwell) or Siemens TIA ZIP export to create or update a project. Billed identically to a UI upload.

Files up to ~4.5 MB may be sent inline as base64 in file.inline. Larger files use the large-file flow: upload to the returned blob URL and pass file.blob_url. Requires project_upload.

A project-scoped key may only add a version to an in-scope identity; it can never create a new identity.

Parameters

NameInTypeDescription
Idempotency-Key requiredheaderstringA unique key (e.g. a UUID) for this write. Retrying with the same key and body replays the original result without double-billing.

Request body required

FieldTypeDescription
originalFilename requiredstringThe export file name, e.g. "Conveyor.L5X" or "TIA_Export.zip".
namestringOptional display name for the project.
acknowledge_billingbooleanAcknowledges the per-project charge for an enterprise per-project organization. Only consulted when this upload would create a NEW billable project; ignored for every other org type and for add-version / identical-file. When a new billable project is created without this set to true, the request is rejected with 402 billing_acknowledgement_required (carrying the projected cost); resend with true to confirm. Ignored on POST /projects/{id}/versions.
file requiredobjectExactly one of inline or blob_url must be set.
file.inlinestringBase64-encoded file bytes (for files up to ~4.5 MB).
file.blob_urlstring (uri)A blob URL for the large-file flow.
json
{
  "originalFilename": "string",
  "name": "string",
  "acknowledge_billing": true,
  "file": {
    "inline": "string",
    "blob_url": "https://…"
  }
}

Responses

StatusDescription
201The resolved project identity and version.
400The request was malformed.
401No valid credential, or the key was revoked.
402An enterprise per-project organization tried to create a NEW billable project over the API. The error code is one of: - billing_setup_required — billing isn't set up yet (e.g. their first project); a charge can't be approved with no payment configured. Set up billing in the PLCs desktop app first, then retry. - billing_acknowledgement_required — billing is set up but the charge wasn't acknowledged. Disclose the cost from the billing block, then resend with acknowledge_billing: true. Only ever returned for enterprise per-project orgs on a new-project create — never for other org types, add-version, or identical-file.
403The key lacks the permission (or project scope) this endpoint needs.
409A request with this Idempotency-Key is still being processed.
413The inline body exceeded the limit; use the large-file flow.
422This Idempotency-Key was already used with a different body.
429Per-key rate limit exceeded.

Response · 201

FieldTypeDescription
identity_id requiredstring
display_namestring
project_id requiredstring
version_idstring
version_numberinteger
resolution requiredstringHow the identity was resolved (e.g. created / existing / identical_file).
vendor requiredstring enum
Values: allen-bradley siemens
json
{
  "identity_id": "string",
  "display_name": "string",
  "project_id": "string",
  "version_id": "string",
  "version_number": 0,
  "resolution": "string",
  "vendor": "allen-bradley"
}

Every 4xx/5xx uses the standard error envelope and carries a request-id header.

Get a project

get/projects/{id}

Identity + current-version metadata for one project, plus an analysis_status summary (not the full results blob). Requires only a valid key (no extra permission); scoped to the key's project scope. Unknown or out-of-scope id → 404.

Parameters

NameInTypeDescription
id requiredpathstringThe project id.

Responses

StatusDescription
200The project metadata.
401No valid credential, or the key was revoked.
403The key lacks the permission (or project scope) this endpoint needs.
404The resource was not found, or is not visible to this key's org.
429Per-key rate limit exceeded.

Response · 200

FieldTypeDescription
project_id requiredstring
identity_id requiredstring
name requiredstring
display_namestring
vendorstring
file_typestring
file_size_bytesinteger
original_filenamestring
current_version_id requiredstring
version_numberinteger
analysis_statusstring enumSummary only — poll GET /analyses/{id} for full results. null = never analyzed.
Values: queued running complete error null
created_at requiredstring (date-time)
updated_at requiredstring (date-time)
json
{
  "project_id": "string",
  "identity_id": "string",
  "name": "string",
  "display_name": "string",
  "vendor": "string",
  "file_type": "string",
  "file_size_bytes": 0,
  "original_filename": "string",
  "current_version_id": "string",
  "version_number": 0,
  "analysis_status": "queued",
  "created_at": "2026-05-31T18:15:00.000Z",
  "updated_at": "2026-05-31T18:15:00.000Z"
}

Every 4xx/5xx uses the standard error envelope and carries a request-id header.

Commit a new version (Save project)

post/projects/{id}/versions

Save a new version of an existing project from an updated vendor file — the headless equivalent of the platform's "Save project". The new version becomes the project's current version (billed identically to a UI save). Requires code_write.

The uploaded file must be the same vendor as the project (an L5X stays L5X, a Siemens ZIP stays Siemens) — a mismatch returns 400. Re-sending the exact bytes of the current version is a no-op: it returns 200 with resolution: identical_file and no new version.

Files up to ~4.5 MB may be sent inline as base64 in file.inline; larger files use the large-file flow via file.blob_url. A project-scoped key may only commit to in-scope projects.

Parameters

NameInTypeDescription
id requiredpathstringThe project id.
Idempotency-Key requiredheaderstringA unique key (e.g. a UUID) for this write. Retrying with the same key and body replays the original result without double-billing.

Request body required

FieldTypeDescription
originalFilename requiredstringThe export file name, e.g. "Conveyor.L5X" or "TIA_Export.zip".
namestringOptional display name for the project.
acknowledge_billingbooleanAcknowledges the per-project charge for an enterprise per-project organization. Only consulted when this upload would create a NEW billable project; ignored for every other org type and for add-version / identical-file. When a new billable project is created without this set to true, the request is rejected with 402 billing_acknowledgement_required (carrying the projected cost); resend with true to confirm. Ignored on POST /projects/{id}/versions.
file requiredobjectExactly one of inline or blob_url must be set.
file.inlinestringBase64-encoded file bytes (for files up to ~4.5 MB).
file.blob_urlstring (uri)A blob URL for the large-file flow.
json
{
  "originalFilename": "string",
  "name": "string",
  "acknowledge_billing": true,
  "file": {
    "inline": "string",
    "blob_url": "https://…"
  }
}

Responses

StatusDescription
200The uploaded bytes matched the current version; no new version was created.
201A new version was committed.
400The request was malformed.
401No valid credential, or the key was revoked.
403The key lacks the permission (or project scope) this endpoint needs.
404The resource was not found, or is not visible to this key's org.
409A request with this Idempotency-Key is still being processed.
413The inline body exceeded the limit; use the large-file flow.
422This Idempotency-Key was already used with a different body.
429Per-key rate limit exceeded.

Response · 200

FieldTypeDescription
project_id requiredstring
identity_id requiredstring
version_idstringThe new version's id; null when resolution is identical_file.
version_number requiredinteger
resolution requiredstring enumadd_version when a new version was committed; identical_file when the uploaded bytes matched the current version (no-op).
Values: add_version identical_file
vendor requiredstring enum
Values: allen-bradley siemens
json
{
  "project_id": "string",
  "identity_id": "string",
  "version_id": "string",
  "version_number": 0,
  "resolution": "add_version",
  "vendor": "allen-bradley"
}

Every 4xx/5xx uses the standard error envelope and carries a request-id header.

Read a project's source

get/projects/{id}/source

Return the project's source in one of several representations. Requires code_read.

  • format=parsed (default): the vendor-neutral parsed structure as JSON. Projects whose parsed JSON exceeds the 4.5 MB inline ceiling return 413; use format=raw for those.
  • format=raw: the original uploaded file (L5X XML or Siemens ZIP), streamed or 302-redirected as a binary download.
  • format=scl: the aggregated Structured-Text view ({ scl }).
  • format=ladder: the aggregated ladder view ({ ladder }).

Parameters

NameInTypeDescription
id requiredpathstringThe project id.
formatquerystring enum

Responses

StatusDescription
200The requested representation. JSON for parsed/scl/ladder; a binary stream (or 302 redirect) for raw.
400The request was malformed.
401No valid credential, or the key was revoked.
403The key lacks the permission (or project scope) this endpoint needs.
404The resource was not found, or is not visible to this key's org.
413The parsed structure is too large to return inline; use format=raw.
429Per-key rate limit exceeded.

Response · 200

FieldTypeDescription
format requiredstring enum
Values: parsed scl ladder
vendor requiredstring enum
Values: allen-bradley siemens
parsedobjectPresent when format=parsed — the vendor-neutral parsed structure.
sclstringPresent when format=scl — aggregated Structured Text.
ladderarray<object>Present when format=ladder — aggregated ladder rungs.
json
{
  "format": "parsed",
  "vendor": "allen-bradley",
  "parsed": null,
  "scl": "string",
  "ladder": [
    {}
  ]
}

Every 4xx/5xx uses the standard error envelope and carries a request-id header.

Latest live tag values

get/projects/{id}/hmi/values

The most recent tag snapshot pushed by a Desktop Companion App (DCA) session for this project. Requires hmi_view. Returns data only while a DCA is actively streaming; with no live session, live is false and tags is empty (this is a normal 200, not an error).

Parameters

NameInTypeDescription
id requiredpathstringThe project id.

Responses

StatusDescription
200The latest snapshot, or an empty live=false body.
401No valid credential, or the key was revoked.
403The key lacks the permission (or project scope) this endpoint needs.
404The resource was not found, or is not visible to this key's org.
429Per-key rate limit exceeded.

Response · 200

FieldTypeDescription
project_id requiredstring
live requiredbooleanTrue when a DCA session is actively streaming this project.
messagestringPresent when live=false — explains why there are no values.
device_idstring
timestampstring (date-time)
controllerobject
controller.namestring
controller.typestring
controller.statusstring
controller.ipAddressstring
sequenceinteger
tags requiredmap<string, object>Map of tag name → latest value.
json
{
  "project_id": "string",
  "live": true,
  "message": "string",
  "device_id": "string",
  "timestamp": "2026-05-31T18:15:00.000Z",
  "controller": {
    "name": "string",
    "type": "string",
    "status": "string",
    "ipAddress": "string"
  },
  "sequence": 0,
  "tags": {
    "example_permission": null
  }
}

Every 4xx/5xx uses the standard error envelope and carries a request-id header.

Recent value history for a tag

get/projects/{id}/hmi/history

The most-recent-first value history a DCA session pushed for one tag. Requires hmi_view and a tag query parameter. Empty when no live session has streamed that tag.

Parameters

NameInTypeDescription
id requiredpathstringThe project id.
tag requiredquerystringThe tag name to fetch history for.
limitqueryintegerMax entries (default 50, max 600).

Responses

StatusDescription
200The tag's recent history.
400The request was malformed.
401No valid credential, or the key was revoked.
403The key lacks the permission (or project scope) this endpoint needs.
404The resource was not found, or is not visible to this key's org.
429Per-key rate limit exceeded.

Response · 200

FieldTypeDescription
project_id requiredstring
tag requiredstring
count requiredinteger
history requiredarray<object>Most-recent-first history entries.
json
{
  "project_id": "string",
  "tag": "string",
  "count": 0,
  "history": [
    {
      "value": null,
      "timestamp": "2026-05-31T18:15:00.000Z",
      "sequence": 0
    }
  ]
}

Every 4xx/5xx uses the standard error envelope and carries a request-id header.

Mint a read-only embed token

post/embed-tokens

Mint a short-lived, project-scoped token for the embeddable read-only assistant iframe. Regardless of the minting key's scope, the token is intersected down to read-only (ai_explain + hmi_view) — a browser-delivered token can never carry a write scope. The minting key must itself have at least ai_explain.

Parameters

NameInTypeDescription
Idempotency-Key requiredheaderstringA unique key (e.g. a UUID) for this write. Retrying with the same key and body replays the original result without double-billing.

Request body required

FieldTypeDescription
project_id requiredstringThe project the embed token may access.
json
{
  "project_id": "string"
}

Responses

StatusDescription
201The minted read-only embed token.
400The request was malformed.
401No valid credential, or the key was revoked.
403The key lacks the permission (or project scope) this endpoint needs.
404The resource was not found, or is not visible to this key's org.
409A request with this Idempotency-Key is still being processed.
422This Idempotency-Key was already used with a different body.
429Per-key rate limit exceeded.

Response · 201

FieldTypeDescription
token requiredstringThe signed, read-only embed token to hand to a browser.
expires_at requiredstring (date-time)
permissions requiredmap<string, boolean>The intersected read-only permissions (only ai_explain / hmi_view).
project_id requiredstring
json
{
  "token": "string",
  "expires_at": "2026-05-31T18:15:00.000Z",
  "permissions": {
    "example_permission": true
  },
  "project_id": "string"
}

Every 4xx/5xx uses the standard error envelope and carries a request-id header.