{"openapi":"3.0.3","info":{"title":"SteelFrame REST Admin API","version":"1.0.0","description":"REST admin API for SteelFrame Server (GAPS-ROADMAP 3.1, ESCWA-parity).\n\n## Authentication\nEvery endpoint except the public ones (`POST /api/logon`,\n`GET /api/openapi.json`, `GET /api/health`, `GET /metrics`)\nrequires `Authorization: Bearer <token>`. Two kinds of token exist:\n\n- **Session tokens** — returned by `POST /api/logon` (TSO userid +\n  password). Interactive operator sessions; carry the wildcard scope\n  `*` (every permission).\n- **API tokens** — minted with `POST /api/tokens` (requires the\n  `admin` scope), persisted across restarts, carrying an explicit\n  scope list. The token value is returned once at creation and stored\n  hashed. Intended for CI, the modernization IDE, and automation.\n- **Account cookie** — `__Secure-sf_acct`, set by `POST /api/logon`\n  with `accountCookie: true` (browser surfaces) or\n  `POST /api/account/session`. It is honoured ONLY by operations marked\n  `x-cookie-auth` (the `/api/account/*` surface), carries exactly the\n  `account.self` scope, is never a bearer token, and its writes must pass\n  a CSRF gate (allow-listed `Origin`, `X-SF-CSRF: 1`, JSON body).\n  `POST /api/logoff` ends a session server-side; sessions also expire\n  (idle and absolute lifetimes).\n\n## Scopes\nEach operation declares its required scope in `x-required-scope`.\nA token satisfies a scope if it holds `*`, the exact scope, or — for\n`<area>.read` — the same area's `.write` or `.admin` scope\n(mutation rights imply read rights within an area). A request with a\nvalid token but an insufficient scope gets `403`.\n\n## Conventions\n- Datasets are EBCDIC at rest. The `records` endpoints move raw\n  records as uppercase hex strings (binary-safe: packed decimal, zoned\n  overpunch signs and binary fields round-trip exactly); the `member`\n  endpoints move text lines converted at the API boundary.\n- Job spool, syslog and subsystem logs are returned as text/line arrays\n  exactly as a 3270 user would see them.\n- CICS JSON web services (URIMAP-style paths defined in the CSD via\n  JSONSERVICE definitions) are served OUTSIDE /api/ at their defined\n  URIs; they are application endpoints, not admin surfaces, and are\n  documented by their CSD definitions.\n\n## WebSocket endpoints\n- `/ws/terminal` — the 3270 terminal stream (JSON screen protocol).\n  `?sub=ims` connects to the IMS TM region (MFS) instead of CICS. ONE\n  logon per socket: `Authorization: Bearer <token>` on the upgrade (session\n  or API token with `cics.exec`, `ims.read` for `?sub=ims`), or a first\n  message `{\"type\":\"hello\",\"bearer\":\"<session token>\"}` within 10 s\n  (browsers). The terminal session starts only then; closed 4401 when the\n  logon ends (4400 no hello, 4403 missing scope).\n- `/ws/events` — JES2 job lifecycle events (JSON, one object per\n  message) for ONE logon: `Authorization: Bearer <token>` on the upgrade\n  (session or API token with `jobs.read`), or a first message\n  `{\"type\":\"hello\",\"bearer\":\"<session token>\"}` within 10 s (browsers).\n  Nothing is sent before; then `{\"type\":\"ready\"}` and only the caller's own\n  jobs' events (owner or NOTIFY= user); a RACF SPECIAL full-scope logon gets\n  the whole system (all jobs, syslog). Closed 4401 when the logon ends.\n\n## MCP and the reference oracle\nThe same route registry is projected a second time as an MCP tool\ncatalog (`GET /api/mcp/tools?lane=persistent|ephemeral`, served by the\nstdio bridge `bin/steelframe-mcp.mjs` and the in-process JSON-RPC door\n`POST /mcp`). A route with an `mcp` flag is one tool; scope checks and\naudit are identical on both surfaces by construction. The `oracle` and\n`sched` tags are the REFERENCE-ORACLE surface for modernization\ncomparison: SteelFrame RETURNS what the mainframe holds and does (files\nand decoded records, a batch run's joblog + output datasets, online CICS\nscreens one keystroke at a time, scheduler cycles) — it never judges\nequivalence and never converts code; your harness replays the same\ninputs against the modernized system and compares on its side. Pass\n`workspace:<id>` (`POST /api/workspaces`) to run any call on an\nisolated copy of the estate. Human-readable guide with the workflow and\nthe live tool reference: `/mcp-docs.html`.\n\n## z/OSMF-compatible REST (Zowe)\nBesides /api, the engine answers a subset of IBM's z/OSMF REST services under\n`/zosmf`: the jobs interface (`/zosmf/restjobs/jobs`), the data set interface\n(`/zosmf/restfiles/ds`), console commands (`/zosmf/restconsoles`) and\n`/zosmf/info`. Zowe CLI, Zowe Explorer and your own z/OSMF client work against\nit; the operations are listed under the `zosmf` tag below. It is a thin\nadapter over the same handlers as /api: the same RACF data set checks, JESSPOOL\njob visibility and audit apply. The native equivalents are `/api/jobs`,\n`/api/submit`, `/api/jobs/{jobid}/file/{name}` and the `datasets` routes.\n\n- **Authentication**, per request: HTTP Basic with your SteelFrame (RACF)\n  userid and password (the same logon check as the web: REVOKE, failed-logon\n  throttling), or `Authorization: Bearer <API key>` (an `sf_` key; a key\n  whose surface is `mcp` only is refused with 403), or a z/OSMF login token:\n  `POST /zosmf/services/authenticate` with Basic credentials answers 204 and\n  sets the `jwtToken` and `LtpaToken2` cookies (Path=/zosmf);\n  `DELETE /zosmf/services/authenticate` ends that login. Whatever the\n  credential, the door narrows it to `datasets.read`, `datasets.write`,\n  `jobs.read` and `jobs.write` (never more than the userid's own logon has),\n  so it never reaches TSO, SQL, CICS, RACF or admin routes. An API key needs\n  the scope shown on each operation. Missing or wrong credentials answer 401\n  with `WWW-Authenticate: Basic realm=\"SAFRealm\"` and the z/OSMF error\n  document `{ category, rc, reason, message, details }`.\n- **Writes**: every PUT, POST and DELETE must carry the header\n  `X-CSRF-ZOSMF-HEADER` (any value), as on z/OSMF; without it the answer is\n  403. GET needs no extra header.\n- **AI-credit gate**: where the credit gate is on (the hosted estate), a userid\n  whose AI credit balance is $0 is refused until it tops up in the SteelFrame\n  assistant panel. With Basic credentials: 401, message\n  `SFCR001A CREDIT REQUIRED - TOP UP YOUR AI CREDIT IN THE STEELFRAME ASSISTANT PANEL`.\n  With an API key or a login token: 402, message `CREDIT REQUIRED - ...`.\n  `/zosmf/info` stays open.\n- **Metering**: calls made with an API key are metered like the REST door\n  (reads are free); Basic-authenticated calls are not metered.\n- **Job visibility (JESSPOOL)**: you list and read your own jobs, jobs whose\n  NOTIFY= names you, and any job a JESSPOOL READ grant on\n  `SFNODE.<owner>.<jobname>.<jobid>` gives you (RACF SPECIAL / OPERATIONS:\n  every job). A job you may not see answers 404, exactly like a job that does\n  not exist. Cancel and purge need JESSPOOL ALTER.\n- **Job list filters** (`GET /zosmf/restjobs/jobs`): `owner` (default: you;\n  `*` = every owner you may see; `*` and `%` wildcards), `prefix` (job name,\n  default `*`; a name without wildcards matches as a prefix, so `ZV` finds\n  ZVOK), `jobid`, `status=active` (only executing jobs; other status values\n  are not applied), `max-jobs` (1-1000, default 1000), `exec-data=Y`. Newest\n  job first.\n- **retcode**: null until the job is on OUTPUT, then `CC nnnn` (the highest\n  step condition code, four digits), `JCL ERROR`, `ABEND Sxxx` / `ABEND Unnnn`\n  or `CANCELED`. `status` is `INPUT`, `ACTIVE` or `OUTPUT`.\n- **URLs in answers**: `url`, `files-url` and `records-url` are absolute, on the\n  scheme and host you called (`https://steelframe.cobolstack.com/...` on the\n  hosted estate). `url` and `files-url` use the job-correlator form\n  `/zosmf/restjobs/jobs/<job-correlator>[/files]`, which answers exactly like\n  `/{jobname}/{jobid}`.\n- **Spool**: JES files keep ids 2 (JESMSGLG), 3 (JESJCL) and 4 (JESYSMSG); your\n  SYSOUT files are numbered from 101. `.../files/{id}/records` returns one\n  file as text; `X-IBM-Record-Range: SSS-EEE` or `SSS,NNN` (0-based) returns\n  part of it. `.../files/JCL/records` returns the JCL as submitted.\n- **Not modelled** (answer 501): z/OS UNIX files (`/zosmf/restfiles/fs`,\n  `/zosmf/restfiles/mfs`), IDCAMS over REST (`/zosmf/restfiles/ams`) and TSO\n  address-space services (`/zosmf/tsoApp`).\n\nZowe CLI team profile (`zowe.config.json`) for the hosted estate:\n\n    {\n      \"$schema\": \"./zowe.schema.json\",\n      \"profiles\": {\n        \"steelframe\": {\n          \"type\": \"zosmf\",\n          \"properties\": { \"host\": \"steelframe.cobolstack.com\", \"port\": 443, \"protocol\": \"https\", \"rejectUnauthorized\": true },\n          \"secure\": [\"user\", \"password\"]\n        }\n      },\n      \"defaults\": { \"zosmf\": \"steelframe\" }\n    }\n\nthen `zowe zosmf check status`, `zowe zos-jobs list jobs --owner <USERID>` and\n`zowe zos-jobs view spool-file-by-id <JOBID> <id>`.\n\ncurl (read-only, no CSRF header needed):\n\n    curl -u <USERID>:<PASSWORD> \"https://steelframe.cobolstack.com/zosmf/restjobs/jobs?owner=<USERID>&prefix=*\"\n    curl -u <USERID>:<PASSWORD> \"https://steelframe.cobolstack.com/zosmf/restjobs/jobs/<JOBNAME>/<JOBID>/files\"\n    curl -u <USERID>:<PASSWORD> \"https://steelframe.cobolstack.com/zosmf/restjobs/jobs/<JOBNAME>/<JOBID>/files/2/records\"\n\nSubmit (a write, so the CSRF header):\n\n    curl -u <USERID>:<PASSWORD> -X PUT -H \"X-CSRF-ZOSMF-HEADER: true\" -H \"Content-Type: text/plain\" \\\n         --data-binary @job.jcl \"https://steelframe.cobolstack.com/zosmf/restjobs/jobs\""},"servers":[{"url":"http://{host}:{port}","variables":{"host":{"default":"localhost"},"port":{"default":"3270"}}}],"tags":[{"name":"session","description":"Logon, logoff, self-registration and token→user identity; also the public MCP tool catalog."},{"name":"account","description":"The SteelFrame ID account surface for cobolstack.com: the account-session cookie (the only routes a cookie can authenticate), its minting and logout."},{"name":"seats"},{"name":"vscode"},{"name":"develop","description":"The MCP developer composites: upload source, compile+link through the real IGYWCL deck, run a GO deck — one call each."},{"name":"tokens","description":"Mint, list and revoke scoped API tokens (CI, harnesses, the IDE)."},{"name":"vault","description":"Region secrets vault: metadata only, values never readable back."},{"name":"system","description":"Instance information, region configuration, users, audit, metrics and security posture."},{"name":"jobs","description":"The JES2 spine: submit, list, wait, spool files, WTOR replies, hold/release/cancel/purge, output dispositions."},{"name":"fileshare","description":"Fileshare-class record-lock broker and journal/recovery posture of the region files."},{"name":"uow","description":"The two-phase-commit coordinator: in-flight units of work and in-doubt resolution."},{"name":"cics","description":"CICS region administration and inspection: CSD, journals, BMS preview, region posture."},{"name":"instances","description":"Scratch child engines (provision, inspect, dispose)."},{"name":"snapshots","description":"Consistent data-root snapshots (JES2 drained first) and restores."},{"name":"apps","description":"Application packaging: version an estate slice as a .sfapp bundle, import, promote."},{"name":"onboard","description":"Estate onboarding (the rehost funnel): plan, load, compile tallies."},{"name":"debug","description":"The in-process COBOL debugger: arm a session, breakpoints, step, inspect."},{"name":"datasets","description":"Catalog, allocation, members and raw records (hex, binary-safe), VSAM info, search."},{"name":"sql","description":"Live SQL views over datasets + copybooks (typed columns; also reachable over pgwire)."},{"name":"connectors"},{"name":"git"},{"name":"mainframes"},{"name":"screen"},{"name":"modernize","description":"Static portfolio inventory, analysis model/graphs/impact/metrics, program explanation, the migration wave board."},{"name":"verify","description":"Golden-run captures and compares (the raw capture primitive under run_batch) and run records."},{"name":"oracle","description":"SteelFrame as a REFERENCE ORACLE for modernization comparison: find and export source/copybooks/JCL/maps/CSD, decode and encode records through copybooks, seed datasets and GDGs, run a batch job and get the joblog + output datasets back (run_batch), drive CICS screen by screen (sessions, send one AID, scripts, headless LINK), wait for a scheduler cycle, dump state, and isolate everything in a workspace. Returns facts — never a verdict, never a conversion."},{"name":"tso","description":"TSO/ISPF command sessions and edit macros."},{"name":"db2","description":"SPUFI-style SQL batches against the DB2 subsystem."},{"name":"ims","description":"IMS TM region configuration, queues and MFS."},{"name":"mq","description":"Queue manager and queue inspection."},{"name":"ndvr","description":"Endevor-style SCM repository: elements, levels, generate."},{"name":"sched","description":"CA-7 / Control-M scheduler: definitions and the dependency graph as data, demand/order a cycle, conditions, symbols, calendars, operator actions, New Day, alerts."},{"name":"racf","description":"RACF database inspection and the ESM security posture."},{"name":"import","description":"Import estate artifacts (region XML, CSD decks, ESCWA JSON) into the canonical region model."},{"name":"estates","description":"Installable sample estates and their install/battle runs."},{"name":"autopilot"},{"name":"zosmf","description":"z/OSMF-compatible REST (Zowe): the IBM z/OSMF jobs, data set, console and info services that Zowe CLI, Zowe Explorer and z/OSMF clients use - HTTP Basic (RACF userid + password) or a Bearer API key, narrowed to datasets.*/jobs.*; writes need X-CSRF-ZOSMF-HEADER (see the z/OSMF section of the description above)."}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Session token from POST /api/logon or an API token from POST /api/tokens"},"zosmfBasic":{"type":"http","scheme":"basic","description":"The z/OSMF door (tag zosmf) only: HTTP Basic with the SteelFrame (RACF) userid and password; realm SAFRealm"},"adminCookie":{"type":"apiKey","in":"cookie","name":"__Secure-sf_admin","description":"Owner admin session cookie for learn.cobolstack.com/account/admin (email + password login at POST /api/account/admin/login, not RACF). Host-only, HttpOnly, Secure, SameSite=Strict, Path=/api/account/admin; 8 h absolute, 30 min idle. Honoured only by x-admin-auth operations; writes require an allow-listed Origin and X-SF-CSRF: 1"},"accountCookie":{"type":"apiKey","in":"cookie","name":"__Secure-sf_acct","description":"Account-session cookie (HttpOnly, Secure, SameSite=Lax, Path=/api/account). Honoured only by x-cookie-auth operations, scope account.self only; writes require an allow-listed Origin and X-SF-CSRF: 1"}}},"x-scopes":{"admin":"manage API tokens (POST/GET/DELETE /api/tokens)","datasets.read":"read the catalog, dataset contents, members, records, VSAM info","datasets.write":"allocate/delete/rename/copy datasets and members, write records, define/alter VSAM","jobs.read":"list jobs, read job status and spool files, read the syslog via jobs surfaces","jobs.write":"submit JCL, purge jobs","tso.exec":"run TSO/ISPF commands and edit macros","db2.exec":"execute SQL through the SPUFI endpoint","cics.read":"read the CSD (definitions, libraries, group lists) and the CICS region log; the read-only CEDA verbs (DISPLAY/VIEW/CHECK/EXPAND/LIST)","cics.admin":"CICS administration: region lifecycle, and CEDA/CEMT on ANY resource (the SFCSDGRP group rule does not apply) - never on a self-service key","cics.exec":"run CICS work: LINK a program with a COMMAREA, drive terminal sessions screen by screen (MCP oracle); CEDA and CEMT as your RACF user (your own CSD groups, the same decision as the 3270 transactions)","ims.read":"read the IMS TM region configuration, queues and log","ims.admin":"configure the IMS TM control region","mq.read":"browse the queue manager, queues, messages and processes","ndvr.read":"browse the Endevor-style repository and elements","ndvr.admin":"reset the Endevor-style repository","sched.read":"browse the ZWS scheduler store, jobs and cycles","sched.admin":"order/demand cycles, set symbols/options/conditions, reset the store","racf.read":"browse the RACF store and general-resource classes","racf.admin":"reset the RACF store","system.read":"system information, syslog, logon-user list","accounting.read":"read per-job/per-transaction accounting records (G11 chargeback export)","system.admin":"listener lifecycle verbs (start/stop network listeners)","instances.read":"list/inspect ephemeral child instances","instances.admin":"provision and dispose ephemeral child instances","snapshots.read":"list/inspect/download snapshots","snapshots.admin":"create/delete snapshots, restore a snapshot into a child instance","debug.exec":"arm/control interactive debug sessions (breakpoints, step, variable inspection)","apps.read":"browse the application registry: bundles, versions, manifests, diffs, deployments","apps.write":"package/upload/delete application bundle versions","apps.admin":"deploy, promote and roll back applications on target systems","ephemeral.exec":"the private zero-retention sandbox lane (MCP #1): one-shot compiles/runs, and RAM-only workspaces that carry the whole tool surface (inside one, each routed tool is checked against your own scopes)","workspace.read":"list/inspect your oracle workspaces (isolated child engines on a copy of the estate)","workspace.write":"create/reset/destroy oracle workspaces and run tools inside them (minted explicitly, like sched.admin)","vscode.drive":"drive your own VS Code seat (the vscode_* tools on /mcp/vscode: open, edit and save Zowe members, submit jobs, and on a container seat write, build, run and test Java, write, run, test and type-check Python, write, build, run and test C# (.NET) and Node.js / TypeScript / Angular, and query, change and fill (DB2 and VSAM imports) your own PostgreSQL database) while your VS Code tab is open; never another user's seat","zos.remote":"use your own connected IBM mainframes (z/OSMF) through the z/OS MCP (/mcp/zos) and /api/zos/*: list data sets and members, read and save members, submit jobs, job status and spool, cancel / purge, copy to / from your SteelFrame data sets - only what you switched on per connection in the Mainframes tab (MCP: read / write / submit, the data set and job-name lists); never create, change or remove a connection or see its password. In no preset: tick it in a Custom key","vscode.headless":"let this key start and hold your VS Code container seat without a website logon: with vscode.drive, the VS Code MCP (/mcp/vscode) then opens a headless VS Code window on the SteelFrame engine for your agent when none of yours is open (it closes after a while without a vscode_* call and at the operator's maximum lifetime; your own website logon takes over at once; one seat stays reserved for website users). In no preset: tick it (and vscode.drive) in a Custom key.","screen.drive":"drive your own open SteelFrame page the way the AI chat does (the screen MCP, /mcp/screen): read and type on the 3270 terminal, press keys, select rows, write the ISPF editor, show a tab, narrate, read members and job output, and in the Postgres tab list, open, query and change your own PostgreSQL database - every action visible on your page with a Stop button; only while that page is open; never another user's page. In no preset: tick it in a Custom key. Not for RACF SPECIAL / OPERATIONS user ids.","connectors.use":"use your connected GitHub / GitLab accounts through the Git MCP (/mcp/git) and /api/git/*: list accounts (masked) and repositories, link repositories, status / diff / log / branches, pull into your own data sets, push / commit, auto-sync and conflicts, clone into your VS Code seat, PostgreSQL export and migrations (pushes publish your code to that provider); never connect or disconnect an account or see a token. In no preset: tick it in a Custom key","autopilot.admin":"the Custom Software House store (or another tenant store) creates paid autopilot build orders, reads their progress and recording, fetches the release, and takes the operator actions (resume / pause / abort / waive / top up / model) - for its own tenant only. Minted by the owner with POST /api/tokens; in no preset","autopilot.quote":"run the one-turn \"Describe your software\" analysis of a tenant store (POST /api/autopilot/quote): the store's prompt texts in, the model's text out, charged to the tenant build pool and capped per tenant; nothing else. Minted by the owner with POST /api/tokens; in no preset","autopilot.read":"read a tenant's autopilot builds: their documentation portal (the project's documents, the traceability matrix) and their status - for the development team, for its own tenant only; nothing can be changed with it. Minted by the owner with POST /api/tokens; in no preset","account.self":"view your own account profile and session, read the course catalog and enroll in / withdraw from courses, keep your own session tracker (your own records only); the cobolstack.com account cookie carries this scope"},"paths":{"/api/logon":{"post":{"operationId":"logon","summary":"Log on with a TSO userid; returns a bearer session token (scope * for a RACF SPECIAL user, a fixed non-admin working set otherwise). With `appl`, the password field may carry a single-use PassTicket for that application (W4.3: evaluated first when a PTKTDATA profile exists, then as a normal password)","tags":["session"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"user":{"description":"TSO userid (`userid` is accepted as an alias; a request carrying neither is refused 400 IKJ56714A ENTER USERID - never mistaken for a wrong password)"},"password":{"description":"password (or a PassTicket when appl is given)"},"appl":{"description":"application name for PassTicket evaluation (optional)"},"newPassword":{"description":"optional change-password-at-logon: accepted only when the current password verifies AND is expired (IKJ56416I) — changes it and completes the logon in one call (the real-TSO expired cycle; an expired refusal without this field carries expired:true)"},"language":{"description":"optional UI-language session override for this logon (the web-door analog of CESN LANGUAGE=, NLS plan §4.3 level 1; unknown values fall through to the normal precedence)"},"accountCookie":{"description":"optional boolean (browser surfaces): also set the __Secure-sf_acct account-session cookie (HttpOnly, Secure, SameSite=Lax, Path=/api/account, Domain from STEELFRAME_ACCOUNT_COOKIE_DOMAIN) for the learn.cobolstack.com account pages. It authenticates ONLY /api/account/* routes and is never a bearer token. Any account cookie the request presents is revoked first (rotation)"}}}}}},"responses":{"200":{"description":"{ token, user, scopes, language, account? } — account:true when the account cookie was set. Interactive sessions expire server-side (idle STEELFRAME_SESSION_IDLE_S, default 12 h; absolute STEELFRAME_SESSION_TTL_S, default 7 days) and end at POST /api/logoff"},"400":{"description":"No userid in the request (IKJ56714A ENTER USERID), or an invalid / policy-refused new password on a change-at-logon"},"401":{"description":"Password not authorized or userid revoked (IKJ564xxI message in error); an expired password carries expired:true"},"429":{"description":"ZWS0956E too many failed logon attempts for this userid or from this client address (Retry-After header); the password was not checked"}},"security":[]}},"/api/register":{"post":{"operationId":"register","summary":"Self-service user-ID registration (\"Get User ID\" on the web logon panel): creates a RACF user in group ZUSERS with a random one-time temporary password, EXPIRED and shown once in the response (first logon forces a password change), and records the email in the account registry outside the z security DB (ownership-verify / password-reset mapping)","tags":["session"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"user":{"description":"wanted userid (1-8 chars, A-Z 0-9 # $ @; uppercased)"},"email":{"description":"contact email — used to verify ownership of the user ID and for password reset / account requests; stored outside the RACF database; one registration per address"}}}}}},"responses":{"200":{"description":"{ ok, user, tempPassword, mustChange: true, passwordRule } — tempPassword is a random one-time password, already expired, returned ONCE; passwordRule tells the new-password rule up front (1-8 characters A-Z 0-9 # $ @)"},"400":{"description":"Bad or duplicate userid / bad or duplicate email"},"403":{"description":"Registration disabled (STEELFRAME_REG_OFF)"},"429":{"description":"Rate limit or registration cap reached"}},"security":[]}},"/api/me":{"get":{"operationId":"whoami","summary":"The user behind the presented bearer token (authoritative token→user mapping; both web surfaces refresh their cached user from this at boot)","tags":["session"],"responses":{"200":{"description":"{ user, scopes }"},"401":{"description":"Missing or invalid token"}},"security":[]}},"/api/logoff":{"post":{"operationId":"logoff","summary":"Log off: end the presented interactive session server-side (the bearer token stops working at once) and every account-session cookie linked to it, and expire the account cookie in this browser. With everywhere:true, end ALL of the caller's interactive and account sessions. Persistent API tokens are not sessions: logoff never revokes one (DELETE /api/tokens/{id} does)","tags":["session"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"everywhere":{"description":"optional boolean: also end every other interactive session and account session of this user (all devices)"}}}}}},"responses":{"200":{"description":"{ ok, user, ended, accountSessionsEnded, everywhere? }"},"401":{"description":"Missing or invalid token (NOT LOGGED ON)"}},"security":[]}},"/api/account/session":{"get":{"operationId":"accountSessionInfo","summary":"Who the account session belongs to: the userid behind the __Secure-sf_acct cookie (learn.cobolstack.com account pages) or behind a bearer token. The cookie is honoured ONLY on /api/account/* routes and carries only the account.self scope","tags":["account"],"responses":{"200":{"description":"{ user, via: \"cookie\"|\"session\"|\"api-token\", expires?, idleExpires? } (expires/idleExpires: the cookie session's absolute and idle deadlines, ISO-8601)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true},"post":{"operationId":"accountSession","summary":"Mint the account-session cookie for the CURRENT interactive logon session (bearer only; not an API token): used when the user logged on before the cookie existed or it expired, and by the return-URL hand-off to learn.cobolstack.com/account. Any account cookie the request presents is revoked first (rotation). Rate-limited per user","tags":["account"],"responses":{"200":{"description":"{ ok, user, expires } + Set-Cookie __Secure-sf_acct"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"429":{"description":"Too many account writes for this user (Retry-After)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"account.self"}},"/api/site":{"get":{"operationId":"siteInfo","summary":"The site profile of the host you reached the engine on (one engine serves several public hostnames): the workspace tab a new visit opens on (terminal or vscode), the page title (null = the page's own), the course catalogue link and the products the AI tutor teaches here. Public; no configuration paths or secrets","tags":["session"],"responses":{"200":{"description":"{ site, default, defaultTab: \"terminal\" | \"vscode\", title, catalogUrl, products: [string] }"}},"security":[]}},"/api/account/config":{"get":{"operationId":"accountConfig","summary":"Account hand-off configuration for the SteelFrame web clients: the learn.cobolstack.com account page URL (the \"My account & courses\" link) and the allowed return origins for the logon page's ?return= hand-off. Public; production always answers https://learn.cobolstack.com/account/. Loopback dev origins (STEELFRAME_ACCOUNT_RETURN_ORIGINS / STEELFRAME_ACCOUNT_URL) are listed only when the request Host is loopback","tags":["account"],"responses":{"200":{"description":"{ accountUrl, returnOrigins: [origin], returnPath: \"/account/\", fragment: \"#CSnnn (optional)\", payments: { enabled, amount?, currency?, display?, oneTime?, courses?: { CSnnn: { amount, currency, display } } } } — payments = whether \"Paid individual\" checkout is open, its default one-time price and the per-course prices that differ from it (never a key, mode or provider detail)"}},"security":[]}},"/api/account/logout":{"post":{"operationId":"accountLogout","summary":"Log out from the learn.cobolstack.com account pages: end this account session AND the linked steelframe interactive session (logout on one site ends both), and expire the cookie. Cookie callers must pass the CSRF gate (allow-listed Origin, X-SF-CSRF: 1, JSON body). With everywhere:true, end every interactive and account session of the user","tags":["account"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"everywhere":{"description":"optional boolean: end every interactive and account session of this user (all devices)"}}}}}},"responses":{"200":{"description":"{ ok, user, bearerSessionEnded, accountSessionsEnded, everywhere? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/apps/config":{"get":{"operationId":"appsConfig","summary":"Web apps in the VS Code container seats (notes/SEAT-WEB-APPS-PLAN.md): is the App Preview tab on here (STEELFRAME_SEAT_APPS with a separate app origin)? The allowed app ports, the per-seat cap, the idle stop and lifetime (minutes) and whether the AI app browser is on. No hosts, no secrets","tags":["seats"],"responses":{"200":{"description":"{ enabled, ports, portsLabel, max, idleMin, maxLifeMin, browser }"}},"security":[]}},"/api/account/seat/open":{"get":{"operationId":"seatOpen","summary":"Open your browser VS Code seat (navigation, not XHR). Reads the account-session cookie (__Secure-sf_acct — sent here because of its Path=/api/account), mints the host-only seat cookie __Secure-sf_seat (Path=/vscode, HttpOnly, Secure, SameSite=Lax; it names the account session by hash, so logging out ends the seat) and redirects to ?next= (a /vscode path; default /vscode/). Without a live account session it redirects to the shared SteelFrame logon page (/logon/, the same card as the Studio logon: Terms of Use and support lines, change-at-logon) with ?return=/vscode/","tags":["seats"],"parameters":[{"name":"next","in":"query","required":false,"schema":{"type":"string"},"description":"optional /vscode/... path to land on (anything else = /vscode/)"}],"responses":{"200":{"description":"302 to the seat (Set-Cookie __Secure-sf_seat) or to /logon/?return=%2Fvscode%2F"}},"security":[]}},"/api/seat/auth":{"get":{"operationId":"seatAuth","summary":"Caddy forward_auth for /vscode/*: 200 + X-Seat-Assert (a 120 s Ed25519-signed { userid, account-session hash }) when the request carries a live seat cookie; otherwise a 302 to /api/account/seat/open for a browser navigation, or 401. The box Caddy calls it on loopback and refuses it from outside","tags":["seats"],"responses":{"200":{"description":"{ ok, user } + X-Seat-Assert, X-Seat-User headers"},"401":{"description":"No live seat (XHR / WebSocket / non-navigation)"}},"security":[]}},"/api/seat/pubkey":{"get":{"operationId":"seatPubkey","summary":"The Ed25519 public key (SPKI PEM) the VS Code seat host verifies seat assertions with. Public by design: it can verify, never sign","tags":["seats"],"responses":{"200":{"description":"{ alg: \"Ed25519\", pem }"}},"security":[]}},"/api/seat/verify":{"post":{"operationId":"seatVerify","summary":"Seat host liveness sweep: for each engine-signed seat assertion (expired ones included) answer whether its account session is still alive, so the seat host can close the open WebSockets of a user who has logged out. Answers only alive/dead for assertions the engine itself signed","tags":["seats"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"assertions":{"description":"array (<= 500) of X-Seat-Assert values"}}}}}},"responses":{"200":{"description":"{ alive: [boolean] } (same order)"},"400":{"description":"assertions must be an array of at most 500 strings"}},"security":[]}},"/api/seat/token":{"post":{"operationId":"seatToken","summary":"Mint the SteelFrame API token a VS Code seat is started with (the sf CLI and the sf-vscode extension then work without a second logon). Proof = a FRESH engine-signed seat assertion for a live account session (only the proxy path ever holds one). The token acts as that user with the seat scope set (own datasets/jobs/SQL/CICS/debug; never admin), is named vscode-seat, and replaces the user's previous vscode-seat token. Rate-limited per user","tags":["seats"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"assertion":{"description":"a fresh X-Seat-Assert value"}}}}}},"responses":{"200":{"description":"{ token, user, scopes, id }"},"401":{"description":"Assertion missing, expired, forged, or its account session ended"},"429":{"description":"Too many seat tokens for this user (Retry-After)"}},"security":[]}},"/api/account/seat/status":{"get":{"operationId":"seatStatus","summary":"May the caller open a VS Code seat on this host? The web page asks before enabling its VS Code tab. Identity = the bearer token, else the account-session cookie; logged out = user null, allowed null (the seat door shows the logon card). restricted = this host limits seats to an allow-list of userids (STEELFRAME_VSCODE_USERS; the list itself is never disclosed)","tags":["seats"],"responses":{"200":{"description":"{ user, restricted, allowed, kind } — allowed: true | false | null (not logged on); kind: host | container (which seat this user gets: STEELFRAME_VSCODE_MODE)"}},"security":[]}},"/api/account":{"get":{"operationId":"account","summary":"Your own account profile: userid, the email you registered with (your own record only; never another user's; masked when the caller is an API token, which an administrator may have minted to act as you), default group, RACF creation date, registration time, last logon and the previous one (session-starting doors: web, TN3270, FTP, PG wire), and how many courses you are enrolled in or waitlisted for. Always the caller: there is no userid parameter","tags":["account"],"responses":{"200":{"description":"{ user, email, emailMasked, registered, emailVerified, emailVerifiedAt, emailVerifyAvailable, group, created, lastLogon, previousLogon, enrollments, prefs: { lang }, via } — email/registered null when the user did not self-register; emailVerified only while the verified address is still the one on file; emailVerifyAvailable = a mail transport is configured; lastLogon/previousLogon ISO-8601 or null (recorded since this feature shipped); prefs.lang = the preferred course language (code, or null = English)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/prefs":{"put":{"operationId":"accountPrefs","summary":"Set your preferred course language: the default for every course you take that has no language of its own (My courses lets you choose per course). One of the ten course languages (en, ja, ko, zh-Hans, zh-Hant, de, fr, es, it, pt — any usual spelling such as pt-BR or zh-TW is accepted); null clears it (English). A session video that does not exist in your language is shown in English and labelled so. Cookie callers must pass the CSRF gate. Rate-limited per user","tags":["account"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"lang":{"description":"a course-language code, or null to clear"}}}}}},"responses":{"200":{"description":"{ prefs: { lang }, updated }"},"400":{"description":"lang missing or not one of the course languages (the body lists them as langs)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"413":{"description":"Body over 1 KB"},"429":{"description":"Too many account writes for this user (Retry-After)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/courses":{"get":{"operationId":"accountCourses","summary":"The course catalog (public fields projected from the site's cobolstack/src/data/courses.json, re-read when it changes) with YOUR enrollment state per course, plus your enrollment list (a course no longer in the catalog is listed as retired). action per course: enroll (self-paced, instant), waitlist (cohort, register interest) or contact (corporate / not self-service). prereqMet is advisory only (true/false/null = undecidable from enrollments)","tags":["account"],"responses":{"200":{"description":"{ catalog: [{ code, title, track, level, duration, availability, prereq, hasCert, free, url, action, paidOffered, paidPrice: {amount, currency}|null, price: {amount, currency, display, source}|null, enrollment: {status, at, plan, lang}|null, prereqMet }], enrollments: [{ code, status, at, title, retired, plan, lang, langFrom, langSet }], prefs: { lang }, langs: [{ code, name }], catalogVersion, catalogLoaded, payments: { enabled, amount?, currency?, display?, oneTime?, courses? } } — plan = free | paid (\"Paid individual\"); paidOffered = the course can be bought as Paid individual; paidPrice = the course's own price from the catalog (null = tenant default); price = the amount this course is charged right now (source course | default); payments.courses = the per-course prices in force keyed by code; lang = the course language the enrollment is taken in (langFrom: course = chosen for that course, preference = your preferred language, default = English; langSet = the per-course choice or null); prefs.lang = your preferred course language; langs = the ten course languages with their native names"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"503":{"description":"Course catalog unavailable (the catalog file was never readable)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/enroll":{"post":{"operationId":"accountEnroll","summary":"Enroll yourself in a course (free only in v1): a self-paced course -> enrolled at once; a cohort course -> waitlisted (register interest); a corporate course is not self-enrollable (400 with a /contact pointer). Idempotent: re-enrolling returns the existing record (200, created:false); a waitlisted course that has become self-paced is promoted. At most 30 active enrollments. An optional lang (a course-language code) becomes the new enrollment's own course language; without it the course follows your preferred language (PUT /api/account/prefs), then English. Cookie callers must pass the CSRF gate (allow-listed Origin, X-SF-CSRF: 1, JSON body). Rate-limited per user","tags":["account"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"course":{"description":"course code, e.g. CS100 (alias: code)"},"lang":{"description":"optional course-language code for this enrollment (e.g. ja)"}}}}}},"responses":{"200":{"description":"{ code, status: \"enrolled\"|\"waitlisted\", at, updated, created, promoted?, prereqMet, title, lang?, langFrom? } — HTTP 201 when a row was created, 200 when it already existed"},"201":{"description":"Created: a new enrollment (self-paced) or waitlist entry (cohort)"},"400":{"description":"Missing/invalid course code, a language outside the course-language list, or a course that is not self-enrollable (corporate: body carries contact:\"/contact\")"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"402":{"description":"The course is not free (paid enrollment is not available yet)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No such course in the catalog"},"409":{"description":"Enrollment limit reached (30 active)"},"413":{"description":"Body over 1 KB"},"429":{"description":"Too many account writes for this user (Retry-After)"},"503":{"description":"Course catalog unavailable"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/enroll/{code}/lang":{"put":{"operationId":"accountEnrollLang","summary":"Set the course language of one of your enrollments (enrolled or waitlisted): the session tracker then shows each video in that language where one exists, else in English (labelled). One of the ten course-language codes; null returns the course to your preferred language. Recorded in your account history. Cookie callers must pass the CSRF gate. Rate-limited per user","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code, e.g. CS100"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"lang":{"description":"a course-language code (e.g. ja), or null for your preferred language"}}}}}},"responses":{"200":{"description":"{ code, status, lang, langFrom: \"course\"|\"preference\"|\"default\", langSet, at } — lang = the effective course language now"},"400":{"description":"Invalid course code, lang missing, or not one of the course languages"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"Not enrolled in that course"},"429":{"description":"Too many account writes for this user (Retry-After)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/enroll/{code}":{"delete":{"operationId":"accountUnenroll","summary":"Withdraw from a course (or leave its waitlist): the enrollment row is removed and the withdrawal kept in your account history. Works for a course that has since left the catalog. Cookie callers must pass the CSRF gate. Rate-limited per user","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code, e.g. CS100"}],"responses":{"200":{"description":"{ code, status: \"withdrawn\", from: \"enrolled\"|\"waitlisted\", at }"},"400":{"description":"Invalid course code"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"Not enrolled in that course"},"409":{"description":"A Paid individual enrollment cannot be withdrawn here (contact us)"},"429":{"description":"Too many account writes for this user (Retry-After)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/checkout":{"post":{"operationId":"accountCheckout","summary":"Start a \"Paid individual\" checkout for one of YOUR courses (self-paced courses only): creates an order and a provider-hosted payment page and returns its URL for the browser to open. The success/cancel return URLs are fixed by the server (learn.cobolstack.com/account). Nothing is granted here: the enrollment becomes Paid individual only when the payment provider's signed webhook confirms the payment. A pending order with time left is reused (no duplicate payment pages). Refused when already paid, or when you are not enrolled and at the 30-course cap. Cookie callers must pass the CSRF gate. Rate-limited per user","tags":["account"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"course":{"description":"course code, e.g. CS120 (alias: code)"}}}}}},"responses":{"200":{"description":"{ order, url, expiresAt, amount, currency, display, course, reused }"},"400":{"description":"Missing/invalid course code, or Paid individual is not offered for that course"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No such course in the catalog"},"409":{"description":"Already on the Paid individual plan for that course, or the 30-course limit is reached"},"413":{"description":"Body over 1 KB"},"429":{"description":"Too many checkout attempts for this user (Retry-After)"},"502":{"description":"The payment provider refused or could not be reached (try again later)"},"503":{"description":"Payments not configured (PAYMENTS NOT CONFIGURED), or the course catalog is unavailable"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/orders/{order}":{"get":{"operationId":"accountOrder","summary":"One of YOUR \"Paid individual\" orders (the account page polls it after returning from the payment page): status pending / processing / paid / failed / expired / error / mismatch. paid means the provider's signed webhook confirmed the payment and the enrollment is Paid individual. Another user's order id answers 404","tags":["account"],"parameters":[{"name":"order","in":"path","required":true,"schema":{"type":"string"},"description":"order id (ord_ + 24 characters)"}],"responses":{"200":{"description":"{ order, course, title, status, plan, amount, currency, display, created, updated, paidAt, refunded, disputed, downgraded }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No such order (or not yours)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/payments/webhook/{provider}":{"post":{"operationId":"paymentsWebhook","summary":"Payment provider webhook (public; the provider calls it, e.g. https://cobolstack.com/api/account/payments/webhook/stripe). The raw body is verified with the provider's signature scheme (Stripe: Stripe-Signature HMAC-SHA256, 5-minute timestamp tolerance, constant-time compare) BEFORE it is parsed; each event id is applied once (replays answer duplicate); an order is granted only when the event's checkout reference, metadata, amount and currency match the stored order. Grants the Paid individual enrollment; records failures, expiry, refunds and disputes. A FULL refund or a LOST dispute returns the enrollment to the Free plan only when the tenant's payments config says so (onRefund / onDispute = \"downgrade\"; default \"keep\" = the owner decides)","tags":["account"],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string"},"description":"payment provider name (stripe)"}],"responses":{"200":{"description":"{ received: true, outcome, type, order } — outcome granted / granted-duplicate / already-applied / processing / failed / expired / stale / refund-recorded / refund-downgraded / dispute-recorded / dispute-closed / dispute-downgraded / ignored / unknown-order / mismatch / duplicate"},"400":{"description":"Signature missing/invalid, timestamp outside the tolerance, or not a provider event"},"404":{"description":"Unknown payment provider"},"413":{"description":"Body over 256 KB"},"429":{"description":"Too many rejected deliveries from this address (Retry-After)"},"503":{"description":"Payments not configured for this provider (the provider retries later)"}},"security":[]}},"/api/account/progress":{"get":{"operationId":"accountProgressList","summary":"Your progress in every course you are enrolled in (or waitlisted for) that has online checkpoints: each checkpoint with its status (passed / not-yet / todo = not gradable online yet), the job that proved it, and the certificate state. Reads only; POST .../check grades","tags":["account"],"responses":{"200":{"description":"{ courses: [{ code, title, enrolled, gradable, certificateCourse, checkpoints: [{ id, session, lab, title, hint, required, status, at?, jobid?, jobname?, submitted?, evidenceHash? }], passed, total, requiredPassed, requiredTotal, complete, lastCheck, certificate: { issued, certId?, verifyPath?, eligible?, blockers? } }], specsLoaded }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/progress/{code}":{"get":{"operationId":"accountProgress","summary":"Your progress in one course (no grading): checkpoints, their status and evidence, and the certificate state","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code, e.g. CS120"}],"responses":{"200":{"description":"the course object of GET /api/account/progress"},"400":{"description":"Invalid course code"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No checkpoints are defined for that course"},"503":{"description":"Checkpoint specifications unavailable"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/progress/{code}/check":{"post":{"operationId":"accountProgressCheck","summary":"\"Check my progress\": grade the course's checkpoints NOW against engine evidence that is yours — jobs that ran under your userid since your ID was created (job name, MAX-RC, step programs and RCs, the spool files each step wrote, the allocation messages), your PDS members (last saved by you) and datasets under your HLQ. A passed checkpoint stays passed; for the rest, feedback names the closest job and the first check it missed. The request carries no result: nothing the browser says can pass a checkpoint. Requires an enrollment (or waitlist entry) in the course. Cookie callers must pass the CSRF gate. Rate-limited per user","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code, e.g. CS120"}],"responses":{"200":{"description":"the course object of GET /api/account/progress/{code} plus { newlyPassed: [id], feedback: { id: [line] } }"},"400":{"description":"Invalid course code"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No checkpoints are defined for that course"},"409":{"description":"Not enrolled in (or waitlisted for) the course"},"429":{"description":"Too many checks for this user (Retry-After)"},"503":{"description":"Checkpoint specifications unavailable, or checks for the course are paused"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/email/verify":{"post":{"operationId":"accountEmailVerify","summary":"Send a verification link to the email address on your registration (needed for certificates). The link is single-use, expires (24 h by default) and supersedes any earlier one; it opens the learn.cobolstack.com account page, which confirms it. Delivery uses the site's configured mail transport (SMTP, or a local outbox in development). Cookie callers must pass the CSRF gate. Rate-limited per user","tags":["account"],"responses":{"200":{"description":"{ sent, to (masked), expires, transport } or { sent:false, alreadyVerified:true, verified:true, verifiedAt, to }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"409":{"description":"No email address on record (the ID was not self-registered)"},"429":{"description":"Too many verification mails for this user (Retry-After)"},"502":{"description":"The mail could not be sent"},"503":{"description":"Email delivery is not configured on this system"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/email/confirm":{"post":{"operationId":"accountEmailConfirm","summary":"Confirm an email address with the code from the verification link (the account page sends it from the link's #verify= fragment, or the user pastes it). The code is the credential: no logon is needed. Single use; expired codes are refused; the address on the account must still be the one the code was sent to. There is no GET form on purpose (mail scanners open GET links and would use up the code). Rate-limited per client address","tags":["account"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"description":"the 43-character code from the link"}}}}}},"responses":{"200":{"description":"{ verified: true, user }"},"400":{"description":"Malformed code"},"404":{"description":"Unknown or already used code"},"409":{"description":"The account's address changed since the code was sent"},"410":{"description":"The code has expired"},"429":{"description":"Too many attempts from this address (Retry-After)"}},"security":[]}},"/api/account/certificates":{"get":{"operationId":"accountCertificates","summary":"Your certificates, each with its full signed record (verify it offline with the public keys from GET /api/certs/keys: Ed25519 over the canonical JSON of every field except signature, keys sorted) and its public verify page path","tags":["account"],"responses":{"200":{"description":"{ certificates: [{ certId, code, title, certName, name, issuedAt, status, showName, verifyPath, record }], signing: { configured, keyId } }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true},"post":{"operationId":"accountCertificateClaim","summary":"Claim the certificate for a course: issued only when the course awards one online, every required checkpoint is passed, you are enrolled, and your email is verified. Optional name (self-declared, 1-64 letters/spaces/. , ' -) is signed into the record; showName opts in to showing it on the public verify page (default: \"Verified holder\"). Idempotent: one valid certificate per course. Cookie callers must pass the CSRF gate. Rate-limited per user","tags":["account"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"course":{"description":"course code (alias: code)"},"name":{"description":"optional name on the certificate"},"showName":{"description":"optional boolean: show the name on the public verify page"}}}}}},"responses":{"200":{"description":"{ created, certId, code, title, certName, name, issuedAt, status, showName, verifyPath, record } — HTTP 201 when issued now"},"400":{"description":"Invalid course code or name"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No such course"},"409":{"description":"Not eligible yet (body: blockers[])"},"429":{"description":"Too many requests (Retry-After)"},"503":{"description":"Certificate signing is not configured"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/certificates/{certId}":{"post":{"operationId":"accountCertificateUpdate","summary":"Change whether your name is shown on a certificate's public verify page (the name itself is signed into the record and cannot change). Cookie callers must pass the CSRF gate","tags":["account"],"parameters":[{"name":"certId","in":"path","required":true,"schema":{"type":"string"},"description":"SF-XXXX-XXXX-XXXX-XXXX"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"showName":{"description":"boolean"}}}}}},"responses":{"200":{"description":"the certificate (as in GET /api/account/certificates)"},"400":{"description":"showName missing"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"Not your certificate"},"409":{"description":"The certificate has no name to show"},"429":{"description":"Too many requests (Retry-After)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/certs/verify/{certId}":{"get":{"operationId":"certVerify","summary":"Public certificate check (cobolstack.com/verify/<certId>): course, certificate name, issue date and validity (the stored record's Ed25519 signature is re-verified on every request; revoked certificates say so). The holder's name appears only if the holder opted in, otherwise \"Verified holder\"; never a userid, email or evidence. Rate-limited per client address","tags":["account"],"parameters":[{"name":"certId","in":"path","required":true,"schema":{"type":"string"},"description":"SF-XXXX-XXXX-XXXX-XXXX"}],"responses":{"200":{"description":"{ certId, valid, status: \"valid\"|\"revoked\"|\"signature-invalid\", signatureValid, issuer, course: { code, title }, certificate, issuedAt, holder, holderNamed, emailVerified, checkpoints, keyId, revokedAt? }"},"400":{"description":"Malformed certificate id"},"404":{"description":"No such certificate (valid:false)"},"429":{"description":"Too many lookups from this address (Retry-After)"}},"security":[]}},"/api/certs/keys":{"get":{"operationId":"certKeys","summary":"The public Ed25519 keys that sign certificates (every key ever used, so older certificates keep verifying after a rotation). With a certificate record from GET /api/account/certificates anyone can verify it offline","tags":["account"],"responses":{"200":{"description":"{ current, keys: [{ keyId, algorithm: \"Ed25519\", publicKey (PEM, SPKI), created, retired }] }"}},"security":[]}},"/api/account/tracker":{"get":{"operationId":"accountTrackerList","summary":"Your session trackers: every course you are enrolled in (or waitlisted for) that has a per-video session plan, with counts (jobs, files, graded sessions, videos available — in any language and in the course language), the course language of each enrollment, your attachment storage use and the limits","tags":["account"],"responses":{"200":{"description":"{ courses: [{ code, title, status, rows, sessions, jobs, attachments, graded, videos, lang, langFrom, videosInLang, videosByLang: { <lang>: n }, watched, completed, skipped }], langs: [{ code, name }], usage: { bytes, files, quotaBytes }, limits: { fileBytes, filesPerSession, quotaBytes, jobsPerSession, extensions } }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/tracker/{code}":{"get":{"operationId":"accountTracker","summary":"Your session tracker for one course: every session from the intro (0) to the last video, each with the video link in your course language (else the English one, videoFallback:true) plus the map of every language it exists in, the exercises (from the course admin), your jobs (with verified:true when the job ran under your User ID with that name), your notes and code files, and the admin remarks and grade (0-100)","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code, e.g. CS100"}],"responses":{"200":{"description":"{ code, title, enrolled, lang, langFrom, langs, videos, videosInLang, videosByLang, sessions: [{ session, title }], rows: [{ id, title, session, minutes, videoUrl, videoLang, videoFallback, videos: { <lang>: url }, exercises, jobs: [{ jobname, jobid, verified, verifiedAt }], notes, attachments: [{ id, name, size, at }], remarks, grade, gradedAt, updated, watch: { count, first, last, lang, fallback } | null, status: done | skipped | null, statusAt, statusBy, statusDerived, completed: <iso> | null, skipped: <iso> | null }], progress: { rows, watched, completed, skipped, lastWatched, lastCompleted, lastSkipped }, usage, limits } — videoUrl = the video in lang, else the English one (videoFallback:true, videoLang:\"en\"), else null"},"400":{"description":"Invalid course code"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No session tracker for that course"},"409":{"description":"Not enrolled in (or waitlisted for) the course"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/tracker/{code}/{session}":{"put":{"operationId":"accountTrackerSave","summary":"Save the jobs you ran for a session and/or your notes (each field given replaces the saved one). jobs: up to 20 { jobname (1-8 of A-Z 0-9 @ # $, not starting with a digit), jobid (JOBnnnnn; a bare number is padded) }; each is verified against the engine (it must have run under your User ID with that job name since your ID was created) and the result is kept. notes: plain text up to 4000 characters (null clears). Cookie callers must pass the CSRF gate. Rate-limited per user","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code"},{"name":"session","in":"path","required":true,"schema":{"type":"string"},"description":"session id: 0 (intro) or e.g. 1.1"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"jobs":{"description":"optional [{ jobname, jobid }]"},"notes":{"description":"optional text or null"}}}}}},"responses":{"200":{"description":"the session row (as in GET /api/account/tracker/{code})"},"400":{"description":"Invalid job name / job number / text, or nothing to save"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No such course tracker or session"},"409":{"description":"Not enrolled"},"429":{"description":"Too many tracker writes (Retry-After)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/tracker/{code}/{session}/watch":{"post":{"operationId":"accountTrackerWatch","summary":"Record that you opened a session video (the tracker's Watch button or an \"Also in\" language link). lang = the language of the video you opened (omitted = the one the row's Watch button opens); it must have a video for that session. Keeps per session: first and last watch time, a click count (a repeat click within 10 seconds in the same language only moves the last time), the language and whether it was the English fallback. Nothing else is stored (no URL, address or browser details). Cookie callers must pass the CSRF gate. Rate-limited per user in its own bucket","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code"},{"name":"session","in":"path","required":true,"schema":{"type":"string"},"description":"session id: 0 (intro) or e.g. 1.1"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"lang":{"description":"optional course-language code of the video opened"}}}}}},"responses":{"200":{"description":"{ id, watch: { count, first, last, lang, fallback }, status, statusAt, statusBy, statusDerived, completed, skipped, deduped, progress: { rows, watched, completed, skipped, lastWatched, lastCompleted, lastSkipped } }"},"400":{"description":"Unknown language or bad session id"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No such course tracker or session, or no video in that language"},"409":{"description":"Not enrolled"},"429":{"description":"Too many watch records (Retry-After)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/tracker/{code}/{session}/complete":{"put":{"operationId":"accountTrackerComplete","summary":"Mark a session complete ({ status: \"done\" } or { completed: true }; a session already complete keeps its first completion time), skipped ({ status: \"skipped\" }) or open again ({ status: null } or { completed: false }). A session that is a mini step of the AI chat's course (every video row but the intro) shares its mark with the chat: marks made in the chat show here and marks made here show in the chat. Shown to you and the course admin. Cookie callers must pass the CSRF gate. Rate-limited per user","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code"},{"name":"session","in":"path","required":true,"schema":{"type":"string"},"description":"session id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"description":"\"done\", \"skipped\" or null"},"completed":{"description":"true or false (the older form: true = done, false = open)"}}}}}},"responses":{"200":{"description":"{ id, status: done | skipped | null, statusAt, statusBy: user | tutor | evidence | null, statusDerived, completed: <iso> | null, skipped: <iso> | null, watch, sessionStatus?, chatSession?, progress: { rows, watched, completed, skipped, lastWatched, lastCompleted, lastSkipped } }"},"400":{"description":"status is not \"done\"/\"skipped\"/null (or completed not true/false), or bad session id"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No such course tracker or session"},"409":{"description":"Not enrolled"},"429":{"description":"Too many tracker writes (Retry-After)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/tracker/{code}/{session}/attachments":{"post":{"operationId":"accountTrackerAttach","summary":"Attach a code file to a session: JSON { name, content } where content is the file text (UTF-8). Text source files only (.cbl .cob .cpy .jcl .asm .mac .rexx .rex .clist .txt .sql .bms .pli .ezt .prc .lst .log .csv .md; no NUL or control characters), at most 64 KB each, 10 per session and 2 MB per user by default. Files are stored, never executed, and served back only to you and the course admin. Cookie callers must pass the CSRF gate. Rate-limited per user","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code"},{"name":"session","in":"path","required":true,"schema":{"type":"string"},"description":"session id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"file name with a text extension, e.g. PAYROLL.cbl"},"content":{"description":"the file text"}}}}}},"responses":{"200":{"description":"{ id, name, size, sha256, at, usage }"},"400":{"description":"Bad name / empty file"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No such course tracker or session"},"409":{"description":"Not enrolled, or the per-session file limit is reached"},"413":{"description":"File too large or quota reached"},"415":{"description":"Not a text source file"},"429":{"description":"Too many tracker writes (Retry-After)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/tracker/{code}/{session}/attachments/{id}":{"get":{"operationId":"accountTrackerFile","summary":"Download one of your attached files: always text/plain; charset=utf-8 as an attachment (Content-Disposition: attachment, X-Content-Type-Options: nosniff, a sandbox CSP), never rendered or executed","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code"},{"name":"session","in":"path","required":true,"schema":{"type":"string"},"description":"session id"},{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"attachment id"}],"responses":{"200":{"description":"the file text (text/plain)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No such attachment (or not yours)"},"409":{"description":"Not enrolled"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true},"delete":{"operationId":"accountTrackerFileDelete","summary":"Remove one of your attached files. Cookie callers must pass the CSRF gate. Rate-limited per user","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code"},{"name":"session","in":"path","required":true,"schema":{"type":"string"},"description":"session id"},{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"attachment id"}],"responses":{"200":{"description":"{ deleted, id, usage }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No such attachment"},"409":{"description":"Not enrolled"},"429":{"description":"Too many tracker writes (Retry-After)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/learner":{"get":{"operationId":"accountLearner","summary":"Your learner view for the AI chat: the current course (the one the chat's course button shows and the tutor teaches) with every syllabus session and its status (done / skipped / in progress, who marked it and the evidence: your own jobs that ran during the session, checkpoints passed), your enrolled courses with progress, the courses you marked \"already know / not interested\", and the rest of the catalog you can add. The first call enrolls you in the platform's default course (CS100 on z/OS) once, unless you already changed your courses","tags":["account"],"responses":{"200":{"description":"{ product, defaultCourse, defaulted, current: { code, title, url, total, done, skipped, open, complete, active, next: { n, title, url, desc, lab } | null, sessions: [{ n, title, url, status, by, at, evidence, summary, videos }] } | null, enrolled: [{ code, title, status, url, product, known, isCurrent, done, skipped, total, complete }], known: [code], addable: [{ code, title, track, level, duration, availability, action, url, product, sessions }], catalogUrl }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/learner/current":{"put":{"operationId":"accountLearnerCurrent","summary":"Make one of your enrolled courses the current one (the chat's course button and the tutor follow it). Clears an \"already know\" mark on it. Cookie callers must pass the CSRF gate. Rate-limited per user","tags":["account"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"course":{"description":"course code, e.g. CS105"}}}}}},"responses":{"200":{"description":"{ code, current, at }"},"400":{"description":"Invalid course code, or a course of another platform"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No such course"},"409":{"description":"Not enrolled in that course"},"429":{"description":"Too many account writes (Retry-After)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/learner/known/{code}":{"put":{"operationId":"accountLearnerKnown","summary":"Mark a course as \"I already know this / not interested\" ({ known: true }) or unmark it ({ known: false }). The tutor never teaches a known course and the current course moves to the next one; your enrollment is kept. Cookie callers must pass the CSRF gate. Rate-limited per user","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"known":{"description":"true or false"}}}}}},"responses":{"200":{"description":"{ code, known, current, at }"},"400":{"description":"Invalid course code or known not true/false"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No such course"},"429":{"description":"Too many account writes (Retry-After)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/learner/{code}/sessions/{n}":{"put":{"operationId":"accountLearnerSession","summary":"Mark a syllabus session of one of your courses done ({ status: \"done\" }), skipped / already known ({ status: \"skipped\" }) or open again ({ status: null }). A \"done\" records the evidence the engine has (your own terminal jobs that ran since the tutor started the session; checkpoints of that session that pass). Cookie callers must pass the CSRF gate. Rate-limited per user","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code"},{"name":"n","in":"path","required":true,"schema":{"type":"string"},"description":"session number (1-based, as on the course page)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"description":"\"done\", \"skipped\" or null"}}}}}},"responses":{"200":{"description":"{ code, session, title, status, at, by, evidence? }"},"400":{"description":"Invalid course code, session number or status"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No such course or session"},"409":{"description":"Not enrolled in that course"},"429":{"description":"Too many account writes (Retry-After)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/learner/{code}/steps/{id}":{"put":{"operationId":"accountLearnerStep","summary":"Mark one MINI STEP (a video row of the course plan, e.g. 3.2) of one of your courses: { status: \"start\" } makes it the step the tutor is on (its session in progress), \"done\" / \"skipped\" mark it, null opens it again. When every step of a session is done or skipped the session completes by itself (done when at least one step was done). A session-level mark covers all its steps. Cookie callers must pass the CSRF gate. Rate-limited per user","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code"},{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"step id as on the course page (e.g. 3.2)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"description":"\"start\", \"done\", \"skipped\" or null"}}}}}},"responses":{"200":{"description":"{ code, session, step, title, status, at, by?, sessionStatus?, sessionComplete? }"},"400":{"description":"Invalid course code, step id or status"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No such course or step (or the course has no mini steps)"},"409":{"description":"Not enrolled in that course"},"429":{"description":"Too many account writes (Retry-After)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/admin/login":{"post":{"operationId":"adminLogin","summary":"Owner admin login for learn.cobolstack.com/account/admin: JSON { email, password } (NOT a RACF userid). CSRF-gated (Origin https://learn.cobolstack.com or STEELFRAME_ADMIN_ORIGINS, X-SF-CSRF: 1, application/json). Throttled before the password is checked: per email 5 and per client IP 10 failures per 15 minutes, and a lockout after 15 failures per 24 hours (429 + Retry-After, even with the right password). Every failure is the same 401. Success sets the host-only admin cookie __Secure-sf_admin (HttpOnly, Secure, SameSite=Strict, Path=/api/account/admin; 8 h absolute, 30 min idle) and revokes any admin cookie the request presented","tags":["account"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"description":"the owner admin email"},"password":{"description":"the owner admin password (case-sensitive)"}}}}}},"responses":{"200":{"description":"{ ok, admin: { id, email (masked) }, expires, idleExpires, ttlS, idleS }"},"401":{"description":"INVALID EMAIL OR PASSWORD (always the same)"},"403":{"description":"CSRF check failed"},"429":{"description":"Too many attempts (Retry-After)"}},"security":[],"x-admin-auth":true}},"/api/account/admin/logout":{"post":{"operationId":"adminLogout","summary":"Owner admin logout: ends the admin session(s) this browser presents ({ everywhere: true }: every session of that admin) and expires the admin cookie. CSRF-gated; idempotent (200 with ended:false when there was no live session)","tags":["account"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"everywhere":{"description":"optional boolean"}}}}}},"responses":{"200":{"description":"{ ok, ended, sessions }"},"403":{"description":"CSRF check failed"}},"security":[],"x-admin-auth":true}},"/api/account/admin/session":{"get":{"operationId":"adminSession","summary":"The owner admin session behind the admin cookie: the masked email, the admin id and when the session ends (absolute and idle)","tags":["account"],"responses":{"200":{"description":"{ admin: { id, email (masked) }, expires, idleExpires, ttlS, idleS }"},"401":{"description":"No live owner admin session (ADMIN LOGIN REQUIRED)"},"403":{"description":"CSRF check failed, or a bearer token / account cookie was presented instead of the owner admin session (OWNER ADMIN SESSION REQUIRED)"}},"security":[{"adminCookie":[]}],"x-admin-auth":true}},"/api/account/admin/tracker":{"get":{"operationId":"adminTrackerCourses","summary":"Owner admin: every course that has a session tracker, with the overview counts (students = enrolled + waitlisted, enrolled, waitlisted, withdrawn-with-data, sessions with a video link in any language and per language, sessions with exercises, graded entries, graded students, students with work, jobs, verified jobs, files) and the course-language list. Counts only","tags":["account"],"responses":{"200":{"description":"{ courses: [{ code, title, rows, sessions, students, enrolled, waitlisted, withdrawn, videos, videosByLang: { <lang>: n }, exercises, graded, gradedStudents, activeStudents, jobs, verified, attachments, watched, completed }], langs: [{ code, name }] } — watched / completed = student x session pairs (§29)"},"401":{"description":"No live owner admin session (ADMIN LOGIN REQUIRED)"},"403":{"description":"CSRF check failed, or a bearer token / account cookie was presented instead of the owner admin session (OWNER ADMIN SESSION REQUIRED)"}},"security":[{"adminCookie":[]}],"x-admin-auth":true}},"/api/account/admin/tracker/{code}":{"get":{"operationId":"adminTrackerCourse","summary":"Owner admin: one course's sessions with their video links per language (videos map; videoUrl = the English one) and exercises, and its students (enrolled, waitlisted, or withdrawn with tracker data kept) with per-student counts. Userids only, never emails","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code"}],"responses":{"200":{"description":"{ code, title, sessions, langs, videos, videosByLang, rows: [{ id, title, session, minutes, videos: { <lang>: url }, videoUrl, exercises, updated, watchedBy, completedBy }], students: [{ user, status, jobs, verified, attachments, graded, updated, watched, completed, lastWatched, lastCompleted }] } — watchedBy / completedBy = roster students with a Watch click / Complete mark on that session (§29)"},"401":{"description":"No live owner admin session (ADMIN LOGIN REQUIRED)"},"403":{"description":"CSRF check failed, or a bearer token / account cookie was presented instead of the owner admin session (OWNER ADMIN SESSION REQUIRED)"},"404":{"description":"No session tracker for that course"}},"security":[{"adminCookie":[]}],"x-admin-auth":true}},"/api/account/admin/tracker/{code}/videos":{"put":{"operationId":"adminTrackerVideos","summary":"Owner admin: set the video links of MANY sessions in ONE language at once — body { lang, videos: { \"<session id>\": \"https://...\" | null } } (null or \"\" clears that language on that session; at most 600 sessions). All-or-nothing: an unknown session id, a duplicate, or an invalid URL (https only, no credentials, max 500) refuses the whole request and nothing is written. Other languages and the exercises are untouched. CSRF-gated; rate-limited per admin","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"lang":{"description":"the course-language code the URLs are in (e.g. ja)"},"videos":{"description":"{ \"<session id>\": https URL | null }"}}}}}},"responses":{"200":{"description":"{ code, lang, rows, set, cleared, sessions: [{ id, videos, videoUrl }] }"},"400":{"description":"lang missing/unknown, videos not an object or empty, over 600 sessions, a session twice, or an invalid URL (the message names the session)"},"401":{"description":"No live owner admin session (ADMIN LOGIN REQUIRED)"},"403":{"description":"CSRF check failed, or a bearer token / account cookie was presented instead of the owner admin session (OWNER ADMIN SESSION REQUIRED)"},"404":{"description":"No such course tracker, or a session id that is not in the course"},"413":{"description":"Body over 64 KB"},"429":{"description":"Too many admin writes (Retry-After)"}},"security":[{"adminCookie":[]}],"x-admin-auth":true}},"/api/account/admin/tracker/{code}/{session}":{"put":{"operationId":"adminTrackerSession","summary":"Owner admin: set a session's video links per language — videos: { \"<lang>\": https URL | null } (null clears that language; https only, no credentials, max 500) — and/or exercises (plain text, max 4000; null clears), the same for every student. videoUrl is accepted as the English link (videos.en). A student sees the video in their course language, else the English one labelled \"(English)\". CSRF-gated; rate-limited per admin","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code"},{"name":"session","in":"path","required":true,"schema":{"type":"string"},"description":"session id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"videos":{"description":"optional { \"<lang>\": https URL | null } — lang one of en, ja, ko, zh-Hans, zh-Hant, de, fr, es, it, pt"},"videoUrl":{"description":"optional https URL or null (= videos.en)"},"exercises":{"description":"optional text or null"}}}}}},"responses":{"200":{"description":"{ id, title, videos: { <lang>: url }, videoUrl, exercises, updated }"},"400":{"description":"Invalid URL or text, or a language outside the course-language list"},"401":{"description":"No live owner admin session (ADMIN LOGIN REQUIRED)"},"403":{"description":"CSRF check failed, or a bearer token / account cookie was presented instead of the owner admin session (OWNER ADMIN SESSION REQUIRED)"},"404":{"description":"No such course tracker or session"},"429":{"description":"Too many admin writes (Retry-After)"}},"security":[{"adminCookie":[]}],"x-admin-auth":true}},"/api/account/admin/tracker/{code}/students/{user}":{"get":{"operationId":"adminTrackerStudent","summary":"Owner admin: one student's tracker for a course (the same rows the student sees: jobs with verification, notes, files, remarks, grade, and per session the Watch clicks — count, first/last time, language, English fallback — and the Complete mark)","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code"},{"name":"user","in":"path","required":true,"schema":{"type":"string"},"description":"the student's userid"}],"responses":{"200":{"description":"as GET /api/account/tracker/{code}, plus user"},"401":{"description":"No live owner admin session (ADMIN LOGIN REQUIRED)"},"403":{"description":"CSRF check failed, or a bearer token / account cookie was presented instead of the owner admin session (OWNER ADMIN SESSION REQUIRED)"},"404":{"description":"No tracker for that user in that course"}},"security":[{"adminCookie":[]}],"x-admin-auth":true}},"/api/account/admin/tracker/{code}/students/{user}/{session}":{"put":{"operationId":"adminTrackerGrade","summary":"Owner admin: set a student's remarks (plain text, max 2000; null clears) and/or grade (whole number 0-100; null clears) for one session. CSRF-gated; rate-limited per admin","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code"},{"name":"user","in":"path","required":true,"schema":{"type":"string"},"description":"the student's userid"},{"name":"session","in":"path","required":true,"schema":{"type":"string"},"description":"session id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"remarks":{"description":"optional text or null"},"grade":{"description":"optional integer 0-100 or null"}}}}}},"responses":{"200":{"description":"the student's session row"},"400":{"description":"Invalid grade or text"},"401":{"description":"No live owner admin session (ADMIN LOGIN REQUIRED)"},"403":{"description":"CSRF check failed, or a bearer token / account cookie was presented instead of the owner admin session (OWNER ADMIN SESSION REQUIRED)"},"404":{"description":"No such course tracker, session or student"},"429":{"description":"Too many admin writes (Retry-After)"}},"security":[{"adminCookie":[]}],"x-admin-auth":true}},"/api/account/admin/tracker/{code}/students/{user}/{session}/attachments/{id}":{"get":{"operationId":"adminTrackerFile","summary":"Owner admin: download a student's attached file (text/plain attachment, nosniff, sandbox CSP; never rendered)","tags":["account"],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"course code"},{"name":"user","in":"path","required":true,"schema":{"type":"string"},"description":"the student's userid"},{"name":"session","in":"path","required":true,"schema":{"type":"string"},"description":"session id"},{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"attachment id"}],"responses":{"200":{"description":"the file text (text/plain)"},"401":{"description":"No live owner admin session (ADMIN LOGIN REQUIRED)"},"403":{"description":"CSRF check failed, or a bearer token / account cookie was presented instead of the owner admin session (OWNER ADMIN SESSION REQUIRED)"},"404":{"description":"No such attachment"}},"security":[{"adminCookie":[]}],"x-admin-auth":true}},"/api/account/admin/waitlist":{"get":{"operationId":"adminWaitlist","summary":"Owner admin: the course waitlists (read-only). Per course: waitlisted and enrolled counts, the waitlisted students in FIFO order (position by join time) with userid, FULL email (for contacting them; never audited), joined date, days waiting, last logon and tracker activity counts, and the recent waitlist changes (joined / withdrew / promoted) from the enrollment history. Every cohort course is listed; a course that left the catalog but still has waitlist rows is shown with retired:true","tags":["account"],"parameters":[{"name":"course","in":"query","required":false,"schema":{"type":"string"},"description":"optional course code (e.g. CS110)"},{"name":"days","in":"query","required":false,"schema":{"type":"string"},"description":"optional window for the recent changes, 1-365 (default 30)"}],"responses":{"200":{"description":"{ generated, days, course, totals: { courses, coursesWithWaitlist, waitlisted, students, enrolled, recent }, courses: [{ code, title, availability, retired, waitlistOpen, tracker, waitlisted, enrolled, oldestDays, students: [{ position, user, email, emailVerified, joined, daysWaiting, lastLogon, activity: { jobs, verified, attachments } | null }], recent: [{ at, user, action }] }] }"},"400":{"description":"Invalid course code or days"},"401":{"description":"No live owner admin session (ADMIN LOGIN REQUIRED)"},"403":{"description":"CSRF check failed, or a bearer token / account cookie was presented instead of the owner admin session (OWNER ADMIN SESSION REQUIRED)"},"404":{"description":"No such course"}},"security":[{"adminCookie":[]}],"x-admin-auth":true}},"/api/account/admin/waitlist.csv":{"get":{"operationId":"adminWaitlistCsv","summary":"Owner admin: the waitlist as a CSV download (one row per waitlisted student, FIFO per course; Content-Disposition: attachment; UTF-8 with BOM; cells starting with = + - @ are prefixed with an apostrophe against spreadsheet formula injection). The export is recorded in the admin audit with the course and the row count only","tags":["account"],"parameters":[{"name":"course","in":"query","required":false,"schema":{"type":"string"},"description":"optional course code (e.g. CS110); all courses when absent"}],"responses":{"200":{"description":"text/csv: course, course_title, retired, position, userid, email, email_verified, joined_waitlist, days_waiting, last_logon, tracker_jobs, tracker_verified_jobs, tracker_files"},"400":{"description":"Invalid course code"},"401":{"description":"No live owner admin session (ADMIN LOGIN REQUIRED)"},"403":{"description":"CSRF check failed, or a bearer token / account cookie was presented instead of the owner admin session (OWNER ADMIN SESSION REQUIRED)"},"404":{"description":"No such course"}},"security":[{"adminCookie":[]}],"x-admin-auth":true}},"/api/account/admin/enrolled":{"get":{"operationId":"adminEnrolled","summary":"Owner admin: the enrolled students (read-only). Per course: enrolled and waitlisted counts, average progress, certificates, and the enrolled students (userid order) with userid, FULL email (for contacting them; never audited), enrolled date (the promotion time for a row promoted from the waitlist), days enrolled, last logon, session-tracker progress (sessions with a job logged of all rows, jobs, verified jobs, files, graded sessions, average grade; null without a tracker), Phase 5 checkpoints passed of total (null without a spec), the valid certificate, progress pct (checkpoints, else tracker sessions) and last activity (latest tracker save, checkpoint check or logon); plus the recent changes (enrolled / withdrew / promoted). Every self-paced course is listed; a course that left the catalog but still has enrolled rows is shown with retired:true","tags":["account"],"parameters":[{"name":"course","in":"query","required":false,"schema":{"type":"string"},"description":"optional course code (e.g. CS100)"},{"name":"days","in":"query","required":false,"schema":{"type":"string"},"description":"optional window for the recent changes, 1-365 (default 30)"}],"responses":{"200":{"description":"{ generated, days, course, totals: { courses, coursesWithEnrolled, enrolled, students, avgProgress, certificates, recent }, courses: [{ code, title, availability, retired, enrollOpen, tracker, checkpoints, hasCert, enrolled, waitlisted, promoted, certificates, avgProgress, students: [{ user, email, emailVerified, enrolled, daysEnrolled, promoted, waitlistJoined, plan, paidAt, lang, lastLogon, tracker: { rows, sessionsLogged, jobs, verified, attachments, graded, avgGrade, lastSave, watched, completed, lastWatched, lastCompleted } | null, checkpoints: { passed, total, requiredPassed, requiredTotal, complete, lastCheck } | null, certificate: { certId, issuedAt } | null, progress: { pct, basis }, lastActivity, lastActivitySource }], recent: [{ at, user, action }] }] } — lang = the course language the student takes the course in (their choice for the course, else their preferred language, else en)"},"400":{"description":"Invalid course code or days"},"401":{"description":"No live owner admin session (ADMIN LOGIN REQUIRED)"},"403":{"description":"CSRF check failed, or a bearer token / account cookie was presented instead of the owner admin session (OWNER ADMIN SESSION REQUIRED)"},"404":{"description":"No such course"}},"security":[{"adminCookie":[]}],"x-admin-auth":true}},"/api/account/admin/enrolled.csv":{"get":{"operationId":"adminEnrolledCsv","summary":"Owner admin: the enrolled students as a CSV download (one row per enrolled student; Content-Disposition: attachment; UTF-8 with BOM; cells starting with = + - @ are prefixed with an apostrophe against spreadsheet formula injection). The export is recorded in the admin audit with the course and the row count only","tags":["account"],"parameters":[{"name":"course","in":"query","required":false,"schema":{"type":"string"},"description":"optional course code (e.g. CS100); all courses when absent"}],"responses":{"200":{"description":"text/csv: course, course_title, retired, userid, email, email_verified, enrolled, days_enrolled, promoted_from_waitlist, last_logon, tracker_sessions_logged, tracker_sessions_total, tracker_jobs, tracker_verified_jobs, tracker_files, graded_sessions, average_grade, checkpoints_passed, checkpoints_total, certificate_id, progress_pct, progress_basis, last_activity, plan, lang, tracker_sessions_watched, tracker_sessions_completed, last_watched, last_completed"},"400":{"description":"Invalid course code"},"401":{"description":"No live owner admin session (ADMIN LOGIN REQUIRED)"},"403":{"description":"CSRF check failed, or a bearer token / account cookie was presented instead of the owner admin session (OWNER ADMIN SESSION REQUIRED)"},"404":{"description":"No such course"}},"security":[{"adminCookie":[]}],"x-admin-auth":true}},"/api/account/admin/orders":{"get":{"operationId":"adminOrders","summary":"Owner admin: the \"Paid individual\" orders (read-only), newest first: order id, created/updated, userid, FULL email, course, amount, status (pending / processing / paid / failed / expired / error / mismatch), refunded / disputed / downgraded / duplicate flags, provider, test/live mode, the provider checkout and payment references, paid time, and why an event was not applied. Plus the payments configuration state (provider, mode, price, refund/dispute policy, enabled or the not-configured reason; never a key) and totals (orders by status, paid revenue per currency and mode). No card data exists anywhere: the provider holds it","tags":["account"],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string"},"description":"optional: pending, processing, paid, failed, expired, error, mismatch, refunded, disputed or downgraded"},{"name":"course","in":"query","required":false,"schema":{"type":"string"},"description":"optional course code, or a product code such as AICHAT (AI assistant credit top-ups)"}],"responses":{"200":{"description":"{ generated, course, status, config: { tenant, enabled, provider, mode, currency, amount, display, priceId, onRefund, onDispute, problem, webhookPath }, totals: { orders, listed, byStatus, paid, refunded, disputed, downgraded, revenue: [{ mode, currency, amount, display }] }, orders: [{ order, created, updated, user, email, emailVerified, course, title, kind, plan, amount, currency, display, status, provider, mode, checkoutRef, paymentRef, paidAt, grant, refunded, disputed, downgraded, duplicate, problem }] } — kind = course (a Paid individual enrollment) or a product kind such as credit (an AI assistant top-up; course = the product code, title = the product name)"},"400":{"description":"Invalid course code or status"},"401":{"description":"No live owner admin session (ADMIN LOGIN REQUIRED)"},"403":{"description":"CSRF check failed, or a bearer token / account cookie was presented instead of the owner admin session (OWNER ADMIN SESSION REQUIRED)"}},"security":[{"adminCookie":[]}],"x-admin-auth":true}},"/api/account/admin/orders.csv":{"get":{"operationId":"adminOrdersCsv","summary":"Owner admin: the orders as a CSV download (same filters; Content-Disposition: attachment; UTF-8 with BOM; formula-injection-safe cells). The export is recorded in the admin audit with the course and the row count only","tags":["account"],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string"},"description":"optional status filter"},{"name":"course","in":"query","required":false,"schema":{"type":"string"},"description":"optional course code"}],"responses":{"200":{"description":"text/csv: order, created, updated, userid, email, course, course_title, plan, amount, currency, status, mode, provider, checkout_ref, payment_ref, paid_at, refunded, disputed, duplicate, problem, downgraded"},"400":{"description":"Invalid course code or status"},"401":{"description":"No live owner admin session (ADMIN LOGIN REQUIRED)"},"403":{"description":"CSRF check failed, or a bearer token / account cookie was presented instead of the owner admin session (OWNER ADMIN SESSION REQUIRED)"}},"security":[{"adminCookie":[]}],"x-admin-auth":true}},"/api/account/admin/mcp-usage":{"get":{"operationId":"adminMcpUsage","summary":"Owner admin: programmatic tool usage (MCP door, stdio bridge, API tokens) from the billing usage log, newest first: user, door, tool, class, status, target, CPU seconds and their source, base/CPU/total USD (6 decimals), charged or why not (free, retry-free, failed, shadow). Plus totals by class and the billing mode","tags":["account"],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"string"},"description":"how many UTC days back (1-31, default 7)"},{"name":"user","in":"query","required":false,"schema":{"type":"string"},"description":"optional userid filter"}],"responses":{"200":{"description":"{ generated, days, mode, totals: { calls, chargedUsd, wouldChargeUsd, byClass }, rows: [...] }"},"401":{"description":"No live owner admin session (ADMIN LOGIN REQUIRED)"},"403":{"description":"CSRF check failed, or a bearer token / account cookie was presented instead of the owner admin session (OWNER ADMIN SESSION REQUIRED)"}},"security":[{"adminCookie":[]}],"x-admin-auth":true}},"/api/account/admin/mcp-usage.csv":{"get":{"operationId":"adminMcpUsageCsv","summary":"Owner admin: the programmatic tool usage as a CSV download (UTF-8 with BOM, formula-injection-safe cells, USD to 6 decimals)","tags":["account"],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"string"},"description":"UTC days back (1-31, default 7)"},{"name":"user","in":"query","required":false,"schema":{"type":"string"},"description":"optional userid filter"}],"responses":{"200":{"description":"text/csv: time, user, tenant, mode, door, token_key, route, tool, class, status, target, cpu_s, cpu_source, base_usd, cpu_usd, usd, charged, reason, phase"},"401":{"description":"No live owner admin session (ADMIN LOGIN REQUIRED)"},"403":{"description":"CSRF check failed, or a bearer token / account cookie was presented instead of the owner admin session (OWNER ADMIN SESSION REQUIRED)"}},"security":[{"adminCookie":[]}],"x-admin-auth":true}},"/api/passticket":{"post":{"operationId":"generatePassticket","summary":"Generate a single-use PassTicket (W4.3 analog): requires a PTKTDATA application profile with an SSIGNON key in the vault; under enforcement the caller needs UPDATE on IRRPTAUTH.<appl>.<user>. Valid ≤60s, consumed on first evaluation","tags":["session"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"appl":{"description":"PTKTDATA application name"},"user":{"description":"target userid (default: the caller)"}}}}}},"responses":{"200":{"description":"{ ticket, user, appl, validSeconds, singleUse } — the ticket is shown once and never stored"},"400":{"description":"No PTKTDATA profile / no SSIGNON key / vault unconfigured"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (racf.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"racf.admin"}},"/api/openapi.json":{"get":{"operationId":"openapi","summary":"This document (generated live from the route registry)","tags":["session"],"responses":{"200":{"description":"OpenAPI 3.0 document"}},"security":[]}},"/api/vscode/status":{"get":{"operationId":"vscodeStatus","summary":"VS Code MCP (notes/VSCODE-MCP-PLAN.md): your own VS Code seat — kind (container | host | null), state, whether a VS Code window (the bridge) is connected, the page to open and the tools available. Free","tags":["vscode"],"responses":{"200":{"description":"{ user, seat, state, outdated, updating, connected, windows, page, javaTools, pythonTools, dbTools, dotnetTools, nodeTools, angularTools, langs, commandPassthrough, tools, next }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/start":{"post":{"operationId":"vscodeStart","summary":"VS Code MCP: start your container seat if it is not running and wait (≤ 30 s, wait_s) for a VS Code window to connect. The tools need the VS Code tab open in the SteelFrame web (code-server runs extensions only for a connected window). Free","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"wait_s":{"description":"seconds to wait for a window (0-30, default 20)"}}}}}},"responses":{"200":{"description":"{ ...status, started, waitedS }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/say":{"post":{"operationId":"vscodeSay","summary":"VS Code MCP (Claude Code in your own seat, notes/SEAT-CLAUDE-CODE-PLAN.md §15): narrate one short sentence on your open SteelFrame page (a caption and the narrator voice). Free; at most 20 a minute","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"description":"what to say (max 220 characters)"}}}}}},"responses":{"200":{"description":"{ tool, ok, shown, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/screen":{"post":{"operationId":"vscodeScreen","summary":"VS Code MCP tool vscode_screen on your own seat: Read the VS Code tab: the active editor (which data set member, dirty or saved), the cursor, the visible lines numbered, the open editor tabs, the Zowe Data Sets filter/selection and a Problems summary. Read-only. Call it first in VS Code and whenever you are unsure what VS Code shows.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/open-member":{"post":{"operationId":"vscodeOpenMember","summary":"VS Code MCP tool vscode_open_member on your own seat: Open a data set member in the VS Code editor through Zowe Explorer (the Zowe tree reveals it) and show its first lines. create:true first creates the member empty when it does not exist (and the data set itself as a FB-80 partitioned data set when that is missing). Omit member for a sequential data set.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dsn":{"description":"data set name, e.g. IBMUSER.SOURCE"},"member":{"description":"member name (1-8 characters), e.g. HELLO"},"create":{"description":"create the member (and the PDS) when missing (default false)"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/type":{"post":{"operationId":"vscodeType","summary":"VS Code MCP tool vscode_type on your own seat: Type text into the active VS Code editor at the cursor (or at line/column first), visibly at typing speed. Only Zowe data set documents can be edited. Newlines start new lines; no auto-indent is added. Does NOT save.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"description":"text to type (max 4000 chars)"},"line":{"description":"1-based line to move the cursor to first (optional)"},"column":{"description":"1-based column (optional, default 1 when line is given)"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/set-text":{"post":{"operationId":"vscodeSetText","summary":"VS Code MCP tool vscode_set_text on your own seat: Replace the WHOLE text of the active VS Code editor (a Zowe data set member), typed visibly line by line. Use real columns: COBOL division/section/paragraph headers start in column 8 (7 spaces), statements in column 12; JCL starts with // in column 1; max 72 (COBOL) / 71 (JCL) columns. Does NOT save: call vscode_save next.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"description":"the full text, lines separated by \n (max 20000 chars)"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/insert-lines":{"post":{"operationId":"vscodeInsertLines","summary":"VS Code MCP tool vscode_insert_lines on your own seat: Insert lines into the active VS Code editor BEFORE line N (N = number of lines + 1 appends at the end), typed visibly. Does NOT save.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"line":{"description":"1-based line number to insert before"},"text":{"description":"the lines to insert, separated by \n (max 8000 chars)"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/save":{"post":{"operationId":"vscodeSave","summary":"VS Code MCP tool vscode_save on your own seat: Save the active VS Code editor back to the mainframe through Zowe Explorer, then read the member back to verify it. Report the save as done only when the result says VERIFIED.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/zowe-filter":{"post":{"operationId":"vscodeZoweFilter","summary":"VS Code MCP tool vscode_zowe_filter on your own seat: Filter the Zowe Explorer Data Sets tree by a data set name pattern (e.g. \"IBMUSER.*\" or \"IBMUSER.SOURCE\") and return the matching data set names.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pattern":{"description":"data set name pattern, e.g. IBMUSER.*"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/refresh":{"post":{"operationId":"vscodeRefresh","summary":"VS Code MCP tool vscode_refresh on your own seat: Refresh the Zowe Explorer trees (data sets, jobs or both) so new members/jobs appear.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"view":{"description":"\"datasets\" | \"jobs\" | \"all\" (default all)"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/submit-job":{"post":{"operationId":"vscodeSubmitJob","summary":"VS Code MCP tool vscode_submit_job on your own seat: Submit JCL through Zowe: the member in the active editor (it must be saved first), or dsn+member. Shows the \"job submitted\" notification in VS Code and returns the job id (JOBnnnnn). Afterwards ALWAYS call vscode_job_output to show the result.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dsn":{"description":"data set name, e.g. IBMUSER.SOURCE"},"member":{"description":"member name (1-8 characters), e.g. HELLO"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/job-output":{"post":{"operationId":"vscodeJobOutput","summary":"VS Code MCP tool vscode_job_output on your own seat: Wait for a job to finish (up to 40 s), then open its output in a VS Code editor (Zowe Jobs) and return the status, each step's return code, the spool file list and the text of one spool file (default: the program output such as GO.SYSOUT / SYSPRINT; dd picks one, e.g. \"SYSPRINT\" or \"GO.SYSOUT\").","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"jobid":{"description":"JES2 job id, e.g. JOB00123"},"dd":{"description":"spool file: DD or STEP.DD (optional)"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/run-command":{"post":{"operationId":"vscodeRunCommand","summary":"VS Code MCP tool vscode_run_command on your own seat: Run ONE VS Code command from the allow-list: workbench.action.files.save, workbench.action.closeActiveEditor, workbench.action.nextEditor, workbench.action.previousEditor, undo, redo, editor.action.selectAll, cursorTop, cursorBottom, editor.foldAll, editor.unfoldAll, actions.find, workbench.actions.view.problems, zowe.ds.refresh, zowe.jobs.refresh. Anything else (terminals, tasks, debugging, extensions, settings) is refused.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"command":{"description":"the command id"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/java-open":{"post":{"operationId":"vscodeJavaOpen","summary":"VS Code MCP tool vscode_java_open on your own seat: Java (container seat): list the user's java/ folder (no path), a project folder (e.g. \"hello-java\"), or open a source file in the VS Code editor and return its numbered lines (e.g. \"hello-java/src/main/java/com/steelframe/hello/Hello.java\"). Read-only, except that a new seat has no java/ folder: the first Java tool call creates it with the hello-world project java/hello-java (Maven, compiles for Java 21, JUnit 5). Samples (copied from the seat's image when a tool names one as the project): hello-postgres, carddemo-postgres, carddemo-web.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"description":"folder or file under java/, e.g. \"hello-java\" (omit for the java/ folder itself)"},"from_line":{"description":"a file: the first line to return (default 1). A long file comes in pages of up to 200 lines / ~5000 characters; the result names the from_line of the next page"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/java-write":{"post":{"operationId":"vscodeJavaWrite","summary":"VS Code MCP tool vscode_java_write on your own seat: Java (container seat): create or replace ONE file under java/ with the given full text, typed visibly in the VS Code editor and saved to disk (\"via MCP\": written straight to disk, no editor). path = <project>/<path>/<file>, e.g. \"hello-java/src/main/java/com/steelframe/hello/HelloWorld.java\" (the folder of a Java package must match its package line). Allowed: .java, pom.xml/.xml, .properties, .txt, .md, .csv, .json, .sql, .yml/.yaml, .cpy, .cbl, .dat. A new project needs its own pom.xml: copy the plugin versions of java/hello-java/pom.xml (the seat is offline; other plugin versions may not resolve). Then call vscode_java_build.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"description":"file path under java/"},"text":{"description":"the complete file content (max 60000 chars)"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/java-build":{"post":{"operationId":"vscodeJavaBuild","summary":"VS Code MCP tool vscode_java_build on your own seat: Java (container seat): compile a project under java/ with a FIXED command, shown in the VS Code Output panel \"SteelFrame AI: Java\": Maven (pom.xml present) `mvn -q -DskipTests package` (offline, built-in repository), otherwise `javac --release 21` of every .java file into target/classes. Returns BUILD OK or the compiler errors (file:[line,col] message). Limit 150 s.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder under java/, e.g. \"hello-java\""}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/java-run":{"post":{"operationId":"vscodeJavaRun","summary":"VS Code MCP tool vscode_java_run on your own seat: Java (container seat): run a BUILT project's main class with a FIXED command `java -Xmx256m -cp target/classes:<dependencies> <main_class> <args>` in the Output panel \"SteelFrame AI: Java\"; returns the exit code and the program output (stdout+stderr). main_class may be omitted when the project has exactly one main method. No stdin. Limit 60 s (then the program is killed). Call vscode_java_build first after every change.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder under java/, e.g. \"hello-java\""},"main_class":{"description":"fully qualified class name, e.g. com.steelframe.hello.Hello"},"args":{"description":"program arguments (max 8; letters, digits, space and _ . , : = @ # / + % ( ) * - only)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/java-test":{"post":{"operationId":"vscodeJavaTest","summary":"VS Code MCP tool vscode_java_test on your own seat: Java (container seat): run a Maven project's JUnit tests with a FIXED command `mvn test [-Dtest=<test>]` in the Output panel \"SteelFrame AI: Java\"; returns the test summary (Tests run / Failures / Errors) and failure details. Limit 150 s. Code coverage: the seat's offline Maven repository has JaCoCo in ONE version only, org.jacoco:jacoco-maven-plugin 0.8.15 (prepare-agent, report in the test phase -> target/site/jacoco/jacoco.csv and index.html); never guess another version.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder under java/, e.g. \"hello-java\""},"test":{"description":"optional: one test class or Class#method (e.g. HelloTest or HelloTest#greetsTheWorld)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/python-open":{"post":{"operationId":"vscodePythonOpen","summary":"VS Code MCP tool vscode_python_open on your own seat: Python (container seat): list the user's python/ folder (no path), a project folder (e.g. \"hello-python\"), or open a file in the VS Code editor and return its numbered lines (e.g. \"hello-python/hello.py\"). Read-only, except that a new seat has no python/ folder: the first Python tool call creates it (with the user's venv python/.venv) and the hello-world project python/hello-python (hello.py, test_hello.py with pytest, read_dataset.py reading a mainframe member through z/OSMF, pandas_summary.py loading records into a pandas DataFrame). Samples (copied from the seat's image when a tool names one as the project): hello-postgres, carddemo-postgres.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"description":"folder or file under python/, e.g. \"hello-python\" (omit for the python/ folder itself)"},"from_line":{"description":"a file: the first line to return (default 1). A long file comes in pages of up to 200 lines / ~5000 characters; the result names the from_line of the next page"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/python-write":{"post":{"operationId":"vscodePythonWrite","summary":"VS Code MCP tool vscode_python_write on your own seat: Python (container seat): create or replace ONE file under python/ with the given full text, typed visibly in the VS Code editor and saved to disk (\"via MCP\": written straight to disk, no editor). path = <project>/<path>/<file>, e.g. \"hello-python/hello_world.py\" (a new folder under python/ is a new project). Allowed: .py, .pyi, requirements.txt/.txt, .md, .toml, .cfg, .ini, .json, .csv, .yml/.yaml, .cpy, .cbl, .dat. Then call vscode_python_run (or vscode_python_test for test_*.py).","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"description":"file path under python/"},"text":{"description":"the complete file content (max 60000 chars)"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/python-run":{"post":{"operationId":"vscodePythonRun","summary":"VS Code MCP tool vscode_python_run on your own seat: Python (container seat): run a script of a project with a FIXED command `python -u <file> <args>` (Python 3.13, the user's venv, memory limit 1 GiB) in the VS Code Output panel \"SteelFrame AI: Python\"; returns the exit code and the program output (stdout+stderr; a syntax error or traceback shows there). file is relative to the project (e.g. \"hello.py\"); it may be omitted when the project has exactly one script with an if __name__ == \"__main__\" block. No stdin. Limit 60 s (then the program is killed). No internet inside the seat.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder under python/, e.g. \"hello-python\""},"file":{"description":"the .py file inside the project, e.g. \"hello.py\""},"args":{"description":"program arguments (max 8; letters, digits, space and _ . , : = @ # / + % ( ) * - only)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/python-test":{"post":{"operationId":"vscodePythonTest","summary":"VS Code MCP tool vscode_python_test on your own seat: Python (container seat): run a project's pytest tests with a FIXED command `python -m pytest -q [<test>]` in the Output panel \"SteelFrame AI: Python\"; returns TESTS PASSED / FAILED with pytest's summary and failure details. test (optional) = a file, a folder, file.py::test_name or file.py::Class::test_name. Limit 150 s.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder under python/, e.g. \"hello-python\""},"test":{"description":"optional: e.g. \"test_hello.py\" or \"test_hello.py::test_greets_the_world\""}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/python-install":{"post":{"operationId":"vscodePythonInstall","summary":"VS Code MCP tool vscode_python_install on your own seat: Python (container seat): install the packages of a project's requirements.txt into the user's venv with a FIXED command `pip install --no-index --find-links <the seat's wheelhouse> -r requirements.txt` (OFFLINE: only the built-in packages exist: pytest, requests, numpy, pandas, openpyxl, tabulate, PyYAML, python-dateutil and their dependencies, all already installed). requirements.txt may only contain package names with optional versions (no options, URLs or paths). Limit 150 s.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder under python/, e.g. \"hello-python\""}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/python-typecheck":{"post":{"operationId":"vscodePythonTypecheck","summary":"VS Code MCP tool vscode_python_typecheck on your own seat: Python (container seat): TYPE-CHECK a project (or one file/folder of it) with a FIXED command: basedpyright (the same checker the VS Code editor uses; standard mode unless the project has its own pyrightconfig.json / [tool.basedpyright]) in the Output panel \"SteelFrame AI: Python\". Returns TYPECHECK OK or TYPECHECK FOUND n error(s) with file:line:col and the message. Nothing runs the code. Limit 120 s.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder under python/, e.g. \"hello-python\""},"path":{"description":"optional: a .py file or a folder inside the project, e.g. \"pandas_summary.py\""}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/dotnet-open":{"post":{"operationId":"vscodeDotnetOpen","summary":"VS Code MCP tool vscode_dotnet_open on your own seat: .NET (container seat): list the user's dotnet/ folder (no path), a project folder (e.g. \"hello-dotnet\"), or open a file in the VS Code editor and return its numbered lines (e.g. \"hello-dotnet/Hello/Program.cs\"). Read-only, except that a new seat has no dotnet/ folder: the first .NET tool call creates it with the hello-world project dotnet/hello-dotnet (console app Hello + xUnit tests Hello.Tests, solution hello-dotnet.slnx). Samples (copied from the seat's image when a tool names one as the project): dotnet/dotnet-postgres (Npgsql + Dapper on the user's own PostgreSQL), dotnet/carddemo-postgres (the CardDemo account/card/transaction join), dotnet/carddemo-web.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"description":"folder or file under dotnet/, e.g. \"hello-dotnet\" (omit for the dotnet/ folder itself)"},"from_line":{"description":"a file: the first line to return (default 1). A long file comes in pages of up to 200 lines / ~5000 characters; the result names the from_line of the next page"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/dotnet-write":{"post":{"operationId":"vscodeDotnetWrite","summary":"VS Code MCP tool vscode_dotnet_write on your own seat: .NET (container seat): create or replace ONE file under dotnet/ with the given full text, typed visibly in the VS Code editor and saved to disk (\"via MCP\": written straight to disk, no editor). path = <project>/<path>/<file>, e.g. \"hello-dotnet/Hello/Calculator.cs\". Allowed: .cs, .csproj, .sln/.slnx, .props/.targets, .json, .xml, .txt, .md, .csv, .sql, .yml/.yaml, .cpy, .cbl, .dat, .http; never NuGet.Config, bin/ or obj/. A new project needs its own .csproj (copy dotnet/hello-dotnet/Hello/Hello.csproj: TargetFramework net10.0; the seat is OFFLINE, so PackageReference versions must be the built-in ones: xunit 2.9.3, xunit.runner.visualstudio 3.1.4, Microsoft.NET.Test.Sdk 17.14.1, coverlet.collector 6.0.4, Npgsql 10.0.3, Dapper 2.1.86, Microsoft.EntityFrameworkCore 10.0.13, Npgsql.EntityFrameworkCore.PostgreSQL 10.0.3, Microsoft.AspNetCore.OpenApi 10.0.13). Then call vscode_dotnet_build.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"description":"file path under dotnet/"},"text":{"description":"the complete file content (max 60000 chars)"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/dotnet-build":{"post":{"operationId":"vscodeDotnetBuild","summary":"VS Code MCP tool vscode_dotnet_build on your own seat: .NET (container seat): build a project (or the solution in the folder) under dotnet/ with a FIXED command `dotnet build` (.NET 10 SDK, packages restored OFFLINE from the seat's built-in NuGet folder only) in the VS Code Output panel \"SteelFrame AI: .NET\". Returns BUILD OK (and the runnable projects) or the compiler errors (file(line,col): error CSnnnn: message). Limit 150 s.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder under dotnet/, e.g. \"hello-dotnet\""}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/dotnet-run":{"post":{"operationId":"vscodeDotnetRun","summary":"VS Code MCP tool vscode_dotnet_run on your own seat: .NET (container seat): run a BUILT console project with a FIXED command `dotnet <its bin/Debug/<tfm>/<name>.dll> <args>` (GC heap 256 MiB) in the Output panel \"SteelFrame AI: .NET\"; returns the exit code and the program output (stdout+stderr). project = the folder of the console project or of a solution with exactly one console project (e.g. \"hello-dotnet\" or \"hello-dotnet/Hello\"). No stdin. Limit 60 s (then the program is killed). Call vscode_dotnet_build first after every change. No internet inside the seat.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder under dotnet/, e.g. \"hello-dotnet\""},"args":{"description":"program arguments (max 8; letters, digits, space and _ . , : = @ # / + % ( ) * - only)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/dotnet-test":{"post":{"operationId":"vscodeDotnetTest","summary":"VS Code MCP tool vscode_dotnet_test on your own seat: .NET (container seat): run a project's or solution's xUnit tests with a FIXED command `dotnet test [--filter FullyQualifiedName~<test>]` (offline restore) in the Output panel \"SteelFrame AI: .NET\"; returns TESTS PASSED / FAILED with the totals and the failure details. Limit 150 s.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder under dotnet/, e.g. \"hello-dotnet\""},"test":{"description":"optional: a namespace, class or method name, e.g. \"GreetingTests\" or \"Hello.Tests.GreetingTests.GreetsTheWorld\""}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/node-open":{"post":{"operationId":"vscodeNodeOpen","summary":"VS Code MCP tool vscode_node_open on your own seat: Node.js / TypeScript / Angular (container seat): list the user's node/ and angular/ folders (no path), a project folder (e.g. \"node/hello-node\" or \"angular/carddemo-ui\"), or open a file in the VS Code editor and return its numbered lines (e.g. \"node/hello-node/src/index.ts\"). Read-only, except that a new seat has no node/ or angular/ folder: the first tool call on node/ creates it with the hello-world project node/hello-js (plain JavaScript ES modules + Vitest), the first on angular/ creates it with angular/carddemo-ui (an Angular 22 app listing CardDemo accounts from a small Node API, server/api.ts, over the user's database); without a path the listing creates nothing. Samples (copied from the seat's image when a tool names one as the project): node/hello-node (TypeScript + Vitest), node/node-postgres (pg on the user's own PostgreSQL).","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"description":"folder or file under node/ or angular/, e.g. \"node/hello-node\" (omit for both folders)"},"from_line":{"description":"a file: the first line to return (default 1). A long file comes in pages of up to 200 lines / ~5000 characters; the result names the from_line of the next page"},"paths":{"description":"several files in ONE call (2-12 paths; each one page): instead of path; not with from_line"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/node-write":{"post":{"operationId":"vscodeNodeWrite","summary":"VS Code MCP tool vscode_node_write on your own seat: Node.js / TypeScript / Angular (container seat): create or replace ONE file under node/ or angular/ with the given full text, typed visibly in the VS Code editor and saved to disk (\"via MCP\": written straight to disk, no editor). path = node/<project>/<path>/<file> or angular/<project>/<path>/<file> (a bare \"hello-node/...\" means node/). Allowed: .ts, .tsx, .mts, .cts, .js, .mjs, .cjs, .jsx, .json, .html, .css, .scss, .md, .txt, .csv, .sql, .yml/.yaml, .cpy, .cbl, .dat, .svg; never node_modules/, lock files or .npmrc. The seat's built-in toolchain (TypeScript 6, tsx, Vitest, ESLint, Prettier, pg, @types/node; Angular 22 for angular/) needs NO install. Then call vscode_node_run, vscode_node_test or vscode_node_build.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"description":"file path under node/ or angular/"},"text":{"description":"the complete file content (max 60000 chars)"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/node-edit":{"post":{"operationId":"vscodeNodeEdit","summary":"VS Code MCP tool vscode_node_edit on your own seat: Node.js / TypeScript / Angular (container seat): change ONE existing file under node/ or angular/ by exact string replacement - old_string must occur in the file exactly as written (whitespace included) and exactly ONCE unless replace_all is true; new_string must differ. Open the file first (vscode_node_open). Preferred over vscode_node_write for every change to an existing file (a few lines, a function, a paragraph); use vscode_node_write for a new file or a near-total rewrite. The change is applied in the editor at its place and saved (\"via MCP\": written straight to disk).","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"description":"file path under node/ or angular/"},"old_string":{"description":"the exact text to replace"},"new_string":{"description":"the replacement text (must differ from old_string)"},"replace_all":{"description":"replace every occurrence (default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/node-search":{"post":{"operationId":"vscodeNodeSearch","summary":"VS Code MCP tool vscode_node_search on your own seat: Node.js / TypeScript / Angular (container seat): regular-expression search over a project's files (not node_modules / .next / dot folders): project = \"node/<project>\" (or a folder inside it), pattern = a regex (max 300 chars), glob = an optional file filter such as \"*.ts\" or \"lib/**/*.test.ts\", context = lines around each match (0-10), mode = content (default: path:line: text) | files (paths only) | count. Up to 250 lines. Use it to find where something is instead of opening many files.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"the project folder, e.g. \"node/my-app\", or a folder inside it"},"pattern":{"description":"the regular expression"},"glob":{"description":"optional file glob"},"context":{"description":"context lines around each match (0-10)"},"mode":{"description":"what to return (default content)"},"ignore_case":{"description":"case-insensitive (default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/node-delete":{"post":{"operationId":"vscodeNodeDelete","summary":"VS Code MCP tool vscode_node_delete on your own seat: Node.js / TypeScript / Angular (container seat): DELETE one file or one folder (with everything in it) INSIDE a project under node/ or angular/, e.g. \"node/my-app/app/notes\" or \"node/my-app/lib/notes.ts\". Never node/, angular/ or a project folder itself, never node_modules/ or dot-files; at most 2000 files and folders at once. It cannot be undone. Then run vscode_node_typecheck / vscode_node_test to find anything that still imports what was removed.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"description":"the file or folder to delete, inside a project under node/ or angular/"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/node-install":{"post":{"operationId":"vscodeNodeInstall","summary":"VS Code MCP tool vscode_node_install on your own seat: Node.js (container seat): install the packages a project's package.json lists that the built-in toolchain does not already provide, with a FIXED command `npm install --offline --ignore-scripts` from the seat's OFFLINE package cache only (no internet, no install scripts; besides the toolchain the cache has express + @types/express, decimal.js, zod and their dependencies). package.json may only use \"name\": \"version-range\" (no URLs, git, file:, link:, workspace:, aliases; no preinstall/install/postinstall/prepare scripts). Limit 150 s.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder, e.g. \"node/hello-node\""}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/node-run":{"post":{"operationId":"vscodeNodeRun","summary":"VS Code MCP tool vscode_node_run on your own seat: Node.js (container seat): run a script of a project with a FIXED command `node <file> <args>` (Node 22; a .ts/.mts/.cts file runs through tsx; heap 256 MB) in the Output panel \"SteelFrame AI: Node\"; returns the exit code and the program output (stdout+stderr). file is relative to the project (e.g. \"src/index.ts\"); omitted = package.json \"main\", else src/index.ts / index.ts / index.js. No stdin. Limit 60 s (then the program and everything it started are killed): a server that keeps running is stopped at the limit. No internet inside the seat.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder, e.g. \"node/hello-node\" or \"angular/carddemo-ui\""},"file":{"description":"the script inside the project, e.g. \"src/index.ts\""},"args":{"description":"program arguments (max 8; letters, digits, space and _ . , : = @ # / + % ( ) * - only)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/node-test":{"post":{"operationId":"vscodeNodeTest","summary":"VS Code MCP tool vscode_node_test on your own seat: Node.js / Angular (container seat): run a project's tests with a FIXED command in the Output panel \"SteelFrame AI: Node\": Angular projects (angular.json) `ng test --watch=false` (Vitest + jsdom, no browser), other projects `vitest run`; returns TESTS PASSED / FAILED with the summary and failure details. Code coverage (provider @vitest/coverage-v8 5.0.5 is already in the seat's toolchain: never install it): plain Vitest = vitest.config test.coverage { enabled: true, thresholds }; Angular = angular.json architect.test.options { \"coverage\": true, \"runnerConfig\": \"vitest.config.ts\" } with the thresholds in that file. test (optional) = one test file inside the project, e.g. \"src/greeting.test.ts\". Limit 150 s.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder, e.g. \"node/hello-node\" or \"angular/carddemo-ui\""},"test":{"description":"optional: a test file inside the project, e.g. \"src/greeting.test.ts\""}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/node-build":{"post":{"operationId":"vscodeNodeBuild","summary":"VS Code MCP tool vscode_node_build on your own seat: Node.js / TypeScript / Angular (container seat): build a project with a FIXED command in the Output panel \"SteelFrame AI: Node\": Angular projects (angular.json) `ng build` (output in dist/), Next.js projects (next.config.*) `next build` of the project's own node_modules/next (run vscode_node_install first; limit 300 s; a project folder named like a software id is built under that base path), other projects `tsc -p tsconfig.json` (type check + compile). Returns BUILD OK or the errors (file(line,col): error TSnnnn: message). Limit 150 s.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder, e.g. \"node/hello-node\" or \"angular/carddemo-ui\""}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/node-typecheck":{"post":{"operationId":"vscodeNodeTypecheck","summary":"VS Code MCP tool vscode_node_typecheck on your own seat: Node.js / TypeScript (container seat): TYPE-CHECK a project with a FIXED command `tsc -p tsconfig.json --noEmit` (the seat's TypeScript; nothing is written) in the Output panel \"SteelFrame AI: Node\"; returns TYPECHECK OK or the errors (file(line,col): error TSnnnn: message). Limit 150 s.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder, e.g. \"node/my-app\""}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/node-lint":{"post":{"operationId":"vscodeNodeLint","summary":"VS Code MCP tool vscode_node_lint on your own seat: Node.js / TypeScript (container seat): LINT a project with a FIXED command `eslint . --max-warnings 0` (the seat's ESLint + typescript-eslint; the project's eslint.config.mjs) in the Output panel \"SteelFrame AI: Node\"; returns LINT OK or every problem (file, line, rule). Limit 150 s.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder, e.g. \"node/my-app\""}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/lang-open":{"post":{"operationId":"vscodeLangOpen","summary":"VS Code MCP tool vscode_lang_open on your own seat: C / C++, Go, shell, PHP, Lua, Kotlin, Rust, PowerShell (container seat): list the user's language folders c/, go/, shell/, php/, lua/, kotlin/, rust/ and pwsh/ (no path; only the ones this seat has), one of them (\"go\"), a project folder (e.g. \"c/hello-c\") or open a file in the VS Code editor and return its numbered lines (e.g. \"rust/hello-rust/src/main.rs\"). Read-only, except that a new seat has no language folder: the first tool call of a language creates its folder with its hello-world project (the hello-* below; without a path the listing creates nothing); the other projects are samples copied from the seat's image when a tool names one as the project. Projects: c/hello-c (gcc + Makefile, assert tests), c/record-reader (a COBOL copybook record: packed decimal COMP-3, zoned decimal and EBCDIC decoded in C; CMake + ctest), go/hello-go, go/go-postgres (pgx on the user's own PostgreSQL), shell/hello-shell (bash + bats), shell/jcl-to-shell (a SORT / SUM / report batch job as a shell pipeline), php/hello-php (Composer + PHPUnit), php/php-postgres (PDO pgsql), lua/hello-lua, kotlin/hello-kotlin (Maven), rust/hello-rust, rust/rust-postgres (the postgres crate), pwsh/hello-pwsh (Pester).","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"description":"a language folder (\"c\", \"go\", \"shell\", \"php\", \"lua\", \"kotlin\", \"rust\", \"pwsh\"), or a folder or file under one, e.g. \"c/hello-c\" (omit for all language folders)"},"from_line":{"description":"a file: the first line to return (default 1). A long file comes in pages of up to 200 lines / ~5000 characters; the result names the from_line of the next page"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/lang-write":{"post":{"operationId":"vscodeLangWrite","summary":"VS Code MCP tool vscode_lang_write on your own seat: C / C++, Go, shell, PHP, Lua, Kotlin, Rust, PowerShell (container seat): create or replace ONE file under a language folder with the given full text, typed visibly in the VS Code editor and saved to disk (\"via MCP\": written straight to disk, no editor). path = <top>/<project>/<path>/<file>, the top folder is the language: c/ (.c .h .cc .cpp .cxx .hh .hpp .hxx .inc .cmake, CMakeLists.txt, Makefile, .txt .md .json .csv .sql .yml .cpy .cbl .dat .hex), go/ (.go, go.mod, .txt .md .json .csv .sql .yml .cpy .cbl .dat .tmpl), shell/ (.sh .bash .bats .txt .md .json .csv .sql .yml .cpy .cbl .dat .jcl .conf .cfg .env), php/ (.php .phpt, composer.json, phpunit.xml, .json .xml .ini .html .css .txt .md .csv .sql .yml .cpy .cbl .dat), lua/ (.lua .txt .md .json .csv .sql .yml .cpy .cbl .dat), kotlin/ (.kt .java, pom.xml, .xml .properties .txt .md .json .csv .sql .yml .cpy .cbl .dat), rust/ (.rs, Cargo.toml, .toml .txt .md .json .csv .sql .yml .cpy .cbl .dat), pwsh/ (.ps1 .psm1 .psd1 .ps1xml .xml .txt .md .json .csv .sql .yml .cpy .cbl .dat). Never build/, bin/, target/ or vendor/, never go.sum, go.work, Cargo.lock, composer.lock or auth.json (the tools write the lock files). A new Go project needs go.mod (\"module <name>\\n\\ngo 1.27\\n\"), a Rust project Cargo.toml (edition 2024), a Kotlin project a pom.xml copied from kotlin/hello-kotlin. Then call vscode_lang_build, vscode_lang_run or vscode_lang_test.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"description":"file path, e.g. \"c/hello-c/src/hello.c\", \"go/hello-go/main.go\", \"php/hello-php/hello.php\" or \"rust/hello-rust/src/main.rs\""},"text":{"description":"the complete file content (max 60000 chars)"},"snapshot":{"description":"also return what the VS Code tab shows after the action (a free vscode_screen read; default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/lang-build":{"post":{"operationId":"vscodeLangBuild","summary":"VS Code MCP tool vscode_lang_build on your own seat: C / C++, Go, shell, PHP, Lua, Kotlin, Rust, PowerShell (container seat): build or check a project with a FIXED command in the VS Code Output panel \"SteelFrame AI: Languages\". c/: a CMakeLists.txt -> `cmake -S . -B build` + `cmake --build build`; else a Makefile -> `make`; else `gcc -std=c17` (or `g++ -std=c++20`) -Wall -Wextra -g -O0 of every source but the tests into build/<project> (gcc 12). go/: `go build -o bin/ ./...` then `go vet ./...` (Go 1.27). shell/: `bash -n` + `shellcheck`. php/: `php -l` of every .php + `composer validate`. lua/: `luac5.4 -p` of every .lua. kotlin/: Maven package (kotlin-maven-plugin, Kotlin 2.4, JDK 25; reports the main classes). rust/: `cargo build` (Rust 1.99, offline, into the shared build folder rust/.target; limit 300 s). pwsh/: the PowerShell parser + PSScriptAnalyzer. Returns BUILD OK (the programs; warnings) or BUILD FAILED with file:line:col: error: message. Limit 150 s (Rust 300 s).","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder, e.g. \"c/hello-c\", \"go/hello-go\", \"php/hello-php\" or \"rust/hello-rust\""}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/lang-install":{"post":{"operationId":"vscodeLangInstall","summary":"VS Code MCP tool vscode_lang_install on your own seat: Go, PHP, Rust (container seat): install a project's dependencies OFFLINE from the seat's own read-only package set (no internet). go/: `go mod tidy` (the module cache has github.com/jackc/pgx/v5, github.com/go-chi/chi/v5, github.com/stretchr/testify, github.com/spf13/cobra, github.com/shopspring/decimal, gopkg.in/yaml.v3, golang.org/x/text and what they need; writes go.mod + go.sum). php/: `composer update` from the seat's package repository (phpunit/phpunit 11, brick/math, monolog/monolog, league/csv and what they need; no package scripts or plugins; writes composer.lock + vendor/; composer.json may not name its own \"repositories\"). rust/: `cargo fetch` against the vendored crates (serde, serde_json, anyhow, thiserror, clap, tokio, postgres, rust_decimal, chrono, regex, rand, itertools, csv and what they need; writes Cargo.lock). Something the seat does not have fails: say so, do not retry. c/, shell/, lua/, kotlin/ (Maven resolves at build) and pwsh/ have nothing to install (refused). Limit 150 s.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"a go/, php/ or rust/ project folder, e.g. \"go/go-postgres\" or \"php/hello-php\""}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/lang-run":{"post":{"operationId":"vscodeLangRun","summary":"VS Code MCP tool vscode_lang_run on your own seat: C / C++, Go, shell, PHP, Lua, Kotlin, Rust, PowerShell (container seat): run a program with a FIXED command in the Output panel \"SteelFrame AI: Languages\"; returns the exit code and the program output (stdout+stderr). c/: the BUILT program build/<file> (default: the one program the build made; memory limit 1 GiB). go/: the BUILT program bin/<file> (never `go run`). rust/: the BUILT program (file = its name, default the package's). kotlin/: `java` with the main class (file, e.g. hello.HelloKt; default the only one) on the built classes. shell/: `bash <file>`; php/: `php <file>`; lua/: `lua5.4 <file>`; pwsh/: `pwsh -File <file>` (file = a script of the project; default <project>.<ext>, main, hello or the only one). No stdin. Limit 60 s (then the program and everything it started are killed). Build first after every change (c/, go/, rust/, kotlin/). No internet inside the seat.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder, e.g. \"c/hello-c\", \"rust/hello-rust\" or \"php/hello-php\""},"file":{"description":"c/, go/, rust/: the program name, e.g. \"hello\"; kotlin/: the main class, e.g. \"hello.HelloKt\"; shell/, php/, lua/, pwsh/: the script inside the project, e.g. \"hello.sh\""},"args":{"description":"program arguments (max 8; letters, digits, space and _ . , : = @ # / + % ( ) * - only)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/lang-test":{"post":{"operationId":"vscodeLangTest","summary":"VS Code MCP tool vscode_lang_test on your own seat: C / C++, Go, shell, PHP, Lua, Kotlin, Rust, PowerShell (container seat): run a project's tests with a FIXED command in the Output panel \"SteelFrame AI: Languages\": c/ with CMakeLists.txt `ctest --test-dir build` (build first), with a Makefile test target `make test`, else tests/test_*.c compiled with the project's non-main sources and run; go/ `go test -count=1 ./...`; shell/ `bats` on tests/; php/ `vendor/bin/phpunit` (vscode_lang_install first); lua/ `lua5.4 tests/run.lua` (or each tests/*_test.lua); kotlin/ `mvn test` (kotlin-test + JUnit 5); rust/ `cargo test` (limit 300 s); pwsh/ Pester on every *.Tests.ps1. test (optional) = a filter: ctest -R / go test -run / bats --filter / phpunit --filter / the run.lua argument / -Dtest= / cargo test <filter> / Pester full name, e.g. \"TestHello\". Returns TESTS PASSED / FAILED with the failures. Limit 150 s (Rust 300 s).","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"description":"project folder, e.g. \"go/hello-go\" or \"pwsh/hello-pwsh\""},"test":{"description":"optional: a test name or regular expression, e.g. \"TestHello\" or \"greets\""}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/db-schema":{"post":{"operationId":"vscodeDbSchema","summary":"VS Code MCP tool vscode_db_schema on your own seat: PostgreSQL (container seat): describe the user's own PostgreSQL 17 database (named after the userid): without table, every schema/table with its estimated rows and size and the database size vs its 200 MB budget; with table (\"schema.table\" or \"table\"), its columns, types, keys, indexes and exact row count. Read-only. Shown in the Output panel \"SteelFrame AI: SQL\".","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"table":{"description":"optional: a table, e.g. \"carddemo.transaction_type\""}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/db-query":{"post":{"operationId":"vscodeDbQuery","summary":"VS Code MCP tool vscode_db_query on your own seat: PostgreSQL (container seat): run ONE read-only statement (SELECT, WITH, VALUES, TABLE, SHOW or EXPLAIN) in the user's database, in a READ ONLY transaction; returns the rows as a text table (max_rows default 50, at most 200; long cells are cut; when MORE rows exist it says so). Limit 15 s (then the statement is cancelled). Shown in the Output panel \"SteelFrame AI: SQL\". Use vscode_db_exec to change anything.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sql":{"description":"one SQL statement, e.g. \"SELECT * FROM carddemo.transaction_type ORDER BY tr_type\""},"max_rows":{"description":"rows to return (default 50, max 200)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/db-exec":{"post":{"operationId":"vscodeDbExec","summary":"VS Code MCP tool vscode_db_exec on your own seat: PostgreSQL (container seat): run a SQL script (DDL / DML: CREATE TABLE, INSERT, UPDATE, DELETE, CREATE INDEX, CREATE VIEW, ...; statements separated by ;) in the user's database as ONE transaction: all statements commit together or, on the first error, NOTHING changes (the result names the failing statement). Returns each statement's status (and the rows of a RETURNING / SELECT). Not allowed: COPY (vscode_db_import loads DB2 tables), psql backslash commands, server files/programs, roles, ALTER SYSTEM, changing the time/memory limits, extensions outside the trusted list (pgcrypto, uuid-ossp, citext, hstore, pg_trgm, ...). Over the 200 MB budget only DROP/TRUNCATE/DELETE/VACUUM run. Limit 60 s. VACUUM / CREATE INDEX CONCURRENTLY must be sent alone.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sql":{"description":"the SQL script"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/db-import":{"post":{"operationId":"vscodeDbImport","summary":"VS Code MCP tool vscode_db_import on your own seat: PostgreSQL (container seat): import a DB2 table from the user's SteelFrame mainframe into the user's PostgreSQL, with a PARITY CHECK. It submits two jobs through the user's own z/OSMF door (the user's DB2 SELECT privilege applies): job 1 reads the DB2 catalog, job 2 unloads the table with DSNTIAUL (DB2 internal format: EBCDIC, packed decimal, binary integers, null indicators) into the user's own data sets <USERID>.SFPG.T*.REC/.PUNCH, computes DB2-side aggregates and a DSNUTILB DELIMITED text unload. The seat decodes the unload, converts the DDL (DECIMAL->numeric, CHAR/VARCHAR->char/varchar, GRAPHIC->char, DATE/TIME/TIMESTAMP, SMALLINT/INTEGER/BIGINT, nullability, primary key), loads with COPY in one transaction, then compares row counts, per-column counts/sums/length sums and value hashes DB2 vs PostgreSQL: PARITY OK or PARITY MISMATCH. The report opens in the editor (db/imports/<schema>.<table>/PARITY.txt) with create.sql and the two jobs. The PostgreSQL table is <creator>.<name> in lower case unless target is given; an existing one is replaced only with replace:true. Limit 300 s, 200 000 rows.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"table":{"description":"the DB2 table CREATOR.NAME, e.g. \"CARDDEMO.TRANSACTION_TYPE\" (without a creator: the user's own)"},"target":{"description":"optional PostgreSQL schema.table (default: the DB2 creator.name in lower case)"},"replace":{"description":"drop and re-create the PostgreSQL table if it exists (default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/vscode/db-import-vsam":{"post":{"operationId":"vscodeDbImportVsam","summary":"VS Code MCP tool vscode_db_import_vsam on your own seat: PostgreSQL (container seat): import a VSAM cluster (KSDS, ESDS, RRDS) or a sequential data set (or a PDS member) from the user's SteelFrame mainframe into the user's PostgreSQL THROUGH ITS COBOL COPYBOOK, with a PARITY CHECK. The mainframe's own copybook decoder reads the records as the user (the user's RACF READ on the data set and the copybook library applies; nothing is written on the mainframe): VSAM records are the program image, sequential data sets EBCDIC at rest; zoned (overpunch / SIGN SEPARATE), COMP-3 and COMP/COMP-5 numbers decode exactly. Table: PIC X -> varchar(n); PIC 9/S9 zoned and COMP-3 -> numeric(p,s) (V99 = scale 2); COMP/COMP-5 -> smallint/integer/bigint (scaled: numeric); COMP-1/COMP-2 -> real/double precision; OCCURS -> arrays; FILLER skipped; 88-levels ignored; REDEFINES: the first definition (the others are named in the report); the KSDS key -> PRIMARY KEY and alternate indexes -> indexes (otherwise rec_no, the record number, is the key); blank/LOW-VALUES numerics -> NULL, invalid numeric data -> NULL and listed. CREATE + COPY in one transaction, then PARITY OK / PARITY MISMATCH: row counts, sha256 of the records, an independent raw-byte decode of every number, per-column SUMs, and a byte proof (the mainframe re-encodes every PostgreSQL row through the copybook; it must equal the source record on every mapped field). The report opens in the editor (db/imports/<schema>.<table>/PARITY.txt) with create.sql. Default target vsam.<record name>; an existing table is replaced only with replace:true. Limit 300 s, 200 000 records. CardDemo: AWS.M2.CARDDEMO.ACCTDATA.VSAM.KSDS + CARDDEMO.COPYLIB(CVACT01Y) (accounts), CARDDATA + CVACT02Y (cards), CUSTDATA + CVCUS01Y (customers), CARDXREF + CVACT03Y, TRANSACT + CVTRA05Y (transactions), TCATBALF + CVTRA01Y.","tags":["vscode"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dataset":{"description":"the data set: a VSAM cluster or a sequential data set (or LIB(MEMBER)), e.g. \"AWS.M2.CARDDEMO.ACCTDATA.VSAM.KSDS\""},"copybook":{"description":"the record layout as LIB(MEMBER), e.g. \"CARDDEMO.COPYLIB(CVACT01Y)\""},"record":{"description":"optional: the 01-level record name when the copybook has several"},"target":{"description":"optional PostgreSQL schema.table, e.g. \"carddemo.account\" (default: vsam.<record name>)"},"replace":{"description":"drop and re-create the PostgreSQL table if it exists (default false)"}}}}}},"responses":{"200":{"description":"{ tool, seat, ok, result, snapshot?, jobid?, elapsedS? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (vscode.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"vscode.drive"}},"/api/mcp/tools":{"get":{"operationId":"mcpTools","summary":"The MCP tool catalog (generated live from the route registry; the stdio bridge and the /mcp door both serve exactly this list)","tags":["session"],"parameters":[{"name":"lane","in":"query","required":false,"schema":{"type":"string"},"description":"'persistent' (default) or 'ephemeral' (the private lane: the one-shots + RAM-only workspaces + every persistent tool projected with workspace REQUIRED)"}],"responses":{"200":{"description":"{ server: {name, version}, lane, instructions (the per-lane prose an MCP client gets from initialize), workspaceProxy (the lane's POST .../{id}/call path the stdio bridge routes workspace:<id> through), tools: [{name, description, inputSchema, annotations, scope, _binding}] }"}},"security":[]}},"/api/mcp/upload":{"post":{"operationId":"mcpUploadSource","summary":"MCP composite upload_source: batch-write source members into real cataloged datasets under the caller HLQ (allocate-if-missing PO FB80). kind cbl→<HLQ>.SOURCE, cpy→<HLQ>.COPYLIB, jcl→<HLQ>.JCL","tags":["develop"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"description":"array of { member, lines, kind: 'cbl'|'cpy'|'jcl', dsn (optional override) }"},"hlq":{"description":"target dataset-name prefix: one or more dotted qualifiers, e.g. SYNUT or SYN.UT (default: your userid)"}}}}}},"responses":{"200":{"description":"{ ok, uploaded: [{dsn, member, lines, etag}] }"},"400":{"description":"Missing/invalid items, member name or HLQ"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/mcp/compile":{"post":{"operationId":"mcpCompileProgram","summary":"MCP composite compile_program: one-shot compile+link of a COBOL program through the REAL pipeline — source into <HLQ>.SOURCE, a generated EXEC IGYWCL deck through JES2, per-step RCs, diagnostics parsed from the genuine SYSPRINT listing; the load module lands in <HLQ>.LOADLIB (persistent, visible in the web as your job/datasets). Oracle use: loadlib + syslib install the module INTO an estate library (e.g. AWS.M2.CARDDEMO.LOADLIB) with the estate's copybooks","tags":["develop"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"program":{"description":"program/member name (1-8 chars) — becomes GOPGM and the load-module name"},"lines":{"description":"COBOL source card images (omit to compile an existing member)"},"copybooks":{"description":"array of { member, lines } staged into <HLQ>.COPYLIB and searched via SYSLIB (optional)"},"parm":{"description":"compile PARM, e.g. 'SQL' (DB2 precompile) or 'CICS' (translator); auto-detected from the source when omitted"},"hlq":{"description":"dataset-name prefix: one or more dotted qualifiers, e.g. SYNUT or SYN.UT (default: your userid)"},"sourceDsn":{"description":"source PDS override (default <HLQ>.SOURCE)"},"sourceMember":{"description":"source member override (default: program)"},"loadlib":{"description":"target load library override (default <HLQ>.LOADLIB) — install the module into an estate library, e.g. AWS.M2.CARDDEMO.LOADLIB"},"syslib":{"description":"copybook library search order: an ARRAY of cataloged PDS names (one string, comma-separated, also accepted; any other type is a 400); SYS2.COBOL.COPYLIB is appended — default <HLQ>.COPYLIB + SYS2.COBOL.COPYLIB"},"timeout":{"description":"seconds to wait for the compile job (default 120, max 300); on timeout the jobid is returned for wait_job re-polling"}}}}}},"responses":{"200":{"description":"{ jobid, jobname, ok, maxcc, steps: [{name, pgm, rc}], diagnostics, loadModule, jcl, listingExcerpt? (on failure), timedOut? }"},"400":{"description":"Missing/invalid program name, lines, PARM or HLQ"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/mcp/run":{"post":{"operationId":"mcpRunProgram","summary":"MCP composite run_program: generate+submit a GO deck (EXEC PGM= with STEPLIB <HLQ>.LOADLIB and DDs from a simple JSON spec) through JES2, wait, and return the RC plus the SYSOUT spool contents","tags":["develop"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"program":{"description":"load-module name in the STEPLIB (compile_program output)"},"parm":{"description":"PARM= string passed to the program (optional)"},"dd":{"description":"DD spec object: { DDNAME: {lines: [...]} (instream) | {dsn, disp?, attrs?} | {sysout: true} | {dummy: true} } — STEPLIB and a default SYSOUT DD are generated"},"hlq":{"description":"STEPLIB HLQ (default: your userid → <HLQ>.LOADLIB)"},"steplib":{"description":"explicit STEPLIB dataset override"},"timeout":{"description":"seconds to wait (default 120, max 300)"},"tail":{"description":"max lines of each SYSOUT file returned (default 500)"}}}}}},"responses":{"200":{"description":"{ jobid, jobname, ok, maxcc, abend, steps, sysout: {ddname: content}, files, jcl, timedOut? }"},"400":{"description":"Missing/invalid program name, DD spec, PARM or HLQ"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/ephemeral/check":{"post":{"operationId":"ephemeralCheck","summary":"PRIVATE LANE check_source: compile-check inline source inside a single-use sandbox destroyed after the response — zero retention, invisible in the web","tags":["develop"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"language":{"description":"'COBOL' (default) or 'JCL'"},"lines":{"description":"source card images"},"parm":{"description":"compile PARM (optional)"}}}}}},"responses":{"200":{"description":"{ rc, diagnostics, lane, ramBacked, retained: false }"},"400":{"description":"Missing/invalid lines"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ephemeral.exec)"},"413":{"description":"Payload over the lane cap"},"429":{"description":"Lane busy"},"504":{"description":"Sandbox wall-clock timeout"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ephemeral.exec"}},"/api/ephemeral/compile":{"post":{"operationId":"ephemeralCompile","summary":"PRIVATE LANE compile_inline: compile+link inline COBOL through the REAL IGYWCL pipeline inside a single-use sandbox; the verdict/diagnostics/listing excerpt return inline and the sandbox (load module included) is destroyed — zero retention","tags":["develop"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"program":{"description":"program name (1-8 chars)"},"lines":{"description":"COBOL source card images"},"copybooks":{"description":"array of { member, lines } (optional)"},"parm":{"description":"compile PARM, e.g. 'SQL' or 'CICS' (optional)"},"timeout":{"description":"seconds (default 120, max 300)"}}}}}},"responses":{"200":{"description":"{ ok, maxcc, steps, diagnostics, listingExcerpt?, lane, ramBacked, retained: false }"},"400":{"description":"Missing/invalid program or lines"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ephemeral.exec)"},"413":{"description":"Payload over the lane cap"},"429":{"description":"Lane busy"},"504":{"description":"Sandbox wall-clock timeout"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ephemeral.exec"}},"/api/ephemeral/run":{"post":{"operationId":"ephemeralRun","summary":"PRIVATE LANE run_inline: one sandbox lease — upload inline source (+copybooks/data DDs), compile via the real IGYWCL deck, run with STEPLIB, and return RC + SYSOUT + requested output-dataset contents INLINE; the sandbox is destroyed before the response (nothing survives to be fetched later)","tags":["develop"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"program":{"description":"program name"},"lines":{"description":"COBOL source card images"},"copybooks":{"description":"array of { member, lines } (optional)"},"parm":{"description":"compile PARM (optional)"},"runParm":{"description":"PARM= for the run step (optional)"},"dd":{"description":"run-step DD spec: { DDNAME: {lines:[...]} | {dsn, disp?} | {sysout:true} | {dummy:true} }"},"outputs":{"description":"dataset names whose contents to return inline after the run (max 8)"},"timeout":{"description":"seconds (default 120, max 300)"},"tail":{"description":"max SYSOUT lines per file (default 500)"}}}}}},"responses":{"200":{"description":"{ phase, ok, compile: {maxcc, diagnostics}, jobid, maxcc, steps, sysout, outputs?, lane, ramBacked, retained: false }"},"400":{"description":"Missing/invalid program or lines"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ephemeral.exec)"},"413":{"description":"Payload over the lane cap"},"429":{"description":"Lane busy"},"504":{"description":"Sandbox wall-clock timeout"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ephemeral.exec"}},"/api/ephemeral/compile-run":{"post":{"operationId":"ephemeralCompileRun","summary":"PRIVATE LANE compile_and_run — the flagship one-shot: identical to run_inline (compile + run in one sandbox lease, everything returned inline, sandbox destroyed)","tags":["develop"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"program":{"description":"program name"},"lines":{"description":"COBOL source card images"},"copybooks":{"description":"array of { member, lines } (optional)"},"parm":{"description":"compile PARM (optional)"},"runParm":{"description":"PARM= for the run step (optional)"},"dd":{"description":"run-step DD spec (see run_inline)"},"outputs":{"description":"dataset names to return inline (max 8)"},"timeout":{"description":"seconds (default 120, max 300)"},"tail":{"description":"max SYSOUT lines per file (default 500)"}}}}}},"responses":{"200":{"description":"run_inline shape"},"400":{"description":"Missing/invalid program or lines"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ephemeral.exec)"},"413":{"description":"Payload over the lane cap"},"429":{"description":"Lane busy"},"504":{"description":"Sandbox wall-clock timeout"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ephemeral.exec"}},"/api/ephemeral/jcl":{"post":{"operationId":"ephemeralJcl","summary":"PRIVATE LANE jcl_inline: submit a full JCL deck against a single-use sandbox (seeded PROCLIB present) and get the joblog + spool files back inline — the generalization lever for any one-shot batch capability (IDCAMS, sort, utilities)","tags":["develop"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"lines":{"description":"JCL card images"},"timeout":{"description":"seconds (default 120, max 300)"},"tail":{"description":"max lines per spool file (default 500)"}}}}}},"responses":{"200":{"description":"{ jobid, jobname, status, maxcc, steps, files: {name: content}, lane, ramBacked, retained: false }"},"400":{"description":"Missing/invalid lines"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ephemeral.exec)"},"413":{"description":"Payload over the lane cap"},"429":{"description":"Lane busy"},"504":{"description":"Sandbox wall-clock timeout"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ephemeral.exec"}},"/api/account/apikeys":{"get":{"operationId":"accountApiKeys","summary":"Your own self-service API keys for MCP / API use (metadata only, never a secret): status, scopes, surface, expiry, per-key daily cap and what it spent in the last 24 h, allow-list, last use, 7-day usage; plus the presets and scopes you may choose from (clamped to your own rights), the limits, the price list, the engine endpoint, each key's setup snippets with a placeholder, your key activity trail, and how many tokens an administrator issued that act as you","tags":["account","tokens"],"responses":{"200":{"description":"{ user, keys: [{ id, name, prefix, preset, surface, scopes, created, expires, rotated, status: live|expired, capUsd, spentTodayUsd, remainingTodayUsd, allowIps, lastUsed, lastUsedIp, lastUsedDoor, wallet, usage: { calls, chargedUsd, lastCall }|null, setup }], presets: { id: { label, blurb, scopes } }, scopes: [{ id, desc }], surfaces, limits, pricing: { mode, writeUsd, compileUsd, runUsd, coreHourUsd, freeCpuS, dailyCapUsd, retryFreeS }, endpoint: { mcp, api, docs, rest }, events: [...], adminIssued, canMint, reason }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true},"post":{"operationId":"accountApiKeyCreate","summary":"Mint an API key for YOURSELF. The secret is returned ONCE (sf_ + 48 hex) and stored hashed; the response carries the key's metadata and copy-pasteable setup snippets (Claude Code, MCP JSON, the stdio bridge, curl, a first prompt) with your real endpoint and key filled in. Scopes: a preset (readonly | developer | full) or an explicit list, always clamped to your own ordinary rights (never admin, never act-as). Refused with an API key, a seat token or a z/OSMF session. Cookie callers pass the CSRF gate. Rate-limited (default 10 mints/hour) and capped per user (default 10 live keys)","tags":["account","tokens"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"label, 1..40 printable characters (e.g. \"claude-code laptop\", \"ci nightly\")"},"preset":{"description":"readonly | developer (default) | full | custom"},"scopes":{"description":"explicit scope list (preset custom)"},"surface":{"description":"any (default) | mcp (the MCP tool surface only) | rest (REST only; the /mcp door refuses it)"},"expiresDays":{"description":"integer days (default 90) or null for no expiry"},"capUsd":{"description":"per-key rolling 24-hour spend cap in USD (default the engine's per-token cap; bounded by the limits)"},"allowIps":{"description":"optional list of IP addresses / CIDRs the key may be used from"}}}}}},"responses":{"200":{"description":"201 { key (metadata, see GET), secret, setup } — the secret appears here only"},"400":{"description":"Bad name / scopes outside self-service / bad expiry, cap, surface or allow-list"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"409":{"description":"Key limit reached"},"413":{"description":"Body over 4 KB"},"429":{"description":"Too many mints for this user (Retry-After)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/apikeys/usage":{"get":{"operationId":"accountApiKeyUsage","summary":"Your own programmatic usage per key from the billing usage log (?days=7|30, default 7): per key calls, charged calls, USD (6 decimals), by class, first/last call (a revoked key is attributed by its id); the recent rows (newest first, 100); totals. Rows without a key (password sessions through the stdio bridge) are grouped as session","tags":["account","tokens"],"responses":{"200":{"description":"{ days, mode, keys: [{ keyId, name, revoked, calls, charged, chargedUsd, byClass, firstCall, lastCall }], totals: { calls, chargedUsd }, rows: [...] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/apikeys/usage.csv":{"get":{"operationId":"accountApiKeyUsageCsv","summary":"The same per-call rows as /api/account/apikeys/usage as a CSV download (?days=7|30|90), for expense reports: time, key id, key name, door, tool, class, status, target, CPU seconds, USD (6 decimals), charged, reason, phase","tags":["account","tokens"],"responses":{"200":{"description":"text/csv (UTF-8 BOM, CRLF), Content-Disposition attachment"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/apikeys/{id}":{"put":{"operationId":"accountApiKeyUpdate","summary":"Change one of your keys: name, per-key daily cap, allow-list, expiry (expiresDays from now, or null for none). Scopes and surface are fixed — mint a new key or rotate instead. Takes effect at once (a live session of the key sees the new cap). Rate-limited per user","tags":["account","tokens"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"key id from the list"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"new label (optional)"},"capUsd":{"description":"new daily cap (optional)"},"allowIps":{"description":"new allow-list, [] = any address (optional)"},"expiresDays":{"description":"days from now, or null for no expiry (optional)"}}}}}},"responses":{"200":{"description":"{ key, updated: [field...] }"},"400":{"description":"Bad value"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No such key of yours"},"429":{"description":"Too many account writes (Retry-After)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true},"delete":{"operationId":"accountApiKeyDelete","summary":"Revoke one of your keys. Effective immediately on every door (the next call with it answers 401). Rate-limited per user","tags":["account","tokens"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"key id from the list"}],"responses":{"200":{"description":"{ ok, id }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No such key of yours"},"429":{"description":"Too many account writes (Retry-After)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/apikeys/{id}/rotate":{"post":{"operationId":"accountApiKeyRotate","summary":"Rotate one of your keys: a new secret (shown once) under the same id, scopes, cap and settings; the old secret stops working immediately. An expired key can be rotated with a fresh expiry (expiresDays, default 90 when it had one). Rate-limited per user","tags":["account","tokens"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"key id from the list"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"expiresDays":{"description":"optional new expiry in days (null = no expiry); default keeps the current one, or 90 days when the key had expired"}}}}}},"responses":{"200":{"description":"{ key, secret, setup }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"No such key of yours"},"429":{"description":"Too many account writes (Retry-After)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/tokens":{"post":{"operationId":"createToken","summary":"Mint a persistent API token with an explicit scope list; admin callers may mint on behalf of a user (plane gateways do — audit then carries the real user)","tags":["tokens"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"token label (e.g. \"ide\", \"ci\")"},"scopes":{"description":"array from the x-scopes list, or [\"*\"]"},"user":{"description":"act-as userid (optional; must exist in the logon map)"}}}}}},"responses":{"200":{"description":"{ id, name, token, scopes, user } — token value is shown only once, stored hashed"},"400":{"description":"Missing name, unknown scope, or unknown act-as user"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"},"get":{"operationId":"listTokens","summary":"List API tokens (metadata only, never the token value)","tags":["tokens"],"responses":{"200":{"description":"[{ id, name, scopes, user, created }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"}},"/api/tokens/{id}":{"delete":{"operationId":"deleteToken","summary":"Revoke an API token","tags":["tokens"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"token id from creation/list"}],"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"},"404":{"description":"No such token"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"}},"/api/vault":{"get":{"operationId":"listVaultSecrets","summary":"Secrets vault posture: provider, key-configured flag, and secret METADATA (name/created/rotated) — never values","tags":["vault"],"responses":{"200":{"description":"{ provider, configured, secrets: [{ name, created, rotated }] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"}},"/api/vault/secrets/{name}":{"put":{"operationId":"putVaultSecret","summary":"Store (or rotate) a secret in the region vault — encrypted at rest (AES-256-GCM), value never readable back through the API","tags":["vault"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"secret name (letters, digits, . _ -; case-sensitive)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"value":{"description":"the secret value (string)"}}}}}},"responses":{"200":{"description":"{ name, rotated } — rotated=true when an existing secret was replaced"},"400":{"description":"Invalid name or empty value"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"},"503":{"description":"Vault not configured (no key material)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"},"delete":{"operationId":"deleteVaultSecret","summary":"Delete a secret from the region vault","tags":["vault"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"secret name"}],"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"},"404":{"description":"No such secret"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"}},"/api/system/info":{"get":{"operationId":"systemInfo","summary":"Instance information: product/release, uptime, data root, subsystem status, engine-wide security posture","tags":["system"],"responses":{"200":{"description":"{ product, release, apiVersion, started, uptimeSeconds, pid, osUser, node, port, dataRoot, catalogDatasets, jes2Jobs, subsystems, security: { posture, enforce, cmdsec, ressec, secprfx, datasetProtect: false|FAILURES|WARNING } (the ENGINE-WIDE W7 posture — there are no per-region security profiles; datasetProtect is the separate SETROPTS PROTECTALL switch that binds on API reads/writes, batch DD OPEN and search_source whatever the posture), debug: { allowDynamic } (the region's dynamic-debug gate), entitlement: { org, plan, seats, cores, maxInstances, expires, verified } | null (engine-local license doc; verified null = no public key to check) }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.read"}},"/api/jes/utilities":{"get":{"operationId":"jesUtilities","summary":"The utility alias table (read-only): every registered built-in program name with its implementing module and alias grouping (names sharing a handler — SORT/ICEMAN/IERRCO00, IEBGENER/ICEGENER, ZWSRACF/SFRACF). This registry IS what EXEC PGM= dispatch consults before the loadlib search","tags":["jobs"],"responses":{"200":{"description":"[{ name, module (file:line of the registering module), aliasOf (primary name when the row is an alias, else null) }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.read"}},"/api/region/validate":{"post":{"operationId":"regionValidate","summary":"Region-config Validate action (the ESCWA/ESMAC Validate page): lint a region definition and compute auto-fixes. Safe fixes (casing, type coercions, duplicate-listener suffixing) are pre-applied in the returned fixed config; behavior-changing ones are suggested only. No body config = validate THIS engine's region.json; apply:true persists the fixed config back to it","tags":["system"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"config":{"description":"a region.json-shaped object to validate (optional — default: this engine's region.json)"},"apply":{"description":"true to write the fixed config back to this engine's region.json (ignored when a body config was supplied; takes effect at next boot)"}}}}}},"responses":{"200":{"description":"{ source, problems: [{ item, problem, fix, applied }], changed, fixed, written }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.admin)"},"404":{"description":"No region.json in the data root (and no body config supplied)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.admin"}},"/api/fileshare/locks":{"get":{"operationId":"fileshareLocks","summary":"The Fileshare-class lock table (W2.1/A6.3): every record with a live hold or waiter in the region's record-lock broker (SHR/EX mode, holder owners, wait queue with ages), broker counters (grants/waits/timeouts/deadlocks/breaks), plus the file-level SYSDSN/VSAMWR ENQ contention snapshot — the ESCWA \"Locks\" view","tags":["fileshare"],"responses":{"200":{"description":"{ records: [{ res (base cluster dsn), key (hex primary key | R<rrn>), holders: [{ owner, mode: SHR|EX, heldMs }], waiters: [{ owner, mode, waitedMs }] }], stats: { granted, waits, timeouts, deadlocks, breaks }, txTimeoutMs, files: [{ qname, rname, holders, waiters }] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.read"}},"/api/fileshare/status":{"get":{"operationId":"fileshareStatus","summary":"Fileshare recovery posture (W2.2/A6.3b): the dbase registry (files under journal care with their /o option letters and update sequence numbers), the current recovery log (.Lnn generation, flush cadence, size), backup directory, and the last rollforward report","tags":["fileshare"],"responses":{"200":{"description":"{ configured, log: { name, file (.Lnn), gen, flushEvery, diskPct, sizeBytes, open } | null, backupDir, txTimeoutSec, files: [{ dsn, log, seq, tp, seq }], lastRecovery }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.read"}},"/api/fileshare/config":{"post":{"operationId":"fileshareConfig","summary":"The `fs /d dbase.ref` verb family: addFile (/f dsn [/o l|s|t — each letter DISABLES logging/sequence-numbers/transaction-processing]), eraseFile (/f /e), setLog (/l name [/lc flushEvery] [/p diskPct] — a name with an extension is corrected with FS180-W), eraseLog, setBackup (/backup dir), setTxTimeout (/t seconds, 0 disables the idle-transaction break)","tags":["fileshare"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"description":"'addFile' | 'eraseFile' | 'setLog' | 'eraseLog' | 'setBackup' | 'setTxTimeout'"},"dsn":{"description":"cataloged VSAM cluster (addFile/eraseFile)"},"options":{"description":"MF option letters for addFile, e.g. 'l', 'tl' (each PRESENT letter disables the feature)"},"name":{"description":"recovery log name (setLog)"},"flushEvery":{"description":"log flush cadence in records (setLog, default 100 — the /lc option)"},"diskPct":{"description":"free-disk warning threshold percent (setLog, default 5 — the /p option)"},"dir":{"description":"backup directory (setBackup; null/empty clears it)"},"seconds":{"description":"transaction timeout in seconds (setTxTimeout)"}}}}}},"responses":{"200":{"description":"action-shaped result; setLog may carry warning FS180-W"},"400":{"description":"unknown action / dsn not a cataloged VSAM cluster / SQL-hosted cluster (MFDBFH recovery belongs to the RDBMS)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.admin"}},"/api/fileshare/backup":{"post":{"operationId":"fileshareBackup","summary":"Hot backup NOW: copy every registered file to the backup directory (each under its EXCLUSIVE writer lease — a consistent committed image), archive the current recovery log as .Bnn and continue on .L(nn+1). The same sequence runs automatically at every startup when a backup directory is configured","tags":["fileshare"],"responses":{"200":{"description":"{ files: [dsn], dir, log (the new .Lnn) }"},"400":{"description":"no recovery log / no backup directory configured"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.admin"}},"/api/fileshare/rollforward":{"post":{"operationId":"fileshareRollforward","summary":"Rollforward recovery (fs /r): restore every registered file from the backup directory, then reapply the COMMITTED journal units logged since that backup in order — sequence continuity verified per file (FS038-S on mismatch), in-flight units at crash time NOT reapplied (FS290-W), optional point-in-time stop (/dt). Runs automatically at boot when the previous session left no terminating record","tags":["fileshare"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dt":{"description":"point-in-time stop, YYMMDDHHMMSS (the /dt option; omit = full replay)"},"verbose":{"description":"true for per-unit detail (/v)"}}}}}},"responses":{"200":{"description":"{ backupTs, log, upTo, files, unitsApplied, opsApplied, warnings (FS290-W...), errors (FS038-S...), detail }"},"400":{"description":"no log/backup configured, no manifest, bad /dt"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.admin"}},"/api/uow":{"get":{"operationId":"uowList","summary":"The 2PC coordinator's unit-of-work monitor (W2.4/A4.14): in-flight UOWs (state active/preparing/prepared/committing with each enlisted resource manager's vote), IN-DOUBT units (a forced commit decision whose phase-2 legs are not all complete — re-drivable), and the coordinator counters. Protocol is presumed abort: only commit decisions are logged; prepared state without a decision backs out at restart","tags":["uow"],"responses":{"200":{"description":"{ live: [{ id, owner, state, started, meta, rms: [{ name, vote, state, error }] }], indoubt: [{ id, verdict, decidedAt, owner, meta, rms: [{ name, done, error }] }], stats: { begun, committed, backedOut, vetoes, onePhase, twoPhase, readOnly, redriven, heuristics } }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.read"}},"/api/uow/resolve":{"post":{"operationId":"uowResolve","summary":"Operator resolution of an IN-DOUBT unit of work (the CEMT SET UOW analog): action 'commit' re-drives the decided outcome's unfinished legs now; action 'backout' is a HEURISTIC abandonment of a decided-commit's unfinished legs (recorded in the in-doubt log — the heuristic-mixed hazard is the operator's, exactly like SET UOW BACKOUT against an in-doubt unit)","tags":["uow"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"description":"the in-doubt UOW id (from GET /api/uow)"},"action":{"description":"'commit' (default — re-drive now) | 'backout' (heuristic)"}}}}}},"responses":{"200":{"description":"{ outcome: 'committed' | 'in-doubt' (some legs still failing, with per-leg errors) | 'heuristic-backout' (with warning) }"},"400":{"description":"unknown UOW id / bad action"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.admin"}},"/api/cics/journals":{"get":{"operationId":"cicsJournals","summary":"User journals (EXEC CICS WRITE JOURNALNAME/JOURNALNUM targets): per-journal record/byte tallies, last write, and the journal-name policy disposition (default mapping vs installed JOURNALMODEL)","tags":["cics"],"responses":{"200":{"description":"[{ name, records, bytes, lastWrite, lastJtypeid, model: 'default' | 'model' | 'none-matched' }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.read"}},"/api/users":{"get":{"operationId":"listUsers","summary":"Logon-capable userids (no passwords; full RACF detail is under /api/racf)","tags":["system"],"responses":{"200":{"description":"[{ user, revoked }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.read"},"post":{"operationId":"addUser","summary":"Add a logon user (the plane gateway's SSO JIT-provisioning path; RACF ADDUSER via TSO remains the native route)","tags":["system"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"user":{"description":"userid (1-8 chars)"},"password":{"description":"initial password"}}}}}},"responses":{"200":{"description":"{ ok, user }"},"400":{"description":"Bad userid or user exists"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"}},"/api/admin/registrations":{"get":{"operationId":"listRegistrations","summary":"Self-service registrations reconciled against RACF and the logon map (email masked)","tags":["system"],"responses":{"200":{"description":"{ count, missing, registrations: [{ user, registered, email (masked), inRacf, inLogonMap, revoked }] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"}},"/api/admin/enrollments":{"get":{"operationId":"adminEnrollments","summary":"Course enrollments for the operator: per course, the enrolled and waitlisted counts and the userids (no emails or other PII). ?course=CS100 for one course","tags":["system"],"parameters":[{"name":"course","in":"query","required":false,"schema":{"type":"string"},"description":"optional course code (e.g. CS100)"}],"responses":{"200":{"description":"{ courses: [{ code, title, retired, enrolled, waitlisted, users: [{ user, status, at }] }], totals: { users, enrolled, waitlisted } }"},"400":{"description":"Invalid course code"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"},"404":{"description":"No such course in the catalog"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"}},"/api/admin/certs":{"get":{"operationId":"adminCerts","summary":"Issued certificates for the operator: id, userid, course, issue time and status (valid / revoked / signature-invalid). No names or emails. Also the signing-key state","tags":["system"],"responses":{"200":{"description":"{ certificates: [{ certId, user, code, issuedAt, status, revokedAt }], signing: { configured, keyId, keys } }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"}},"/api/admin/certs/{certId}/revoke":{"post":{"operationId":"adminCertRevoke","summary":"Revoke a certificate (e.g. evidence found to be someone else's): the public verify page then reports it revoked. The record and its signature are kept","tags":["system"],"parameters":[{"name":"certId","in":"path","required":true,"schema":{"type":"string"},"description":"SF-XXXX-XXXX-XXXX-XXXX"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"description":"optional short reason (kept with the record, not shown publicly)"}}}}}},"responses":{"200":{"description":"{ certId, status: \"revoked\", revokedAt, already? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"},"404":{"description":"No such certificate"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"}},"/api/admin/certs/rotate-key":{"post":{"operationId":"adminCertRotateKey","summary":"Generate a new certificate signing key (Ed25519, stored in the state-root certificate vault). The previous public key stays published, so earlier certificates keep verifying. Back up <state>/certs and the vault key material afterwards","tags":["system"],"responses":{"200":{"description":"{ keyId, previous }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"},"503":{"description":"Certificate signing is not configured (no vault key material)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"}},"/api/admin/registrations/{user}":{"delete":{"operationId":"deleteRegistration","summary":"Remove a row from the self-service registry (frees the email for re-registration). Does NOT delete the RACF user — use DELUSER for that","tags":["system"],"parameters":[{"name":"user","in":"path","required":true,"schema":{"type":"string"},"description":"registered userid"}],"responses":{"200":{"description":"{ ok, user }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"},"404":{"description":"No such registration"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"}},"/api/syslog":{"get":{"operationId":"syslog","summary":"Console syslog (last 300 lines). RACF SPECIAL/OPERATIONS: the whole system log; any other user: only the lines about itself (its own jobs, its own logons and submissions)","tags":["system"],"responses":{"200":{"description":"[string]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.read"}},"/api/ccsid/table/{ccsid}":{"get":{"operationId":"ccsidTable","summary":"Generated CCSID conversion-table artifact (the server/ccsid-tables JSON the engine itself loads; browser mirror source of truth)","tags":["system"],"parameters":[{"name":"ccsid","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"{ ccsid, name, class, subchar, subchar1, sb, db, meta }"},"404":{"description":"no generated table for that CCSID"}},"security":[]}},"/api/nls":{"get":{"operationId":"nlsLanguages","summary":"Available product-chrome language sets (ENU + loaded catalogs) with authoring tier and coverage","tags":["system"],"responses":{"200":{"description":"{ languages: [{ lang, translated, total, authoredBy }] }"}},"security":[]}},"/api/nls/{lang}":{"get":{"operationId":"nlsCatalog","summary":"Product-chrome NLS catalog for a language (flat key->text; per-key fallback to English happens client-side; unknown languages are a loud 404, never a guess)","tags":["system"],"parameters":[{"name":"lang","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"{ lang, entries: { key: text } }"},"404":{"description":"unknown language code"}},"security":[]}},"/api/catalog":{"get":{"operationId":"catalogLanguages","summary":"Valid-construct catalogs available (one per language). Reference data — the honest supported/unsupported/invalid map + per-kind coverage. Reads server/catalog/<lang>.json live.","tags":["system"],"responses":{"200":{"description":"{ languages: [{ lang, language, completeness, counts }] }"}},"security":[]}},"/api/catalog/{lang}":{"get":{"operationId":"catalogLang","summary":"The full valid-construct catalog for a language (HLASM today): every entry (name/kind/format/opcode/implemented/action/docRef) plus the code-verified coverage summary. Served straight from server/catalog/<lang>.json — any edit to the JSON reflects on reload, no data duplicated. Unknown languages are a loud 404, never a guess.","tags":["system"],"parameters":[{"name":"lang","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"{ language, authority, completeness, kinds, counts, coverage, entries }"},"404":{"description":"unknown catalog language"}},"security":[]}},"/api/ccsid/terminal":{"get":{"operationId":"ccsidTerminal","summary":"Terminal-session code page (the ZOSWEB/STEELFRAME_TN3270_CCSID knob, default 37) — the web terminal mirrors the wire door's session CCSID (plan §4.4 3270 row). With ?lang=, a DBCS-bearing UI language whose configured session CCSID cannot carry DBCS gets the documented NLS-plan-§7 pairing, and an SBCS-Latin language gets its recommended national EBCDIC page (German -> 273, French -> 297, …) when that differs from the configured SBCS page (paired:true + configured); language and CCSID stay separate knobs — a DBCS-capable configured CCSID is kept as-is for any language, and a recommendation without a generated converter table keeps the configured page","tags":["system"],"responses":{"200":{"description":"{ ccsid, name, mixed, sbcs, dbcs, paired?, configured? }"}},"security":[]}},"/api/health":{"get":{"operationId":"health","summary":"Liveness/readiness probe (public)","tags":["system"],"responses":{"200":{"description":"{ status: 'UP', release, version, apiVersion, uptimeSeconds, subsystems }"}},"security":[]}},"/api/system/loopguard/selftest":{"post":{"operationId":"loopguardSelftest","summary":"Deliberately stall the event loop for blockMs (watchdog self-test; armed only with STEELFRAME_LOOPGUARD_SELFTEST=1)","tags":["system"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"blockMs":{"description":"milliseconds to block the main thread synchronously (1..60000)"}}}}}},"responses":{"200":{"description":"{ blockedMs, loop }"},"400":{"description":"blockMs out of range"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.admin)"},"404":{"description":"Self-test not armed"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.admin"}},"/metrics":{"get":{"operationId":"metrics","summary":"Prometheus metrics (text format 0.0.4, public: counts only)","tags":["system"],"responses":{"200":{"description":"each series under BOTH prefixes (rename step 1): {zosweb|steelframe}_info, _uptime_seconds, _sessions_active, _api_tokens, _catalog_datasets, _jes_jobs{status}, _mq_queue_depth{qmgr,queue}, _ims_queue_depth{trancode}, _api_requests_total{op,status}"}},"security":[]}},"/api/listeners":{"get":{"operationId":"listListeners","summary":"Listener registry: name/type/endpoint/status rows for every network endpoint, generated from live config (TLS key material redacted)","tags":["system"],"responses":{"200":{"description":"[{ name, cp, connectorType: web|json-svc|websocket|sfapp-deploy|ftp-jes|pgwire|tn3270e|na, endpoint: { proto, host, port }, actual, status: Started|Stopped|Disabled|Blocked|NotResponding, lastStatusChange (ISO timestamp of the last observed status transition), configBlob, config (imported rows: { sections (verbatim INI), per-type parse — web: paths/allow/security/options, tn3270e: tn3270e/defaultTerminalType/dcas…, json-svc: operation/responseHeaders — plus recognizedUnapplied[] and unknown[] honesty lists), tls, source: builtin|imported, description, lifecycle (boolean: start/stop verbs available) }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.read"}},"/api/listeners/{name}":{"get":{"operationId":"getListener","summary":"One listener registry row (status evaluated live)","tags":["system"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"listener name from the registry list"}],"responses":{"200":{"description":"listener row"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.read)"},"404":{"description":"No such listener"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.read"}},"/api/listeners/{name}/start":{"post":{"operationId":"startListener","summary":"Start a stopped listener (W8 lifecycle verb — rows whose protocol module registered a start handle, tn3270e first; others answer 409)","tags":["system"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"listener name from the registry list"}],"responses":{"200":{"description":"listener row with status re-evaluated live"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.admin)"},"404":{"description":"No such listener"},"409":{"description":"No lifecycle handle / already started / bind failed"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.admin"}},"/api/listeners/{name}/stop":{"post":{"operationId":"stopListener","summary":"Stop a started listener: close the server and end its live sessions (W8 lifecycle verb)","tags":["system"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"listener name from the registry list"}],"responses":{"200":{"description":"listener row with status re-evaluated live"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.admin)"},"404":{"description":"No such listener"},"409":{"description":"No lifecycle handle / not started"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.admin"}},"/api/instances":{"post":{"operationId":"createInstance","summary":"Provision a scratch child instance and wait until it is healthy","tags":["instances"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"label (default = id)"},"seed":{"description":"'fresh' (seeded new system, default) or 'clone' (copy of this instance's data root)"},"ttlSeconds":{"description":"auto-dispose after N seconds (1..86400, optional)"},"description":{"description":"free-text operator description (the region-grid Description column, max 200 chars, optional)"}}}}}},"responses":{"200":{"description":"{ id, name, seed, description, status: RUNNING|FAILED, url, port, ftpPort, dataDir, created, ttlSeconds }"},"400":{"description":"Bad seed/ttl"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (instances.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"instances.admin"},"get":{"operationId":"listInstances","summary":"List ephemeral child instances (your own; a SPECIAL admin sees all)","tags":["instances"],"responses":{"200":{"description":"[instance]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (instances.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"instances.read"}},"/api/instances/{id}":{"get":{"operationId":"getInstance","summary":"One child instance (FAILED instances include their boot log tail)","tags":["instances"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"instance id"}],"responses":{"200":{"description":"instance"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (instances.read)"},"404":{"description":"No such instance"}},"security":[{"bearerAuth":[]}],"x-required-scope":"instances.read"},"delete":{"operationId":"destroyInstance","summary":"Dispose a child instance: kill the process, delete its data dir","tags":["instances"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"instance id"}],"responses":{"200":{"description":"{ ok, id }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (instances.admin)"},"404":{"description":"No such instance"}},"security":[{"bearerAuth":[]}],"x-required-scope":"instances.admin"}},"/api/instances/{id}/stop":{"post":{"operationId":"stopInstance","summary":"Stop a child instance in place (process killed; data dir and registry entry kept, restartable) — the Operate region-grid inline stop","tags":["instances"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"instance id"}],"responses":{"200":{"description":"instance (status STOPPED)"},"400":{"description":"Instance is not running"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (instances.admin)"},"404":{"description":"No such instance"}},"security":[{"bearerAuth":[]}],"x-required-scope":"instances.admin"}},"/api/instances/{id}/start":{"post":{"operationId":"startInstance","summary":"Start a stopped/down child instance on its original ports and data dir; waits until healthy","tags":["instances"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"instance id"}],"responses":{"200":{"description":"instance (status RUNNING|FAILED)"},"400":{"description":"Instance already running"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (instances.admin)"},"404":{"description":"No such instance"}},"security":[{"bearerAuth":[]}],"x-required-scope":"instances.admin"}},"/api/snapshots":{"post":{"operationId":"createSnapshot","summary":"Take a consistent snapshot: JES2 drains (running job finishes), then the data root is tarred","tags":["snapshots"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"label (default = id)"}}}}}},"responses":{"200":{"description":"{ id, name, created, bytes, sha256, quiesced, jesQueuedAtSnap }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (snapshots.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"snapshots.admin"},"get":{"operationId":"listSnapshots","summary":"List snapshots","tags":["snapshots"],"responses":{"200":{"description":"[snapshot meta]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (snapshots.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"snapshots.read"}},"/api/snapshots/{id}":{"get":{"operationId":"getSnapshot","summary":"One snapshot (metadata incl. sha256)","tags":["snapshots"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"snapshot id"}],"responses":{"200":{"description":"snapshot meta"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (snapshots.read)"},"404":{"description":"No such snapshot"}},"security":[{"bearerAuth":[]}],"x-required-scope":"snapshots.read"},"delete":{"operationId":"deleteSnapshot","summary":"Delete a snapshot archive + metadata","tags":["snapshots"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"snapshot id"}],"responses":{"200":{"description":"{ ok, id }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (snapshots.admin)"},"404":{"description":"No such snapshot"}},"security":[{"bearerAuth":[]}],"x-required-scope":"snapshots.admin"}},"/api/snapshots/{id}/download":{"get":{"operationId":"downloadSnapshot","summary":"Download the snapshot archive (tar.gz; verify against the meta sha256)","tags":["snapshots"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"snapshot id"}],"responses":{"200":{"description":"tar.gz bytes"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (snapshots.read)"},"404":{"description":"No such snapshot"}},"security":[{"bearerAuth":[]}],"x-required-scope":"snapshots.read"}},"/api/snapshots/{id}/restore":{"post":{"operationId":"restoreSnapshot","summary":"Boot the snapshot as an ephemeral child instance (in-place restore: tools/restore.mjs offline)","tags":["snapshots"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"snapshot id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"instance label (optional)"},"ttlSeconds":{"description":"auto-dispose (optional)"}}}}}},"responses":{"200":{"description":"instance (see createInstance)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (snapshots.admin)"},"404":{"description":"No such snapshot"}},"security":[{"bearerAuth":[]}],"x-required-scope":"snapshots.admin"}},"/api/apps":{"post":{"operationId":"appPackage","summary":"Package an application version from the live estate (datasets under the given HLQ prefixes)","tags":["apps"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"application name"},"version":{"description":"version label (immutable once created)"},"description":{"description":"free text (optional)"},"hlqs":{"description":"dataset name prefixes to package, e.g. ['CARDDEMO', 'AWS.M2.CARDDEMO']"}}}}}},"responses":{"200":{"description":"{ name, version, created, bytes, sha256, summary }"},"400":{"description":"Bad name/version, version exists, or no datasets under the prefixes"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.write"},"get":{"operationId":"appList","summary":"List applications in the registry","tags":["apps"],"responses":{"200":{"description":"[{ name, versions, latest, updated }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.read"}},"/api/apps/upload":{"post":{"operationId":"appUpload","summary":"Import a .sfapp bundle (raw tar.gz body); content sha256s are verified before it enters the registry","tags":["apps"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"(raw)":{"description":"the .sfapp bytes as the request body"}}}}}},"responses":{"200":{"description":"bundle meta"},"400":{"description":"Not an sfapp, integrity failure, or version exists"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.write)"},"413":{"description":"Body over the upload cap"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.write"}},"/api/apps/{name}":{"get":{"operationId":"appVersions","summary":"Version history of one application","tags":["apps"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"application name"}],"responses":{"200":{"description":"[bundle meta]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.read)"},"404":{"description":"No such application"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.read"}},"/api/apps/{name}/deployments":{"get":{"operationId":"appDeployments","summary":"Deployment history of an application (deploys and rollbacks, newest first)","tags":["apps"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"application name"}],"responses":{"200":{"description":"[deployment record]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.read"}},"/api/apps/{name}/deployments/{id}":{"get":{"operationId":"appDeployment","summary":"One deployment record: per-step status with the target jobids (poll while state=RUNNING)","tags":["apps"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"application name"},{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"deployment id"}],"responses":{"200":{"description":"deployment record"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.read)"},"404":{"description":"No such deployment"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.read"}},"/api/apps/{name}/{version}/deploy":{"post":{"operationId":"appDeploy","summary":"Deploy a bundle version to a target system: allocate + load source + seed data + assemble BMS + compile-link every COBOL program (real JCL jobs on the target) + install CSD. Returns immediately; poll the deployment record","tags":["apps"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"application name"},{"name":"version","in":"path","required":true,"schema":{"type":"string"},"description":"version label"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"target":{"description":"{ url?, instanceId?, token?, user?, password? } — default: this system with the caller’s own token"},"options":{"description":"{ loadlib (default IBMUSER.LOADLIB), replaceData (default false: live data kept on redeploy), excludePrograms: [names] (skip programs that intentionally do not compile) }"}}}}}},"responses":{"200":{"description":"deployment record (state RUNNING)"},"400":{"description":"No such version, target unreachable, or deploy already in progress for this app+target"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.admin"}},"/api/apps/{name}/rollback":{"post":{"operationId":"appRollback","summary":"Roll back the last successful deploy on a target: restore the pre-deploy load library and replaced CSD entries (source members and seeded data stay — load-library-level rollback)","tags":["apps"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"application name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"target":{"description":"same shape as appDeploy"}}}}}},"responses":{"200":{"description":"rollback deployment record"},"400":{"description":"No successful deployment on that target"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.admin"}},"/api/apps/{name}/diff":{"get":{"operationId":"appDiff","summary":"Source-level diff between two versions (members added/removed/changed with line diffs, dataset and CSD deltas)","tags":["apps"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"application name"},{"name":"from","in":"query","required":false,"schema":{"type":"string"},"description":"base version"},{"name":"to","in":"query","required":false,"schema":{"type":"string"},"description":"other version"}],"responses":{"200":{"description":"{ members, datasets, csd }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.read)"},"404":{"description":"No such version"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.read"}},"/api/apps/{name}/{version}":{"get":{"operationId":"appManifest","summary":"Bundle meta + full manifest of one version","tags":["apps"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"application name"},{"name":"version","in":"path","required":true,"schema":{"type":"string"},"description":"version label"}],"responses":{"200":{"description":"{ meta, manifest }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.read)"},"404":{"description":"No such version"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.read"},"delete":{"operationId":"appDelete","summary":"Delete one bundle version from the registry","tags":["apps"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"application name"},{"name":"version","in":"path","required":true,"schema":{"type":"string"},"description":"version label"}],"responses":{"200":{"description":"{ ok, name, version }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.admin)"},"404":{"description":"No such version"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.admin"}},"/api/apps/{name}/{version}/download":{"get":{"operationId":"appDownload","summary":"Download the .sfapp bundle (verify against the meta sha256)","tags":["apps"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"application name"},{"name":"version","in":"path","required":true,"schema":{"type":"string"},"description":"version label"}],"responses":{"200":{"description":"tar.gz bytes"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.read)"},"404":{"description":"No such version"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.read"}},"/api/onboard":{"post":{"operationId":"onboardCreate","summary":"Start an estate onboarding (the rehost funnel)","tags":["onboard"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"onboarding/application name"},"hlq":{"description":"target HLQ for loaded libraries (default: name)"}}}}}},"responses":{"200":{"description":"onboarding state"},"400":{"description":"Bad name"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.write"},"get":{"operationId":"onboardList","summary":"List onboardings (state + compile tallies)","tags":["onboard"],"responses":{"200":{"description":"[onboarding head]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.read"}},"/api/onboard/{id}":{"get":{"operationId":"onboardGet","summary":"Full onboarding state (plan, load, compile results)","tags":["onboard"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"onboarding id"}],"responses":{"200":{"description":"onboarding state"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.read)"},"404":{"description":"No such onboarding"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.read"},"delete":{"operationId":"onboardDelete","summary":"Delete an onboarding (staged files included; loaded datasets stay)","tags":["onboard"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"onboarding id"}],"responses":{"200":{"description":"{ ok, id }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.write)"},"404":{"description":"No such onboarding"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.write"}},"/api/onboard/{id}/upload":{"post":{"operationId":"onboardUpload","summary":"Upload an estate archive (zip / tar.gz / single file as raw body; ?filename= names it). Big estates: use FTP (TYPE I + SITE RECFM/LRECL) instead","tags":["onboard"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"onboarding id"}],"responses":{"200":{"description":"{ ok, stagedFiles }"},"400":{"description":"Bad archive (zip64 unsupported — use FTP)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.write)"},"404":{"description":"No such onboarding"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.write"}},"/api/onboard/{id}/plan":{"post":{"operationId":"onboardPlan","summary":"Classify the staged estate and build the readiness plan: members by language, program facts, missing copybooks, blocked jobs, VSAM geometry harvested from the estate's own IDCAMS statements, detected RACF/scheduler importables","tags":["onboard"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"onboarding id"}],"responses":{"200":{"description":"plan"},"400":{"description":"Nothing staged"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.write)"},"404":{"description":"No such onboarding"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.write"},"put":{"operationId":"onboardOverride","summary":"Override proposed data-file DSN/LRECL/RECFM (the wizard grid edits)","tags":["onboard"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"onboarding id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dataFiles":{"description":"[{ path, dsn?, lrecl?, recfm? }]"}}}}}},"responses":{"200":{"description":"plan"},"400":{"description":"No plan yet"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.write"}},"/api/onboard/{id}/load":{"post":{"operationId":"onboardLoad","summary":"Load the planned estate into this system: allocate libraries, write members, write PS data records (VSAM clusters stay with the estate's own DEFINE/REPRO JCL — the authentic path)","tags":["onboard"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"onboarding id"}],"responses":{"200":{"description":"{ libraries, members, datasets, skipped }"},"400":{"description":"Not planned yet"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.write"}},"/api/onboard/{id}/compile":{"post":{"operationId":"onboardCompile","summary":"Compile every COBOL program through the real IGYWCL pipeline; per-program RC + first diagnostics harvested from SYSPRINT","tags":["onboard"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"onboarding id"}],"responses":{"200":{"description":"{ clean, failed, results }"},"400":{"description":"Not loaded yet"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.write"}},"/api/onboard/{id}/import":{"post":{"operationId":"onboardImport","summary":"Run a detected import through its native path: racf (ZWSRACF unload→deck→IKJEFT01), esf (SFESF ESF-rules→deck→IKJEFT01), or ca7/ctm (ZWSCHED)","tags":["onboard"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"onboarding id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"description":"'racf' | 'esf' | 'ca7' | 'ctm'"}}}}}},"responses":{"200":{"description":"{ kind, jobid, maxcc }"},"400":{"description":"Nothing detected for that kind"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.write"}},"/api/onboard/{id}/report":{"get":{"operationId":"onboardReport","summary":"The exportable readiness/conformance report","tags":["onboard"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"onboarding id"}],"responses":{"200":{"description":"report"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.read)"},"404":{"description":"No such onboarding"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.read"}},"/api/onboard/{id}/finish":{"post":{"operationId":"onboardFinish","summary":"Package the loaded estate as a draft .sfapp and optionally provision a fresh instance and deploy it there","tags":["onboard"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"onboarding id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"app":{"description":"{ name?, version? } (defaults: onboarding name, 0.1)"},"provision":{"description":"{ name?, ttlSeconds? } — omit to only package"},"deployOptions":{"description":"appDeploy options (loadlib, excludePrograms, …)"}}}}}},"responses":{"200":{"description":"{ bundle, instance, deployment }"},"400":{"description":"Not loaded yet"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.admin"}},"/api/debug/sessions":{"post":{"operationId":"debugArm","summary":"Arm a debug session for a PARM=TEST-compiled program; the next matching run stops under the debugger","tags":["debug"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"program":{"description":"program id (compiled with PARM=TEST); shorthand for criteria { type:JCL, program }"},"breakpoints":{"description":"[{line} | {paragraph}, + optional condition/hitCondition per line — see debugBp] — empty = stop at the first statement"},"criteria":{"description":"{ type: JCL|CICS|WS, program?, jobname?, stepname?, user?, transaction?, termid?, servicename? } — absent field = wildcard; most-specific match wins; WS selects JSON web-service tasks by their JSONSERVICE name (SPEC-W6 §2.1-2.2)"}}}}}},"responses":{"200":{"description":"{ id, program, kind, criteria, state: ARMED, breakpoints }"},"400":{"description":"No debug artifacts (compile with PARM=TEST), invalid criteria, or identical criteria already registered"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (debug.exec)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"debug.exec"},"get":{"operationId":"debugSessions","summary":"List debug sessions (your own; a SPECIAL admin sees all)","tags":["debug"],"responses":{"200":{"description":"[session]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (debug.exec)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"debug.exec"}},"/api/debug/sessions/{id}":{"get":{"operationId":"debugSession","summary":"One session: state (ARMED/WAITING/RUNNING/STOPPED/ENDED), position, breakpoints, event log","tags":["debug"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"session id"}],"responses":{"200":{"description":"session"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (debug.exec)"},"404":{"description":"No such session"}},"security":[{"bearerAuth":[]}],"x-required-scope":"debug.exec"},"delete":{"operationId":"debugKill","summary":"Disarm (if not yet running) or terminate the debugged program","tags":["debug"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"session id"}],"responses":{"200":{"description":"{ ok, id, state }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (debug.exec)"},"404":{"description":"No such session"}},"security":[{"bearerAuth":[]}],"x-required-scope":"debug.exec"}},"/api/debug/sessions/{id}/fields":{"get":{"operationId":"debugFields","summary":"Inspectable fields (name, PIC, usage, offset within its 01 group)","tags":["debug"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"session id"}],"responses":{"200":{"description":"[{ name, base01, offset, size, pic, usage }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (debug.exec)"},"404":{"description":"No such session"}},"security":[{"bearerAuth":[]}],"x-required-scope":"debug.exec"}},"/api/debug/sessions/{id}/var":{"get":{"operationId":"debugVar","summary":"Read one variable from the stopped program (live memory, decoded by PIC/USAGE + hex)","tags":["debug"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"session id"},{"name":"name","in":"query","required":false,"schema":{"type":"string"},"description":"COBOL data name"}],"responses":{"200":{"description":"{ name, pic, usage, size, hex, value }"},"400":{"description":"Session not stopped / unknown field"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (debug.exec)"},"404":{"description":"No such session"}},"security":[{"bearerAuth":[]}],"x-required-scope":"debug.exec"},"post":{"operationId":"debugSetVar","summary":"Modify one variable in the stopped program (watch/modify — value encoded per PIC/USAGE, written to live memory, re-read back)","tags":["debug"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"session id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"COBOL data name"},"value":{"description":"new value (text, or numeric for COMP-3/BINARY/numeric DISPLAY)"}}}}}},"responses":{"200":{"description":"{ name, pic, usage, size, hex, value }"},"400":{"description":"Session not stopped / unknown field / value does not fit the PIC"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (debug.exec)"},"404":{"description":"No such session"}},"security":[{"bearerAuth":[]}],"x-required-scope":"debug.exec"}},"/api/debug/sessions/{id}/bp":{"post":{"operationId":"debugBp","summary":"Set or clear a breakpoint (by line or paragraph) on a session; optional condition/hit count (C1/C2)","tags":["debug"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"session id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"line":{"description":"source line"},"paragraph":{"description":"paragraph name (alternative)"},"clear":{"description":"true to remove"},"condition":{"description":"optional COBOL comparison '<data-name> <op> <literal>' (ops = <> > < >= <=) — the stop only surfaces when TRUE; false auto-continues"},"hitCondition":{"description":"optional positive integer N — the stop surfaces from the Nth condition-passing hit on"}}}}}},"responses":{"200":{"description":"session"},"400":{"description":"Malformed condition or hit condition"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (debug.exec)"},"404":{"description":"No such session (or NO SUCH FIELD in a condition — the NO-SUCH family maps to 404, the debugVar precedent)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"debug.exec"}},"/api/debug/sessions/{id}/continue":{"post":{"operationId":"debugContinue","summary":"Resume until the next breakpoint (returns when stopped again or ended)","tags":["debug"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"session id"}],"responses":{"200":{"description":"session"},"400":{"description":"Not stopped"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (debug.exec)"},"404":{"description":"No such session"}},"security":[{"bearerAuth":[]}],"x-required-scope":"debug.exec"}},"/api/debug/sessions/{id}/step":{"post":{"operationId":"debugStep","summary":"Execute one statement and stop again","tags":["debug"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"session id"}],"responses":{"200":{"description":"session"},"400":{"description":"Not stopped"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (debug.exec)"},"404":{"description":"No such session"}},"security":[{"bearerAuth":[]}],"x-required-scope":"debug.exec"}},"/api/audit":{"get":{"operationId":"auditRead","summary":"Structured audit trail of mutating API calls (in-process tail of ROOT/audit.jsonl)","tags":["system"],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"string"},"description":"max entries, newest last (default 200)"},{"name":"user","in":"query","required":false,"schema":{"type":"string"},"description":"filter by userid"},{"name":"op","in":"query","required":false,"schema":{"type":"string"},"description":"filter by operationId"}],"responses":{"200":{"description":"[{ t, user, tokenKind, op, method, path, status, ...detail }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"}},"/api/accounting":{"get":{"operationId":"accountingRead","summary":"G11 accounting records for chargeback: one JOB record per finished job (per-step CCs, elapsed, abends) and one TRAN record per CICS transaction, from ROOT/accounting JSONL (the same records tools/acctexport.mjs exports). ?format=csv serves the same CSV acctexport renders (accounting.js renderCsv is the single implementation)","tags":["system"],"parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string"},"description":"inclusive start date on the record end timestamp (YYYY-MM-DD)"},{"name":"to","in":"query","required":false,"schema":{"type":"string"},"description":"inclusive end date on the record end timestamp (YYYY-MM-DD)"},{"name":"type","in":"query","required":false,"schema":{"type":"string"},"description":"record type: 'JOB' or 'TRAN' (case-insensitive; default both — but csv REQUIRES one type, the two record shapes have different columns)"},{"name":"format","in":"query","required":false,"schema":{"type":"string"},"description":"'json' (default) or 'csv' (text/csv; identical bytes to tools/acctexport.mjs --format csv)"}],"responses":{"200":{"description":"{ enabled, count, records } (json) or the CSV text (csv) — enabled is the live ZWS_ACCOUNTING flag; the flag gates WRITING only, so records from when it was on are still served, and an engine that never wrote any answers { enabled: false, count: 0, records: [] } / a header-only CSV rather than an error"},"400":{"description":"Bad from/to date (want YYYY-MM-DD), bad type (want JOB or TRAN), bad format (want json or csv), or format=csv without a type"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (accounting.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"accounting.read"}},"/api/datasets":{"get":{"operationId":"listDatasets","summary":"List catalog entries matching an MVS pattern (or a name prefix); the whole list by default, a page with total/truncated/next when max or from is given","tags":["datasets"],"parameters":[{"name":"pattern","in":"query","required":false,"schema":{"type":"string"},"description":"MVS pattern (* = one qualifier chunk, ** = any, % = one char); default <user>.**"},{"name":"prefix","in":"query","required":false,"schema":{"type":"string"},"description":"dataset-name prefix instead of a pattern: SYN.BANK lists SYN.BANK and every SYN.BANK.* entry"},{"name":"max","in":"query","required":false,"schema":{"type":"string"},"description":"page size (1-5000); giving max or from returns { datasets, total, from, count, truncated, next } instead of the bare array"},{"name":"from","in":"query","required":false,"schema":{"type":"string"},"description":"first entry of the page (0-based)"}],"responses":{"200":{"description":"[dataset info] — or { datasets: [info], total, from, count, truncated, next? } when max/from is given"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/search":{"get":{"operationId":"searchCatalog","summary":"Search the catalog: dataset names, member names, and optionally member text content","tags":["datasets"],"parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string"},"description":"MVS dataset pattern (default **) or bare string matched as **string** (query is an alias)"},{"name":"member","in":"query","required":false,"schema":{"type":"string"},"description":"member-name pattern (* wildcard) — lists matching members of matching PO datasets"},{"name":"content","in":"query","required":false,"schema":{"type":"string"},"description":"substring grep (case-insensitive) over member text of matching PO datasets"},{"name":"max","in":"query","required":false,"schema":{"type":"string"},"description":"result cap per section (default 200, max 1000)"},{"name":"from","in":"query","required":false,"schema":{"type":"string"},"description":"first dataset of the page (0-based) — page the datasets section with total/next"}],"responses":{"200":{"description":"{ datasets: [info], members: [{dsn, member}], hits: [{dsn, member, line, text}], truncated, total: { datasets }, from, next? (next from when the datasets section is truncated) }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/check":{"post":{"operationId":"checkSource","summary":"Compile-check source through the engine compiler pipeline (no artifacts); diagnostics cannot drift from a real compile step","tags":["develop"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"language":{"description":"'COBOL' (default) or 'JCL'"},"lines":{"description":"source card images"},"syslib":{"description":"array of PO dataset names for COPY resolution (optional)"},"parm":{"description":"compile PARM string, e.g. 'CICS' to force the translator (optional)"}}}}}},"responses":{"200":{"description":"{ rc, program?, diagnostics: [{ line, severity: E|W|I, message, copybook? }] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/dataset":{"post":{"operationId":"allocateDataset","summary":"Allocate (catalog) a new dataset; omitted BLKSIZE is system-determined","tags":["datasets"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dsn":{"description":"dataset name"},"attrs":{"description":"{ dsorg, recfm, lrecl, ... }"}}}}}},"responses":{"200":{"description":"catalog entry"},"400":{"description":"Invalid DCB attributes (LRECL range, FB blocking, V* minimum)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"},"409":{"description":"DUPLICATE DATASET NAME ON CATALOG (Lane-9 F9.4: a conflict, not a server fault)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/dataset/{dsn}":{"get":{"operationId":"getDataset","summary":"Dataset info (PO datasets include memberList)","tags":["datasets"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"dataset name"}],"responses":{"200":{"description":"dataset info"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"404":{"description":"Not cataloged"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"},"delete":{"operationId":"deleteDataset","summary":"Delete/uncatalog a dataset (VSAM clusters included)","tags":["datasets"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"dataset name"}],"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"},"404":{"description":"Not cataloged"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/dataset/{dsn}/members":{"get":{"operationId":"listMembers","summary":"List the members of a PDS (the memberList of dataset_info on its own): name, changed, size, inUse when another session holds an edit","tags":["datasets"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"PDS name"}],"responses":{"200":{"description":"{ dsn, count, members: [{ name, ... }] }"},"400":{"description":"Not a PDS"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"404":{"description":"Not cataloged"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/dataset/{dsn}/rename":{"post":{"operationId":"renameDataset","summary":"Rename a dataset","tags":["datasets"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"dataset name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"newName":{"description":"new dataset name"}}}}}},"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"},"404":{"description":"Not cataloged"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/dataset/{dsn}/copy":{"post":{"operationId":"copyDataset","summary":"Copy a dataset","tags":["datasets"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"dataset name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"newName":{"description":"target dataset name"}}}}}},"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"},"404":{"description":"Not cataloged"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/dataset/{dsn}/records":{"get":{"operationId":"readRecords","summary":"Read raw records as hex (PS + VSAM; binary-safe for packed/zoned/binary fields). GDG relative names BASE(0)/BASE(-n) resolve to the current/older generation","tags":["datasets"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"dataset name (GDG relative form BASE(0) / BASE(-n) accepted)"},{"name":"from","in":"query","required":false,"schema":{"type":"string"},"description":"first record index (default 0)"},{"name":"count","in":"query","required":false,"schema":{"type":"string"},"description":"record count (default 1000, max 10000)"}],"responses":{"200":{"description":"{ recfm, lrecl, dsorg, total, from, records: [hex] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"404":{"description":"Not cataloged"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"},"put":{"operationId":"writeRecords","summary":"Write raw records from hex (VSAM: keyed writes into the cluster)","tags":["datasets"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"dataset name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"records":{"description":"array of hex-encoded records"}}}}}},"responses":{"200":{"description":"{ ok, written }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"},"404":{"description":"Not cataloged"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/dataset/{dsn}/records/{member}":{"get":{"operationId":"readMemberRecords","summary":"Read raw records of a PDS member as hex","tags":["datasets"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"dataset name"},{"name":"member","in":"path","required":true,"schema":{"type":"string"},"description":"member name"},{"name":"from","in":"query","required":false,"schema":{"type":"string"},"description":"first record index (default 0)"},{"name":"count","in":"query","required":false,"schema":{"type":"string"},"description":"record count (default 1000, max 10000)"}],"responses":{"200":{"description":"{ recfm, lrecl, dsorg, total, from, records: [hex] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"404":{"description":"Not cataloged"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"},"put":{"operationId":"writeMemberRecords","summary":"Write raw records of a PDS member from hex","tags":["datasets"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"dataset name"},{"name":"member","in":"path","required":true,"schema":{"type":"string"},"description":"member name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"records":{"description":"array of hex-encoded records"}}}}}},"responses":{"200":{"description":"{ ok, written }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"},"404":{"description":"Not cataloged"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/sql/views":{"get":{"operationId":"sqlListViews","summary":"List the registered SQL views (dataset + copybook bindings)","tags":["sql"],"responses":{"200":{"description":"[{ name, dsn, copybook }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"},"post":{"operationId":"sqlDefineView","summary":"Register a SQL view: a dataset (PS or VSAM) + a copybook become live typed columns","tags":["sql"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"view name (SQL identifier)"},"dsn":{"description":"dataset name"},"copybook":{"description":"layout copybook as 'LIB(MEMBER)'"}}}}}},"responses":{"200":{"description":"{ name, dsn, copybook, columns: [{name, type}] }"},"400":{"description":"Bad name / dsn / unparsable copybook"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/sql/views/{name}":{"delete":{"operationId":"sqlDeleteView","summary":"Drop a registered SQL view (the dataset is untouched)","tags":["sql"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"view name"}],"responses":{"200":{"description":"{ deleted }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"},"404":{"description":"No such view"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/sql":{"post":{"operationId":"sqlQuery","summary":"Run a read-only SELECT over the registered views — LIVE dataset bytes, re-materialized per query (also served on the PG wire port, ZOSWEB_SQL_PORT)","tags":["sql"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sql":{"description":"SELECT/WITH/EXPLAIN statement"}}}}}},"responses":{"200":{"description":"{ columns: [name], rows: [[value]] }"},"400":{"description":"Not a SELECT, unknown view, or SQL error"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/sql/views/{name}/rows":{"get":{"operationId":"viewRows","summary":"Decoded records of a view with layout metadata (the Studio data grid): live bytes, copybook offsets, per-record hex","tags":["sql"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"view name"},{"name":"from","in":"query","required":false,"schema":{"type":"string"},"description":"first record (0)"},{"name":"count","in":"query","required":false,"schema":{"type":"string"},"description":"records (default 100, max 1000)"}],"responses":{"200":{"description":"{ dsn, charset, total, columns: [{name, off, len, usage, numeric, signed, scale}], rows: [{i, hex, values}] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"404":{"description":"No such view"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/sql/views/{name}/rows/{n}":{"put":{"operationId":"writeViewField","summary":"Typed single-field write-back through the view layout (encodes zoned/packed/binary/char with the at-rest charset rules)","tags":["sql"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"view name"},{"name":"n","in":"path","required":true,"schema":{"type":"string"},"description":"record index"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"column":{"description":"column name from the view layout"},"value":{"description":"new value"}}}}}},"responses":{"200":{"description":"{ i, column, value (re-decoded), hex }"},"400":{"description":"Bad column or value"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"},"404":{"description":"No such view/record"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/dataset/{dsn}/member":{"get":{"operationId":"readDatasetContent","summary":"Read a PS dataset (or browse a VSAM cluster) as text lines; ?view=hex for a hex dump","tags":["datasets"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"dataset name"},{"name":"view","in":"query","required":false,"schema":{"type":"string"},"description":"'hex' for a hex/EBCDIC dump"},{"name":"start","in":"query","required":false,"schema":{"type":"string"},"description":"first record number for a paged read (0-based; with count, returns { lines, paged, start, total })"},{"name":"count","in":"query","required":false,"schema":{"type":"string"},"description":"record count for a paged read (default 1000, max 100000)"}],"responses":{"200":{"description":"{ lines, recfm, lrecl } | { lines, paged, start, total } | { lines, truncated, total, bytes } (dataset over ZWS_DS_JSON_MAX_MB — browse-only first page, never save it back) | { vsam, records } | { hex, rows } | { binary, size }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"404":{"description":"Not cataloged"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"},"put":{"operationId":"writeDatasetContent","summary":"Write a PS dataset as text lines (converted to EBCDIC at rest). Honours If-Match/ifMatch against the dataset's version tag (412 on stale copy); refused 409 while a job or another edit session holds the dataset (Lane-9 F9.1/F9.2/F9.3)","tags":["datasets"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"dataset name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"lines":{"description":"array of text lines"},"ifMatch":{"description":"version tag from GET (optional; stale copy -> 412)"}}}}}},"responses":{"200":{"description":"{ ok, etag }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"},"404":{"description":"Not cataloged"},"409":{"description":"Dataset in use (batch SYSDSN ENQ or another edit session)"},"412":{"description":"ifMatch/If-Match does not match the current version"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/dataset/{dsn}/member/{member}":{"get":{"operationId":"readMember","summary":"Read a PDS member as text lines; ?view=hex for a hex dump","tags":["datasets"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"dataset name"},{"name":"member","in":"path","required":true,"schema":{"type":"string"},"description":"member name"},{"name":"view","in":"query","required":false,"schema":{"type":"string"},"description":"'hex' for a hex/EBCDIC dump"},{"name":"start","in":"query","required":false,"schema":{"type":"string"},"description":"first record number for a paged read (0-based)"},{"name":"count","in":"query","required":false,"schema":{"type":"string"},"description":"record count for a paged read (default 1000, max 100000)"}],"responses":{"200":{"description":"{ lines, recfm, lrecl } | { lines, paged, start, total } | { lines, truncated, total, bytes } | { hex, rows } | { binary, size }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"404":{"description":"Not cataloged / member not found"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"},"put":{"operationId":"writeMember","summary":"Write a PDS member as text lines. Honours If-Match/ifMatch against the member's version tag (412 on stale copy); refused 409 while a job or another edit session holds it (Lane-9 F9.1/F9.2/F9.3). A dataset that is not cataloged is a 404 unless allocate is given (then it is allocated first, PO FB 80 by default — the same allocate-if-missing upload_source does)","tags":["datasets"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"dataset name"},{"name":"member","in":"path","required":true,"schema":{"type":"string"},"description":"member name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"lines":{"description":"array of text lines"},"ifMatch":{"description":"version tag from GET (optional; stale copy -> 412)"},"allocate":{"description":"true = allocate the PDS if it is not cataloged (PO FB LRECL 80), or { dsorg, recfm, lrecl, ... } attributes for it"}}}}}},"responses":{"200":{"description":"{ ok, etag, allocated? }"},"400":{"description":"allocate given but not true/attributes object"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"},"404":{"description":"Not cataloged (pass allocate:true, or allocate_dataset / upload_source first)"},"409":{"description":"Member/dataset in use (batch SYSDSN ENQ or another edit session)"},"412":{"description":"ifMatch/If-Match does not match the current version"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"},"delete":{"operationId":"deleteMember","summary":"Delete a PDS member","tags":["datasets"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"dataset name"},{"name":"member","in":"path","required":true,"schema":{"type":"string"},"description":"member name"}],"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"},"404":{"description":"Not cataloged"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/dataset/{dsn}/member/{member}/rename":{"post":{"operationId":"renameMember","summary":"Rename a PDS member","tags":["datasets"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"dataset name"},{"name":"member","in":"path","required":true,"schema":{"type":"string"},"description":"member name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"newName":{"description":"new member name"}}}}}},"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"},"404":{"description":"Not cataloged"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/dataset/{dsn}/member/{member}/copy":{"post":{"operationId":"copyMember","summary":"Copy a PDS member (optionally to another PDS)","tags":["datasets"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"dataset name"},{"name":"member","in":"path","required":true,"schema":{"type":"string"},"description":"member name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"toDsn":{"description":"target PDS (default same)"},"toMember":{"description":"target member name"}}}}}},"responses":{"200":{"description":"{ ok }"},"400":{"description":"No target / target same as source"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"},"404":{"description":"Not cataloged"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/dataset/{dsn}/enq":{"post":{"operationId":"acquireEditEnq","summary":"Take the ISPF EDIT enqueue (SPFEDIT analog) on a dataset or member at edit entry. Refused 409 while another edit session holds it or a running job holds the dataset EXCLUSIVE (DISP=OLD/NEW/MOD). Re-acquire by the same session refreshes the hold; holds expire after ZWS_EDIT_ENQ_TTL_MS (default 30 min) of inactivity","tags":["datasets"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"dataset name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"member":{"description":"member name (omit for a PS dataset)"}}}}}},"responses":{"200":{"description":"{ ok, key }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"},"404":{"description":"Not cataloged"},"409":{"description":"In use by another edit session or a running job"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"},"delete":{"operationId":"releaseEditEnq","summary":"Release the ISPF EDIT enqueue taken by this session (END/CANCEL/F3 leaving the editor). Idempotent; releasing a hold you do not own is a no-op","tags":["datasets"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"dataset name"},{"name":"member","in":"query","required":false,"schema":{"type":"string"},"description":"member name (omit for a PS dataset)"}],"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/xfer/config":{"get":{"operationId":"xferConfig","summary":"File Transfer tab settings: size limits, host code pages (generated CCSIDs), the terminal session CCSID, PC encodings and the text/binary file-type defaults","tags":["datasets"],"responses":{"200":{"description":"{ user, maxUploadBytes, maxDownloadBytes, hostPages: [{ ccsid, name, mixed }], sessionCcsid, pcEncodings, textExt, binaryExt, uss: false }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/xfer/check":{"get":{"operationId":"xferCheck","summary":"Pre-flight for a transfer: validates the name, says whether the dataset/member exists, its DCB and CCSID, and whether this user may read / write / allocate it (RACF, the ICH408I text when not)","tags":["datasets"],"parameters":[{"name":"dsn","in":"query","required":false,"schema":{"type":"string"},"description":"dataset name (or DSN(MEMBER))"},{"name":"member","in":"query","required":false,"schema":{"type":"string"},"description":"member name"},{"name":"dir","in":"query","required":false,"schema":{"type":"string"},"description":"'up' (default) or 'down'"}],"responses":{"200":{"description":"{ dsn, member, dsExists, exists, entry?, ccsid?, access: { allowed, need, message? } }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/xfer/upload":{"post":{"operationId":"xferUpload","summary":"Upload one file into a PS dataset or PDS member (the body is the raw file). TEXT converts PC text to EBCDIC records through the host code page (CRLF/LF/CR or NOCRLF framing, Ctrl-Z, tabs, trailing blanks, long-line policy); BINARY stores the bytes framed by RECFM/LRECL. A missing dataset is allocated only with alloc=1 (dsorg/recfm/lrecl/blksize/space); an existing member is replaced only with replace=1 (or extended with append=1)","tags":["datasets"],"parameters":[{"name":"dsn","in":"query","required":false,"schema":{"type":"string"},"description":"target dataset (or DSN(MEMBER))"},{"name":"member","in":"query","required":false,"schema":{"type":"string"},"description":"target member (PDS)"},{"name":"mode","in":"query","required":false,"schema":{"type":"string"},"description":"'text' (default) or 'binary'"},{"name":"pcenc","in":"query","required":false,"schema":{"type":"string"},"description":"PC encoding for text: 'utf8' (default), 'cp1252', 'cp437', 'cp850'"},{"name":"ccsid","in":"query","required":false,"schema":{"type":"string"},"description":"host code page for text (default: the dataset's effective CCSID)"},{"name":"eol","in":"query","required":false,"schema":{"type":"string"},"description":"'auto' (default: CRLF/LF/CR) or 'none' (NOCRLF: cut into LRECL records)"},{"name":"ctrlz","in":"query","required":false,"schema":{"type":"string"},"description":"'0' keeps a trailing Ctrl-Z (default strips it)"},{"name":"tabs","in":"query","required":false,"schema":{"type":"string"},"description":"expand TABs to this tab stop (0 = keep)"},{"name":"trim","in":"query","required":false,"schema":{"type":"string"},"description":"'1' strips trailing blanks of each line"},{"name":"long","in":"query","required":false,"schema":{"type":"string"},"description":"'fail' (default), 'truncate' or 'wrap'"},{"name":"replace","in":"query","required":false,"schema":{"type":"string"},"description":"'1' replaces an existing member/dataset content"},{"name":"append","in":"query","required":false,"schema":{"type":"string"},"description":"'1' appends the records (IND$FILE APPEND)"},{"name":"alloc","in":"query","required":false,"schema":{"type":"string"},"description":"'1' allocates the dataset when it does not exist"},{"name":"dsorg","in":"query","required":false,"schema":{"type":"string"},"description":"PO|PS for a new dataset (default PO with a member, else PS)"},{"name":"recfm","in":"query","required":false,"schema":{"type":"string"},"description":"new dataset RECFM (text default FB, binary default U)"},{"name":"lrecl","in":"query","required":false,"schema":{"type":"string"},"description":"new dataset LRECL (default 80)"},{"name":"blksize","in":"query","required":false,"schema":{"type":"string"},"description":"new dataset BLKSIZE (0/omitted = system-determined)"},{"name":"space","in":"query","required":false,"schema":{"type":"string"},"description":"new dataset SPACE 'primary,secondary'"},{"name":"spaceUnit","in":"query","required":false,"schema":{"type":"string"},"description":"'TRK' (default), 'CYL' or 'BLK'"}],"responses":{"200":{"description":"{ ok, dsn, member, mode, records, bytes, allocated?, replaced?, appended?, subs?, truncated?, wrapped?, padded?, ccsid?, warnings }"},"400":{"description":"invalid name / options / long line / not valid UTF-8 / VSAM or GDG target"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"},"404":{"description":"dataset not cataloged (pass alloc=1)"},"409":{"description":"member exists (pass replace=1) or in use"},"413":{"description":"file larger than STEELFRAME_XFER_MAX_MB"},"429":{"description":"too many uploads"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/xfer/download":{"get":{"operationId":"xferDownload","summary":"Download a PS dataset or PDS member as a file. TEXT converts EBCDIC records to PC text through the host code page (CRLF/LF/none, trailing blanks removed by default); BINARY returns the record bytes (V without RDWs unless rdw=1)","tags":["datasets"],"parameters":[{"name":"dsn","in":"query","required":false,"schema":{"type":"string"},"description":"dataset (or DSN(MEMBER))"},{"name":"member","in":"query","required":false,"schema":{"type":"string"},"description":"member"},{"name":"mode","in":"query","required":false,"schema":{"type":"string"},"description":"'text' (default) or 'binary'"},{"name":"pcenc","in":"query","required":false,"schema":{"type":"string"},"description":"'utf8' (default), 'cp1252', 'cp437', 'cp850'"},{"name":"ccsid","in":"query","required":false,"schema":{"type":"string"},"description":"host code page (default: the dataset's effective CCSID)"},{"name":"eol","in":"query","required":false,"schema":{"type":"string"},"description":"'crlf' (default), 'lf' or 'none'"},{"name":"trim","in":"query","required":false,"schema":{"type":"string"},"description":"'0' keeps trailing blanks"},{"name":"rdw","in":"query","required":false,"schema":{"type":"string"},"description":"'1' keeps V record descriptor words (binary)"}],"responses":{"200":{"description":"the file bytes (application/octet-stream or text/plain), X-SteelFrame-Records / X-SteelFrame-Subs headers"},"400":{"description":"invalid name / VSAM / PDS without member"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"404":{"description":"not cataloged / member not found"},"413":{"description":"larger than STEELFRAME_XFER_MAX_DOWNLOAD_MB"},"429":{"description":"too many downloads"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/connectors/config":{"get":{"operationId":"connectorsConfig","summary":"Is the Connectors tab on here (STEELFRAME_GIT_CONNECTORS)? Providers (GitHub; GitLab base URLs on the allow-list), whether GitHub sign-in (device flow) is configured, and the limits. No secrets","tags":["connectors"],"responses":{"200":{"description":"{ enabled, autosync, webhooks, github: { web, oauth }, gitlab: { bases, any }, limits }"}},"security":[]}},"/api/connectors":{"get":{"operationId":"connectorsList","summary":"Your connected GitHub / GitLab accounts (masked: login, token hint, scopes, expiry, last used — never the token) and your linked repositories with their mainframe / VS Code / PostgreSQL settings","tags":["connectors"],"responses":{"200":{"description":"{ user, connections: [...], links: [...], seat: { kind } }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/connectors/connect":{"post":{"operationId":"connectorsConnect","summary":"Connect your GitHub or GitLab account with a personal access token. The token is checked with the provider, stored encrypted (AES-256-GCM) and never returned; reconnecting replaces it","tags":["connectors"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"description":"'github' or 'gitlab'"},"token":{"description":"the personal access token"},"baseUrl":{"description":"GitLab only: the server (default https://gitlab.com; others from the operator's allow-list)"}}}}}},"responses":{"200":{"description":"the connection (masked)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/connectors/accounts/{id}":{"delete":{"operationId":"connectorsDisconnect","summary":"Disconnect an account: its token is deleted at once (linked repositories stay, without an account)","tags":["connectors"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"}],"responses":{"200":{"description":"{ ok, id, provider, host }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/connectors/accounts/{id}/repos":{"get":{"operationId":"connectorsRepos","summary":"Repositories the connected account can see (at most 100, newest first; q filters by name)","tags":["connectors"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"},{"name":"q","in":"query","required":false,"schema":{"type":"string"},"description":"name filter"}],"responses":{"200":{"description":"{ repos: [{ repo, private, defaultBranch, push }] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/connectors/oauth/github":{"post":{"operationId":"connectorsOauthStart","summary":"Start \"Sign in with GitHub\" (OAuth device flow; only when the operator configured STEELFRAME_GIT_GITHUB_CLIENT_ID): returns the code to enter at github.com/login/device","tags":["connectors"],"responses":{"200":{"description":"{ flow, userCode, verificationUri, interval, expiresIn }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/connectors/oauth/github/poll":{"post":{"operationId":"connectorsOauthPoll","summary":"Poll a \"Sign in with GitHub\" flow: pending, or connected (the token is stored like a personal access token, never returned)","tags":["connectors"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"flow":{"description":"the flow id from the start call"}}}}}},"responses":{"200":{"description":"{ state: 'pending' | 'connected', interval?, connection? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/connectors/links":{"post":{"operationId":"connectorsLinkAdd","summary":"Link one repository of a connected account (checked with the provider: it exists, the branch exists)","tags":["connectors"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"conn":{"description":"connection id"},"repo":{"description":"owner/name (GitHub) or group/project (GitLab)"},"branch":{"description":"branch (default: the repository default)"}}}}}},"responses":{"200":{"description":"the link"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/connectors/links/{link}":{"put":{"operationId":"connectorsLinkUpdate","summary":"Change a link: its branch, its mainframe mappings (folder <-> one of your own PDSs, file extension, sequence numbers keep|strip), its PostgreSQL folder","tags":["connectors"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"branch":{"description":"branch"},"mainframe":{"description":"[{ dir, dsn, ext, seq }] (at most 8)"},"postgres":{"description":"{ dir }"}}}}}},"responses":{"200":{"description":"the link"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"},"delete":{"operationId":"connectorsLinkDelete","summary":"Unlink a repository (nothing is deleted in the repository, the datasets, the seat or the database)","tags":["connectors"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"responses":{"200":{"description":"{ ok, id }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/connectors/links/{link}/mainframe":{"get":{"operationId":"connectorsMfStatus","summary":"Compare a folder of the repository with the members of your PDS (git blob ids; nothing is downloaded): same / changed / only on the mainframe / only in the repository / refused (binary member, two files for one member)","tags":["connectors"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"},{"name":"map","in":"query","required":false,"schema":{"type":"string"},"description":"mapping number (default 0)"}],"responses":{"200":{"description":"{ dsn, dir, branch, commit, rows: [{ member, file, state, reason? }], skipped }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/connectors/links/{link}/mainframe/diff":{"get":{"operationId":"connectorsMfDiff","summary":"A unified diff of one member: the repository version against the mainframe version","tags":["connectors"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"},{"name":"map","in":"query","required":false,"schema":{"type":"string"},"description":"mapping number"},{"name":"member","in":"query","required":false,"schema":{"type":"string"},"description":"member name"}],"responses":{"200":{"description":"{ member, state, file, diff }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/connectors/links/{link}/mainframe/pull":{"post":{"operationId":"connectorsMfPull","summary":"Pull the repository folder into your PDS: the changed and new files (or the listed members) are converted (UTF-8 -> the dataset CCSID, LRECL rules) and written - ALL OR NOTHING (one long line, unmappable character or invalid file = nothing written). Members missing from the repository are never deleted","tags":["connectors"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"map":{"description":"mapping number (default 0)"},"members":{"description":"optional list of members"}}}}}},"responses":{"200":{"description":"{ ok, dsn, written: [{ member, file, records, new }], unchanged, mainframeOnly, skipped, tabsExpanded }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"},"422":{"description":"refused files (nothing written): extra.refused"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/connectors/links/{link}/mainframe/push":{"post":{"operationId":"connectorsMfPush","summary":"Push your PDS members to the repository as ONE commit with your message (changed and mainframe-only members, or the listed ones), on the link branch or a new branch made from it. Never forced","tags":["connectors"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"map":{"description":"mapping number"},"message":{"description":"commit message"},"newBranch":{"description":"optional new branch name"},"members":{"description":"optional list of members"}}}}}},"responses":{"200":{"description":"{ ok, branch, commit, files } or { ok, nothing: true }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/connectors/links/{link}/seat":{"get":{"operationId":"connectorsSeat","summary":"The repository in your VS Code container seat: the clone URL VS Code's Source Control uses there (through SteelFrame; the seat signs in by itself, your token never enters the seat) and whether it is cloned","tags":["connectors"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"responses":{"200":{"description":"{ kind, url, dir, cloned }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/connectors/links/{link}/seat/clone":{"post":{"operationId":"connectorsSeatClone","summary":"Clone the repository into /workspace/<dir> of your VS Code container seat (one fixed git command in your own seat; hooks off; through the SteelFrame git door). Afterwards VS Code Source Control works on it","tags":["connectors"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dir":{"description":"folder name in /workspace (default: the repository name)"}}}}}},"responses":{"200":{"description":"{ ok, dir }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/connectors/links/{link}/postgres/migrations":{"get":{"operationId":"connectorsPgMigrations","summary":"The SQL migrations in <dir>/migrations of the repository against your seat database: applied, pending, and problems (an applied file that changed, an out-of-order version)","tags":["connectors"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"responses":{"200":{"description":"{ dir, branch, migrations: [{ version, file, state }], problems }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/connectors/links/{link}/postgres/migrate":{"post":{"operationId":"connectorsPgMigrate","summary":"Apply every pending migration to your seat database in ONE transaction (all or nothing) as your own non-superuser role, under the vscode_db_exec rules (no COPY / PROGRAM, no role changes); transaction control inside a migration is refused","tags":["connectors"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"responses":{"200":{"description":"{ ok, applied: [versions], nothing? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/connectors/links/{link}/postgres/export":{"post":{"operationId":"connectorsPgExport","summary":"Export your seat database into the repository as ONE commit: <dir>/schema.sql (the DDL) and, for the listed tables, <dir>/data/<table>.csv (first N rows, with a header). Unchanged files are not committed","tags":["connectors"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"description":"commit message (default given)"},"tables":{"description":"optional list of tables (schema.table, at most 20)"},"rows":{"description":"rows per table (1..10000, default 1000)"},"newBranch":{"description":"optional new branch"}}}}}},"responses":{"200":{"description":"{ ok, branch, commit, files, truncated } or { ok, nothing: true }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/connectors/links/{link}/hook":{"get":{"operationId":"connectorsHook","summary":"The link's push webhook: whether webhooks are available on this engine (STEELFRAME_GIT_AUTOSYNC + STEELFRAME_GIT_WEBHOOK_URL), its URL, deliveries; reveal=1 also returns the secret for setting it up by hand on the provider","tags":["connectors"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"},{"name":"reveal","in":"query","required":false,"schema":{"type":"string"},"description":"1 = include the secret (a manual webhook)"}],"responses":{"200":{"description":"{ available, provider, hook, url, polling, secret? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"},"post":{"operationId":"connectorsHookCreate","summary":"Set up the push webhook: auto = SteelFrame registers it on GitHub / GitLab with your token (push events only, TLS verification on; the token may need more rights), else a manual one whose URL and secret you paste into the provider. Replaces an earlier one","tags":["connectors"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"auto":{"description":"true (default) = register it on the provider"}}}}}},"responses":{"200":{"description":"{ ok, hook, url, secret? (manual only) }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"},"delete":{"operationId":"connectorsHookDelete","summary":"Remove the webhook (on the provider too when SteelFrame created it); polling keeps auto-sync going","tags":["connectors"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/git/accounts":{"get":{"operationId":"gitAccounts","summary":"Your connected GitHub / GitLab accounts (masked: login, token hint, scopes, expiry — never a token) and your linked repositories with their mappings and auto-sync state","tags":["git"],"responses":{"200":{"description":"{ user, connections, links, seat }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/accounts/{account}/repos":{"get":{"operationId":"gitRepos","summary":"Repositories a connected account can see (at most 100)","tags":["git"],"parameters":[{"name":"account","in":"path","required":true,"schema":{"type":"string"},"description":"account (connection) id"},{"name":"query","in":"query","required":false,"schema":{"type":"string"},"description":"name filter"}],"responses":{"200":{"description":"{ repos: [{ repo, private, defaultBranch, push }] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/links":{"post":{"operationId":"gitLink","summary":"Link a repository of one of your connected accounts","tags":["git"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"description":"account id"},"repo":{"description":"owner/name or group/project"},"branch":{"description":"optional branch (default: the repository default)"}}}}}},"responses":{"200":{"description":"the link"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/links/{link}":{"delete":{"operationId":"gitUnlink","summary":"Unlink a repository (nothing is deleted anywhere; a webhook SteelFrame created is removed)","tags":["git"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"responses":{"200":{"description":"{ ok, id }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/repos":{"post":{"operationId":"gitCreateRepo","summary":"\"Create a new repository for me\": a new (private) repository on the account, initialised with a README, and linked. A token that may not create repositories gets 403 naming the permission it needs","tags":["git"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"account":{"description":"account id"},"name":{"description":"repository name"},"private":{"description":"true (default) or false"},"description":{"description":"optional"}}}}}},"responses":{"200":{"description":"{ ok, created, private, link }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/links/{link}/status":{"get":{"operationId":"gitStatus","summary":"Compare a mapping (repository folder <-> your PDS): same / changed / only on the mainframe / only in the repository / refused, plus its auto-sync state and conflicts","tags":["git"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"},{"name":"map","in":"query","required":false,"schema":{"type":"string"},"description":"mapping number (default 0)"}],"responses":{"200":{"description":"{ repo, branch, dsn, dir, commit, rows, skipped, sync }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/links/{link}/diff":{"get":{"operationId":"gitDiff","summary":"A unified diff of one member: the repository version against the mainframe version","tags":["git"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"},{"name":"map","in":"query","required":false,"schema":{"type":"string"},"description":"mapping number"},{"name":"member","in":"query","required":false,"schema":{"type":"string"},"description":"member name"}],"responses":{"200":{"description":"{ member, state, file, diff }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/links/{link}/log":{"get":{"operationId":"gitLog","summary":"The newest commits of the linked branch (title, author, date)","tags":["git"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"},{"name":"limit","in":"query","required":false,"schema":{"type":"string"},"description":"commits (1..50, default 20)"}],"responses":{"200":{"description":"{ repo, branch, commits: [{ sha, title, author, date }] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/links/{link}/branches":{"get":{"operationId":"gitBranches","summary":"The repository's branches (the synced one marked)","tags":["git"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"responses":{"200":{"description":"{ repo, synced, branches: [{ name, sha, synced }] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"},"post":{"operationId":"gitBranchCreate","summary":"Create a branch on the provider from the head of the synced (or another) branch","tags":["git"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"new branch"},"from":{"description":"optional existing branch (default: the synced branch)"}}}}}},"responses":{"200":{"description":"{ ok, branch, from, commit }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/links/{link}/switch":{"post":{"operationId":"gitBranchSwitch","summary":"Switch the branch the link syncs with; auto-sync is turned OFF for its mappings (turn it on again for a fresh comparison)","tags":["git"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"branch":{"description":"existing branch"}}}}}},"responses":{"200":{"description":"{ ok, branch, previous, autosyncTurnedOff }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/links/{link}/pull":{"post":{"operationId":"gitPull","summary":"Pull the repository folder into your PDS (changed and new files, or the listed members): converted to the data set's code page, ALL OR NOTHING, members missing from the repository never deleted","tags":["git"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"map":{"description":"mapping number (default 0)"},"members":{"description":"optional list of members"}}}}}},"responses":{"200":{"description":"{ ok, dsn, written, unchanged, mainframeOnly, skipped }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/links/{link}/push":{"post":{"operationId":"gitPush","summary":"Push your PDS members to the repository as ONE commit (the changed and mainframe-only members, or the listed ones), on the synced branch or a new branch. Never forced: a branch that moved answers 409","tags":["git"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"map":{"description":"mapping number"},"message":{"description":"commit message"},"newBranch":{"description":"optional new branch"},"members":{"description":"optional list of members"}}}}}},"responses":{"200":{"description":"{ ok, branch, commit, files } or { ok, nothing }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/links/{link}/sync":{"post":{"operationId":"gitSync","summary":"Auto-sync (STEELFRAME_GIT_AUTOSYNC): mainframe saves are committed and pushed automatically (batched), provider pushes are pulled automatically (webhook or polling); both sides changed = a conflict that stops it until resolved","tags":["git"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"map":{"description":"mapping number"},"on":{"description":"true = turn auto-sync on (a fresh comparison now), false = off"}}}}}},"responses":{"200":{"description":"{ ok, map, sync }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/links/{link}/sync/run":{"post":{"operationId":"gitSyncRun","summary":"Run auto-sync of one mapping now (instead of waiting for the next save, webhook or poll)","tags":["git"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"map":{"description":"mapping number"}}}}}},"responses":{"200":{"description":"{ pushed?, pulled?, commit?, conflict?, sync }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/links/{link}/resolve":{"post":{"operationId":"gitResolve","summary":"Resolve an auto-sync conflict without losing data (never forced, nothing deleted); auto-sync resumes","tags":["git"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"map":{"description":"mapping number"},"choice":{"description":"'mainframe' (commit the mainframe versions) | 'repository' (pull the repository versions) | 'branch' (the mainframe versions to a NEW branch, then pull the repository versions)"},"branch":{"description":"optional new branch name for 'branch'"},"members":{"description":"optional: only these conflicting members"}}}}}},"responses":{"200":{"description":"{ ok, choice, resolved, commit, branch, compare?, pulled, sync }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/links/{link}/seat":{"get":{"operationId":"gitSeat","summary":"The repository in your VS Code container seat: the clone URL VS Code uses (through SteelFrame; no token in the seat) and whether it is cloned","tags":["git"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"responses":{"200":{"description":"{ kind, url, dir, cloned }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/links/{link}/seat/clone":{"post":{"operationId":"gitSeatClone","summary":"Clone the repository into /workspace/<dir> of your VS Code container seat (one fixed git command; hooks off)","tags":["git"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dir":{"description":"folder in /workspace (default: the repository name)"}}}}}},"responses":{"200":{"description":"{ ok, dir, path }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/links/{link}/postgres/migrations":{"get":{"operationId":"gitPgMigrations","summary":"The SQL migrations in <dir>/migrations against your seat database: applied, pending, problems","tags":["git"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"responses":{"200":{"description":"{ dir, branch, migrations, problems }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/links/{link}/postgres/migrate":{"post":{"operationId":"gitPgMigrate","summary":"Apply every pending migration to your seat database in ONE transaction (all or nothing) as your non-superuser role","tags":["git"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"responses":{"200":{"description":"{ ok, applied }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/git/links/{link}/postgres/export":{"post":{"operationId":"gitPgExport","summary":"Export your seat database (schema.sql + optional CSVs) into the repository as ONE commit","tags":["git"],"parameters":[{"name":"link","in":"path","required":true,"schema":{"type":"string"},"description":"link id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"description":"commit message"},"tables":{"description":"optional tables"},"rows":{"description":"rows per table (1..10000)"},"newBranch":{"description":"optional new branch"}}}}}},"responses":{"200":{"description":"{ ok, branch, commit, files } or { ok, nothing }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (connectors.use)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"connectors.use"}},"/api/zos/config":{"get":{"operationId":"zosConfig","summary":"Is the Mainframes tab on here (STEELFRAME_ZOS_CONNECT)? Which ports may be used, whether any public host may be entered, the API ML base path, the code pages and the limits. No host list, no secrets","tags":["mainframes"],"responses":{"200":{"description":"{ enabled, publicHosts, ports, apimlBase, codepages, limits }"}},"security":[]}},"/api/zos/connections":{"get":{"operationId":"zosList","summary":"Your mainframe connections (masked: host, user id, auth type, a hint of the credential - never the credential) with their last test and what the AI chat and MCP may do on each","tags":["mainframes"],"responses":{"200":{"description":"{ user, connections: [...] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"},"post":{"operationId":"zosCreate","summary":"Connect one of your own IBM mainframes (website logon only): host, port, z/OSMF directly or through Zowe API ML (base path), the user id and a password / passphrase, a one-time MFA passcode (only the session token is kept), a z/OSMF / API ML token, or a client certificate; an optional CA certificate and TLS server name. It is tested (GET /zosmf/info + a data set list) before anything is stored; the credential is stored encrypted (AES-256-GCM) and never returned. AI chat and MCP access start OFF","tags":["mainframes"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"a name"},"host":{"description":"DNS name or IP"},"port":{"description":"z/OSMF or gateway port (443)"},"via":{"description":"'zosmf' | 'apiml'"},"basePath":{"description":"'' or e.g. /ibmzosmf/api/v1"},"user":{"description":"mainframe user id"},"auth":{"description":"'password' | 'passcode' | 'token' | 'cert'"},"password":{"description":"password / passphrase (auth password)"},"passcode":{"description":"one-time passcode (auth passcode)"},"token":{"description":"token (auth token)"},"tokenType":{"description":"jwtToken | LtpaToken2 | apimlAuthenticationToken"},"cert":{"description":"PEM client certificate (auth cert)"},"key":{"description":"PEM private key (auth cert)"},"passphrase":{"description":"the key's passphrase"},"codepage":{"description":"IBM-1047 (default), IBM-037, ..."},"ca":{"description":"PEM CA certificate(s)"},"tlsName":{"description":"the name in the server certificate"}}}}}},"responses":{"200":{"description":"the connection (masked)"},"400":{"description":"a refused value (host, port, name, certificate)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"},"502":{"description":"not reachable / TLS refused (the reason named)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"}},"/api/zos/connections/{id}":{"put":{"operationId":"zosUpdate","summary":"Change a connection (website logon only): its name, code page, the AI chat / MCP / VS Code seat access switches and the data set / job-name lists (no remote call); or its host, TLS settings or credential (tested again before it is stored)","tags":["mainframes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"access":{"description":"{ ai: { read, write, submit, confirm }, mcp: { read, write, submit }, allow: [patterns], deny: [patterns], jobs: [patterns], jclScan, seat: off|read|write }"},"...":{"description":"any field of the create call"}}}}}},"responses":{"200":{"description":"the connection (masked)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"},"delete":{"operationId":"zosDelete","summary":"Disconnect: the connection and its stored credential are deleted at once","tags":["mainframes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"}],"responses":{"200":{"description":"{ ok, id, host, name }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"}},"/api/zos/connections/{id}/test":{"post":{"operationId":"zosTest","summary":"Test a connection now (GET /zosmf/info + an authenticated data set list)","tags":["mainframes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"}],"responses":{"200":{"description":"{ ok, at, zosmf, zos } or { ok:false, error }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"}},"/api/zos/connections/{id}/logon":{"post":{"operationId":"zosLogon","summary":"Log on again with a new one-time MFA passcode (passcode connections): only the new session token is stored","tags":["mainframes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"passcode":{"description":"a new one-time passcode"}}}}}},"responses":{"200":{"description":"the connection (masked)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"}},"/api/zos/certificate":{"post":{"operationId":"zosCertificate","summary":"\"Show the server's certificate\": a TLS handshake that sends nothing (no request, no credentials) under the same host policy; returns the presented chain (subject, issuer, names, expiry, SHA-256 fingerprint, PEM) and whether it verifies","tags":["mainframes"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"host":{"description":"host"},"port":{"description":"port"},"tlsName":{"description":"optional TLS server name"},"ca":{"description":"optional PEM CA to verify against"}}}}}},"responses":{"200":{"description":"{ host, port, name, verified, error?, chain }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"}},"/api/zos/connections/{id}/datasets":{"get":{"operationId":"zosDatasets","summary":"List data sets on your mainframe (name, DSORG, RECFM, LRECL, volume); for an API key only those inside the connection's allow-list","tags":["mainframes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"},{"name":"level","in":"query","required":false,"schema":{"type":"string"},"description":"data set filter (default <USER>.*)"},{"name":"max","in":"query","required":false,"schema":{"type":"string"},"description":"at most (default 500)"}],"responses":{"200":{"description":"{ conn, level, items, more, note? } (an API key or the AI chat: a filter that cannot list one allowed name is refused 403 ZOS_ACCESS before anything is sent to the mainframe)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"}},"/api/zos/connections/{id}/members":{"get":{"operationId":"zosMembers","summary":"List the members of a PDS on your mainframe","tags":["mainframes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"},{"name":"dsn","in":"query","required":false,"schema":{"type":"string"},"description":"PDS name"},{"name":"pattern","in":"query","required":false,"schema":{"type":"string"},"description":"member pattern"}],"responses":{"200":{"description":"{ conn, dsn, items, more }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"}},"/api/zos/connections/{id}/member":{"get":{"operationId":"zosRead","summary":"Read a member or sequential data set as text (z/OSMF converts from the connection's code page), with its ETag","tags":["mainframes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"},{"name":"dsn","in":"query","required":false,"schema":{"type":"string"},"description":"data set"},{"name":"member","in":"query","required":false,"schema":{"type":"string"},"description":"member (for a PDS)"}],"responses":{"200":{"description":"{ conn, dsn, member, text, etag, codepage }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"},"put":{"operationId":"zosWriteMember","summary":"Save a member / sequential data set on your mainframe as text. Refused before sending (nothing cut): a line longer than the record, a character the code page cannot hold, RECFM U","tags":["mainframes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dsn":{"description":"data set"},"member":{"description":"member"},"text":{"description":"the whole text"},"etag":{"description":"optional: the ETag you read (412 if it changed)"}}}}}},"responses":{"200":{"description":"{ conn, dsn, member, etag, lines }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"}},"/api/zos/connections/{id}/submit":{"post":{"operationId":"zosSubmit","summary":"Submit a job on your mainframe from a member or from JCL text (for an API key: the job name, the JCL's data sets (best effort) and the allow-list are checked)","tags":["mainframes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dsn":{"description":"data set holding the JCL"},"member":{"description":"its member"},"jcl":{"description":"or the JCL text"}}}}}},"responses":{"200":{"description":"{ conn, submitted: { jobname, jobid, owner, status } }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"}},"/api/zos/connections/{id}/jobs":{"get":{"operationId":"zosJobs","summary":"List jobs on your mainframe (an API key: only the connection user's own jobs inside the job-name list)","tags":["mainframes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"},{"name":"owner","in":"query","required":false,"schema":{"type":"string"},"description":"owner (default your mainframe user id)"},{"name":"prefix","in":"query","required":false,"schema":{"type":"string"},"description":"job-name prefix"},{"name":"max","in":"query","required":false,"schema":{"type":"string"},"description":"at most"}],"responses":{"200":{"description":"{ conn, jobs: [{ jobname, jobid, owner, status, retcode }] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"}},"/api/zos/connections/{id}/jobs/{jobname}/{jobid}":{"get":{"operationId":"zosJob","summary":"One job's status and return code","tags":["mainframes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"},{"name":"jobname","in":"path","required":true,"schema":{"type":"string"},"description":"job name"},{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"job id"}],"responses":{"200":{"description":"{ conn, jobname, jobid, owner, status, retcode }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"},"delete":{"operationId":"zosPurge","summary":"Purge a job (cancel it if it runs; its output is deleted)","tags":["mainframes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"},{"name":"jobname","in":"path","required":true,"schema":{"type":"string"},"description":"job name"},{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"job id"}],"responses":{"200":{"description":"{ conn, jobname, jobid, status }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"}},"/api/zos/connections/{id}/jobs/{jobname}/{jobid}/files":{"get":{"operationId":"zosSpoolFiles","summary":"A job's spool files","tags":["mainframes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"},{"name":"jobname","in":"path","required":true,"schema":{"type":"string"},"description":"job name"},{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"job id"}],"responses":{"200":{"description":"{ conn, jobname, jobid, files: [{ id, ddname, stepname, records }] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"}},"/api/zos/connections/{id}/jobs/{jobname}/{jobid}/files/{file}":{"get":{"operationId":"zosSpool","summary":"One spool file as text (shown, never stored by SteelFrame)","tags":["mainframes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"},{"name":"jobname","in":"path","required":true,"schema":{"type":"string"},"description":"job name"},{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"job id"},{"name":"file","in":"path","required":true,"schema":{"type":"string"},"description":"spool file id (or JCL)"}],"responses":{"200":{"description":"{ conn, jobname, jobid, file, text }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"}},"/api/zos/connections/{id}/jobs/{jobname}/{jobid}/cancel":{"post":{"operationId":"zosCancel","summary":"Cancel a job on your mainframe (an API key: only the connection user's own jobs)","tags":["mainframes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"},{"name":"jobname","in":"path","required":true,"schema":{"type":"string"},"description":"job name"},{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"job id"}],"responses":{"200":{"description":"{ conn, jobname, jobid, status }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"}},"/api/zos/connections/{id}/copy":{"post":{"operationId":"zosCopy","summary":"Copy a member between your mainframe and your SteelFrame data sets (text through both code pages; refused, never cut: long lines, characters a code page cannot hold, binary members)","tags":["mainframes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"direction":{"description":"'to-steelframe' | 'to-mainframe'"},"dsn":{"description":"the mainframe data set"},"member":{"description":"its member"},"localDsn":{"description":"your SteelFrame data set (your own HLQ for to-steelframe)"},"localMember":{"description":"its member"},"replace":{"description":"to-steelframe: replace an existing member"}}}}}},"responses":{"200":{"description":"{ conn, from, to, records | lines }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"}},"/api/zos/connections/{id}/uss":{"get":{"operationId":"zosUss","summary":"z/OS UNIX files (the tab only): list a directory or read a text file","tags":["mainframes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"connection id"},{"name":"path","in":"query","required":false,"schema":{"type":"string"},"description":"absolute z/OS UNIX path"},{"name":"read","in":"query","required":false,"schema":{"type":"string"},"description":"1 = read the file as text"}],"responses":{"200":{"description":"{ conn, path, items } or { conn, path, text }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (zos.remote)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"zos.remote"}},"/api/screen/status":{"get":{"operationId":"sdStatus","summary":"Screen MCP (notes/SEAT-CLAUDE-CODE-PLAN.md §8): is your SteelFrame page open for MCP driving (connected, stopped, busy), the page to open, and the tools you have. Free","tags":["screen"],"responses":{"200":{"description":"{ user, page, connected, stopped, busy, tools, next }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/say":{"post":{"operationId":"sdSay","summary":"Screen MCP tool say on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"description":"What to say (max 220 characters)"}}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/screen-read":{"post":{"operationId":"sdScreenRead","summary":"Screen MCP tool screen_read on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/type-field":{"post":{"operationId":"sdTypeField","summary":"Screen MCP tool type_field on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"field":{"description":"\"#id\", \"@N\" or a label regex"},"text":{"description":"text to type (max 2000 chars)"},"clear":{"description":"clear the field first (default true)"}}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/press-key":{"post":{"operationId":"sdPressKey","summary":"Screen MCP tool press_key on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"description":"ENTER | F1..F24 | PA1 | CLEAR"}}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/select-row":{"post":{"operationId":"sdSelectRow","summary":"Screen MCP tool select_row on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"match":{"description":"regex matched against the row text, e.g. \"IBMUSER\\.SOURCE\\b\" or \"^\\s*HELLO\\b\""},"cmd":{"description":"line command letter(s)"}}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/editor-set-text":{"post":{"operationId":"sdEditorSetText","summary":"Screen MCP tool editor_set_text on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"description":"the full text, lines separated by \\n (max 20000 chars)"},"mode":{"description":"\"replace\" (default) or \"append\""}}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/wait-for":{"post":{"operationId":"sdWaitFor","summary":"Screen MCP tool wait_for on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"description":"regex to wait for"},"timeoutMs":{"description":"max wait in ms (default 20000, max 60000)"}}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/read-member":{"post":{"operationId":"sdReadMember","summary":"Screen MCP tool read_member on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dsn":{"description":"dataset name, e.g. IBMUSER.SOURCE"},"member":{"description":"member name (omit for a sequential dataset)"}}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/show-tab":{"post":{"operationId":"sdShowTab","summary":"Screen MCP tool show_tab on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tab":{"description":"\"terminal\""}}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/job-output":{"post":{"operationId":"sdJobOutput","summary":"Screen MCP tool job_output on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"jobid":{"description":"JES2 job id, e.g. JOB00123"},"dd":{"description":"spool file handle: DD or STEP.DD (optional)"},"tail":{"description":"last N lines (default 60, max 300)"}}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/pg-tables":{"post":{"operationId":"sdPgTables","summary":"Screen MCP tool pg_tables on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/pg-open-table":{"post":{"operationId":"sdPgOpenTable","summary":"Screen MCP tool pg_open_table on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"table":{"description":"the table, \"schema.table\" or \"table\", e.g. \"carddemo.account\""},"view":{"description":"\"rows\" (default) | \"structure\" | \"indexes\" | \"constraints\""},"max_rows":{"description":"rows to return in the rows view (default 10, max 50)"}}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/pg-query":{"post":{"operationId":"sdPgQuery","summary":"Screen MCP tool pg_query on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sql":{"description":"one SQL statement, e.g. \"SELECT acct_id, acct_curr_bal FROM carddemo.account ORDER BY acct_curr_bal DESC LIMIT 5\""},"max_rows":{"description":"rows to return (default 50, max 200)"}}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/pg-explain":{"post":{"operationId":"sdPgExplain","summary":"Screen MCP tool pg_explain on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sql":{"description":"the statement to explain, e.g. \"SELECT * FROM carddemo.transaction WHERE tran_card_num = '4859452612877065'\""},"analyze":{"description":"also run it (read-only) and show actual times (default false)"}}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/pg-exec":{"post":{"operationId":"sdPgExec","summary":"Screen MCP tool pg_exec on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sql":{"description":"the SQL script"}}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/pg-export-csv":{"post":{"operationId":"sdPgExportCsv","summary":"Screen MCP tool pg_export_csv on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sql":{"description":"one read-only statement, e.g. \"SELECT * FROM carddemo.account ORDER BY acct_id\""},"filename":{"description":"optional file name, e.g. \"accounts.csv\" (letters, digits, _ . - only)"}}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/app-open":{"post":{"operationId":"sdAppOpen","summary":"Screen MCP tool app_open on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"port":{"description":"the app's port, e.g. 3000"},"path":{"description":"optional: a path on the app, e.g. \"/\" or \"/accounts?id=1\""}}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/app-read":{"post":{"operationId":"sdAppRead","summary":"Screen MCP tool app_read on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/app-click":{"post":{"operationId":"sdAppClick","summary":"Screen MCP tool app_click on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ref":{"description":"the element number, e.g. 3"},"text":{"description":"or: a visible text, e.g. \"Accounts\""}}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/screen/app-type":{"post":{"operationId":"sdAppType","summary":"Screen MCP tool app_type on your own open SteelFrame page","tags":["screen"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ref":{"description":"the element number of the field"},"text":{"description":"the text (max 2000 chars)"},"enter":{"description":"press Enter afterwards (default false)"}}}}}},"responses":{"200":{"description":"{ tool, ok, result }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (screen.drive)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"screen.drive"}},"/api/vsam/define":{"post":{"operationId":"vsamDefine","summary":"Define a VSAM cluster (IDCAMS DEFINE CLUSTER equivalent)","tags":["datasets"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"cluster name"},"type":{"description":"KSDS|ESDS|RRDS (default KSDS)"},"keylen":{"description":"key length"},"keyoff":{"description":"key offset"},"maxrecl":{"description":"max record length"},"avgrecl":{"description":"average record length"},"volser":{"description":"volume (default WORK01)"},"freespace":{"description":"freespace string"}}}}}},"responses":{"200":{"description":"catalog entry"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/vsam/info":{"get":{"operationId":"vsamInfo","summary":"VSAM cluster attributes and record count","tags":["datasets"],"parameters":[{"name":"dsn","in":"query","required":false,"schema":{"type":"string"},"description":"cluster name"}],"responses":{"200":{"description":"{ dsn, type, keylen, keyoff, recl, volser, freespace, created, alts, recTotal }"},"400":{"description":"IDC3009I not a VSAM cluster"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"404":{"description":"IDC3012I entry not found"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/vsam/alter":{"post":{"operationId":"vsamAlter","summary":"Alter a VSAM cluster (IDCAMS ALTER: NEWNAME/FREESPACE only, like real)","tags":["datasets"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dsn":{"description":"cluster name"},"newname":{"description":"new name (optional)"},"freespace":{"description":"freespace string (optional)"}}}}}},"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"},"404":{"description":"IDC3012I entry not found"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/submit":{"post":{"operationId":"submitJob","summary":"Submit JCL to JES2 (internal-reader equivalent)","tags":["jobs"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"lines":{"description":"array of JCL card images"}}}}}},"responses":{"200":{"description":"{ jobid, jobname }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/jobs":{"get":{"operationId":"listJobs","summary":"List jobs on the queue/output, most recent first - the jobs the caller may see: its own and those that NOTIFY it (RACF SPECIAL/OPERATIONS: every job; a JESSPOOL READ grant on SFNODE.<owner>.<jobname>.<jobid> adds that job)","tags":["jobs"],"parameters":[{"name":"max","in":"query","required":false,"schema":{"type":"string"},"description":"return at most N jobs (default: all)"},{"name":"owner","in":"query","required":false,"schema":{"type":"string"},"description":"only jobs owned by this userid"},{"name":"prefix","in":"query","required":false,"schema":{"type":"string"},"description":"only jobs whose jobname matches (exact name or * wildcard, like SDSF PREFIX)"},{"name":"skip","in":"query","required":false,"schema":{"type":"string"},"description":"skip the first N matching jobs (paging window for SDSF F8/DOWN)"},{"name":"count","in":"query","required":false,"schema":{"type":"string"},"description":"1 = return { total } of matching jobs instead of the list (paging: DOWN MAX)"}],"responses":{"200":{"description":"[job]  (with count=1: { total })"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.read"}},"/api/jobs/{jobid}":{"get":{"operationId":"getJob","summary":"Job status + spool file list","tags":["jobs"],"parameters":[{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"JES2 job id (JOBnnnnn)"}],"responses":{"200":{"description":"{ ...job, files }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.read)"},"404":{"description":"No such job"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.read"},"delete":{"operationId":"purgeJob","summary":"Purge a job and its spool","tags":["jobs"],"parameters":[{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"JES2 job id"}],"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/jobs/{jobid}/wait":{"get":{"operationId":"waitJob","summary":"Long-poll until the job completes — OUTPUT or OUTPUT-HOLD (or timeout)","tags":["jobs"],"parameters":[{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"JES2 job id"},{"name":"timeout","in":"query","required":false,"schema":{"type":"string"},"description":"seconds (default 60, max 300)"}],"responses":{"200":{"description":"{ ...job, files } or { ...job, timedOut: true }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.read)"},"404":{"description":"No such job"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.read"}},"/api/jobs/{jobid}/file/{name}":{"get":{"operationId":"readSpool","summary":"Read one spool file of a job — by its full name from the files list (Dnnnn.STEP.DD) or by the stable STEP.DD / DD handle (the Dnnnn spool-dataset number is assigned per run and shifts between otherwise identical jobs)","tags":["jobs"],"parameters":[{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"JES2 job id"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"spool file name (from the files list), or STEP.DD / PROCSTEP.STEP.DD / DD without the Dnnnn prefix"}],"responses":{"200":{"description":"{ content, name (the resolved spool file name when a handle was given) }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.read)"},"404":{"description":"No such spool file / handle (the message lists the job's spool files)"},"409":{"description":"A DD handle matches more than one spool file (the message lists them — give STEP.DD or the full name)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.read"}},"/api/console":{"post":{"operationId":"consoleCommand","summary":"Issue an MVS/JES2 operator console command in real syntax (D A[,L], D J, D TS, D GRS[,C], D T, D M=CPU/D M=STOR, $DA, $DJ, $D SPOOL, $D I, $PJ, $SJ, $HJ/$AJ/$TJ, $TA/$CA automatic commands, $P JES2[,ABEND[,FORCE]|,TERM]/$S/S JES2, C/CANCEL jobname, MODIFY/F name,cmd, R nn,text, VARY/SET). Returns the console response lines and a return code, mapped onto live job/spool/GRS/instance state","tags":["jobs"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"command":{"description":"the console command text (leading / optional)"}}}}}},"responses":{"200":{"description":"{ lines: [...], rc }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/jes/replies":{"get":{"operationId":"listReplies","summary":"Outstanding operator replies (WTOR): console messages awaiting a reply, with the owning job","tags":["jobs"],"responses":{"200":{"description":"[{ replyId, jobid, jobname, message, since }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.read"}},"/api/jes/replies/{replyId}":{"post":{"operationId":"replyWtor","summary":"Answer an outstanding reply (console R nn,text equivalent) — unblocks the waiting job step","tags":["jobs"],"parameters":[{"name":"replyId","in":"path","required":true,"schema":{"type":"string"},"description":"outstanding reply id (2-digit, leading zero optional)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"description":"reply text delivered to the waiting program"}}}}}},"responses":{"200":{"description":"{ ok, replyId, jobid }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"},"404":{"description":"No such outstanding reply"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/jobs/{jobid}/cancel":{"post":{"operationId":"cancelJob","summary":"Cancel a job ($C J equivalent). ACTIVE: kills the tracked step child processes, unblocks its outstanding replies, and the job completes ABEND S222 with canceled:true. INPUT-HOLD: the held job completes CANCELED without ever running. OUTPUT-HOLD: the held output is canceled — the job is purged","tags":["jobs"],"parameters":[{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"JES2 job id"}],"responses":{"200":{"description":"{ ok, jobid, jobname, purged? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"},"404":{"description":"No such job"},"409":{"description":"Job not ACTIVE or held (queued-job removal is a flush, not a cancel)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/jobs/{jobid}/hold":{"post":{"operationId":"holdJob","summary":"Hold a job still on the input queue ($H J equivalent): it stays INPUT-HOLD — the mined casout /g state 1 — until released. TYPRUN=HOLD jobs arrive already held","tags":["jobs"],"parameters":[{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"JES2 job id"}],"responses":{"200":{"description":"{ ok, jobid, jobname }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"},"404":{"description":"No such job"},"409":{"description":"Job not on the input queue (already held, ACTIVE, or OUTPUT)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/jobs/{jobid}/release":{"post":{"operationId":"releaseJob","summary":"Release a held job ($A J equivalent): an INPUT-HOLD job (operator hold or TYPRUN=HOLD/JCLHOLD) is queued for the initiator and runs","tags":["jobs"],"parameters":[{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"JES2 job id"}],"responses":{"200":{"description":"{ ok, jobid, jobname }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"},"404":{"description":"No such job"},"409":{"description":"Job not held"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/jobs/{jobid}/release-output":{"post":{"operationId":"releaseOutput","summary":"Release a job's HELD output ($O J equivalent): an OUTPUT-HOLD job (finished into a held MSGCLASS — ES_JES_HELD_CLASSES, the mined casout /g state 7) moves to OUTPUT","tags":["jobs"],"parameters":[{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"JES2 job id"}],"responses":{"200":{"description":"{ ok, jobid, jobname }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"},"404":{"description":"No such job"},"409":{"description":"Job output not held"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/jes/output/{class}/release":{"post":{"operationId":"releaseOutputClass","summary":"Release ALL held output of one class at once ($O Q<class> equivalent, the SDSF 'O' action against the whole H queue): every OUTPUT-HOLD job whose MSGCLASS is the class moves to OUTPUT via the per-job releaseOutput machinery. An empty held queue is ok:true count:0, not an error","tags":["jobs"],"parameters":[{"name":"class","in":"path","required":true,"schema":{"type":"string"},"description":"output class (one letter/digit — a held class from ES_JES_HELD_CLASSES)"}],"responses":{"200":{"description":"{ ok, class, count, released: [jobid] }"},"400":{"description":"Invalid output class (want one letter/digit)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/jes/output/{class}/purge":{"post":{"operationId":"purgeOutputClass","summary":"Purge ALL held output of one class ($P against the held-output queue): every OUTPUT-HOLD job of the class is purged — job and spool gone ($SFJS250 each) — through the same JESSPOOL-ALTER-gated purge a direct DELETE uses. An empty held queue is ok:true count:0","tags":["jobs"],"parameters":[{"name":"class","in":"path","required":true,"schema":{"type":"string"},"description":"output class (one letter/digit — a held class from ES_JES_HELD_CLASSES)"}],"responses":{"200":{"description":"{ ok, class, count, purged: [jobid] }"},"400":{"description":"Invalid output class (want one letter/digit)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/jes/printers":{"get":{"operationId":"listPrinters","summary":"Bound TN3270E printer LUs (3287 sessions) with their delivery state — the SDSF printer (PR) panel status columns for the released-sysout->printer routing: a sysout delivered to a 3287 shows 'printed to LU <x>'; nothing bound (or nothing delivered) is visible too","tags":["jobs"],"responses":{"200":{"description":"[{ lu, devType, mode (SCS/LU1 | DSC/LU3), associatedTerminal, delivered, status, lastDelivered: { jobid, file, class, at } }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.read"}},"/api/jobs/{jobid}/requeue":{"post":{"operationId":"requeueJob","summary":"Requeue a COMPLETED job for re-execution ($E J equivalent; the casout /j job[:step[:proc]] restart family): the stored JESJCL spool deck is re-submitted as a NEW job under the original owner. restart=STEP[.PROCSTEP] arms the G4 deferred restart (RESTART= JOB-card equivalent) for the re-run — prior steps BYPASS. Honoured by default like the JOB-card path (z/OS); refused only when ES_JES_RESTART is explicitly 0/NO/OFF (the MF-ES restart-disabled posture)","tags":["jobs"],"parameters":[{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"JES2 job id of the completed job"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"restart":{"description":"STEP[.PROCSTEP] (optional): restart the re-run at this step; refused 409 when ES_JES_RESTART is explicitly off"}}}}}},"responses":{"200":{"description":"{ ok, jobid (the NEW job), jobname, requeuedFrom, restart, errors }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"},"404":{"description":"No such job"},"409":{"description":"Job not complete, restart disabled (ES_JES_RESTART explicitly off), invalid restart step, or JESJCL lost"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/inventory":{"get":{"operationId":"inventoryScan","summary":"Static portfolio scan: programs (language/LOC/CICS/SQL/DLI/MQ flags, CALL+COPY refs), jobs (EXEC PGM steps, DSN refs), BMS mapsets, copybooks","tags":["modernize"],"parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string"},"description":"dataset pattern to scan (default **)"}],"responses":{"200":{"description":"{ programs, jobs, screens, copybooks, truncated }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/waves":{"get":{"operationId":"wavesGet","summary":"The migration wave board (waves of programs/jobs/screens with framework + sign-off state)","tags":["modernize"],"responses":{"200":{"description":"{ waves: [{ id, name, framework, status, items, notes, updated }] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"},"put":{"operationId":"wavesPut","summary":"Replace the wave board document","tags":["modernize"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"waves":{"description":"array of waves"}}}}}},"responses":{"200":{"description":"the stored document"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/analysis/model":{"get":{"operationId":"analysisModel","summary":"The estate analysis model index (W7.1): per-program paragraphs/calls/files/SQL with dynamic-target resolution counts, per-job step+DD detail, screens, copybooks","tags":["modernize"],"parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string"},"description":"dataset pattern to scan (default **)"},{"name":"refresh","in":"query","required":false,"schema":{"type":"string"},"description":"bypass the 30s model cache when \"1\""}],"responses":{"200":{"description":"{ programs, jobs, screens, copybooks, truncated, origins }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/analysis/graph":{"get":{"operationId":"analysisGraph","summary":"Analysis graphs (W7.1): kind=call (CALL/LINK/XCTL edges with literal/resolved/unresolved provenance), kind=job (job→program→dataset with I/O direction + cross-job dataflow), kind=screen (mapsets/transids + XCTL/RETURN-TRANSID navigation; transids resolve through the region CSD)","tags":["modernize"],"parameters":[{"name":"kind","in":"query","required":false,"schema":{"type":"string"},"description":"call | job | screen (required)"},{"name":"q","in":"query","required":false,"schema":{"type":"string"},"description":"dataset pattern to scan (default **)"},{"name":"refresh","in":"query","required":false,"schema":{"type":"string"},"description":"bypass the model cache when \"1\""}],"responses":{"200":{"description":"{ kind, nodes, edges, truncated }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/analysis/impact":{"post":{"operationId":"analysisImpact","summary":"Field-level impact trace (W7.2, A13.2b): BFS over the estate impact graph — MOVE/COMPUTE/arith dataflow, group/REDEFINES aliasing, copybook identity, CALL USING linkage, COMMAREA, WRITE→dataset→READ file flow — from a seed field; expand:true answers the Change-Analyzer-style worklist grouped by program/copybook/dataset","tags":["modernize"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"field":{"description":"seed field name (required)"},"program":{"description":"restrict the seed to one program"},"copybook":{"description":"seed the copybook-identity hub instead"},"depth":{"description":"BFS depth cap (default 6)"},"dir":{"description":"'forward' | 'backward' | 'both' (default both)"},"expand":{"description":"true = seed-expansion worklist shape"},"q":{"description":"dataset pattern to scan (default **)"}}}}}},"responses":{"200":{"description":"{ seed, nodes: [{program|copybook, field, hop, condSites}], edges: [{fromProg, fromField, toProg, toField, kind, ln, dsn}], summary, truncated } (or the expandSeeds shape)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/analysis/metrics":{"get":{"operationId":"analysisMetrics","summary":"Complexity/dead-code metrics (W7.3, A13.2c): per-program cyclomatic complexity (pinned formula 1+IF+WHEN+AND/OR+UNTIL+handlers), dead paragraphs (conservative reachability; ALTER programs refuse loudly), unreferenced data, estate-dead copybook fields, plus the text report","tags":["modernize"],"parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string"},"description":"dataset pattern to scan (default **)"},{"name":"program","in":"query","required":false,"schema":{"type":"string"},"description":"single program (full metrics row)"},{"name":"report","in":"query","required":false,"schema":{"type":"string"},"description":"\"text\" adds the rendered report"},{"name":"refresh","in":"query","required":false,"schema":{"type":"string"},"description":"bypass the model cache when \"1\""}],"responses":{"200":{"description":"{ programs: [metrics rows], estate, copybookDead, report? } or { program: metrics row }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/analysis/explain":{"get":{"operationId":"analysisExplain","summary":"LLM program explanation over the analysis model (W7.4, A12.12): assembles a deterministic context pack (structure, call neighborhood, jobs/datasets, screens, metrics, shared copybooks, capped source) into a provider-agnostic request. GATED without tenant AI config (SF_AI_PROVIDER/SF_AI_MODEL/SF_AI_KEY/SF_AI_URL): returns the assembled prompt+request with gated:true, never a fabricated answer; with a key the live call runs","tags":["modernize"],"parameters":[{"name":"program","in":"query","required":false,"schema":{"type":"string"},"description":"program name (required)"},{"name":"paragraph","in":"query","required":false,"schema":{"type":"string"},"description":"focus one paragraph"},{"name":"q","in":"query","required":false,"schema":{"type":"string"},"description":"dataset pattern to scan (default **)"}],"responses":{"200":{"description":"{ gated, reason?, provider, model, prompt, request, context } or { answer, stopReason, provider, model }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/captures":{"post":{"operationId":"captureRun","summary":"Run a JCL job and capture its golden envelope: RC/abend, all spool files, named output datasets as raw record hex","tags":["verify"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"capture name"},"jcl":{"description":"JCL card images"},"datasets":{"description":"output dataset names to snapshot (optional)"},"masks":{"description":"regexes masked before spool compare (defaults: jobids/timestamps)"}}}}}},"responses":{"200":{"description":"capture summary { id, jobname, maxcc, spoolFiles, datasets, sha256 }"},"400":{"description":"No JCL / run timed out"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"},"get":{"operationId":"captureList","summary":"List golden-run captures (with last compare verdicts)","tags":["verify"],"responses":{"200":{"description":"[capture summary]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.read"}},"/api/captures/{id}":{"get":{"operationId":"captureGet","summary":"Full capture: JCL, masks, baseline envelope (spool text + dataset record hex)","tags":["verify"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"capture id"}],"responses":{"200":{"description":"capture"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.read)"},"404":{"description":"No such capture"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.read"},"delete":{"operationId":"captureDelete","summary":"Delete a run record (run_batch / cics_run_script / sched_wait_cycle) or a golden capture by id","tags":["verify"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"run record / capture id"}],"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"},"404":{"description":"No such capture"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/captures/{id}/compare":{"post":{"operationId":"captureCompare","summary":"Re-run the captured JCL now and diff the envelope against the baseline — verdicts identical/different/missing per artifact, masked spool compare, byte-true dataset compare","tags":["verify"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"capture id"}],"responses":{"200":{"description":"{ verdict, verdicts: {identical,different,missing}, diffs: [{kind,name,verdict,detail}] }"},"400":{"description":"Re-run failed"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"},"404":{"description":"No such capture"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/search/source":{"get":{"operationId":"searchSource","summary":"Find source members by kind and/or content across the text PO libraries: kind is detected from content (program|copybook|jcl|proc|bms|csd|other); with q the matching lines are returned with optional context, without q the members of the wanted kinds are listed","tags":["oracle"],"parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string"},"description":"text to find (substring, case-insensitive; regex=true for a regular expression); omit to list members by kind"},{"name":"regex","in":"query","required":false,"schema":{"type":"string"},"description":"'true' = q is a regular expression"},{"name":"kinds","in":"query","required":false,"schema":{"type":"string"},"description":"comma list of kinds to keep: program,copybook,jcl,proc,bms,csd,other"},{"name":"libraries","in":"query","required":false,"schema":{"type":"string"},"description":"comma list of PO datasets to scan (default: every non-load PO library; the 2000-member scan cap applies — give libraries on big estates); dsn / library are aliases"},{"name":"member","in":"query","required":false,"schema":{"type":"string"},"description":"member-name pattern (* wildcard)"},{"name":"max","in":"query","required":false,"schema":{"type":"string"},"description":"result cap (default 200, max 2000)"},{"name":"context","in":"query","required":false,"schema":{"type":"string"},"description":"lines of context before/after each hit (0-20)"}],"responses":{"200":{"description":"{ hits: [{dsn, member, kind, line, text, before?, after?}], members: [{dsn, member, kind, lines}], scanned, truncated, denied: [dsn the caller may not READ — skipped, same DATASET gate as read_member] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/search/program/{name}":{"get":{"operationId":"findProgram","summary":"Everything the estate knows about one program, as data: source location, transitive copybooks (COPY / EXEC SQL INCLUDE closure through the copybook libraries), load modules, every JCL step that runs it (+ the deck location), the CSD slice (PPT entry, transactions, FILEs the source names), mapsets, and the scheduler jobs that run those decks","tags":["oracle"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"program name"},{"name":"syslib","in":"query","required":false,"schema":{"type":"string"},"description":"comma list of copybook libraries to resolve COPY through (default: the source library, every *COPY*/DCLGEN PO, SYS2.COBOL.COPYLIB)"}],"responses":{"200":{"description":"{ program, found, source: {dsn, member}, copybooks: [{name, dsn, via?, missing?}], loadModules, jclRunning: [{job, member, dsn, step, pgm}], csd: {program, transactions, files}, mapsets, scheduledBy: [{folder, job, member, triggers}], summary }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/dataset/{dsn}/decoded":{"get":{"operationId":"decodeRecords","summary":"Records of a dataset decoded through a copybook: byte truth (hex, charset stated — EBCDIC at rest for PS/PDS, program image for KSDS/ESDS) beside the decoded rows (alphanumerics right-trimmed, numerics as exact scaled-decimal strings, OCCURS expanded, FILLER omitted) and the field layout","tags":["oracle"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"dataset name (GDG relative (0)/(-n) accepted)"},{"name":"copybook","in":"query","required":false,"schema":{"type":"string"},"description":"record layout as 'LIB(MEMBER)' or { dsn, member } (required)"},{"name":"record","in":"query","required":false,"schema":{"type":"string"},"description":"which 01 level to use when the copybook holds several"},{"name":"member","in":"query","required":false,"schema":{"type":"string"},"description":"PDS member (for a PO dataset)"},{"name":"from","in":"query","required":false,"schema":{"type":"string"},"description":"first record (0-based, default 0)"},{"name":"count","in":"query","required":false,"schema":{"type":"string"},"description":"records to return (default 1000, max 10000)"},{"name":"hex","in":"query","required":false,"schema":{"type":"string"},"description":"'false' = rows only (default true: hex beside rows)"},{"name":"syslib","in":"query","required":false,"schema":{"type":"string"},"description":"comma list of libraries nested COPY statements resolve through"},{"name":"ccsid","in":"query","required":false,"schema":{"type":"string"},"description":"CCSID the EBCDIC-at-rest alphanumerics decode through (SBCS 37/273/284/285/297/500/1140/... or mixed 930/939/933/935/937/1399 with SO/SI); default = the dataset's effective CCSID (37). EBCDIC-at-rest datasets (PS/PDS/GDG) only: on a program-charset VSAM cluster it has no effect and the answer says so (ccsidIgnored: true + ccsidNote). PIC G is DBCS, PIC N UTF-16BE regardless"},{"name":"numbers","in":"query","required":false,"schema":{"type":"string"},"description":"numeric output form: 'native' (default: a JSON number when a double carries the exact decimal, else the exact decimal string — a whole-valued S9(10)V99 shows as 194, a 9(9) as 20973888), 'decimal' (ALWAYS the exact decimal text at the PICTURE scale: \"194.00\", \"-0.05\", \"20973888\") or 'display' (the fixed-width digit image of the PICTURE: \"0000000194.00\", \"020973888\"). Same byte-true magnitude in every form; layout[] carries digits/scale/signed per numeric field"}],"responses":{"200":{"description":"{ dsn, dsorg, recfm, lrecl, charset, ccsid?, ccsidIgnored?, ccsidNote?, numbers, copybook, record, records, recordLength, layout: [{field, offset, length, pic, usage, digits?, scale?, signed?}], total, from, count, sha256, rows: [{...}], hex?: [..] }"},"400":{"description":"No copybook / ODO copybook / bad record name / unknown ccsid / bad numbers form"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"404":{"description":"Dataset or copybook not found"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/records/encode":{"post":{"operationId":"encodeRecords","summary":"JSON rows -> record images through a copybook (the inverse of decode_records): charset ebcdic (PS at rest — DISPLAY fields transcoded, COMP/COMP-3 bit-exact) or program (KSDS/ESDS image); feed the hex to write_records","tags":["oracle"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"copybook":{"description":"record layout as 'LIB(MEMBER)' or { dsn, member }"},"lines":{"description":"or the copybook card images inline"},"record":{"description":"which 01 level when the copybook holds several"},"rows":{"description":"array of row objects (keys = item names, case/hyphen-insensitive; groups nested or flat; OCCURS as arrays; numerics as strings or numbers)"},"charset":{"description":"'ebcdic' (default, PS/PDS at rest) or 'program' (KSDS/ESDS image)"},"ccsid":{"description":"CCSID of the EBCDIC alphanumerics (default 37): SBCS pages 273/284/285/297/500/1140/... or mixed 930/939/933/935/937/1399 (SO/SI framed); unmappable characters -> the page's SUB X'3F'. PIC G = DBCS 2 bytes/char (X'4040' pad), PIC N = UTF-16BE 2 bytes/char regardless"},"syslib":{"description":"libraries nested COPY statements resolve through"}}}}}},"responses":{"200":{"description":"{ charset, ccsid?, record, recordLength, layout, count, hex: [..] }"},"400":{"description":"No copybook/rows, ODO copybook, bad charset, unknown ccsid"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"404":{"description":"Copybook not found"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/dataset/{dsn}/load":{"put":{"operationId":"loadDataset","summary":"SEED a dataset with records (hex, charset stated) or rows (+copybook) in one call: PS replace/append (all-or-nothing), KSDS replace (delete every key + write, one batched op list — cluster/AIX/PATH/catalog untouched) / append (duplicates reported) / upsert (rewrite-or-write), ESDS replace/append; allocates the dataset first when allocate:{attrs}|{like} is given. Refused for system HLQs and while a CICS task holds record locks","tags":["oracle"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"target dataset (PS, KSDS, ESDS; GDG generation by absolute name or (0)/(-n))"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"records":{"description":"array of hex record images"},"charset":{"description":"charset of `records`: 'auto' (default = the own convention of the dataset: PS = EBCDIC at rest, KSDS/ESDS = program image) | 'ebcdic' | 'program' (a mismatch needs copybook so packed/binary fields convert correctly)"},"rows":{"description":"array of row objects (needs copybook or lines)"},"copybook":{"description":"record layout LIB(MEMBER)"},"lines":{"description":"or the copybook inline"},"record":{"description":"which 01 level"},"syslib":{"description":"copybook libraries"},"mode":{"description":"'replace' (default) | 'append' | 'upsert' (KSDS only)"},"member":{"description":"PDS member (PS-style load into one member)"},"allocate":{"description":"when not cataloged: { attrs: {dsorg, recfm, lrecl, blksize?, volser?} | {dsorg:'VS', vsam:{type, keylen, keyoff, recl, alts?}} | {esds:true, lrecl} } or { like: 'MODEL.DSN' }"}}}}}},"responses":{"200":{"description":"{ ok, dsn, dsorg, mode, charset, given, written, deleted?, updated?, duplicates?, failed?, total, sha256, allocated?, layout? }"},"400":{"description":"Bad records/rows/mode, RRDS, AIX/PATH target, LRECL overflow"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.write)"},"404":{"description":"Not cataloged (no allocate)"},"409":{"description":"Record locks held / edit ENQ"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/api/dataset/{dsn}/gdg":{"post":{"operationId":"stageGdg","summary":"Roll a NEW generation into a GDG base from records/rows: a staging PS is loaded, then a real IEBGENER step with DSN=BASE(+1),DISP=(NEW,CATLG) creates the generation through the JES DISP path exactly as a production job would; returns the absolute GnnnnV00 name and the joblog","tags":["oracle"],"parameters":[{"name":"dsn","in":"path","required":true,"schema":{"type":"string"},"description":"GDG base name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"records":{"description":"hex record images (EBCDIC at rest)"},"rows":{"description":"rows (+copybook)"},"copybook":{"description":"LIB(MEMBER)"},"lines":{"description":"copybook inline"},"record":{"description":"01 level"},"charset":{"description":"'auto'|'ebcdic'|'program' for records"},"attrs":{"description":"{ recfm, lrecl } (default: the DCB of the newest generation, else the base model)"}}}}}},"responses":{"200":{"description":"{ ok, base, generation, records, jobid, maxcc, steps, joblog, gens }"},"400":{"description":"Bad records"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"},"404":{"description":"Not a GDG base"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/export/state":{"post":{"operationId":"exportState","summary":"A pure DUMP of what the mainframe holds right now: named datasets (hex + rows when a copybook is given, charset stated, sha256), DB2 tables (rows), and optionally one job's spool — persisted server-side (get_state) and returned inline. Take two dumps (before/after, or oracle vs candidate) and compare them on YOUR side; SteelFrame does not diff","tags":["oracle"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"datasets":{"description":"array of dataset names or { dsn, copybook: 'LIB(MEMBER)', record?, member? }"},"db2":{"description":"array of table names or { table, orderBy }  (needs db2.exec)"},"spool":{"description":"{ jobid, files?: [STEP.DD names] } to include a joblog"},"records":{"description":"'both' (default) | 'hex' | 'rows' | 'none' (hashes + counts only)"},"name":{"description":"label"}}}}}},"responses":{"200":{"description":"{ id, name, created, sha256, artifacts: [{kind, name, charset, count, sha256}], datasets: {dsn: {..., vsam?, aixes?, define?}}, db2: {table: {columns, rows, count, sha256, type, ddl[] (CREATE TABLE + indexes)}}, spool }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"},"get":{"operationId":"listStates","summary":"List persisted state dumps (export_state), newest first","tags":["oracle"],"responses":{"200":{"description":"[{ id, name, created, user, sha256, artifacts }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/workspaces":{"post":{"operationId":"createWorkspace","summary":"Create an ISOLATED workspace: a child engine on a copy of the estate (seed clone = copy of the live root incl. datasets/CSD/scheduler store, the parent's spool left behind unless includeSpool:true; snapshot:<id> = a quiesced snapshot; fresh = a seeded new system). Every tool then runs INSIDE it (pass workspace:<id> on any tool call) as you, and the live estate is never touched. Disposed at the TTL or by destroy_workspace. ram:true = a RAM-only zero-retention sandbox-class child instead of a disk child (what the private lane always makes). CREATION IS ASYNCHRONOUS: the workspace is registered at once with status CREATING (phase + progress in the view) while the estate copy and child boot run in the background; the call returns as soon as status leaves CREATING or after waitSeconds (default 20, max 45 — always under a 60 s MCP client timeout). If the response says status:CREATING, poll get_workspace every 10-15 s until status=RUNNING (ready:true) before passing workspace:<id> on other tools — they are refused 409 NOT READY until then. Do NOT call create_workspace again meanwhile: the same name returns the in-flight row (reused:true), a different name counts against your cap (429). A clone takes seconds to a few minutes depending on the host (the view's progress.typicalSeconds is the last one on this engine)","tags":["oracle"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"seed":{"description":"'clone' (default) | 'fresh' | 'snapshot:<id>'"},"ttlSeconds":{"description":"dispose after N seconds (default 3600, max 86400)"},"name":{"description":"label AND per-user idempotency key: naming a workspace of yours that is CREATING or RUNNING (same seed/kind) returns that one (reused:true) instead of cloning again — give every workspace a name"},"waitSeconds":{"description":"how long this call may wait for status to leave CREATING before answering (default 20, 0 = answer at once, max 45)"},"jobNumber":{"description":"set the child JES2 job-number counter (JOBIDs line up across re-runs)"},"ram":{"description":"true = RAM-only zero-retention sandbox-class child (the private lane's kind); default false = disk child under the data root"},"includeSpool":{"description":"clone only: true = also copy the parent's JES2 spool (every past job's output — most of the estate's files, minutes on a big one); default false = the workspace starts with an empty spool and the parent's job-number counter"}}}}}},"responses":{"200":{"description":"{ workspace, name, owner, seed, created, booted, expires, ttlSeconds, jobNumber, status: CREATING|RUNNING|FAILED|GONE|CANCELLING|DESTROYING, ready, phase?, progress?: { phase, elapsedSeconds, typicalSeconds }, error?, next? (what to do: poll / destroy+recreate / wait for an unwinding row to disappear), instance, calls, ram, ramBacked?, retained?: false } + reused (true when an existing CREATING/RUNNING workspace of yours with this name was returned)"},"400":{"description":"Bad seed/ttl/waitSeconds"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (workspace.write)"},"404":{"description":"No such snapshot"},"429":{"description":"Per-user / plane cap (counts workspaces still CREATING and ones still CANCELLING/DESTROYING after a destroy — the message names them: poll get_workspace, do not re-create; an unwinding row is gone within seconds)"},"503":{"description":"Child failed to boot (synchronous only for a seed that fails validation; a boot failure after the wait shows as status FAILED + error in the view)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"workspace.write"},"get":{"operationId":"listWorkspaces","summary":"List your workspaces (a SPECIAL user sees all; ram:true marks the RAM-only ones) — including the ones still CREATING (status/phase/progress) and recently FAILED ones (error)","tags":["oracle"],"responses":{"200":{"description":"[{ workspace, name, owner, seed, created, booted, expires, ttlSeconds, jobNumber, status: CREATING|RUNNING|FAILED|GONE|CANCELLING|DESTROYING, ready, phase?, progress?: { phase, elapsedSeconds, typicalSeconds }, error?, next? (what to do: poll / destroy+recreate / wait for an unwinding row to disappear), instance, calls, ram, ramBacked?, retained?: false }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (workspace.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"workspace.read"}},"/api/workspaces/{id}":{"get":{"operationId":"getWorkspace","summary":"One workspace — THE POLL after create_workspace / reset_workspace: status CREATING (phase, progress.elapsedSeconds, progress.typicalSeconds) → RUNNING (ready:true, use it) | FAILED (error: destroy and recreate); after destroy_workspace: CANCELLING | DESTROYING until the row is gone (404)","tags":["oracle"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"workspace id"}],"responses":{"200":{"description":"{ workspace, name, owner, seed, created, booted, expires, ttlSeconds, jobNumber, status: CREATING|RUNNING|FAILED|GONE|CANCELLING|DESTROYING, ready, phase?, progress?: { phase, elapsedSeconds, typicalSeconds }, error?, next? (what to do: poll / destroy+recreate / wait for an unwinding row to disappear), instance, calls, ram, ramBacked?, retained?: false }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (workspace.read)"},"404":{"description":"No such workspace"},"410":{"description":"Gone (TTL/child died)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"workspace.read"},"delete":{"operationId":"destroyWorkspace","summary":"Destroy a workspace (the child engine and its copy of the estate are removed). On a workspace still CREATING this cancels it (cancelled:true): the estate copy is stopped at once (a queued copy leaves the queue, a running copy process is killed), no child engine boots, the partial directory is removed. The row stays visible as CANCELLING (or DESTROYING for a RUNNING one) and counts toward your cap only until that is done — the call waits for it up to waitSeconds (default 15, max 45) and answers settled:true (row gone) or settled:false (still unwinding: poll get_workspace until 404). Idempotent: destroying an unwinding row again just reports it","tags":["oracle"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"workspace id"},{"name":"waitSeconds","in":"query","required":false,"schema":{"type":"string"},"description":"how long to wait for the child/copy to be fully gone before answering (default 15, 0 = answer at once, max 45)"}],"responses":{"200":{"description":"{ ok, workspace, calls, ram, settled (true = row gone, cap free), status: GONE|CANCELLING|DESTROYING, cancelled? (the workspace was still creating), already? (it was already being destroyed), note? }"},"400":{"description":"Bad waitSeconds"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (workspace.write)"},"404":{"description":"No such workspace"}},"security":[{"bearerAuth":[]}],"x-required-scope":"workspace.write"}},"/api/workspaces/{id}/reset":{"post":{"operationId":"resetWorkspace","summary":"Reset a workspace to its seed baseline (destroy + recreate from the same seed under the SAME id; optional jobNumber so JOBIDs line up across your re-runs). Asynchronous like create_workspace: the view comes back when status leaves CREATING or after waitSeconds — poll get_workspace until status=RUNNING. Refused with 409 while the workspace is still CREATING (poll first) or being CANCELLED/DESTROYED (create a new one)","tags":["oracle"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"workspace id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"jobNumber":{"description":"child JES2 job-number counter after the reset"},"waitSeconds":{"description":"wait for the rebuild up to N seconds before answering (default 20, max 45)"}}}}}},"responses":{"200":{"description":"{ workspace, name, owner, seed, created, booted, expires, ttlSeconds, jobNumber, status: CREATING|RUNNING|FAILED|GONE|CANCELLING|DESTROYING, ready, phase?, progress?: { phase, elapsedSeconds, typicalSeconds }, error?, next? (what to do: poll / destroy+recreate / wait for an unwinding row to disappear), instance, calls, ram, ramBacked?, retained?: false }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (workspace.write)"},"404":{"description":"No such workspace"},"409":{"description":"The workspace is still CREATING (poll get_workspace first) or is being CANCELLED/DESTROYED (create a new one)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"workspace.write"}},"/api/workspaces/{id}/call":{"post":{"operationId":"workspaceCall","summary":"Run one API call INSIDE a workspace as yourself — with exactly the scopes of the token making THIS call (not the one that created the workspace); inside, cics.admin is granted to a cics.exec holder (the stdio bridge routes workspace:<id> tool calls through this; the /mcp door routes in-process). The child enforces the route scope; the parent audits metadata only","tags":["oracle"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"workspace id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"method":{"description":"GET|POST|PUT|DELETE"},"path":{"description":"/api/... (with query)"},"body":{"description":"JSON body"}}}}}},"responses":{"200":{"description":"the child route result"},"400":{"description":"Bad method/path, a non-canonical path (empty, \".\" or \"..\" segments, \"\\\", \"#\"), or a non-routable path (workspaces/instances/snapshots/tokens/logon/ephemeral — a workspace does not nest)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (workspace.write)"},"404":{"description":"No such workspace"},"409":{"description":"WORKSPACE NOT READY — still CREATING: poll get_workspace until status=RUNNING, then retry"},"410":{"description":"The workspace FAILED to create or is gone"}},"security":[{"bearerAuth":[]}],"x-required-scope":"workspace.write"}},"/api/ephemeral/workspaces":{"post":{"operationId":"createRamWorkspace","summary":"Create a RAM-ONLY workspace on the PRIVATE lane: a sandbox-class child engine whose data root and TMPDIR live on the RAM-backed sandbox base (never inside the shared store, never in /api/instances), seeded fresh / as a copy of the estate (clone) / from a snapshot. Every private-lane tool then runs INSIDE it (pass workspace:<id>) as you — the whole reference-oracle chain, RAM-only; destroyed with nothing retained at destroy_workspace or the TTL. ramBacked:false is reported honestly where the host has no RAM base (dev macOS). CREATION IS ASYNCHRONOUS: the workspace is registered at once with status CREATING (phase + progress in the view) while the estate copy and child boot run in the background; the call returns as soon as status leaves CREATING or after waitSeconds (default 20, max 45 — always under a 60 s MCP client timeout). If the response says status:CREATING, poll get_workspace every 10-15 s until status=RUNNING (ready:true) before passing workspace:<id> on other tools — they are refused 409 NOT READY until then. Do NOT call create_workspace again meanwhile: the same name returns the in-flight row (reused:true), a different name counts against your cap (429). A clone takes seconds to a few minutes depending on the host (the view's progress.typicalSeconds is the last one on this engine)","tags":["oracle"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"seed":{"description":"'clone' (default) | 'fresh' | 'snapshot:<id>'"},"ttlSeconds":{"description":"dispose after N seconds (default 3600, max 86400)"},"name":{"description":"label AND per-user idempotency key: naming a workspace of yours that is CREATING or RUNNING (same seed/kind) returns that one (reused:true) instead of cloning again — give every workspace a name"},"waitSeconds":{"description":"how long this call may wait for status to leave CREATING before answering (default 20, 0 = answer at once, max 45)"},"jobNumber":{"description":"set the child JES2 job-number counter (JOBIDs line up across re-runs)"},"includeSpool":{"description":"clone only: true = also copy the parent's JES2 spool (every past job's output — most of the estate's files, minutes on a big one); default false = the workspace starts with an empty spool and the parent's job-number counter"}}}}}},"responses":{"200":{"description":"{ workspace, name, owner, seed, created, booted, expires, ttlSeconds, jobNumber, status: CREATING|RUNNING|FAILED|GONE|CANCELLING|DESTROYING, ready, phase?, progress?: { phase, elapsedSeconds, typicalSeconds }, error?, next? (what to do: poll / destroy+recreate / wait for an unwinding row to disappear), instance, calls, ram, ramBacked?, retained?: false } + reused (true when an existing CREATING/RUNNING workspace of yours with this name was returned)"},"400":{"description":"Bad seed/ttl/waitSeconds"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ephemeral.exec)"},"404":{"description":"No such snapshot"},"429":{"description":"Per-user / plane cap (counts workspaces still CREATING and ones still CANCELLING/DESTROYING after a destroy — the message names them: poll get_workspace, do not re-create; an unwinding row is gone within seconds)"},"503":{"description":"Child failed to boot (synchronous only for a seed that fails validation; a boot failure after the wait shows as status FAILED + error in the view)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ephemeral.exec"},"get":{"operationId":"listRamWorkspaces","summary":"List your RAM-only workspaces on the private lane (a SPECIAL user sees all) — including the ones still CREATING (status/phase/progress) and recently FAILED ones (error)","tags":["oracle"],"responses":{"200":{"description":"[{ workspace, name, owner, seed, created, booted, expires, ttlSeconds, jobNumber, status: CREATING|RUNNING|FAILED|GONE|CANCELLING|DESTROYING, ready, phase?, progress?: { phase, elapsedSeconds, typicalSeconds }, error?, next? (what to do: poll / destroy+recreate / wait for an unwinding row to disappear), instance, calls, ram, ramBacked?, retained?: false }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ephemeral.exec)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ephemeral.exec"}},"/api/ephemeral/workspaces/{id}":{"get":{"operationId":"getRamWorkspace","summary":"One RAM-only workspace — THE POLL after create_workspace / reset_workspace: status CREATING (phase, progress.elapsedSeconds, progress.typicalSeconds) → RUNNING (ready:true, use it) | FAILED (error: destroy and recreate); after destroy_workspace: CANCELLING | DESTROYING until the row is gone (404)","tags":["oracle"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"workspace id"}],"responses":{"200":{"description":"{ workspace, name, owner, seed, created, booted, expires, ttlSeconds, jobNumber, status: CREATING|RUNNING|FAILED|GONE|CANCELLING|DESTROYING, ready, phase?, progress?: { phase, elapsedSeconds, typicalSeconds }, error?, next? (what to do: poll / destroy+recreate / wait for an unwinding row to disappear), instance, calls, ram, ramBacked?, retained?: false }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ephemeral.exec)"},"404":{"description":"No such workspace"},"410":{"description":"Gone (TTL/child died)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ephemeral.exec"},"delete":{"operationId":"destroyRamWorkspace","summary":"Destroy a RAM-only workspace: the sandbox child is SIGKILLed and its RAM directory removed — nothing is retained. On a workspace still CREATING this cancels it (cancelled:true): the estate copy is stopped at once (a queued copy leaves the queue, a running copy process is killed), no child engine boots, the partial directory is removed. The row stays visible as CANCELLING (or DESTROYING for a RUNNING one) and counts toward your cap only until that is done — the call waits for it up to waitSeconds (default 15, max 45) and answers settled:true (row gone) or settled:false (still unwinding: poll get_workspace until 404). Idempotent: destroying an unwinding row again just reports it","tags":["oracle"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"workspace id"},{"name":"waitSeconds","in":"query","required":false,"schema":{"type":"string"},"description":"how long to wait for the child/copy to be fully gone before answering (default 15, 0 = answer at once, max 45)"}],"responses":{"200":{"description":"{ ok, workspace, calls, ram, settled (true = row gone, cap free), status: GONE|CANCELLING|DESTROYING, cancelled? (the workspace was still creating), already? (it was already being destroyed), note? }"},"400":{"description":"Bad waitSeconds"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ephemeral.exec)"},"404":{"description":"No such workspace"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ephemeral.exec"}},"/api/ephemeral/workspaces/{id}/reset":{"post":{"operationId":"resetRamWorkspace","summary":"Reset a workspace to its seed baseline (destroy + recreate from the same seed under the SAME id; optional jobNumber so JOBIDs line up across your re-runs). Asynchronous like create_workspace: the view comes back when status leaves CREATING or after waitSeconds — poll get_workspace until status=RUNNING. Refused with 409 while the workspace is still CREATING (poll first) or being CANCELLED/DESTROYED (create a new one)","tags":["oracle"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"workspace id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"jobNumber":{"description":"child JES2 job-number counter after the reset"},"waitSeconds":{"description":"wait for the rebuild up to N seconds before answering (default 20, max 45)"}}}}}},"responses":{"200":{"description":"{ workspace, name, owner, seed, created, booted, expires, ttlSeconds, jobNumber, status: CREATING|RUNNING|FAILED|GONE|CANCELLING|DESTROYING, ready, phase?, progress?: { phase, elapsedSeconds, typicalSeconds }, error?, next? (what to do: poll / destroy+recreate / wait for an unwinding row to disappear), instance, calls, ram, ramBacked?, retained?: false }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ephemeral.exec)"},"404":{"description":"No such workspace"},"409":{"description":"The workspace is still CREATING (poll get_workspace first) or is being CANCELLED/DESTROYED (create a new one)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ephemeral.exec"}},"/api/ephemeral/workspaces/{id}/call":{"post":{"operationId":"ramWorkspaceCall","summary":"Run one API call INSIDE a RAM-only workspace as yourself (the stdio bridge on the private lane routes workspace:<id> tool calls through this; the /mcp door routes in-process). The child enforces the route scope; the parent audits {workspace, method, bytes} only — never the path or body","tags":["oracle"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"workspace id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"method":{"description":"GET|POST|PUT|DELETE"},"path":{"description":"/api/... (with query)"},"body":{"description":"JSON body"}}}}}},"responses":{"200":{"description":"the child route result"},"400":{"description":"Bad method/path, a non-canonical path (empty, \".\" or \"..\" segments, \"\\\", \"#\"), or a non-routable path (workspaces/instances/snapshots/tokens/logon/ephemeral — a workspace does not nest)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ephemeral.exec)"},"404":{"description":"No such workspace"},"409":{"description":"WORKSPACE NOT READY — still CREATING: poll get_workspace until status=RUNNING, then retry"},"410":{"description":"The workspace FAILED to create or is gone"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ephemeral.exec"}},"/api/jes/jobnumber":{"post":{"operationId":"setJobNumber","summary":"Set the JES2 job-number counter (the NEXT job takes the following free number) — the $T JOBDEF-style knob; a workspace reset uses it inside the child so JOBIDs line up across re-runs","tags":["jobs"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"jobNumber":{"description":"0..99999"}}}}}},"responses":{"200":{"description":"{ ok, jobNumber }"},"400":{"description":"Bad number"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.admin"}},"/api/export/bundles":{"post":{"operationId":"exportBundle","summary":"Export a modernization BUNDLE in one call: programs (source) + their transitive copybooks + JCL (with the DD/dataset list) + procs + BMS mapsets (source, parsed model, the region's physical map) + the CSD slice + the scheduler jobs that run those decks + datasets (hex + rows). Text parts are inline in the returned manifest; dataset parts are stored server-side (get_bundle_part pages them; GET /api/export/bundles/{id}/download = tar.gz). Nothing is converted","tags":["oracle"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"programs":{"description":"array of program names (or {dsn, member})"},"copybooks":{"description":"extra copybook names to include (the COPY closure of every program is included automatically)"},"jcl":{"description":"JCL member names (or {dsn, member})"},"procs":{"description":"proc member names"},"maps":{"description":"extra BMS mapset names (every MAPSET('X') a program names is included automatically; a data-name MAPSET or a mapset found nowhere is a warning)"},"db2":{"description":"extra DB2 table names (every table a program's EXEC SQL references is included automatically as a db2 part: CREATE TABLE DDL + indexes + rows; a referenced table that is not catalogued is a warning)"},"includeDb2":{"description":"default true"},"datasets":{"description":"array of dataset names or { dsn, copybook: 'LIB(MEMBER)', record?, all?: true (no 10000-record cap) }"},"records":{"description":"'both' (default) | 'hex' | 'rows' | 'none'"},"includeCopybooks":{"description":"default true"},"includeCsd":{"description":"default true"},"includeSchedule":{"description":"default true"},"includeLoadModules":{"description":"default false (engine-native modules, labelled)"},"syslib":{"description":"copybook library search order"},"name":{"description":"label"}}}}}},"responses":{"200":{"description":"{ id, format, parts: [{kind, name, dsn, member, lines, sha256, text?|part} | {kind:db2, name, via?, type, columns, ddl[], count, rowsRecords?, part} | {kind:dataset, ..., vsam?, aixes?, define?}], copybooks: [{name, dsn, via, text}], csd, maps: [{mapset, via?, source, model, physical}], schedule: {folders, jobs, symbols, options}, warnings, sha256 }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"},"get":{"operationId":"listBundles","summary":"List exported bundles, newest first","tags":["oracle"],"responses":{"200":{"description":"[{ id, name, created, user, sha256, parts, copybooks, maps, warnings }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/export/bundles/{id}":{"get":{"operationId":"getBundle","summary":"One bundle manifest (text parts inline)","tags":["oracle"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"bundle id"}],"responses":{"200":{"description":"manifest"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"404":{"description":"No such bundle"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"},"delete":{"operationId":"deleteBundle","summary":"Delete a bundle","tags":["oracle"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"bundle id"}],"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"404":{"description":"No such bundle"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/export/bundles/{id}/parts/{n}":{"get":{"operationId":"getBundlePart","summary":"One bundle part: a dataset part paged (hex + rows), a load module as hex, a text part as-is","tags":["oracle"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"bundle id"},{"name":"n","in":"path","required":true,"schema":{"type":"string"},"description":"part index (manifest.parts[n])"},{"name":"from","in":"query","required":false,"schema":{"type":"string"},"description":"first record"},{"name":"count","in":"query","required":false,"schema":{"type":"string"},"description":"records (default 1000, max 10000)"}],"responses":{"200":{"description":"part (+ hex/rows page)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"404":{"description":"No such bundle/part"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/export/bundles/{id}/download":{"get":{"operationId":"downloadBundle","summary":"Download a bundle as tar.gz (manifest.json + parts/)","tags":["oracle"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"bundle id"}],"responses":{"200":{"description":"tar.gz bytes"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"404":{"description":"No such bundle"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/export/state/{id}":{"get":{"operationId":"getState","summary":"One persisted state dump; page one dataset's records with dataset=&from=&count=","tags":["oracle"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"state id"},{"name":"dataset","in":"query","required":false,"schema":{"type":"string"},"description":"return only this dataset artifact (paged)"},{"name":"from","in":"query","required":false,"schema":{"type":"string"},"description":"first record (with dataset)"},{"name":"count","in":"query","required":false,"schema":{"type":"string"},"description":"records (with dataset, default 1000)"}],"responses":{"200":{"description":"the state (or one paged dataset artifact)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"404":{"description":"No such state"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"},"delete":{"operationId":"deleteState","summary":"Delete a persisted state dump","tags":["oracle"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"state id"}],"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"404":{"description":"No such state"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/run/batch":{"post":{"operationId":"runBatch","summary":"Run a batch job and RETURN its run record in one call: submit (inline lines or a JCL member), wait, then step RCs/abend, the whole joblog (JESMSGLG/JESYSMSG/every SYSOUT DD, keyed STEP.DD), and the output datasets as hex + copybook-decoded rows (datasets auto-derived from the deck DDs unless given; GDG (+n) resolved after the run), optional DB2 tables, optional identical dump taken BEFORE the run (verbatim — no diff), WTORs auto-answered. Persisted as a steelframe-run/1 record (get_run)","tags":["oracle"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"lines":{"description":"JCL card images"},"member":{"description":"or a cataloged deck: 'CARDDEMO.JCL(POSTTRAN)'"},"datasets":{"description":"'auto' (default: every non-instream/SYSOUT/DUMMY DD of the deck) or an array of dataset names / { dsn, copybook }"},"copybooks":{"description":"{ DSN-or-last-qualifier: 'LIB(MEMBER)' } record layouts for decoded rows (e.g. { 'AWS.M2.CARDDEMO.TRANSACT.VSAM.KSDS': 'CARDDEMO.COPYLIB(CVTRA05Y)' })"},"db2":{"description":"array of table names / { table, orderBy } to dump after the run (needs db2.exec)"},"before":{"description":"true = also return the same dump taken before submit"},"spool":{"description":"'all' (default) | 'tail' (last 200 lines per file) | 'names'"},"records":{"description":"'both' (default) | 'hex' | 'rows' | 'none' (hashes + counts only)"},"replies":{"description":"[{ match?: regex over the WTOR text, text }] answered in order while waiting"},"timeout":{"description":"seconds to wait (default 300, max 3600); on timeout { timedOut, jobid } is returned for wait_job"},"clock":{"description":"{ fixed: 'YYYY-MM-DD HH:MM:SS' } pins the COBOL runtime clock (ACCEPT FROM DATE/TIME, FUNCTION CURRENT-DATE) for every program step of THIS job so a re-run reproduces byte-for-byte; JES timestamps in JESMSGLG are real"},"name":{"description":"run label"}}}}}},"responses":{"200":{"description":"{ runId, jobid, jobname, status, maxcc, abend, steps: [{name, pgm, rc}], joblog: {STEP.DD: {lines, sha256, text}}, outputs: {dsn: {charset, total, sha256, hex?, rows?, layout?}}, db2?, before?, wtorsAnswered?, elapsedMs, sha256 }"},"400":{"description":"No deck / bad options / JCL parse"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"},"404":{"description":"Member not found"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/cics/link":{"post":{"operationId":"cicsLink","summary":"LINK a CICS program headlessly with a COMMAREA (hex program-image bytes, or rows + copybook) and/or a channel of containers, under a real task with a live EIB (the ECI/JSON-provider path); returns the returned COMMAREA as hex (+ decoded rows when a copybook was given), containers, abend code","tags":["oracle"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"program":{"description":"program name (PPT entry or load module)"},"transid":{"description":"transaction id for the task (default CPIH)"},"commarea":{"description":"hex string (program image) or { rows: {...}, copybook: 'LIB(MEMBER)', record?, length? }"},"channel":{"description":"channel name (optional)"},"containers":{"description":"{ NAME: { hex, type?: BIT|CHAR } } (with channel)"}}}}}},"responses":{"200":{"description":"{ program, transid, tasknum, abend, commarea: {length, hex, charset, rows?}, containers?, elapsedMs }"},"400":{"description":"Bad program/commarea"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.exec)"},"404":{"description":"Program not found"},"503":{"description":"Region not active"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.exec"}},"/api/cics/sessions":{"post":{"operationId":"cicsOpenSession","summary":"Open a headless CICS terminal session as the caller (the same engine terminal the web/Studio/TN3270E use): returns the session id, termid and the initial screen. Then cics_send one AID at a time; cics_close_session when done (idle sessions expire; per-user cap)","tags":["oracle"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"netname":{"description":"LU name (CEDA TERMINAL match / session-continuity key, optional)"},"signon":{"description":"true = mark the terminal signed on as the caller like CESN (identity is attached either way)"},"raw":{"description":"true = include the TN3270E data stream of the screen"},"transaction":{"description":"transid (1-4 chars) to START on the new terminal — typed as the unformatted input line and ENTERed exactly like the first keystroke of a session; the settled result of that step (screens, task, keyboard) is returned with the session. Without it the terminal is blank: send the transid as text on cics_send"},"clock":{"description":"{ fixed: 'YYYY-MM-DD HH:MM:SS' } pins the clock for every task of THIS terminal only (EIBDATE/EIBTIME, ASKTIME/FORMATTIME, FUNCTION CURRENT-DATE / ACCEPT FROM DATE in the programs) so a re-run paints the same screens; 'YYYY-MM-DD' alone = that date with the real time of day. Other terminals and users keep the real clock"}}}}}},"responses":{"200":{"description":"{ session, termid, userid, keyboard, task, clock?, screen: steelframe-screen/1, transaction?, step?, screens?, settled?, events? (the started transaction's first step) }"},"400":{"description":"Bad clock / bad transaction id"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.exec)"},"429":{"description":"Per-user session cap"},"503":{"description":"Region not active / draining"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.exec"},"get":{"operationId":"cicsListSessions","summary":"List your open headless CICS sessions (a SPECIAL user sees all)","tags":["oracle"],"responses":{"200":{"description":"[{ session, termid, userid, created, lastActivity, keyboard, task, steps }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.exec)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.exec"}},"/api/cics/sessions/{id}/send":{"post":{"operationId":"cicsSend","summary":"Send ONE keystroke to a session — an AID with field inputs addressed by BMS field NAME (or row/col) and/or the unformatted input line — and RETURN every screen the engine painted during the step plus the final screen (steelframe-screen/1: named fields, attributes, cursor, 24x80 text). Settles on the engine keyboard signal (task attached → task ended / RECEIVE suspended: task.alive tells you the next send feeds the same task); CLEAR / message screens settle on the write itself. 409 while the keyboard is still locked (task running): re-read with cics_screen or send with queue:true to type ahead","tags":["oracle"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"session id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"aid":{"description":"ENTER (default) | CLEAR | PA1-PA3 | PF1-PF24"},"text":{"description":"unformatted input line (the transaction id on a cleared screen)"},"fields":{"description":"[{ name: 'USERID', text: 'USER0001' } | { row, col, text }] typed into unprotected fields of the current screen"},"cursor":{"description":"[row, col] or { field: name } (default: the first typed field)"},"expect":{"description":"{ text?, field?, timeoutMs? } — after settling, wait until the current screen contains the text / named field (expectMet reported, never an error)"},"settle":{"description":"{ timeoutMs (default 8000), lockWaitMs (default 250) }"},"raw":{"description":"true = include the TN3270E outbound data stream of the final screen"},"queue":{"description":"true = type ahead while the keyboard is locked (queued like a real terminal)"},"force":{"description":"true = allow typing into a protected field / over-length text"}}}}}},"responses":{"200":{"description":"{ session, step, input, screens: [screen...], screen, task: {transid, num, alive, nextTransid?}, keyboard, settled, expectMet?, events, elapsedMs }"},"400":{"description":"Unknown AID / field not on the screen / protected"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.exec)"},"404":{"description":"No such session (or not yours)"},"409":{"description":"Keyboard locked (task running)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.exec"}},"/api/cics/sessions/{id}/screen":{"get":{"operationId":"cicsScreen","summary":"The current screen of a session (re-read without sending anything) + task/keyboard state","tags":["oracle"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"session id"},{"name":"raw","in":"query","required":false,"schema":{"type":"string"},"description":"'true' = include the TN3270E data stream"}],"responses":{"200":{"description":"steelframe-screen/1 + { task, keyboard }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.exec)"},"404":{"description":"No such session"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.exec"}},"/api/cics/sessions/{id}":{"delete":{"operationId":"cicsCloseSession","summary":"Close a session (a running task on it is killed, like a terminal disconnect)","tags":["oracle"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"session id"}],"responses":{"200":{"description":"{ ok, session, termid, steps }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.exec)"},"404":{"description":"No such session"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.exec"}},"/api/cics/scripts/run":{"post":{"operationId":"cicsRunScript","summary":"Run a whole online script in one call — open a session, send every step (same shape as cics_send), dump the named datasets (or state:auto = every CSD FILE), close — and RETURN the transcript: every screen of every step in order, as steelframe-screen/1. Persisted as a run record (kind online, get_run). Stops at the first step that does not settle or whose expect is not met (aborted reported, never a verdict)","tags":["oracle"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"steps":{"description":"[{ aid, text?, fields?, cursor?, expect?, settle? }] in order (fields: [{name|row+col, text}] or an object map { NAME: text })"},"state":{"description":"'auto' (every CSD FILE dataset) or [dsn | {dsn, copybook}] to dump after the script"},"transaction":{"description":"transid (1-4 chars) to START first — run as step 1 (ENTER with the transid as the unformatted input line) before your steps"},"db2":{"description":"tables to dump after the script (needs db2.exec)"},"records":{"description":"'none' (default: counts + sha256) | 'hex' | 'rows' | 'both' for the state dump"},"netname":{"description":"LU name"},"signon":{"description":"true = CESN-like signon as the caller"},"raw":{"description":"true = data streams"},"stopOnUnsettled":{"description":"false = keep going after an unsettled step"},"name":{"description":"run label"},"clock":{"description":"{ fixed: 'YYYY-MM-DD HH:MM:SS' } pins the clock for the script's terminal only (same as cics_open_session clock); echoed in the result and the run record"}}}}}},"responses":{"200":{"description":"{ runId, session, termid, stepsRun, aborted?, clock?, steps: [{step, input, screens, screen, task, keyboard, settled}], state, sha256 }"},"400":{"description":"No steps / bad step / bad clock"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.exec)"},"429":{"description":"Session cap"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.exec"}},"/api/sched/import":{"post":{"operationId":"schedImport","summary":"Import scheduler definitions straight in: a captured CA-7 LJOB,JOB=x,LIST=ALL report (folder = SYSTEM) or a Control-M DEFTABLE XML export — the same importers PGM=ZWSCHED IMPORT runs; optionally set the default JCL library","tags":["oracle"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"format":{"description":"CA7 | CTM"},"lines":{"description":"the report / XML lines"},"member":{"description":"or a cataloged member 'DSN(MEMBER)'"},"jcllib":{"description":"default JCL library for the cycles (sets options.jcllib)"}}}}}},"responses":{"200":{"description":"{ format, report: {jobsAdded, jobsUpdated, triggers|inconds|outconds, folder|folders}, jcllib? }"},"400":{"description":"Unknown format / no lines"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (sched.admin)"},"404":{"description":"Member not found"}},"security":[{"bearerAuth":[]}],"x-required-scope":"sched.admin"}},"/api/sched/jobs":{"post":{"operationId":"schedDefineJob","summary":"Define or update ONE scheduler job with its dependencies from JSON: CA-7 (triggers: this job triggers those jobs on completion) or Control-M (inconds/outconds); the definition is synthesized in the importer's own grammar (LJOB block / one-job DEFTABLE) and merged like an import — unknown trigger targets become stubs to define next","tags":["oracle"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"folder":{"description":"folder (CA-7 SYSTEM name, 1-8 chars; Control-M folder)"},"type":{"description":"'CA7' | 'CTM' (default: the folder's type, CA7 for a new folder)"},"name":{"description":"job name"},"member":{"description":"JCL member (default: name)"},"jcllib":{"description":"JCL library or symbol, e.g. '&CARDDEMOPRODJCL'"},"owner":{"description":"owner"},"class":{"description":"job class"},"msgclass":{"description":"msgclass"},"schid":{"description":"CA-7 schedule id"},"freq":{"description":"DAILY|WEEKLY|MONTHLY"},"days":{"description":"day list (MON,FRI / SA)"},"triggers":{"description":"[{ job, schid?, qtm?, leadtm? }] (CA-7)"},"inconds":{"description":"[{ name, odate?, andOr? }] (Control-M)"},"outconds":{"description":"[{ name, odate?, sign? }] (Control-M)"},"timefrom":{"description":"HHMM"},"timeto":{"description":"HHMM"},"calendar":{"description":"SCAL / CONFCAL name"},"cyclic":{"description":"true (Control-M)"},"interval":{"description":"e.g. '00030M'"},"maxrerun":{"description":"number"}}}}}},"responses":{"200":{"description":"{ folder, type, job, added|updated, graph: {triggers, inconds, outconds}, definition, report }"},"400":{"description":"Bad names / folder type mismatch"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (sched.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"sched.admin"},"get":{"operationId":"schedJobs","summary":"Job definitions (with trigger graph) for a folder","tags":["sched"],"parameters":[{"name":"folder","in":"query","required":false,"schema":{"type":"string"},"description":"folder name (* = all)"}],"responses":{"200":{"description":"[job]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (sched.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"sched.read"}},"/api/sched/ca7":{"post":{"operationId":"schedCa7","summary":"One CA-7 top-line command in CA-7 syntax: DEMAND[H] / RUN[H] (run one job — requirements not checked, completion neither posts nor triggers) / LJOB (definition report; the same grammar sched_import accepts) / LQ,LQUE,LREQ,LRDY,LACT (queues) / LPRRN (prior runs) / HOLD / RELEASE / CANCEL / POST. Report wording is engine-own; the syntax is CA-7's","tags":["oracle"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"command":{"description":"e.g. 'RUN,JOB=POSTTRAN', 'LJOB,JOB=CLOSEFIL,LIST=ALL', 'LQ', 'POST,JOB=WAITSTEP,DEPJOB=POSTTRAN'"}}}}}},"responses":{"200":{"description":"{ command, lines, rc }"},"400":{"description":"Unknown verb / verb error"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (sched.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"sched.admin"}},"/api/sched/cycle/{id}/wait":{"post":{"operationId":"schedWaitCycle","summary":"Wait for a scheduler cycle (sched_demand / sched_order / RUN) to END and RETURN it: the cycle log (order the jobs ran, triggers fired), every job's state/jobid/maxcc/steps and joblog, optional output datasets; on timeout the live state is returned with each waiting job's reason. Persisted as a run record (kind cycle) when ended","tags":["oracle"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"cycle id (CYCnnnnn)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"timeoutMs":{"description":"milliseconds to wait (default 300000)"},"joblogs":{"description":"'all' (default) | 'tail' | 'names' | 'none'"},"outputs":{"description":"array of dataset names / { dsn, copybook } to dump after the cycle"},"records":{"description":"'both' | 'hex' | 'rows' | 'none' for outputs"}}}}}},"responses":{"200":{"description":"{ cycle, ended, result, jobs: [{name, state, jobid, maxcc, reason?, steps?, joblog?}], outputs?, runId?, waitedMs }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (sched.read)"},"404":{"description":"No such cycle"}},"security":[{"bearerAuth":[]}],"x-required-scope":"sched.read"}},"/api/jobs/{jobid}/file/{name}/outdisp":{"put":{"operationId":"setSpoolFileOutdisp","summary":"Change one spool data set output disposition (SDSF JDS O/H/P actions): WRITE releases it, HOLD/LEAVE hold it, KEEP keeps it, PURGE removes the data set — the job is untouched","tags":["jobs"],"parameters":[{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"JES2 job id"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"spool file name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"outdisp":{"description":"WRITE | HOLD | KEEP | LEAVE | PURGE"}}}}}},"responses":{"200":{"description":"{ ok, jobid, name, outdisp, hold?, purged? }"},"400":{"description":"Invalid disposition / JES data set purge"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"},"404":{"description":"No such job or spool data set"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/spool/dests":{"get":{"operationId":"spoolDests","summary":"All output destinations (OUTPUT DEST=, default LOCAL) with their routed spool files and writers","tags":["jobs"],"responses":{"200":{"description":"[{ dest, files, writers, entries: [{ jobid, file, class, writer, forms, groupid }] }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.read"}},"/api/spool/dest/{name}":{"get":{"operationId":"spoolDest","summary":"The spool files routed to one destination","tags":["jobs"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"destination name (LOCAL for unrouted output)"}],"responses":{"200":{"description":"{ dest, files, writers, entries }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.read)"},"404":{"description":"Nothing routed there"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.read"}},"/api/jobs/{jobid}/file/{name}/download":{"get":{"operationId":"downloadSpool","summary":"Export one spool file as raw text or PDF (green-bar form printed through the FCB image: column-1 ANSI (RECFM=..A) or machine (RECFM=..M) carriage control honored automatically — channel skips, overprint, COPIES)","tags":["jobs"],"parameters":[{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"JES2 job id"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"spool file name"},{"name":"format","in":"query","required":false,"schema":{"type":"string"},"description":"'text' (default) or 'pdf'"},{"name":"cc","in":"query","required":false,"schema":{"type":"string"},"description":"override the carriage-control dialect: 'asa' | 'mach' | 'none' (default: from the spool descriptor RECFM / JES data-set type)"},{"name":"fcb","in":"query","required":false,"schema":{"type":"string"},"description":"FCB image for the PDF (STD1 | STD2; default the descriptor FCB= else STD2; unknown names fall back to STD2, noted in the PDF Subject)"}],"responses":{"200":{"description":"text/plain or application/pdf bytes"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.read"}},"/api/tso":{"post":{"operationId":"tsoCommand","summary":"Run a TSO/ISPF command in the per-token session (panel-capable, poll/reply protocol)","tags":["tso"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"cmd":{"description":"TSO command (omit when polling/replying)"},"poll":{"description":"true to poll a running command"},"reply":{"description":"{ aid, fields } panel answer"}}}}}},"responses":{"200":{"description":"{ rc, lines } | { busy, lines } | { panel, lines }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (tso.exec)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"tso.exec"}},"/api/editmacro":{"post":{"operationId":"editMacro","summary":"Run an ISREDIT edit macro over a client-side edit buffer","tags":["tso"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"cmd":{"description":"macro name + parms"},"lines":{"description":"edit buffer lines"},"dsn":{"description":"dataset behind the buffer (width)"},"member":{"description":"member name"}}}}}},"responses":{"200":{"description":"{ found, rc, lines, excluded, notes, msg, output }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (tso.exec)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"tso.exec"}},"/api/spufi":{"post":{"operationId":"spufi","summary":"Execute a SQL batch (SPUFI equivalent)","tags":["db2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sql":{"description":"SQL statements separated by ;"}}}}}},"responses":{"200":{"description":"{ results, formatted }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (db2.exec)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"db2.exec"}},"/api/cics/csd":{"get":{"operationId":"cicsCsd","summary":"The whole CSD as data — every resource definition (PROGRAM, TRANSACTION, FILE, MAPSET, TDQUEUE, TRANCLASS, TSMODEL, JSONSERVICE, ...), the LIBRARY resources (libraries: DSNAME01..16, RANKING, CRITICAL) and the group lists (lists: list name -> CSD groups, e.g. the DFHLIST startup list); each entry carries its CSD group (group; absent = system-owned) and installed:false when defined but not installed. The transid→program→file mapping an online comparison needs; find_program returns the slice for ONE program","tags":["cics"],"responses":{"200":{"description":"CSD object: { programs, transactions, files, mapsets, tdqueues, tranclasses, libraries, lists, ... }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.read"}},"/api/bms/preview":{"post":{"operationId":"bmsPreview","summary":"Parse BMS mapset source into its map model (rows/cols/attributes/initials) — the IDE renders 3270 and HTML5 previews from it","tags":["cics"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"lines":{"description":"BMS macro source (DFHMSD/DFHMDI/DFHMDF card images)"}}}}}},"responses":{"200":{"description":"{ mapset: { name, maps: [{ name, size, fields }] }, errors }"},"400":{"description":"No mapset in the source"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.read"}},"/api/bms/generate":{"post":{"operationId":"bmsGenerate","summary":"Regenerate BMS macro source from a map model (the screen painter write-back) — round-trips through the same parser; X continuation at column 72, operands resume column 16","tags":["cics"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mapset":{"description":"map model as returned by bmsPreview (name, maps[].fields[])"}}}}}},"responses":{"200":{"description":"{ lines }"},"400":{"description":"No mapset model supplied"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.read"}},"/api/cics/define":{"post":{"operationId":"cicsDefine","summary":"CEDA-style resource definition (+install) of one resource from a JSON attribute object, authorized by RACF exactly like the CEDA transaction (cicssec.cedaAuthority, class SFCSDGRP): an administrator (RACF SPECIAL / cics.admin) defines anything; an ordinary user defines LIBRARY / PROGRAM / MAPSET / FILE / TDQUEUE / TRANSACTION in a CSD group it holds SFCSDGRP UPDATE on - GROUP is REQUIRED for an ordinary user: its personal group (named after its userid, provisioned at its first logon) or a group the security administrator granted it. Rules: a name nobody else owns (an existing entry of another group or a system-owned entry, no group, is refused), no C*/built-in TRANSACTION and no DFH* PROGRAM/MAPSET names; LIBRARY needs DSNAME01 (DSNAME01..16 must be datasets the user may READ; RANKING 1-99, CRITICAL YES|NO); a PROGRAM needs a LIBRARY in its group (or the compatibility attribute library=dsn it may READ); a FILE needs dsn/DSNAME = a dataset it may UPDATE (and passes the CASFILE operator check); a TRANSACTION needs program = a PROGRAM defined in the same group and gets the group's TRANCLASS (named after the group) forced. For CEDA command text (INSTALL, ALTER, DELETE, COPY, CHECK, VIEW, ...) use /api/cics/ceda","tags":["cics"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"description":"LIBRARY|PROGRAM|TRANSACTION|FILE|MAPSET|TDQUEUE (ordinary users) | TRANCLASS|TSMODEL|JSONSERVICE|URIMAP|... (administrators)"},"name":{"description":"resource name (1-8 characters; a TRANSACTION 1-4)"},"attrs":{"description":"attribute object, CEDA keywords as keys: LIBRARY { dsname01..dsname16, ranking, critical, status }; PROGRAM { language, library? (compat) }; FILE { dsn|dsname, ... }; TRANSACTION { program, ... }; TDQUEUE { type, dsname|indirectname, ... }"},"group":{"description":"CSD group (REQUIRED for an ordinary user: its personal group = its userid, or a group it holds SFCSDGRP UPDATE on; attrs.group is accepted too; an administrator may omit it = system-owned)"}}}}}},"responses":{"200":{"description":"{ ok: true, kind, name, group, installed: true, definition: { the stored attributes }, message: \"DEFINE SUCCESSFUL - INSTALLED\" } - ONLY the entry just defined, never the rest of the CSD (cics_csd / CEDA DISPLAY show that)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.exec)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.exec"}},"/api/cics/ceda":{"post":{"operationId":"cicsCeda","summary":"Run ONE CEDA command line (DEFINE / ALTER / DELETE / INSTALL / COPY / DISPLAY / VIEW / CHECK / EXPAND / ADD / REMOVE / LIST, every kind including LIBRARY) through the SAME parser and executor as the CEDA transaction, for the session user, decided by the SAME RACF authority (cicssec.cedaAuthority, class SFCSDGRP; CEMT-style result lines, ok=false when the command failed or was refused). Scopes: the read-only verbs (DISPLAY, VIEW, CHECK, EXPAND, LIST) need cics.read; the mutating verbs need cics.exec as well - and then RACF decides: an administrator (cics.admin / SPECIAL) may do anything, an ordinary user acts in the CSD groups it holds SFCSDGRP UPDATE on (its personal group = its userid, plus the groups the security administrator granted), DELETE needs ALTER; a FILE define/alter/install/delete also passes the CASFILE operator check like /api/cics/define","tags":["cics"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"command":{"description":"CEDA command text, e.g. 'DEFINE LIBRARY(RABILIB) GROUP(RABIAPP) DSNAME01(C826RHA.LOADLIB)', 'DEFINE PROGRAM(SGNON01C) GROUP(RABIAPP)', 'DEFINE TRANSACTION(RHSG) GROUP(RABIAPP) PROGRAM(SGNON01C)', 'CHECK GROUP(RABIAPP)', 'INSTALL GROUP(RABIAPP)', 'VIEW PROGRAM(SGNON01C)', 'EXPAND GROUP(RABIAPP)', 'ADD GROUP(RABIAPP) LIST(DFHLIST)', 'LIST' (the leading word CEDA is optional)"}}}}}},"responses":{"200":{"description":"{ ok, lines } - the CEDA result lines (E ... = error / refusal, W ... = warning, DEFINE SUCCESSFUL, INSTALL SUCCESSFUL, the VIEW / EXPAND / CHECK / LIST report)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.read"}},"/api/cics/log":{"get":{"operationId":"cicsLog","summary":"CICS region log","tags":["cics"],"responses":{"200":{"description":"[string]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.read"}},"/api/cics/cemt":{"post":{"operationId":"cicsCemt","summary":"Run one CEMT command line (INQUIRE / SET / PERFORM / DISCARD; FILE, PROGRAM, TRANSACTION, LIBRARY, TDQUEUE, TASK, TERMINAL, ...) through the same parser/executor as the CEMT transaction, for the session user — SET is the real transient runtime-state overlay (never a CSD write), DISCARD removes the installed resource (the CSD entry stays, installed:false). INQUIRE is open; SET / PERFORM / DISCARD are authorized by RACF like the CEMT transaction (cicssec.cemtAuthority): a resource of a CSD group the user holds SFCSDGRP UPDATE on (its own groups), CCICSCMD <resource> UPDATE otherwise, administrators (cics.admin / SPECIAL) always; SET FILE also passes the CASFILE operator check","tags":["cics"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"command":{"description":"CEMT command text, e.g. 'INQUIRE FILE(*)', 'SET FILE(ACCTDAT) CLOSED', 'INQUIRE LIBRARY(RABILIB)', 'SET LIBRARY(RABILIB) DISABLED', 'SET PROGRAM(SGNON01C) NEWCOPY', 'DISCARD TRANSACTION(RHSG)', 'INQUIRE TASK' (the leading word CEMT is optional)"}}}}}},"responses":{"200":{"description":"{ ok, lines } - the CEMT result lines (ok:false with E ... NOT AUTHORIZED - reason when RACF refused, nothing changed)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.exec)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.exec"}},"/api/cics/region":{"post":{"operationId":"cicsRegion","summary":"CICS region lifecycle (W1.70): START restarts a region shut down by CEMT PERFORM SHUTDOWN (SFCSI1517), STATUS reports ACTIVE/QUIESCING/SHUTDOWN + active task count. Shutdown itself is the CEMT PERFORM SHUTDOWN [IMMEDIATE] master-terminal command","tags":["cics"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"description":"START | STATUS"}}}}}},"responses":{"200":{"description":"{ ok, state, activeTasks? } | { ok: false, error }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.admin"}},"/api/cics/stats":{"get":{"operationId":"cicsStats","summary":"CICS region statistics (task attaches total/per-transaction, abends, peak+active tasks) — the CEMT PERFORM STATISTICS data","tags":["cics"],"responses":{"200":{"description":"{ since, attaches, abends, peakTasks, activeTasks, byTran }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.read"}},"/api/pac":{"get":{"operationId":"pacStatus","summary":"PAC posture (W5.1 A10.2): this region's Scale-Out Repository membership, live member list and shared-store counts — the single-operational-image facts. Public probe like /api/health; the SOR token never appears","tags":["cics"],"responses":{"200":{"description":"{ member: false } | { member: true, pac, sor, memberName, connected, models, members: [{name, apiUrl, since}], counts: {ts, td, enq, kv} }"}},"security":[]}},"/api/drain":{"post":{"operationId":"drainStart","summary":"Start draining (W5.5 A10.6): refuse new logons + new terminal connections, let running tasks and live sessions finish. Idempotent; the upgraded engine boots accepting","tags":["system"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"description":"operator/upgrade reason (optional, logged + reported)"}}}}}},"responses":{"200":{"description":"{ draining, since, reason, activeTasks, activeSessions }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"},"get":{"operationId":"drainStatus","summary":"Drain posture + live counts (the control plane polls this until idle)","tags":["system"],"responses":{"200":{"description":"{ draining, since, reason, activeTasks, activeSessions }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"},"delete":{"operationId":"drainStop","summary":"End the drain: the region accepts logons and terminal connections again","tags":["system"],"responses":{"200":{"description":"{ draining, activeTasks, activeSessions }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"}},"/api/services":{"get":{"operationId":"svcList","summary":"Service Mapper catalog: JSONSERVICE entries joined with their SFMAP mapping-manifest meta (operation, target program, field count; mappingError flags a missing/corrupt manifest member)","tags":["cics"],"responses":{"200":{"description":"[{ name, path, program, transaction, group, pipeline, mapping, kind: mapping|commarea|channel, operation?, targetProgram?, fields?, mappingError? }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.read"}},"/api/services/{name}":{"get":{"operationId":"svcGetMapping","summary":"One mapped service: its JSONSERVICE definition plus the parsed SFMAP mapping manifest (the member cicsweb readMapping loads at invoke time)","tags":["cics"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"JSONSERVICE name"}],"responses":{"200":{"description":"{ name, definition, mapping, manifest }"},"400":{"description":"Service has no mapping (legacy copybook/channel definition) or the manifest member is unreadable"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.read)"},"404":{"description":"No such JSONSERVICE"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.read"},"delete":{"operationId":"svcDelete","summary":"Unpublish a Service Mapper service (SPEC-W5 §4.4): removes the JSONSERVICE entry, the recorded PIPELINE when unshared, and the group back-refs. The PROGRAM entry and every member (SFMAP manifest, wrapper source, load module) are KEPT — source belongs to SCM; audited","tags":["cics"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"JSONSERVICE name"}],"responses":{"200":{"description":"{ name, removed: [{ kind, name }], kept: { program, mapping }, group }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.admin)"},"404":{"description":"No such JSONSERVICE"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.admin"}},"/api/services/publish":{"post":{"operationId":"svcPublish","summary":"Service Mapper publish (SPEC-W5 §3): mapping (or build spec with DSN(MEMBER) copybook refs) -> SFMAP member write + generated wrapper member + in-engine IGYWCL compile (MAXCC<=4 gate) + CSD trio install (PROGRAM/PIPELINE/JSONSERVICE + group metadata). Re-publish updates in place with an audit line","tags":["cics"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mapping":{"description":"a svcmap buildMapping manifest (fields[] present) OR a build spec { service, program, operation?, inputCopybook, outputCopybook } with DSN(MEMBER) refs (defaults to the whole request body when the mapping key is absent)"},"opts":{"description":"{ direct: JSONSERVICE targets the program with no wrapper/compile, maplib: SFMAP PDS (default <hlq>.SFMAP), srclib: wrapper source PDS (default <hlq>.SOURCE), template: 'byte' (default) | 'staged' (COPY'd structures + WS output stage + MOVE-back, for split-structures targets), group, pipeline, transaction }"}}}}}},"responses":{"200":{"description":"{ service, endpoint, mapping, mappingDsn, wrapper, compile: { jobid, maxcc } | null, resources, applied }"},"400":{"description":"Bad mapping/build spec, missing copybook members, wrapper compile failure (MAXCC>4), or resource install failure — message carries the failing step"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.admin"}},"/api/services/layout":{"post":{"operationId":"svcLayout","summary":"Service Mapper wizard pane feed (SPEC-W5 §4.4): parse a copybook member into its field layout tree (level/name/pic/usage/occurs/off) plus the 01-group list — the wizard's input/output pickers (wraps copybook.js loadCopybook; nothing is stored)","tags":["cics"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"copybook":{"description":"'DSN(MEMBER)' copybook ref"},"copylibs":{"description":"extra COPY-resolution library list (optional)"}}}}}},"responses":{"200":{"description":"{ copybook, total, groups: [{ name, total }], root: layout tree }"},"400":{"description":"Missing/invalid copybook spec"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"404":{"description":"Copybook member not found"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/services/draft":{"post":{"operationId":"svcDraft","summary":"Service Mapper wizard draft (SPEC-W5 §4.4): build spec with DSN(MEMBER) copybook refs -> Create-Default-Mappings preview (buildMapping) + generated-wrapper preview with REAL compiler diagnostics (syntaxCheckCobol, the editor's no-drift pipeline). NOTHING is installed or written — publish is svcPublish","tags":["cics"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mapping":{"description":"build spec { service, program, operation?, inputCopybook, outputCopybook } with DSN(MEMBER) refs (defaults to the whole request body when the mapping key is absent)"}}}}}},"responses":{"200":{"description":"{ mapping, endpoint, wrapper: { name, lines }, check: { rc, diagnostics } }"},"400":{"description":"Bad build spec or missing copybook members"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (cics.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"cics.read"}},"/api/services/{name}/openapi.json":{"get":{"operationId":"svcOpenapi","summary":"Per-service OpenAPI 3.0 document (SPEC-W5 §6): derived live from the SFMAP mapping manifest via svcmap mappingToOpenapi — version = manifest sha256 short, x-cobol transparency extension per property, DFHJSON_ERROR component. Public, like the service endpoint itself","tags":["cics"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"JSONSERVICE name"}],"responses":{"200":{"description":"OpenAPI 3.0 document for the one service"},"400":{"description":"Service has no mapping (legacy copybook/channel definition) or the manifest member is unreadable"},"404":{"description":"No such JSONSERVICE"}},"security":[]}},"/api/ims/region":{"post":{"operationId":"imsRegionSet","summary":"Configure the IMS TM control region (APPLCTN/TRANSACT analog)","tags":["ims"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"transactions":{"description":"trancode -> { psb, ... } map"},"databases":{"description":"online database list"}}}}}},"responses":{"200":{"description":"region config"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ims.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ims.admin"},"get":{"operationId":"imsRegionGet","summary":"Current IMS TM region configuration","tags":["ims"],"responses":{"200":{"description":"region config (or {})"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ims.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ims.read"}},"/api/ims/queues":{"get":{"operationId":"imsQueues","summary":"IMS TM message queue depths per transaction code","tags":["ims"],"responses":{"200":{"description":"[{ trancode, depth }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ims.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ims.read"}},"/api/ims/log":{"get":{"operationId":"imsLog","summary":"IMS TM region log","tags":["ims"],"responses":{"200":{"description":"[string]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ims.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ims.read"}},"/api/ims/command":{"post":{"operationId":"imsCommand","summary":"IMS operator command surface (W3.5/A5.6): /DIS TRAN|A, /START|/STOP|/PSTOP TRAN (STOP rejects new input, PSTOP holds scheduling only), /START|/STOP REGION (MPR start/renew). Returns the display/completion lines — /DIS TRAN emits the documented column header + *yyddd/hhmmss* trailer, completions the documented DFS058I form","tags":["ims"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"command":{"description":"the command line, e.g. '/DIS TRAN ALL' or '/STOP TRAN PART'"}}}}}},"responses":{"200":{"description":"{ lines }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ims.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ims.admin"}},"/api/mq/qmgr":{"get":{"operationId":"mqQmgr","summary":"Queue manager overview: queues with depth, processes","tags":["mq"],"responses":{"200":{"description":"{ qmgr, queues: [{ name, depth, attrs }], processes }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (mq.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"mq.read"}},"/api/mq/queue/{name}":{"get":{"operationId":"mqQueue","summary":"Browse one queue: attributes, depth, first messages (hex + EBCDIC-decoded text)","tags":["mq"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"queue name"},{"name":"max","in":"query","required":false,"schema":{"type":"string"},"description":"max messages to browse (default 20)"}],"responses":{"200":{"description":"{ name, depth, attrs, messages }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (mq.read)"},"404":{"description":"Unknown queue (CSQU: like MQRC 2085)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"mq.read"}},"/api/ndvr/repo":{"get":{"operationId":"ndvrRepo","summary":"Repository overview: environments, map, systems, types, processor groups","tags":["ndvr"],"responses":{"200":{"description":"repository view"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ndvr.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ndvr.read"}},"/api/ndvr/elements":{"get":{"operationId":"ndvrElements","summary":"Element list by selection criteria (wildcards)","tags":["ndvr"],"parameters":[{"name":"env","in":"query","required":false,"schema":{"type":"string"},"description":"environment (*)"},{"name":"system","in":"query","required":false,"schema":{"type":"string"},"description":"system (*)"},{"name":"subsystem","in":"query","required":false,"schema":{"type":"string"},"description":"subsystem (*)"},{"name":"type","in":"query","required":false,"schema":{"type":"string"},"description":"type (*)"},{"name":"stage","in":"query","required":false,"schema":{"type":"string"},"description":"stage (*)"},{"name":"element","in":"query","required":false,"schema":{"type":"string"},"description":"element (*)"}],"responses":{"200":{"description":"[element]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ndvr.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ndvr.read"}},"/api/ndvr/element":{"get":{"operationId":"ndvrElement","summary":"One element: master info, level history, source","tags":["ndvr"],"parameters":[{"name":"env","in":"query","required":false,"schema":{"type":"string"},"description":"environment"},{"name":"system","in":"query","required":false,"schema":{"type":"string"},"description":"system"},{"name":"subsystem","in":"query","required":false,"schema":{"type":"string"},"description":"subsystem"},{"name":"type","in":"query","required":false,"schema":{"type":"string"},"description":"type"},{"name":"stage","in":"query","required":false,"schema":{"type":"string"},"description":"stage"},{"name":"name","in":"query","required":false,"schema":{"type":"string"},"description":"element name"}],"responses":{"200":{"description":"element detail"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ndvr.read)"},"404":{"description":"Element not found"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ndvr.read"}},"/api/ndvr/packages":{"get":{"operationId":"ndvrPackages","summary":"Package list (batch package facility): id pattern + status filter","tags":["ndvr"],"parameters":[{"name":"id","in":"query","required":false,"schema":{"type":"string"},"description":"package id pattern (*)"},{"name":"status","in":"query","required":false,"schema":{"type":"string"},"description":"package status (IN-EDIT, IN-APPROVAL, APPROVED, DENIED, IN-EXECUTION, EXECUTED, EXEC-FAILED, COMMITTED)"}],"responses":{"200":{"description":"[package summary]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ndvr.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ndvr.read"}},"/api/ndvr/package":{"get":{"operationId":"ndvrPackage","summary":"One package: status lifecycle, SCL, approver groups + votes, execution log, ship history","tags":["ndvr"],"parameters":[{"name":"id","in":"query","required":false,"schema":{"type":"string"},"description":"package id"}],"responses":{"200":{"description":"package detail"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ndvr.read)"},"404":{"description":"Package not found"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ndvr.read"}},"/api/ndvr/reset":{"post":{"operationId":"ndvrReset","summary":"Reset the repository to the seeded configuration (test harness)","tags":["ndvr"],"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (ndvr.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"ndvr.admin"}},"/api/sched/store":{"get":{"operationId":"schedStore","summary":"Scheduler store overview: folders, jobs, conditions, symbols, cycles","tags":["sched"],"responses":{"200":{"description":"store view"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (sched.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"sched.read"}},"/api/sched/cycle":{"get":{"operationId":"schedCycle","summary":"One ordered cycle: per-job state + cycle log","tags":["sched"],"parameters":[{"name":"id","in":"query","required":false,"schema":{"type":"string"},"description":"cycle id"}],"responses":{"200":{"description":"cycle"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (sched.read)"},"404":{"description":"No such cycle"}},"security":[{"bearerAuth":[]}],"x-required-scope":"sched.read"}},"/api/sched/order":{"post":{"operationId":"schedOrder","summary":"Order a folder (asynchronous cycle through JES2)","tags":["sched"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"folder":{"description":"folder name"},"force":{"description":"order even out of schedule"}}}}}},"responses":{"200":{"description":"{ id, jobs }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (sched.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"sched.admin"}},"/api/sched/demand":{"post":{"operationId":"schedDemand","summary":"Demand one job + its trigger closure","tags":["sched"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"job":{"description":"job name"},"schid":{"description":"schedule id variant (optional)"}}}}}},"responses":{"200":{"description":"{ id, jobs }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (sched.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"sched.admin"}},"/api/sched/symbol":{"post":{"operationId":"schedSymbol","summary":"Set a JCLLIB-style symbol (e.g. &CARDDEMOPRODJCL)","tags":["sched"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"symbol name"},"value":{"description":"value"}}}}}},"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (sched.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"sched.admin"}},"/api/sched/options":{"post":{"operationId":"schedOptions","summary":"Set scheduler options: okrc (max RC counted OK), jcllib (default JCL library the cycles submit from), newdayTime, condRetainDays, ca7Rerun (YES lets a CA-7 trigger re-run an already-run job), ca7MaxRuns","tags":["sched"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"okrc":{"description":"max RC counted as OK"},"jcllib":{"description":"default JCL library the cycles submit from (a DSN or a &SYMBOL set with sched_symbol)"},"newdayTime":{"description":"New Day time HHMM (sched_newday's scheduled moment)"},"condRetainDays":{"description":"days a posted condition is kept before New Day ages it out"},"ca7Rerun":{"description":"'YES' lets a CA-7 trigger re-run a job that already ran in the cycle (default 'NO')"},"ca7MaxRuns":{"description":"cap on re-runs of one job per cycle when ca7Rerun is YES (default 10)"}}}}}},"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (sched.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"sched.admin"}},"/api/sched/condition":{"post":{"operationId":"schedCondition","summary":"Add (+) or erase (-) a global IOA-style condition (name/ODATE pair)","tags":["sched"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"condition name"},"sign":{"description":"'+' (default) or '-'"},"odate":{"description":"optional ODATE (yyyymmdd, ODAT, STAT/****; default ODAT=today; '-' with no odate erases every date of the name)"}}}}}},"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (sched.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"sched.admin"}},"/api/sched/jobaction":{"post":{"operationId":"schedJobAction","summary":"Operator action on a cycle job: HOLD, FREE, RUNNOW (release ignoring conditions/time window), BYPASS (force-complete without running; successors release) or RESTART a failed job","tags":["sched"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"cycle":{"description":"cycle id (CYCnnnnn)"},"job":{"description":"job name"},"action":{"description":"HOLD|FREE|RUNNOW|BYPASS|RESTART"}}}}}},"responses":{"200":{"description":"{ cycle, job, state }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (sched.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"sched.admin"}},"/api/sched/cancel":{"post":{"operationId":"schedCancel","summary":"Cancel the remaining (waiting/held) work of an active cycle","tags":["sched"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"cycle":{"description":"cycle id (CYCnnnnn)"}}}}}},"responses":{"200":{"description":"{ cycle, cancelled, status }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (sched.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"sched.admin"}},"/api/sched/newday":{"post":{"operationId":"schedNewday","summary":"Run the New Day procedure: age the conditions table, order every eligible Control-M folder, demand every scheduled CA-7 job (holiday/ROLL calendars applied)","tags":["sched"],"responses":{"200":{"description":"{ odate, removedConds, ordered, demanded, skipped }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (sched.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"sched.admin"}},"/api/sched/calendar":{"put":{"operationId":"schedCalendar","summary":"Define a base calendar (CA-7 SCAL / Control-M CONFCAL): holidays + working week; jobs reference it via SCAL/SCHED_CALENDAR with ROLL/SHIFT semantics","tags":["sched"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"calendar name"},"holidays":{"description":"[yyyymmdd,...]"},"weekdays":{"description":"working week, e.g. 'MO,TU,WE,TH,FR' (optional)"}}}}}},"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (sched.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"sched.admin"}},"/api/sched/alerts":{"get":{"operationId":"schedAlerts","summary":"SHOUT alert log (WHEN OK/NOTOK/LATESUB/LATETIME, destination, urgency), newest first","tags":["sched"],"responses":{"200":{"description":"[alert]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (sched.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"sched.read"}},"/api/sched/reset":{"post":{"operationId":"schedReset","summary":"Reset the scheduler store (test harness)","tags":["sched"],"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (sched.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"sched.admin"}},"/api/racf/store":{"get":{"operationId":"racfStore","summary":"RACF database overview: users, groups, dataset profiles, classes, SETROPTS","tags":["racf"],"responses":{"200":{"description":"store view"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (racf.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"racf.read"}},"/api/me/views":{"get":{"operationId":"myViews","summary":"W4.4 (A1.8) ACL-gated navigation: the Studio workspaces this caller may see. A ZVIEW-class profile per workspace id gates visibility (READ); with the class undefined every view is visible and gated=false","tags":["session"],"parameters":[{"name":"views","in":"query","required":false,"schema":{"type":"string"},"description":"optional comma-separated candidate list (default: the built-in workspace set)"}],"responses":{"200":{"description":"{ user, views: [id], gated } — gated=true means ZVIEW profiles are filtering"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.read"}},"/api/security/posture":{"get":{"operationId":"securityPosture","summary":"ESM/security console posture (W4): enforcement config, identity providers, vault (names + provider only — NEVER values), PassTicket/DCAS configuration, and the resource classes carrying profiles","tags":["racf"],"responses":{"200":{"description":"{ security: {enforce,cmdsec,ressec,secprfx}, identity: { local, ad, oidc, certMaps }, vault: { provider, configured, secrets: [{name,created,rotated}] }, passticket: { appls: [{appl,method}], window }, dcas: { maps: [{label,user,sdnfilter}] }, classes: [{ class, profiles }] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (racf.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"racf.read"}},"/api/racf/class":{"get":{"operationId":"racfClass","summary":"Profiles of one general-resource class","tags":["racf"],"parameters":[{"name":"name","in":"query","required":false,"schema":{"type":"string"},"description":"class name (e.g. FACILITY)"}],"responses":{"200":{"description":"[profile]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (racf.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"racf.read"}},"/api/racf/commands":{"post":{"operationId":"racfExec","summary":"Execute RACF command-processor commands (ADDUSER/ADDGROUP/RDEFINE/PERMIT/SETROPTS/...) as the calling user — the apply path for ESF/ACF2/TSS import decks and security automation. Body: complete commands[] OR text (newline-separated deck; RACF + continuations joined)","tags":["racf"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"commands":{"description":"[string] complete RACF commands (no continuations)"},"text":{"description":"alternative: raw deck text — trailing \" +\" continues at an operand boundary, a bare trailing \"+\" joins mid-word (the IRRDBU00-deck grammar)"}}}}}},"responses":{"200":{"description":"{ results: [{ command, rc, lines }], maxrc } — rc -3 = not a RACF verb (refused, counted as 12 in maxrc); under enforcement the issuer needs command authority (SYSTEM-SPECIAL) for privileged verbs"},"400":{"description":"No commands supplied"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (racf.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"racf.admin"}},"/api/racf/reset":{"post":{"operationId":"racfReset","summary":"Reset the RACF store to the seeded base (test harness)","tags":["racf"],"responses":{"200":{"description":"{ ok }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (racf.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"racf.admin"}},"/api/import":{"post":{"operationId":"importEstate","summary":"Import an estate artifact (region XML, DFHCSDUP-style CSD deck, or ESCWA region JSON) into this engine: parse to the canonical region model, emit catalog datasets, VSAM clusters and CICS resources, and return the reconciling §7 import report","tags":["import"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"description":"'region-xml' | 'csd-deck' | 'escwa-json'"},"content":{"description":"artifact text (region XML / deck cards / ESCWA JSON); EBCDIC CSD decks may be sent as base64 via encoding"},"encoding":{"description":"'base64' to pass binary (e.g. EBCDIC) deck bytes (optional; default utf8 text)"},"name":{"description":"region name for artifacts that carry none (csd-deck; default IMPORT)"},"file":{"description":"original filename, recorded in the report provenance (optional)"},"discardMvsDsn":{"description":"csd-deck only: drop DSNAME operands like casrdtup /d (optional)"}}}}}},"responses":{"200":{"description":"{ region, regions, config, report, counts, renderedReport } — counts reconcile: parsed = mapped+translated+ignored+manual"},"400":{"description":"Unknown kind, missing content, or a parse error (message carries the offending line)"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (apps.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"apps.admin"}},"/api/assess":{"post":{"operationId":"assessEstate","summary":"G1 estate feasibility assessment (third-party detection, 3-tier dialect manifest, verdict tier): send an estate archive (zip / tar.gz / tar / single file as the raw body), or pass ?dir= a server-side estate directory (body then ignored). Returns exactly the `sf assess --json` document","tags":["modernize"],"parameters":[{"name":"dir","in":"query","required":false,"schema":{"type":"string"},"description":"server-side estate directory to scan instead of uploading (raw body ignored)"},{"name":"filename","in":"query","required":false,"schema":{"type":"string"},"description":"uploaded archive name hint; drives .tar/single-file handling (default: upload)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"(raw)":{"description":"the estate archive bytes as the request body (omit when ?dir= is used)"}}}}}},"responses":{"200":{"description":"{ findings, summary, manifest, dir, skipped, verdict } — the `sf assess --json` shape unchanged (uploaded estates report dir: null; verdict.rc is the CLI exit-code tier: 0 clean / 1 manual / 3 non-goal)"},"400":{"description":"Unreadable dir, bad archive, or empty body without ?dir="},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (datasets.read)"},"413":{"description":"Body over the upload cap"}},"security":[{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/api/estates":{"get":{"operationId":"listEstates","summary":"The installable sample-estate registry (z/OS SYN.*, IDMS W-series, Natural/ADABAS) with per-estate installed state (marker dataset cataloged?) and suite counts","tags":["estates"],"responses":{"200":{"description":"[{ id, name, family, marker, installed, installing, installers, suiteCount }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.read"}},"/api/estates/{name}/install":{"post":{"operationId":"installEstate","summary":"Install a sample estate into THIS running region: runs the estate's existing test/*_install.mjs --live installers server-side, in order (batch side, then CICS). Idempotent — installers tolerate \"already present\". One install at a time (409). Poll GET /api/estates/runs/{id}","tags":["estates"],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"estate id from GET /api/estates"}],"responses":{"200":{"description":"{ run } — the run id to poll"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"},"404":{"description":"Unknown estate / installer missing"},"409":{"description":"An install is already running"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/estates/runs/{id}":{"get":{"operationId":"estateRun","summary":"Poll an install/battle run: status + incremental log tail (?from=<byte offset> returns only new output; logSize is the next offset)","tags":["estates"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"run id"},{"name":"from","in":"query","required":false,"schema":{"type":"string"},"description":"log byte offset already received (default 0)"}],"responses":{"200":{"description":"{ id, kind, status, rc, tally, steps, log, logSize, ... }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.read)"},"404":{"description":"No such run"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.read"}},"/api/estates/runs":{"get":{"operationId":"listEstateRuns","summary":"Recent install/battle runs (newest first)","tags":["estates"],"responses":{"200":{"description":"[{ id, kind, label, status, estate, suite, started, ended }]"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.read"}},"/api/estates/battles":{"get":{"operationId":"listBattles","summary":"The battle-suite catalog: per-estate suite groups (scanned from test/) + the platform battlemanifest suites. mode \"own-engine\" boots a private engine; mode \"live\" targets THIS region (mutating — the UI warns)","tags":["estates"],"responses":{"200":{"description":"{ estates: [{ id, name, family, suites: [{name, file, mode}] }], platform: [{name, file, mode, expectPass}] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (system.read)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"system.read"}},"/api/estates/battles/run":{"post":{"operationId":"runBattle","summary":"Run a battle suite server-side (node test/<suite>_battle.mjs), streaming pass/fail into the run log. Suites are validated against the catalog. One battle at a time (409). Poll GET /api/estates/runs/{id}","tags":["estates"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"suite":{"description":"suite name from GET /api/estates/battles"}}}}}},"responses":{"200":{"description":"{ run, suite, mode }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (jobs.write)"},"404":{"description":"Unknown suite"},"409":{"description":"A battle is already running"}},"security":[{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/api/autopilot/orders":{"post":{"operationId":"autopilotCreateOrder","summary":"Create a paid autopilot build order (idempotent on orderId): the buyer's SteelFrame ID is created or linked, the job is queued","tags":["autopilot"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"orderId":{"description":"the store's order id"},"tier":{"description":"small | medium | large"},"budgetUsd":{"description":"per-build soft budget (default: the tenant's per tier)"},"priceUsd":{"description":"the order price (margin view)"},"test":{"description":"true for a test order (claude -p allowed, uncapped)"},"recipe":{"description":"next-pg (default)"},"agents":{"description":"multi (planner / orchestrator / implementer / tester agents) | single; default: the tenant's"},"spec":{"description":"the build spec object"},"contract":{"description":"the system contract text"},"agreement":{"description":"the Build Agreement text (the first user turn of every phase)"},"images":{"description":"[{ url, mime, purpose }]"},"buyer":{"description":"{ storeUserId, name }"},"callbackUrl":{"description":"signed progress callbacks (tenant callbackHosts only)"},"softwareId":{"description":"8-char base32 id of the delivered app"}}}}}},"responses":{"200":{"description":"{ created, jobId, orderId, user, state, phase, phases, progress, ..., queuePosition }"},"400":{"description":"invalid field"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.admin)"},"409":{"description":"no free userid"},"413":{"description":"spec/contract too large"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.admin"},"get":{"operationId":"autopilotListOrders","summary":"The tenant's autopilot orders (newest first, at most 200)","tags":["autopilot"],"responses":{"200":{"description":"{ orders: [view] }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.admin"}},"/api/autopilot/orders/{id}":{"get":{"operationId":"autopilotGetOrder","summary":"One autopilot order: state, phase, progress, cost, budget, margin, open escalation, waivers, release","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"view"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.admin)"},"404":{"description":"no such order for this tenant"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.admin"}},"/api/autopilot/orders/{id}/events":{"get":{"operationId":"autopilotOrderEvents","summary":"The order's recording (events.ndjson) after ?since=<seq>, at most ?limit= (<= 2000)","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"{ events: [...], last }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.admin"}},"/api/autopilot/orders/{id}/engine-review":{"get":{"operationId":"autopilotEngineReview","summary":"The engine review of this order (owner-only): why the engine let each review finding through, the fix draft branch; ?format=md for the record as written","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"{ findings, draft, analysis, cost, at } | text/markdown"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.admin)"},"404":{"description":"no such order, or no engine review yet"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.admin"}},"/api/autopilot/engine-review":{"get":{"operationId":"autopilotEngineReviewAggregate","summary":"The engine findings across orders (owner-only): cause x component, the orders, repeats; ?format=md","tags":["autopilot"],"responses":{"200":{"description":"{ causes, orders } | text/markdown"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.admin"}},"/api/autopilot/orders/{id}/artifact":{"get":{"operationId":"autopilotArtifact","summary":"The latest release tarball (application/gzip); its sha256 is in GET .../release and the order view","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.admin)"},"404":{"description":"no such order, or no release yet"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.admin"}},"/api/autopilot/orders/{id}/release":{"post":{"operationId":"autopilotRelease","summary":"The release record { n, sha256, bytes, file } and, ONCE, the initial admin password of the delivered system (Q17): the first call returns it and the engine forgets it","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"{ n, sha256, bytes, file, at, adminPassword? , adminPasswordDeliveredAt }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.admin)"},"404":{"description":"no release yet"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.admin"}},"/api/autopilot/orders/{id}/access":{"delete":{"operationId":"autopilotRevokeAccess","summary":"Revoke the buyer's access to the build and its recording (refund / dispute): no new watch links, observers refused, the view-only watch page is 404","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.admin"}},"/api/autopilot/orders/{id}/watch-link":{"post":{"operationId":"autopilotWatchLink","summary":"The link for the order's buyer to watch the build. With the stream on (SF_AUTOPILOT_STREAM=1): the view-only watch page <watchOrigin>/watch/<token>?v=live (no sign-in; the same url on every call; body { rotate: true } = a new token, the old link dead at once; expiresInS null). Otherwise a one-time sign-in link (single use, 60 s; the store 302s its signed-in buyer to it; never stored)","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rotate":{"description":"true = a new watch token (stream on only)"}}}}}},"responses":{"200":{"description":"{ url, expiresInS }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.admin)"},"404":{"description":"no such order"},"409":{"description":"the order is over and its access was revoked"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.admin"}},"/api/account/autopilot/redeem":{"post":{"operationId":"autopilotRedeem","summary":"Finish a watch link: the one-time code from the #ap= fragment -> the buyer's interactive session + account cookie (the /api/logon answer) and the build to open. CSRF-gated like the account cookie routes (allowed Origin, X-SF-CSRF: 1, JSON)","tags":["autopilot","session"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"description":"the one-time code from the #ap= fragment"}}}}}},"responses":{"200":{"description":"{ token, user, scopes, language, account: true, autopilot: { jobId, orderId, conv } }"},"401":{"description":"unknown / expired / used code"},"403":{"description":"CSRF check failed, or the buyer can no longer sign in"}},"security":[]}},"/api/account/autopilot/jobs":{"get":{"operationId":"autopilotMyJobs","summary":"Your own autopilot builds (the buyer view: no cost, no engine errors)","tags":["autopilot","account"],"responses":{"200":{"description":"OK"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/autopilot/jobs/{job}/events":{"get":{"operationId":"autopilotMyEvents","summary":"The recording of one of your own builds after ?since=<seq> (at most ?limit=, <= 2000)","tags":["autopilot","account"],"parameters":[{"name":"job","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"not your build, or access revoked"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/autopilot/orders/{id}/video":{"get":{"operationId":"autopilotVideo","summary":"The build's MP4 (rendered from the recording after the build)","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.admin)"},"404":{"description":"not rendered (yet), or removed by retention"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.admin"}},"/api/account/autopilot/jobs/{job}/video":{"get":{"operationId":"autopilotMyVideo","summary":"The MP4 of one of your own builds","tags":["autopilot","account"],"parameters":[{"name":"job","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"not your build, not rendered, or removed"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/account/autopilot/jobs/{job}/shots/{n}":{"get":{"operationId":"autopilotMyShot","summary":"One screenshot of the build's VS Code window (the recording's shot n) of one of your own builds","tags":["autopilot","account"],"parameters":[{"name":"job","in":"path","required":true,"schema":{"type":"string"},"description":""},{"name":"n","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (account.self)"},"404":{"description":"not your build, no such shot, or removed by retention"}},"security":[{"bearerAuth":[]},{"accountCookie":[]}],"x-required-scope":"account.self","x-cookie-auth":true}},"/api/autopilot/orders/{id}/retake":{"post":{"operationId":"autopilotRetake","summary":"Retake the build's footage window (notes/AUTOPILOT-FILM-REAL-SHELL-PLAN.md §5.4): the headless window closes (the seat stays) and opens again at once in the CURRENT film mode (SF_AUTOPILOT_FILM / the tenant's config.json \"film\"), which the job keeps from then on (a job is otherwise pinned to the mode of its first take), at the job's fixed footage size; a new take begins. The mid-build switch and its rollback without an engine restart. A tool call running at that moment fails once (the build retries it)","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"{ ok, mode, size: { width, height }, message? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.admin)"},"404":{"description":"no such order"},"409":{"description":"the build is not being driven, or the stream is off"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.admin"}},"/api/autopilot/orders/{id}/{action}":{"post":{"operationId":"autopilotOrderAction","summary":"Operator action on an order: resume { note? } (also a build that FAILED on its seat: provisioning starts again with a fresh job key; at a FAILED RELEASE the phases owning the failed gates reopen for a fix turn that gets the gate verdict and the note, then the release runs again) | pause | accept (the orchestrator's recommendation on the open escalation: retry / change_approach resume with its plan, waive waives + resumes, abort aborts; topup answers 409 - use topup { usd }) | abort { reason } | waive { gate, reason, scope } (a failed release gate: the release reruns directly) | topup { usd, note } | model { model?, provider? } or model { role, model } (a per-role override; model null clears it) | agents { mode: multi | single | orchestrated } (the phases not yet started) | effort { level?, role?, highCap? } (level default clears) | docs-refresh | purge (a finished build: code, recording, media and its conversations removed; the audit record stays)","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""},{"name":"action","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"view"},"400":{"description":"bad action or body"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.admin)"},"404":{"description":"no such order"},"409":{"description":"not possible in this state"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.admin"}},"/api/autopilot/orders/{id}/docs":{"get":{"operationId":"autopilotDocs","summary":"The documentation portal catalogue of an order: every document of the project's documentation set per audience (management, end users, developers, testers & QA, operations) with its standard, writer, status (planned | missing | draft | current | verified) and sha; working documents (docs/work/*) included; ?trace=1 adds the traceability object","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"{ at, phase, phaseKey, state, audiences, docs: [{ path, title, standard, audiences, writer, phase, engine, status, bytes, sha256, updatedAt }], trace? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.read)"},"404":{"description":"no such order for this tenant"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.read"}},"/api/autopilot/orders/{id}/doc":{"get":{"operationId":"autopilotDoc","summary":"One document of an order's documentation set, rendered (?path=docs/REQUIREMENTS.md; ?raw=1 for the Markdown text)","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"{ path, title, standard, audiences, engine, sha256, bytes, updatedAt, html | text }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.read)"},"404":{"description":"no such order, or no such document in the snapshot"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.read"}},"/api/autopilot/orders/{id}/docs-search":{"get":{"operationId":"autopilotDocsSearch","summary":"Search the order's documents (working documents included) for a phrase: ?q=<2..80 chars> -> hits with the document, the nearest heading (slug = the rendered heading id) and a snippet","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"{ q, hits: [{ path, title, heading, slug, snippet, n }], docs, more? }"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.read)"},"404":{"description":"no such order for this tenant"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.read"}},"/api/autopilot/orders/{id}/ui":{"get":{"operationId":"autopilotUiShot","summary":"A screenshot of the UI/UX report (?name=<file>.jpg; engine-made, from the order folder)","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.read)"},"404":{"description":"no such order, or no such screenshot"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.read"}},"/api/autopilot/orders/{id}/doc.md":{"get":{"operationId":"autopilotDocMd","summary":"One document of the order's set as a Markdown attachment (?path=docs/REQUIREMENTS.md; working documents included)","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.read)"},"404":{"description":"no such order for this tenant, or no such document in the snapshot"},"503":{"description":"the PDF is being prepared (Retry-After)"},"507":{"description":"the PDF would be too large"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.read"}},"/api/autopilot/orders/{id}/doc.pdf":{"get":{"operationId":"autopilotDocPdf","summary":"One document as a PDF attachment (rendered by the engine, cached per content)","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.read)"},"404":{"description":"no such order for this tenant, or no such document in the snapshot"},"503":{"description":"the PDF is being prepared (Retry-After)"},"507":{"description":"the PDF would be too large"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.read"}},"/api/autopilot/orders/{id}/doc.print":{"get":{"operationId":"autopilotDocPrint","summary":"One document as a print view (HTML, no script, the print stylesheet linked)","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.read)"},"404":{"description":"no such order for this tenant, or no such document in the snapshot"},"503":{"description":"the PDF is being prepared (Retry-After)"},"507":{"description":"the PDF would be too large"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.read"}},"/api/autopilot/orders/{id}/docs.zip":{"get":{"operationId":"autopilotDocsZip","summary":"The whole set (working documents under docs/work/) as a ZIP: the Markdown files, DOCUMENTATION.pdf (when it can be prepared in time) and INDEX.txt","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.read)"},"404":{"description":"no such order for this tenant, or no such document in the snapshot"},"503":{"description":"the PDF is being prepared (Retry-After)"},"507":{"description":"the PDF would be too large"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.read"}},"/api/autopilot/orders/{id}/docs.pdf":{"get":{"operationId":"autopilotDocsPdf","summary":"The whole set as ONE PDF: a cover with linked contents, the PDF outline, the working documents under a divider","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.read)"},"404":{"description":"no such order for this tenant, or no such document in the snapshot"},"503":{"description":"the PDF is being prepared (Retry-After)"},"507":{"description":"the PDF would be too large"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.read"}},"/api/autopilot/orders/{id}/docs.print":{"get":{"operationId":"autopilotDocsPrint","summary":"The whole set as one print view (HTML, no script)","tags":["autopilot"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":""}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.read)"},"404":{"description":"no such order for this tenant, or no such document in the snapshot"},"503":{"description":"the PDF is being prepared (Retry-After)"},"507":{"description":"the PDF would be too large"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.read"}},"/api/autopilot/quote":{"post":{"operationId":"autopilotQuote","summary":"One model turn for the store's \"Describe your software\" analysis (no tools, no seat): the store's system + user texts in, the model's text out; charged to the tenant build pool, capped per tenant per day","tags":["autopilot"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"system":{"description":"the analysis instructions (<= 32 KB)"},"user":{"description":"the client's description, fenced by the store (<= 48 KB)"},"model":{"description":"default claude-fable-5-1 (a job model of this engine)"}}}}}},"responses":{"200":{"description":"{ id, text, model, provider, costUsd, usage, durationMs }"},"400":{"description":"user REQUIRED / model not available"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"402":{"description":"the tenant build pool is empty"},"403":{"description":"Token lacks the required scope (autopilot.quote)"},"413":{"description":"system or user too large"},"429":{"description":"the tenant's daily analysis cap or the pool's daily ceiling is reached"},"502":{"description":"the provider failed"},"503":{"description":"the provider is not allowed on this engine"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.quote"}},"/api/autopilot/status":{"get":{"operationId":"autopilotStatus","summary":"The runner: concurrency, the job(s) being driven, the queue, the provider, the tenant pool","tags":["autopilot"],"responses":{"200":{"description":"OK"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (autopilot.admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"autopilot.admin"}},"/api/autopilot/pool":{"get":{"operationId":"autopilotPool","summary":"The tenant build pool (owner): balance (null = uncapped), daily ceiling, today/month spend, latest entries; ?csv=1 for every entry as CSV","tags":["autopilot"],"responses":{"200":{"description":"OK"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"}},"/api/autopilot/pool/adjust":{"post":{"operationId":"autopilotPoolAdjust","summary":"Fund / set the tenant build pool (owner): { addUsd } or { balanceUsd: number | null (uncapped) }, { ceilingDailyUsd: number | null (env default) }, note","tags":["autopilot"],"responses":{"200":{"description":"OK"},"401":{"description":"Missing/invalid token (NOT LOGGED ON)"},"403":{"description":"Token lacks the required scope (admin)"}},"security":[{"bearerAuth":[]}],"x-required-scope":"admin"}},"/zosmf/info":{"get":{"operationId":"zosmfInfo","summary":"z/OSMF information retrieval (no authentication): the host, port and services this door offers; Zowe uses it for \"check status\" and profile validation","tags":["zosmf"],"responses":{"200":{"description":"{ zos_version, zosmf_port, zosmf_version, zosmf_hostname, zosmf_saf_realm, zosmf_full_version, api_version, plugins[], product } - zosmf_hostname / zosmf_port are the host and port you called (443 for https without a port)"}},"x-success-status":"200","security":[]}},"/zosmf/restjobs/jobs":{"get":{"operationId":"zosmfListJobs","summary":"List jobs (z/OSMF GetListJobs): the jobs you may see (JESSPOOL), newest first","tags":["zosmf"],"parameters":[{"name":"owner","in":"query","required":false,"schema":{"type":"string"},"description":"owner userid; default: the caller; * = every owner you may see; * and % wildcards"},{"name":"prefix","in":"query","required":false,"schema":{"type":"string"},"description":"job name; default *; a name without wildcards matches as a prefix; * and % wildcards"},{"name":"jobid","in":"query","required":false,"schema":{"type":"string"},"description":"only this job id"},{"name":"status","in":"query","required":false,"schema":{"type":"string"},"description":"active = only executing jobs (other values are not applied)"},{"name":"max-jobs","in":"query","required":false,"schema":{"type":"string"},"description":"at most N jobs, 1-1000 (default 1000)"},{"name":"exec-data","in":"query","required":false,"schema":{"type":"string"},"description":"Y = add exec-system, exec-member, exec-submitted, exec-started, exec-ended"}],"responses":{"200":{"description":"[ { jobname, jobid, owner, status (INPUT|ACTIVE|OUTPUT), class, retcode (null | CC nnnn | JCL ERROR | ABEND Sxxx | CANCELED), phase, phase-name, subsystem, type, job-correlator, url, files-url } ]"},"401":{"description":"No or wrong credentials (z/OSMF error document; Basic at a $0 AI-credit balance where the credit gate is on: SFCR001A)"},"402":{"description":"API key or login token at a $0 AI-credit balance where the credit gate is on (CREDIT REQUIRED)"}},"x-success-status":"200","security":[{"zosmfBasic":[]},{"bearerAuth":[]}],"x-required-scope":"jobs.read"},"put":{"operationId":"zosmfSubmitJob","summary":"Submit a job (z/OSMF SubmitJob): the JCL as the text/plain body, or application/json { \"file\": \"//'DSN(MEMBER)'\" } to submit a member you may read","tags":["zosmf"],"parameters":[{"name":"X-CSRF-ZOSMF-HEADER","in":"header","required":true,"schema":{"type":"string"},"description":"required on this write (any value)"},{"name":"X-IBM-Intrdr-Mode","in":"header","required":false,"schema":{"type":"string"},"description":"TEXT (the only mode; default)"},{"name":"X-IBM-JCL-Symbol-<NAME>","in":"header","required":false,"schema":{"type":"string"},"description":"adds // SET NAME=value after the JOB statement (Zowe --jcl-symbols)"}],"requestBody":{"required":true,"description":"the JCL, one record per line (Content-Type: text/plain)","content":{"text/plain":{"schema":{"type":"string","description":"the JCL, one record per line (Content-Type: text/plain)"}},"application/json":{"schema":{"type":"object","properties":{"file":{"description":"//'DSN(MEMBER)' or //'DSN' - submit from a data set (application/json)"}}}}}},"responses":{"201":{"description":"the job object (as in the list), status INPUT or later"},"400":{"description":"No JCL, an invalid file reference or an unsupported X-IBM-Intrdr-Mode"},"401":{"description":"No or wrong credentials (z/OSMF error document; Basic at a $0 AI-credit balance where the credit gate is on: SFCR001A)"},"402":{"description":"API key or login token at a $0 AI-credit balance where the credit gate is on (CREDIT REQUIRED)"},"403":{"description":"X-CSRF-ZOSMF-HEADER missing, scope, or RACF READ on the file"},"501":{"description":"file names a z/OS UNIX path"}},"x-success-status":"201","security":[{"zosmfBasic":[]},{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/zosmf/restjobs/jobs/{jobname}/{jobid}":{"get":{"operationId":"zosmfGetJob","summary":"Job status (z/OSMF GetJobStatus); the job-correlator form /zosmf/restjobs/jobs/{job-correlator} (the url field) answers the same","tags":["zosmf"],"parameters":[{"name":"jobname","in":"path","required":true,"schema":{"type":"string"},"description":"job name"},{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"job id (JOBnnnnn)"},{"name":"step-data","in":"query","required":false,"schema":{"type":"string"},"description":"Y = add step-data[] (step-name, proc-step-name, program-name, completion, step-number, active, smfid)"},{"name":"exec-data","in":"query","required":false,"schema":{"type":"string"},"description":"Y = add the exec-* timestamps"}],"responses":{"200":{"description":"the job object"},"401":{"description":"No or wrong credentials (z/OSMF error document; Basic at a $0 AI-credit balance where the credit gate is on: SFCR001A)"},"402":{"description":"API key or login token at a $0 AI-credit balance where the credit gate is on (CREDIT REQUIRED)"},"404":{"description":"No such job, or a job you may not see (JESSPOOL), or a job name that does not match the job id"}},"x-success-status":"200","security":[{"zosmfBasic":[]},{"bearerAuth":[]}],"x-required-scope":"jobs.read"},"put":{"operationId":"zosmfModifyJob","summary":"Cancel, hold or release a job (z/OSMF CancelJob / HoldJob / ReleaseJob); needs JESSPOOL ALTER on someone else's job","tags":["zosmf"],"parameters":[{"name":"jobname","in":"path","required":true,"schema":{"type":"string"},"description":"job name"},{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"job id (JOBnnnnn)"},{"name":"X-CSRF-ZOSMF-HEADER","in":"header","required":true,"schema":{"type":"string"},"description":"required on this write (any value)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"request":{"description":"cancel | hold | release"},"version":{"description":"\"1.0\" (default, 202) or \"2.0\" (200)"}}}}}},"responses":{"200":{"description":"the same, for version 2.0"},"202":{"description":"feedback { jobid, jobname, original-jobid, owner, member, sysname, job-correlator, status (0 = done, 1 = not possible in the job's state, with message) }"},"400":{"description":"request is not cancel, hold or release"},"401":{"description":"No or wrong credentials (z/OSMF error document; Basic at a $0 AI-credit balance where the credit gate is on: SFCR001A)"},"402":{"description":"API key or login token at a $0 AI-credit balance where the credit gate is on (CREDIT REQUIRED)"},"403":{"description":"X-CSRF-ZOSMF-HEADER missing, scope, or JESSPOOL ALTER"},"404":{"description":"No such job, or a job you may not see (JESSPOOL), or a job name that does not match the job id"}},"x-success-status":"202","security":[{"zosmfBasic":[]},{"bearerAuth":[]}],"x-required-scope":"jobs.write"},"delete":{"operationId":"zosmfPurgeJob","summary":"Cancel and purge a job (z/OSMF CancelAndPurgeJob): an executing job is canceled first; needs JESSPOOL ALTER on someone else's job","tags":["zosmf"],"parameters":[{"name":"jobname","in":"path","required":true,"schema":{"type":"string"},"description":"job name"},{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"job id (JOBnnnnn)"},{"name":"X-CSRF-ZOSMF-HEADER","in":"header","required":true,"schema":{"type":"string"},"description":"required on this write (any value)"},{"name":"X-IBM-Job-Modify-Version","in":"header","required":false,"schema":{"type":"string"},"description":"1.0 (default, 202) or 2.0 (200)"}],"responses":{"200":{"description":"the same, for version 2.0"},"202":{"description":"feedback { jobid, jobname, owner, status: 0, ... }"},"401":{"description":"No or wrong credentials (z/OSMF error document; Basic at a $0 AI-credit balance where the credit gate is on: SFCR001A)"},"402":{"description":"API key or login token at a $0 AI-credit balance where the credit gate is on (CREDIT REQUIRED)"},"403":{"description":"X-CSRF-ZOSMF-HEADER missing, scope, or JESSPOOL ALTER"},"404":{"description":"No such job, or a job you may not see (JESSPOOL), or a job name that does not match the job id"}},"x-success-status":"202","security":[{"zosmfBasic":[]},{"bearerAuth":[]}],"x-required-scope":"jobs.write"}},"/zosmf/restjobs/jobs/{jobname}/{jobid}/files":{"get":{"operationId":"zosmfListSpoolFiles","summary":"List a job's spool files (z/OSMF ListSpoolFiles); the files-url form /zosmf/restjobs/jobs/{job-correlator}/files answers the same","tags":["zosmf"],"parameters":[{"name":"jobname","in":"path","required":true,"schema":{"type":"string"},"description":"job name"},{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"job id (JOBnnnnn)"}],"responses":{"200":{"description":"[ { id, ddname, stepname, procstep, class, recfm, lrecl, byte-count, record-count, records-url, jobname, jobid, job-correlator, subsystem } ] - ids 2 JESMSGLG, 3 JESJCL, 4 JESYSMSG, your SYSOUT from 101"},"401":{"description":"No or wrong credentials (z/OSMF error document; Basic at a $0 AI-credit balance where the credit gate is on: SFCR001A)"},"402":{"description":"API key or login token at a $0 AI-credit balance where the credit gate is on (CREDIT REQUIRED)"},"404":{"description":"No such job, or a job you may not see (JESSPOOL), or a job name that does not match the job id"}},"x-success-status":"200","security":[{"zosmfBasic":[]},{"bearerAuth":[]}],"x-required-scope":"jobs.read"}},"/zosmf/restjobs/jobs/{jobname}/{jobid}/files/{id}/records":{"get":{"operationId":"zosmfReadSpoolFile","summary":"Read one spool file (z/OSMF RetrieveSpoolFileContents) as text/plain","tags":["zosmf"],"parameters":[{"name":"jobname","in":"path","required":true,"schema":{"type":"string"},"description":"job name"},{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"job id (JOBnnnnn)"},{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"spool file id from the files list"},{"name":"mode","in":"query","required":false,"schema":{"type":"string"},"description":"text (default), binary or record (the stored text as bytes, application/octet-stream)"},{"name":"X-IBM-Record-Range","in":"header","required":false,"schema":{"type":"string"},"description":"SSS-EEE (records SSS..EEE) or SSS,NNN (NNN records from SSS), 0-based"}],"responses":{"200":{"description":"the spool file text, one record per line"},"400":{"description":"X-IBM-Record-Range is not valid"},"401":{"description":"No or wrong credentials (z/OSMF error document; Basic at a $0 AI-credit balance where the credit gate is on: SFCR001A)"},"402":{"description":"API key or login token at a $0 AI-credit balance where the credit gate is on (CREDIT REQUIRED)"},"404":{"description":"No such job / job not visible, or no spool file with that id"}},"x-success-status":"200","security":[{"zosmfBasic":[]},{"bearerAuth":[]}],"x-required-scope":"jobs.read"}},"/zosmf/restjobs/jobs/{jobname}/{jobid}/files/JCL/records":{"get":{"operationId":"zosmfReadJobJcl","summary":"The JCL the job was submitted with (the JES input stream) as text/plain","tags":["zosmf"],"parameters":[{"name":"jobname","in":"path","required":true,"schema":{"type":"string"},"description":"job name"},{"name":"jobid","in":"path","required":true,"schema":{"type":"string"},"description":"job id (JOBnnnnn)"},{"name":"X-IBM-Record-Range","in":"header","required":false,"schema":{"type":"string"},"description":"SSS-EEE or SSS,NNN, 0-based"}],"responses":{"200":{"description":"the submitted JCL, one record per line"},"401":{"description":"No or wrong credentials (z/OSMF error document; Basic at a $0 AI-credit balance where the credit gate is on: SFCR001A)"},"402":{"description":"API key or login token at a $0 AI-credit balance where the credit gate is on (CREDIT REQUIRED)"},"404":{"description":"No such job, or a job you may not see (JESSPOOL), or a job name that does not match the job id"}},"x-success-status":"200","security":[{"zosmfBasic":[]},{"bearerAuth":[]}],"x-required-scope":"jobs.read"}},"/zosmf/restfiles/ds":{"get":{"operationId":"zosmfListDatasets","summary":"List data sets (z/OSMF ListDataSets): a level without wildcards lists that name and everything below it","tags":["zosmf"],"parameters":[{"name":"dslevel","in":"query","required":false,"schema":{"type":"string"},"description":"required: a high-level qualifier or pattern (* and % wildcards)"},{"name":"start","in":"query","required":false,"schema":{"type":"string"},"description":"list from this name on"},{"name":"volser","in":"query","required":false,"schema":{"type":"string"},"description":"only data sets on this volume"},{"name":"X-IBM-Max-Items","in":"header","required":false,"schema":{"type":"string"},"description":"at most N items (default 1000; 0 = no limit)"},{"name":"X-IBM-Attributes","in":"header","required":false,"schema":{"type":"string"},"description":"base = the attribute set (dsorg, recfm, lrecl, blksz, vol, ...); default: names only"}],"responses":{"200":{"description":"{ items[], returnedRows, totalRows, JSONversion, moreRows? }"},"400":{"description":"dslevel missing"},"401":{"description":"No or wrong credentials (z/OSMF error document; Basic at a $0 AI-credit balance where the credit gate is on: SFCR001A)"},"402":{"description":"API key or login token at a $0 AI-credit balance where the credit gate is on (CREDIT REQUIRED)"}},"x-success-status":"200","security":[{"zosmfBasic":[]},{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/zosmf/restfiles/ds/{dsname}/member":{"get":{"operationId":"zosmfListMembers","summary":"List the members of a PDS / PDSE (z/OSMF GetListDataSetMembers)","tags":["zosmf"],"parameters":[{"name":"dsname","in":"path","required":true,"schema":{"type":"string"},"description":"the data set name"},{"name":"pattern","in":"query","required":false,"schema":{"type":"string"},"description":"member name pattern (* and %)"},{"name":"start","in":"query","required":false,"schema":{"type":"string"},"description":"list from this member on"},{"name":"X-IBM-Max-Items","in":"header","required":false,"schema":{"type":"string"},"description":"at most N items (default 1000; 0 = no limit)"},{"name":"X-IBM-Attributes","in":"header","required":false,"schema":{"type":"string"},"description":"base = ISPF statistics (vers, mod, c4date, m4date, mtime, user, ...)"}],"responses":{"200":{"description":"{ items[], returnedRows, JSONversion, moreRows? }"},"401":{"description":"No or wrong credentials (z/OSMF error document; Basic at a $0 AI-credit balance where the credit gate is on: SFCR001A)"},"402":{"description":"API key or login token at a $0 AI-credit balance where the credit gate is on (CREDIT REQUIRED)"},"403":{"description":"RACF denies the data set access, or the credential lacks the scope"},"404":{"description":"Data set (or member) not found"}},"x-success-status":"200","security":[{"zosmfBasic":[]},{"bearerAuth":[]}],"x-required-scope":"datasets.read"}},"/zosmf/restfiles/ds/{dsname}":{"get":{"operationId":"zosmfReadDataset","summary":"Read a sequential data set or a member (z/OSMF RetrieveDataSetContents); {dsname} is DSN or DSN(MEMBER), optionally after a -(VOLSER)/ segment; VSAM clusters are not readable here","tags":["zosmf"],"parameters":[{"name":"dsname","in":"path","required":true,"schema":{"type":"string"},"description":"DSN or DSN(MEMBER)"},{"name":"X-IBM-Data-Type","in":"header","required":false,"schema":{"type":"string"},"description":"text (default; ;fileEncoding=IBM-nnn for another EBCDIC code page), binary or record (4-byte length prefix per record)"},{"name":"X-IBM-Record-Range","in":"header","required":false,"schema":{"type":"string"},"description":"SSS-EEE or SSS,NNN, 0-based"}],"responses":{"200":{"description":"the content (text/plain, or application/octet-stream for binary / record), with an ETag"},"400":{"description":"a PDS without a member, a GDG base, VSAM, or an invalid header"},"401":{"description":"No or wrong credentials (z/OSMF error document; Basic at a $0 AI-credit balance where the credit gate is on: SFCR001A)"},"402":{"description":"API key or login token at a $0 AI-credit balance where the credit gate is on (CREDIT REQUIRED)"},"403":{"description":"RACF denies the data set access, or the credential lacks the scope"},"404":{"description":"Data set (or member) not found"},"413":{"description":"larger than the door's size limit: read it in parts with X-IBM-Record-Range"}},"x-success-status":"200","security":[{"zosmfBasic":[]},{"bearerAuth":[]}],"x-required-scope":"datasets.read"},"put":{"operationId":"zosmfWriteDataset","summary":"Write a sequential data set or a member (z/OSMF WriteDataSet), or, with an application/json body, a utility request: rename, copy or hrecall","tags":["zosmf"],"parameters":[{"name":"dsname","in":"path","required":true,"schema":{"type":"string"},"description":"DSN or DSN(MEMBER)"},{"name":"X-CSRF-ZOSMF-HEADER","in":"header","required":true,"schema":{"type":"string"},"description":"required on this write (any value)"},{"name":"X-IBM-Data-Type","in":"header","required":false,"schema":{"type":"string"},"description":"text (default), binary or record"},{"name":"If-Match","in":"header","required":false,"schema":{"type":"string"},"description":"the ETag you read: the write fails with 412 when the content changed since"}],"requestBody":{"required":true,"description":"the new content (text: one record per line)","content":{"text/plain":{"schema":{"type":"string","description":"the new content (text: one record per line)"}},"application/json":{"schema":{"type":"object","properties":{"request":{"description":"rename | copy | hrecall (utility request, application/json)"},"from-dataset":{"description":"{ dsn, member? } - the source of a rename or copy (member \"*\" copies every member)"},"replace":{"description":"true = a copy may replace an existing member"}}}}}},"responses":{"200":{"description":"utility request done"},"201":{"description":"a new member was created"},"204":{"description":"written (the data set or member existed), with an ETag"},"400":{"description":"a PDS without a member, a GDG base, VSAM, or an invalid body"},"401":{"description":"No or wrong credentials (z/OSMF error document; Basic at a $0 AI-credit balance where the credit gate is on: SFCR001A)"},"402":{"description":"API key or login token at a $0 AI-credit balance where the credit gate is on (CREDIT REQUIRED)"},"403":{"description":"X-CSRF-ZOSMF-HEADER missing, scope, or RACF UPDATE"},"404":{"description":"Data set not found"},"409":{"description":"copy target member exists without \"replace\": true"},"412":{"description":"If-Match does not match the current content"}},"x-success-status":"204","security":[{"zosmfBasic":[]},{"bearerAuth":[]}],"x-required-scope":"datasets.write"},"post":{"operationId":"zosmfCreateDataset","summary":"Allocate a data set (z/OSMF CreateDataSet): PS, PO or PO-E (PDSE); VSAM clusters are defined with IDCAMS in batch","tags":["zosmf"],"parameters":[{"name":"dsname","in":"path","required":true,"schema":{"type":"string"},"description":"the new data set name (no member)"},{"name":"X-CSRF-ZOSMF-HEADER","in":"header","required":true,"schema":{"type":"string"},"description":"required on this write (any value)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dsorg":{"description":"PS (default), PO or PO-E"},"recfm":{"description":"record format (e.g. FB)"},"lrecl":{"description":"record length"},"blksize":{"description":"block size (blksz also accepted)"},"dsntype":{"description":"LIBRARY = PDSE"},"volser":{"description":"volume (when it exists)"},"like":{"description":"copy dsorg/recfm/lrecl/blksize from this data set"}}}}}},"responses":{"201":{"description":"allocated"},"400":{"description":"unsupported dsorg, or a member name given"},"401":{"description":"No or wrong credentials (z/OSMF error document; Basic at a $0 AI-credit balance where the credit gate is on: SFCR001A)"},"402":{"description":"API key or login token at a $0 AI-credit balance where the credit gate is on (CREDIT REQUIRED)"},"403":{"description":"X-CSRF-ZOSMF-HEADER missing, scope, or RACF"},"404":{"description":"the like data set was not found"},"409":{"description":"the data set already exists"}},"x-success-status":"201","security":[{"zosmfBasic":[]},{"bearerAuth":[]}],"x-required-scope":"datasets.write"},"delete":{"operationId":"zosmfDeleteDataset","summary":"Delete a data set or a member (z/OSMF DeleteDataSet)","tags":["zosmf"],"parameters":[{"name":"dsname","in":"path","required":true,"schema":{"type":"string"},"description":"DSN or DSN(MEMBER)"},{"name":"X-CSRF-ZOSMF-HEADER","in":"header","required":true,"schema":{"type":"string"},"description":"required on this write (any value)"}],"responses":{"204":{"description":"deleted"},"401":{"description":"No or wrong credentials (z/OSMF error document; Basic at a $0 AI-credit balance where the credit gate is on: SFCR001A)"},"402":{"description":"API key or login token at a $0 AI-credit balance where the credit gate is on (CREDIT REQUIRED)"},"403":{"description":"RACF denies the data set access, or the credential lacks the scope"},"404":{"description":"Data set (or member) not found"}},"x-success-status":"204","security":[{"zosmfBasic":[]},{"bearerAuth":[]}],"x-required-scope":"datasets.write"}},"/zosmf/restconsoles/consoles/{consolename}":{"put":{"operationId":"zosmfConsoleCommand","summary":"Issue an MVS / JES2 operator command (z/OSMF console services; RACF OPERCMDS applies)","tags":["zosmf"],"parameters":[{"name":"consolename","in":"path","required":true,"schema":{"type":"string"},"description":"any console name (e.g. defcn)"},{"name":"X-CSRF-ZOSMF-HEADER","in":"header","required":true,"schema":{"type":"string"},"description":"required on this write (any value)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"cmd":{"description":"the command text, e.g. D T"}}}}}},"responses":{"200":{"description":"{ cmd-response, cmd-response-key, cmd-response-url, cmd-response-uri }"},"400":{"description":"cmd missing"},"401":{"description":"No or wrong credentials (z/OSMF error document; Basic at a $0 AI-credit balance where the credit gate is on: SFCR001A)"},"402":{"description":"API key or login token at a $0 AI-credit balance where the credit gate is on (CREDIT REQUIRED)"},"403":{"description":"X-CSRF-ZOSMF-HEADER missing, scope, or OPERCMDS"}},"x-success-status":"200","security":[{"zosmfBasic":[]},{"bearerAuth":[]}],"x-required-scope":"jobs.write"}}}}