Projects & source

Discover and read projects.

Enumerate your organization's projects, read one project's metadata, and pull its source in whichever representation you need.

List & get

GET /projects needs only a valid key (no extra scope) — even an ai_explain-only key can discover which projects exist. Results are filtered to the key's project scope and paginated with an opaque cursor.

bash
curl -s "https://app.plcs.ai/api/v1/projects?limit=50" \
  -H "Authorization: Bearer $PLCS_API_KEY"
python
page = client.list_projects(limit=50)
for p in page.projects:
    print(p.project_id, p.name, p.vendor)

detail = client.get_project(page.projects[0].project_id)
print(detail.analysis_status)  # queued | running | complete | error | None
csharp
var page = await client.ListProjectsAsync(limit: 50);
foreach (var p in page.Projects)
    Console.WriteLine($"{p.ProjectId} {p.Name} {p.Vendor}");

var detail = await client.GetProjectAsync(page.Projects[0].ProjectId);
Console.WriteLine(detail.AnalysisStatus);

Read source

GET /projects/{id}/source requires code_read and supports four representations via ?format=:

FormatReturns
parsed (default)The vendor-neutral parsed structure as JSON (programs, routines, tags, dataTypes…). Projects over the 4.5 MB inline ceiling return 413 — use raw.
rawThe original uploaded file (L5X XML or Siemens ZIP) as a binary download.
sclThe aggregated Structured-Text view ({ scl }).
ladderThe aggregated ladder view ({ ladder }).
python
src = client.get_source("prj_…", format="scl")   # parsed | scl | ladder
print(src.scl)

raw_bytes = client.download_source("prj_…")       # original L5X / ZIP bytes
csharp
var src = await client.GetSourceAsync("prj_…", "scl");
Console.WriteLine(src.Scl);

byte[] rawBytes = await client.DownloadSourceAsync("prj_…");

Live HMI values

With hmi_view, GET /projects/{id}/hmi/values returns the latest tag snapshot pushed by a Desktop Companion App (DCA) session, and /hmi/history?tag=… returns recent history for one tag. These return data only while a DCA is actively streaming; with no live session you get a normal 200 with live: false and an empty tags map (not an error).

Reads need no Idempotency-Key. Listing is scoped to the key's projects; a request for a project outside the scope returns 403 project_scope_forbidden.