Reference

API reference.

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

v1.0.0OpenAPI 3.1.0

The PLCs.ai API exposes the same engine that powers PLCs.ai — 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 and the route-conformance check 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.

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.

Ingest an L5X / Siemens export

post/projects

Upload an L5X (Rockwell) or Siemens TIA ZIP export. The file is parsed server-side, a ProjectIdentity is resolved or created, and analysis + indexing are kicked off. 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.
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",
  "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.
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.

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.