From copybook to JSON
Mainframe programs exchange fixed-layout records described by copybooks; APIs exchange JSON with named fields. Exposing a program as an API means mapping one onto the other, and most bugs live in that mapping.
The same data, two shapes
01 ACCT-REC.
05 ACCT-ID PIC X(8).
05 ACCT-NAME PIC X(30).
05 ACCT-BALANCE PIC S9(9)V99 COMP-3.
05 ACCT-STATUS PIC X.
05 TXN-COUNT PIC 9(2).
05 RECENT-TXN OCCURS 5 TIMES.
10 TXN-DATE PIC X(10).
10 TXN-AMOUNT PIC S9(7)V99 COMP-3.{
"accountId": "00412789",
"name": "Asha Rao",
"balance": 1520.75,
"status": "active",
"recentTransactions": [
{ "date": "2026-09-30", "amount": -45.10 },
{ "date": "2026-09-28", "amount": 1200.00 }
]
}Mapping rules
| COBOL | JSON | Watch out for |
|---|---|---|
| PIC X(n) | string | Trailing spaces — trim them |
| PIC 9 / COMP-3 | number | Implied decimal point (V99); precision of large amounts |
| OCCURS n TIMES | array | Return only the entries in use, not all n |
| Single-letter codes such as 'A' | readable value such as "active" | Agree the code list with consumers |
| Fields only the program needs | left out | Never expose internal or filler fields |
Encoding
COBOL data on z/OS is in EBCDIC; JSON on the wire is UTF-8. The API layer converts it. Names with accented letters, and symbols such as €, are where a wrong code page shows up first, so include them in your test data.
Who does the mapping
You rarely write conversion code by hand. Tools generate it from the copybook: z/OS Connect has a mapping editor, CICS provides the JSON assistant utilities, and Enterprise COBOL can convert directly with JSON GENERATE and JSON PARSE. Your job is to choose the field names and rules and to test the edge cases.
Copybook to JSON, field by field
05 ACCT-ID PIC X(8).05 ACCT-BALANCE PIC S9(9)V99 COMP-3.05 ACCT-STATUS PIC X.05 RECENT-TXN OCCURS 5 TIMES.Try it yourself
A field defined PIC S9(9)V99 holds the digits 152075. What value should the JSON contain?
Show a hint
V99 means two digits after an implied decimal point.
Show the solution
1520.75
Common mistakes
A table defined with OCCURS 5 always has five slots. Use the count field and return only the entries that are filled.
Names like ACCT-BAL-X2 mean nothing to app developers and tie the API to the record layout forever. Choose clear names in camelCase.
PIC S9(9)V99 holding 152075 is 1520.75, not 152075. A missed V99 makes every amount a hundred times too big.
What you will see at work
- Expect long discussions about field names and code values with the app team; agree them in the OpenAPI document before building.
- Copybook changes now affect external consumers. Treat the API contract as fixed and version it when it must change.
- Test data should include empty strings, maximum amounts, negative values, and non-English names.
Key terms
Check your understanding.
Take this lesson's quiz and save your progress. Free.