OpenAPI 3.1, AsyncAPI 2.6 & JSON Schema
Contracts for the new system, written by the old one.
PYD ENTERPRISES turns COMMAREAs, copybooks, EJB remotes and WCF contracts into standards-compliant OpenAPI 3.1, AsyncAPI event schemas and JSON Schema data contracts, with exact type constraints.
- GET
/loans/{loanId}/accrual
LNINQ01 · CICS LINK
- POST
/loans/{loanId}/payments
LNUPD01 · CICS BMS
- GET
/customers/{custNo}/loans
LNCUS02 · VSAM AIX
- SUB
loans.accrual.posted
LNACCR02 · batch WRITE
- PUT
/policies/{policyNo}/quote
PolicyServiceBean · EJB
Spec viewer
Click a COBOL field. Find it in every document.
One CICS COMMAREA, three generated documents. Each property records the PIC clause, byte length and the dataflow evidence for its constraints, and the response code field becomes HTTP statuses instead of a property.
LNINQ01 · CICS TRANSID LNIQ · LINK COMMAREA 37 bytes
1 01 LNIQ-COMMAREA.2 05 CA-LOAN-ID PIC X(10).3 05 CA-AS-OF-DATE PIC 9(08).4 05 CA-RESP-CODE PIC X(02).5 88 CA-OK VALUE '00'.6 88 CA-NOT-FOUND VALUE '04'.7 88 CA-CLOSED VALUE '08'.8 05 CA-PRIN-BAL PIC S9(11)V99 COMP-3.9 05 CA-ANN-RATE PIC SV9(6) COMP-3.10 05 CA-DAILY-ACCR PIC S9(7)V99 COMP-3.11 05 CA-RATE-TYPE PIC X(01).12 88 CA-RATE-FIXED VALUE 'F'.13 88 CA-RATE-VARIABLE VALUE 'V'.
S9(11)V99 COMP-3 · 7 BYTES → principalBalance
13 digits packed into 7 bytes, 2 decimals, signed: decimal string with exactly 2 fraction digits so no client parses money as a float.
1openapi: 3.1.02info:3 title: Loan accrual inquiry4 version: 2026.11.045paths:6 /loans/{loanId}/accrual:7 get:8 operationId: getDailyAccrual9 x-pyd-source: LNINQ01.cbl:220-26810 parameters:11 - name: loanId12 in: path13 required: true14 schema: { type: string, maxLength: 10 }15 - name: asOf16 in: query17 schema: { type: string, format: date }18 responses:19 "200":20 description: CA-OK ('00')21 content:22 application/json:23 schema: { $ref: "#/components/schemas/Accrual" }24 "404": { description: CA-NOT-FOUND ('04') }25 "409": { description: CA-CLOSED ('08') }26components:27 schemas:28 Accrual:29 type: object30 required: [loanId, principalBalance, annualRate, dailyAccrual]31 properties:32 loanId: { type: string, maxLength: 10 }33 principalBalance: { type: string, pattern: "^-?[0-9]{1,11}[.][0-9]{2}$" }34 annualRate: { type: string, pattern: "^-?0[.][0-9]{6}$" }35 dailyAccrual: { type: string, pattern: "^-?[0-9]{1,7}[.][0-9]{2}$" }36 rateType: { type: string, enum: [FIXED, VARIABLE] }
Data contracts
Exact types, not best guesses.
JSON Schema 2020-12 constraints come from storage definitions and from how the program actually uses each field.
| Legacy definition | JSON Schema | Rule |
|---|---|---|
| PIC X(n) | string, maxLength n | Trailing spaces trimmed at the boundary; LOW-VALUES treated as absent. |
| PIC 9(n) DISPLAY | string, pattern ^[0-9]{n}$ | Kept as a string when leading zeros are significant (account numbers). |
| PIC S9(p)V9(s) COMP-3 | string, decimal pattern | Exact decimal; p integer and s fraction digits enforced. |
| PIC S9(4) COMP / S9(9) COMP | integer, int32 bounds | Range narrowed further when every write is bounded. |
| 88-level condition names | enum | Values renamed from the 88 names; original codes kept in x-pyd-values. |
| OCCURS n TIMES | array, maxItems n | Fixed-size tables become arrays; trailing empty entries dropped. |
| OCCURS 0 TO n DEPENDING ON | array, minItems 0, maxItems n | The counter field disappears; array length carries it. |
| REDEFINES with discriminator | oneOf + discriminator | Without a provable discriminator, flagged instead of guessed. |
| PIC 9(8) used as yyyymmdd | string, format date | Only when dataflow proves every source is a date. |
ASYNCAPI 2.6 FOR EVENT-DRIVEN TARGETS
Batch records become events.
The nightly job writes one history record per loan into a GDG that the general ledger job reads the next morning. In a Kafka architecture that is a topic. PYD ENTERPRISES writes an AsyncAPI channel for it, with a payload schema built from the record layout and only the fields the consumers actually read.
Message names, keys and partitioning hints come from the record key (here LH-LOAN-ID). The error branch is plumbing and does not reach the contract.
1 2800-WRITE-HISTORY.2 MOVE LN-LOAN-ID TO LH-LOAN-ID3 MOVE WS-PROC-DATE TO LH-POST-DATE4 MOVE WS-DAILY-INT TO LH-DAILY-ACCR5 MOVE LN-RATE-TYPE TO LH-RATE-TYPE6 WRITE LNHIST-REC7 IF WS-HIST-STATUS NOT = '00'8 PERFORM 9100-LOG-IO-ERROR9 END-IF.
Where specs go next
Into the tools your API teams already run.
FAQ
Spec synthesis questions.
From CICS to REST, step by step: the migration guide.
Where do the operations come from?
From real interface boundaries in the code: CICS programs invoked with a COMMAREA or channel, BMS screen conversations, EJB remote interfaces, SOAP port types, WCF service contracts and stored procedure signatures. PYD ENTERPRISES does not invent endpoints; each operation carries x-pyd-source pointing at the program and lines it came from.
How are HTTP methods and paths chosen?
From behavior. An operation whose call graph writes nothing becomes a GET; one that inserts becomes a POST; idempotent updates become PUT. Paths are derived from the key fields the program reads by. Naming conventions you configure are applied, and architects can rename anything before a baseline is approved.
Why are amounts strings rather than numbers?
Packed decimal values are exact. JSON numbers are commonly parsed as binary floating point, which cannot represent most cents exactly. A string with a strict decimal pattern keeps exactness across languages. You can switch to number with multipleOf if your target stack handles decimals safely.
Can PYD ENTERPRISES emit OpenAPI 3.0 instead of 3.1?
Yes. 3.1 is the default because its schemas align with JSON Schema 2020-12. A 3.0.3 compatibility output converts type arrays to nullable and lists any construct without a 3.0 equivalent in the export report.
When does it generate AsyncAPI rather than OpenAPI?
When the legacy boundary is a record stream rather than a request: batch outputs written for downstream systems, MQ messages, or GDG generations consumed by other jobs. Those become channels with message payload schemas, ready for Kafka or another broker in the target design.
Get the contracts before the build starts.
Run PYD ENTERPRISES on 100,000 lines of COBOL or Java in your private VPC and review OpenAPI specs and DMN tables tomorrow.