Skip to content

REST API (v1)

3270Web exposes a small JSON HTTP API for non-browser clients (RPA bots, CI jobs, integration scripts). The API is versioned and gated by a Bearer token so it can be enabled per-deployment.

Enabling the API

Set the API_TOKEN environment variable to a non-empty secret before starting 3270Web. The simplest way is to add a line to the .env file that 3270Web reads on startup:

API_TOKEN=replace-with-a-long-random-string

When API_TOKEN is unset or empty, every /api/v1/* request returns 503 Service Unavailable with {"error": "API disabled: API_TOKEN not configured"}. This is the default so the API can't be accidentally exposed.

The 3270Web server binds to 127.0.0.1:8080 by default, so the API is only reachable from the local host. The Bearer token is additional defense-in-depth for any deployment that changes the bind address.

Authentication

Every request must include an Authorization: Bearer <token> header. Bad or missing tokens get 401 Unauthorized.

curl -H "Authorization: Bearer $API_TOKEN" \
  http://127.0.0.1:8080/api/v1/sessions

Endpoints

Method Path Description
GET /api/v1/sessions List active sessions
POST /api/v1/sessions Start a new host session
DELETE /api/v1/sessions/:id Disconnect and remove a session
GET /api/v1/sessions/:id/screen Refresh and read the current screen
POST /api/v1/sessions/:id/key Send an AID or navigation key
POST /api/v1/sessions/:id/field Write text into a field
POST /api/v1/sessions/:id/submit Submit modified fields + send Enter (or another AID)
POST /api/v1/sessions/:id/profile Run a host compatibility probe and return the CompatibilityProfile JSON
GET /api/v1/sessions/:id/profile Return the cached CompatibilityProfile from the last probe

POST /api/v1/sessions

Create and start a host session. Sample-app pseudo-hostnames (mock, demo, sampleapp:appN) are rejected by the API — those are reserved for the browser UI.

curl -X POST \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"host":"mainframe.example.com:23"}' \
  http://127.0.0.1:8080/api/v1/sessions

Response:

{ "id": "f1c5...", "host": "mainframe.example.com", "port": 23 }

GET /api/v1/sessions/:id/screen

Refreshes the screen and returns its full structure.

curl -H "Authorization: Bearer $API_TOKEN" \
  http://127.0.0.1:8080/api/v1/sessions/$ID/screen

Response:

{
  "width": 80,
  "height": 24,
  "text": "...screen contents...\n...\n",
  "formatted": true,
  "kbd_lock": "U",
  "cursor": { "row": 5, "col": 12 },
  "fields": [
    {
      "start_row": 1, "start_col": 0,
      "end_row": 1, "end_col": 19,
      "value": "USERID",
      "protected": true, "numeric": false, "hidden": false,
      "length": 20
    }
  ],
  "status": "U F P C(mainframe.example.com) I 4 24 80 5 12 0x0 0.000"
}

kbd_lock is "U" (unlocked), "L" (locked), or "E" (error). The field is omitted when 3270Web could not parse the status line.

POST /api/v1/sessions/:id/key

Send a single key. The key name follows the same vocabulary the Copilot side panel uses: Enter, PF1..PF24, PA1..PA3, Tab, BackTab, Clear, Reset, EraseEOF, EraseInput, Home, Up, Down, Left, Right.

curl -X POST \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"key":"PF3"}' \
  http://127.0.0.1:8080/api/v1/sessions/$ID/key

POST /api/v1/sessions/:id/field

Write text into the input field that contains (row, col). Coordinates are 0-indexed. Text containing CR, LF, or TAB is rejected.

curl -X POST \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"row":3,"col":10,"text":"USER01"}' \
  http://127.0.0.1:8080/api/v1/sessions/$ID/field

POST /api/v1/sessions/:id/submit

Submit any modified fields and send an AID key. The default AID is Enter; pass {"aid": "PF3"} to use a different key. The response includes the updated screen.

curl -X POST \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"aid":"Enter"}' \
  http://127.0.0.1:8080/api/v1/sessions/$ID/submit

DELETE /api/v1/sessions/:id

Disconnect from the host and remove the session.

curl -X DELETE \
  -H "Authorization: Bearer $API_TOKEN" \
  http://127.0.0.1:8080/api/v1/sessions/$ID

POST /api/v1/sessions/:id/profile

Probe the session's connected host and return a CompatibilityProfile JSON document. The schema is shared byte-for-byte with 3270Connect -profile output, so profiles from either tool can be diffed against each other. Body is optional.

curl -X POST \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"collect_raw": true}' \
  http://127.0.0.1:8080/api/v1/sessions/$ID/profile

Supported body fields: ind_file_probe, collect_raw, per_action_timeout_ms. See the Host Compatibility Profiler page for the full walkthrough and the Compatibility Profile Schema for the response shape.

GET /api/v1/sessions/:id/profile

Return the cached CompatibilityProfile from the last probe in this session. 404 Not Found if no probe has run.

curl -H "Authorization: Bearer $API_TOKEN" \
  http://127.0.0.1:8080/api/v1/sessions/$ID/profile

Browser-session endpoints

These endpoints reuse the session cookie set by the connect flow rather than API_TOKEN. They are useful for in-browser callers and for tools that already drive 3270Web through the cookie.

Method Path Description
POST /profile Probe the current session and return the CompatibilityProfile JSON.
GET /profile Return the cached profile for the current session.
POST /chaos/report Markdown discovery report for the active chaos run (ASCII screen graph, per-screen stats, suggested experiments).
POST /chaos/mindmap/compare Diff two previously-exported chaos mind maps. JSON by default; pass Accept: text/html (or ?format=html) for the HTML report. See Chaos Mind-Map Compare.
GET /chaos/screens Every screen discovered by chaos: fields, learned values, key destinations, business annotations, and a truncated preview. ?include_previews=false omits previews.
POST /chaos/screens/annotate Record a screen's business purpose and field semantics. Body: {"screen_hash", "business_purpose", "notes", "field_semantics": {"R5C20L8": {"name", "description", "example", "sensitive"}}}.
GET /chaos/business/functions List cataloged business functions (name, description, steps, parameters).
POST /chaos/business/functions Upsert a business function. Body: {"name", "description", "entry_screen_hash", "steps": [{"screen_hash", "inputs": [{"field_key", "value", "parameter"}], "aid_key", "expect_hash"}], "parameters": [{"name", "description", "screen_hash", "field_key", "example", "required"}]}.
POST /chaos/business/generate-workflow Generate a business-focused workflow JSON from a cataloged function. Body: {"name", "parameters": {"param": "value"}, "host", "port"}. Returns a playback-compatible workflow document with Name/Description/BusinessFunction/Parameters metadata.

System endpoints

Unauthenticated and not session-scoped — intended for liveness/readiness probes.

Method Path Description
GET /healthz Returns 200 OK with {"status":"ok","version":"<app version>"}. Used by the Docker HEALTHCHECK and orchestrators. Performs no session or s3270 work. See Install and Run.

Errors

Status Meaning
400 Bad Request Bad input — e.g. missing host, CR/LF/TAB in field text
401 Unauthorized Missing or bad Authorization header
404 Not Found Session id does not exist
502 Bad Gateway The host or s3270 subprocess returned an error
503 Service Unavailable API_TOKEN not configured — API is disabled

Out of scope (v1)

The following are deliberately not part of v1. Some of them are tracked in the Feature Roadmap.

  • WebSocket / SSE streaming of screen changes
  • File transfer endpoints (IND$FILE)
  • OAuth / OIDC / SAML auth
  • Multiple tokens, per-token scopes, rate limiting
  • API token rotation