JISO is a feature-rich command-line tool for simulating, testing, and debugging ISO8583 payment message flows. It connects to ISO8583 servers, composes and sends transactions from JSON templates, runs multi-step test scenarios, stress-tests payment switches, hosts an embedded mock server, and reverse-engineers PCAP traffic captures — all from a single binary.
- Full-screen TUI (
jiso tui) with command palette, page map, and live worker views (docs/tui.md) - Polymorphic JSON configuration — define
transaction,dataset,scenario, andmock_routeitems in one file - Dynamic target switching at runtime (
target,set ip,set port) with auto-reconnect - Specification hot-swapping (
spec) and transaction file reloading (tx,reload) - Multi-step Scenario Engine with context memory extraction (
{{context.X}}), dataset interpolation ({{data.X}}), and response validation (exact, regex, exists) - Embedded ISO8583 Mock Server with route matching, echo fields, auto-generated auth codes, configurable latency/jitter, required-field validation, and
drop_connectionchaos testing - Unsolicited message handling — connect with
mock_routesto auto-respond to incoming server-initiated messages - PCAP & TCP stream traffic analyzer with flow aggregation, variance analysis, and auto-generation of transaction templates or mock server routes
- Stress testing with gradual TPS ramp-up, concurrent workers, and comprehensive summary reports (latency percentiles, response code breakdown, latency budget, histograms)
- Background workers (
bgsend) with interval-based continuous sending, circuit breakers, and health-check gating - Boilerplate generators (
init-spec,init-tx) compiled into the binary via//go:embed - SQLite session logging for transaction history and analytics (
--db,db stats) - VISA Base I header support with station-ID management and session control
- Mutual TLS (mTLS) Zero-Trust Security & Visa SMC Support — consolidated JSON TLS configuration (
--tls-config), strict PEM certificate validation, client/server mTLS authentication, interactive test certificate generator (scripts/gen-test-certs.sh), and automated Visa 0800 echo keep-alive heartbeat (see TLS Guide) - Hex dump mode (
-hex) for byte-level message inspection - Structured test reports — ANSI-colored terminal trees and JSON export (
--report) for CI/CD pipelines - Automatic field generation — STAN, RRN, Auth Code, date/time fields populated at runtime
- Per-transaction specification override (
"spec"key) for multi-network testing - Composite field support — positional, TLV, BER-TLV/EMV, and bitmap-governed composites
- Features
- Documentation Index
- Installation
- Quick Start
- TUI Screens (page map)
- Command-Line Interface
- REPL Removal (v2.0.0)
- Transaction & Payload Configuration
- Traffic Analyzer (
analyze/pcap) - Stress Testing
- Mutual TLS (mTLS) & Visa SMC Security
- Connection Types
- Unsolicited Message Handling
- Session Database
- Robust Networking
- ISO8583 Specification Files
- Project Structure
- Testing
- Troubleshooting
The docs/ directory contains detailed technical guides and specifications:
| Document | Description |
|---|---|
| 🛡️ Mutual TLS & Visa SMC Guide | Zero-trust mTLS setup, consolidated tls_config.json, interactive certificate generator script (scripts/gen-test-certs.sh), client/server mTLS usage, and Visa 0800 echo keep-alive daemon. |
| 📋 Polymorphic JSON Schema | Complete schema specification for unified transaction, dataset, scenario, and mock_route definitions. |
| 🔄 Scenario Engine Specification | Multi-step transaction workflow definition, context memory extraction ({{context.X}}), and response assertion rules. |
| ⚙️ ISO8583 Specification Format | ISO8583 message layout encoding guide (ASCII, BCD, Hex, Binary, EBCDIC) and composite field definitions. |
| 🖥️ TUI User Guide | Full-screen jiso tui guide: page map, key registry (pinned to the live help overlay), command palette, confirms, masking contract. |
- Go 1.18 or higher
- Make (optional, for using Makefile commands)
git clone https://github.com/Andrei-cloud/jiso.git
cd jiso
make buildThe binary is written to bin/jiso. To build for Linux from macOS:
make build-linuxgo run ./cmd/main.goIf starting from scratch, generate the default specification and transaction files:
# Generate a default ISO8583 specification
jiso spec init
# Generate a comprehensive sample transaction configuration
# (includes transaction templates, datasets, scenarios, and mock routes)
jiso tx initThese write to ./specs/spec.json and ./transactions/transaction.json respectively. You can pass a custom output path:
jiso spec init ./specs/my_custom_spec.json
jiso tx init ./transactions/my_transactions.jsonjiso tuiBare
jisoprints a usage hint and exits 0; interactive mode is only entered explicitly —jiso tuiopens the full-screen TUI (the line-oriented REPL was removed in v2.0.0).
Pass --host/-H, --port/-p, --spec/-s, and --file/-f at launch
(or set the JISO_* environment variables), or edit them live on the TUI
Settings page (open the palette with :), where w persists user defaults.
Press c in the TUI to open the connect dialog (connection mode and length
header selection), then send a loaded transaction from the Transactions page
(2; select a row and press s for the request/response exchange view).
jiso tui is a full-screen page-stack router. Hotkeys 1–8 jump to a screen;
the remaining pages open from the command palette (:) or by drilling in. The
authoritative, always-current version (every key, generated from the live help
registry) is docs/tui.md.
| Hotkey | Screen | Contents |
|---|---|---|
1 |
Dashboard (§A) | Connection / server / session cards, last send & stress cards, quick actions, server log |
2 |
Transactions (§B) | Tx table from the loaded tx file, filter and sort; f picks a file and a rejected load names its reason |
3 |
Message Inspector (§C) | Fields tree, bitmap, packed hex, raw JSON tabs (opened by enter on a tx) |
4 |
Mock Server (§G) | Serve stats, route table, live SERVER LOG, start form |
5 |
Workers & Stress (§H) | Worker table, TPS sparkline, per-worker progress |
6 |
Sessions (§I) | Session list, stats, tx history, per-tx review |
7 |
PCAP Analyze (§J) | 4-step wizard (capture / spec / header / run), per-direction flow table, generated-item picker, unparsable reviewer |
8 |
Help (§M) | Full key registry as a page (same content as the ? overlay) |
| — | Scenarios (§F) | Scenario list, live step stream, report export |
| — | CTF Export (§K) | Visa-eligible sessions, CTF parameters, file preview |
| — | Settings (§L) | Live config editor, w persists user defaults |
| — | Send exchange (§D) | Deep page opened by s on Transactions: request/response split |
Root-owned overlays (never pages in the stack): the connect dialog (§E), command palette, help overlay, file picker, the §N2 start wizards, and §N3 confirms.
A guided tour of the full-screen TUI (jiso tui). Every capture below is a real
session — a JISO client driving JISO's own embedded mock server on
127.0.0.1:9999.
Press c for the connect dialog (mode, TCP length header, target), pick a loaded
transaction on the Transactions page, and send it. The request and the server's
response render side by side while JISO connects, sends, receives, parses,
validates, and correlates the STAN — green echo marks flag every field the mock
server echoed back.
Connect dialog![]() |
Pick a transaction![]() |
Request / response![]() |
4 opens the mock-server page and c starts it on a port and length header with
a spec and a routes file. Watch it match and answer live requests in the SERVER
LOG, with served / matched / fallback / error counters and a per-route hit table.
Configure & start![]() |
Serving live traffic![]() |
Open any recorded transaction for a byte-level hex dump plus the parsed ISO8583 message — MTI, bitmap, and every field with its TLV and dataset subfields expanded. Sensitive values such as the PAN stay masked.
Configure TPS, ramp, duration, and workers; run concurrent senders and watch the live worker table, TPS sparkline, and progress bar. The summary reports latency percentiles, a response-code breakdown, and a latency histogram.
Live run![]() |
Summary![]() |
Launch with --db and every transaction is logged to SQLite. Browse sessions and
their per-transaction history — MTI, response code, latency — and drill into any
record.
The four-step analyze wizard parses a raw capture, lets you choose which
direction to analyze, and previews the generated transaction and dataset
items — each stamped with the spec it was composed with — before you write them.
8 exports approved Visa transactions from a recorded session into a Visa Base II
CTF file: pick the session and the interchange / filter / batch parameters, then
preview the fixed-column records before writing. Card numbers are masked below.
Eligible sessions and parameters

JISO operates in two modes: Direct CLI (v2 Cobra command tree) for automation and CI/CD, and the full-screen TUI (jiso tui, see docs/tui.md) for exploratory testing. The legacy line-oriented REPL was removed in v2.0.0.
Derived from jiso --help on the v2 branch:
| Command | Description |
|---|---|
jiso |
Naked invocation: prints a usage hint to stdout, exits 0 (no REPL drop-in) |
jiso repl |
Removed at v2.0.0: prints a removal notice to stderr and exits 2 (use jiso tui) |
jiso tui |
Launch the interactive Bubble Tea TUI (requires a TTY; without one prints a notice and exits 2 — see docs/tui.md) |
jiso spec init [path] |
Generate a default ISO8583 specification file |
jiso tx init [path] |
Generate a comprehensive sample transaction configuration file |
jiso connect check |
Probe target reachability, exit code reflects reachability (0 reachable, 1 unreachable, 2 host/port unset) |
jiso send <tx-name> |
One-shot connect, send, describe, and disconnect (--wait=false for fire-and-forget) |
jiso inspect [tx-name] |
Show composed message, packed hex, and parsed fields for a transaction |
jiso scenario list |
List all defined test scenarios |
jiso scenario run <name> |
Run a specific test scenario against a server (-R/--report, -l/--length) |
jiso server start [port] [headerType] |
Start embedded ISO8583 mock server in direct mode (alias serve) |
jiso server routes |
List active mock routes for server (alias serve routes) |
jiso stress |
Run a headless stress test against the target (--tx, --tps, --ramp, --duration, --workers, -R/--report) |
jiso analyze [pcap-file] |
Analyze stream/PCAP capture files to extract transaction templates & datasets (alias pcap) |
jiso ctf list |
List recorded sessions with Visa transactions eligible for CTF export (alias clearing) |
jiso ctf export |
Export approved Visa transactions from a session into a Base II CTF file |
jiso db stats [session-id|list|tx <id>] |
Show session transaction statistics and retrospective ISO 8583 message logs |
jiso completion <shell> |
Generate the autocompletion script for bash, zsh, fish, or powershell |
jiso version |
Print version information (alias v; also available as root -v) |
No command in the current tree is a stub; the placeholder path (not implemented yet (planned: <ticket>) on stderr, exit 2) stays reserved for future commands.
Persistent flags available on every command (from jiso --help):
| Flag | Default | Description |
|---|---|---|
--json |
false |
Machine-readable JSON output on stdout (suppresses colors, banners, progress) |
-q, --quiet |
false |
Suppress non-essential stdout notices |
-n, --dry-run |
false |
Show what would happen; write/send nothing |
-v, --version |
— | Print version and exit 0 (root only; never means "verbose") |
-o, --output <path> |
"" |
Output file path on export commands (currently ctf export) |
-s, --spec <path> |
"" |
ISO8583 specification file path |
-f, --file <path> |
"" |
Transaction payload file path |
-d, --db <path> |
"" |
SQLite database file path |
-H, --host <addr> |
"" |
Target server host address |
-p, --port <port> |
"" |
Target server port |
--header <type> |
"" |
Message length header type (ascii4, binary2, bcd2, binary4, NAPS, Visa) |
-x, --hex |
false |
Enable hex dump output for messages |
-r, --reconnect-attempts <n> |
3 |
Number of reconnection attempts on failure |
--connect-timeout <duration> |
5s |
Timeout for individual connection attempts |
--total-connect-timeout <duration> |
10s |
Total timeout for connection establishment |
--response-timeout <duration> |
5s |
Timeout waiting for async message responses |
--listen-timeout <duration> |
5m |
Timeout waiting for incoming client connections in listener mode |
--tls-config <path> |
"" |
Consolidated TLS/mTLS configuration JSON (see TLS Guide) |
--visa-station-id <id> |
"" |
VISA Local Station ID (6-digit hex or decimal) |
Output-format precedence is --json > -q > text. Debug output has no flag by design: use $JISO_DEBUG=1 (extra diagnostics on stderr).
jiso -v (built via make build, which stamps version info with -ldflags):
$ jiso -v
jiso version efe40e4
commit efe40e4
built at 2026-09-06T19:05:07ZA plain go build without ldflags prints dev / none / unknown for these fields.
Every standard setting can come from the environment:
| Env var | Equivalent flag |
|---|---|
JISO_SPEC |
-s, --spec |
JISO_FILE |
-f, --file |
JISO_DB |
-d, --db |
JISO_HOST |
-H, --host |
JISO_PORT |
-p, --port |
JISO_HEADER |
--header |
JISO_TLS_CONFIG |
--tls-config |
JISO_VISA_STATION_ID |
--visa-station-id |
JISO_JSON |
--json |
JISO_QUIET |
-q, --quiet |
JISO_DEBUG |
(no flag — debug diagnostics on stderr) |
JISO_UNSECURE |
-u, --unsecure (analyze: disable payload masking) |
JISO_CONFIG |
(no flag — path to the user config file, ~ expanded) |
Precedence: --flag > $JISO_* env > user config file > built-in default. A value set in a lower layer never overrides one set in a higher layer.
Persistent defaults live in config.yaml under the OS user-config directory:
- Linux (XDG):
$XDG_CONFIG_HOME/jiso/config.yaml(default~/.config/jiso/config.yaml) - macOS:
~/Library/Application Support/jiso/config.yaml - Override the location with
JISO_CONFIG=/path/to/config.yaml
Keys mirror the lowercased env names; omit any key you do not need. A missing file is not an error; a malformed file exits 3 naming the path.
# ~/.config/jiso/config.yaml
spec: ./specs/spec.json
file: ./transactions/transaction.json
host: 127.0.0.1
port: "9999"
header: ascii4
quiet: false| Code | Meaning | Example trigger |
|---|---|---|
0 |
Success | jiso --help, jiso scenario list ... |
1 |
Generic error | runtime failures (e.g. db stats without a usable database) |
2 |
Usage / flag error | unknown flag (--bogus), missing required argument, jiso tui without a TTY |
3 |
Config / file-load error | --spec nope.json (spec file missing or unparseable) |
4 |
Test failure | jiso scenario run with one or more failed steps |
130 |
SIGINT (128+2) | Ctrl+C during a run |
--help and -h print to stdout and exit 0 (safe to pipe into a pager). Warnings, errors, and progress go to stderr; only results go to stdout.
# bash
jiso completion bash > /etc/bash_completion.d/jiso # or: source <(jiso completion bash)
# zsh (a directory on $fpath)
jiso completion zsh > "${fpath[1]}/_jiso"
# fish
jiso completion fish > ~/.config/fish/completions/jiso.fish# Inspect a composed transaction as JSON, piped to jq
jiso inspect "Sign On" -s specs/spec.json -f transactions/transaction.json --json | jq '.mti, .packed_hex'
# Preview a scenario without connecting or sending anything
jiso scenario run "E2E Purchase and Reversal" -s specs/spec.json -f transactions/transaction.json --dry-run
# Session database statistics as JSON
jiso db stats -d ./sessions.db --jsonThe line-oriented interactive REPL was removed in v2.0.0 (standing plan:
the sunset notice shipped in REL-602, the loop is deleted in REL-604).
jiso repl now prints
REPL was removed in v2.0.0 — use 'jiso tui' or the v2 command tree
to stderr and exits 2; -q suppresses the notice (the exit code stays).
Every capability the REPL offered lives on in the v2 command tree (see
Command Tree) and in the full-screen TUI
(jiso tui, see docs/tui.md):
| REPL command | v2 replacement |
|---|---|
connect / disconnect |
jiso connect check (reachability probe), jiso send (one-shot connect+send+disconnect); TUI connect dialog (c) |
send / bgsend / stress |
jiso send <tx>, jiso stress --tx <tx> ... |
info <tx> |
jiso inspect <tx> |
list |
jiso tx list / Transactions page (2) in the TUI |
scenarios / run-scenario |
jiso scenario list / jiso scenario run <name> |
serve ... |
`jiso serve start |
dbstats |
jiso db stats [session-id], jiso db tx <id> |
analyze |
jiso analyze (headless, --yes/modes/-o report) |
ctf |
jiso ctf list / jiso ctf export |
target / spec / tx |
--host/--port, --spec, --file flags or JISO_* env vars |
stats / stop / stop-all |
jiso stress summary output; Workers & Stress page (4) in the TUI |
help / version |
jiso --help, jiso version |
All configuration items — transactions, datasets, scenarios, and mock routes — live in a single flat JSON array file. Each item declares a "type" discriminator.
See also: docs/SCHEMA.md for the complete schema reference.
{
"type": "transaction",
"name": "Sign On",
"description": "Network Management: Sign On (0800)",
"fields": {
"0": "0800",
"7": "auto",
"11": "auto",
"37": "auto",
"70": 1
}
}Field values can use reserved keywords for dynamic runtime value generation:
| Keyword | Aliases | Generated Value |
|---|---|---|
"auto" |
"$auto" |
Context-aware auto-population: DE 7 = timestamp, DE 11 = STAN, DE 12 = local time, DE 13/15/17 = local date, DE 37 = RRN, DE 38 = auth code |
"STAN" |
"$STAN", "stan" |
Atomic thread-safe 6-digit System Trace Audit Number (cyclic, persisted) |
"RRN" |
"$RRN" |
12-digit Retrieval Reference Number (cyclic, persisted) |
"auth_code" |
"$auth_code" |
Random 6-character authorization code |
"datetime" |
"$datetime" |
MMDDhhmmss transmission timestamp |
"date" |
— | MMDD current date |
"time" |
— | hhmmss current time |
"random" |
— | Randomly selected value from the linked dataset |
Transactions can override the global specification by including a "spec" key pointing to a different spec file:
{
"type": "transaction",
"name": "Echo Mastercard",
"description": "Network Management: Echo Mastercard",
"spec": "specs/mastercard.json",
"fields": { ... }
}Transactions can reference a named dataset for dynamic field values:
{
"type": "transaction",
"name": "Purchase Template",
"dataset_name": "card_pool",
"fields": {
"0": "0200",
"2": "{{data.2}}",
"14": "{{data.14}}",
"35": "{{data.35}}"
}
}Placeholders matching {{data.X}} are replaced at runtime with values from a randomly selected entry in the named dataset.
{
"type": "dataset",
"name": "card_pool",
"description": "Sample card data pool for testing scenarios",
"data": [
{
"2": "1234567890123456",
"14": "2512",
"23": "001",
"35": "1234567890123456=2512123"
},
{
"2": "9876543210987654",
"14": "2601",
"23": "002",
"35": "9876543210987654=2601123"
}
]
}Scenarios define multi-step transaction flows with state persistence across steps.
See also: docs/scenarios.md for the full scenario testing documentation.
{
"type": "scenario",
"name": "E2E Purchase and Reversal",
"description": "Sign On -> Purchase (extract AuthId) -> Reversal (use AuthId)",
"dataset_name": "card_pool",
"steps": [
{
"name": "Network Sign On",
"use_transaction_id": "Sign On",
"validate": [
{ "field": "39", "expect": "00" }
]
},
{
"name": "Purchase Authorization",
"use_transaction_id": "Purchase Template",
"fields": { "4": "2500" },
"extract": {
"AuthId": "38",
"OrigMTI": "0",
"OrigSTAN": "11",
"OrigDateTime": "7"
},
"validate": [
{ "field": "39", "expect": "00" },
{ "field": "38", "exists": true }
]
},
{
"name": "Reversal of Purchase",
"use_transaction_id": "Reversal Template",
"fields": { "4": "2500" },
"validate": [
{ "field": "39", "expect": "00" }
]
}
]
}use_transaction_id— References a named transaction template as the base message.fields— Override specific fields for this step (e.g., set amount to"2500").extract— Extract response field values into the scenario context. Subsequent steps can reference extracted values via{{context.VariableName}}.validate— Assert response field values:"expect": "00"— Exact match"regex": "^[0-9]{6}$"— Regular expression match"exists": true— Field presence/absence check
{
"type": "mock_route",
"name": "Purchase Authorization Approval",
"match_fields": {
"0": "0200",
"3": "000000"
},
"required_fields": ["0", "2", "3", "4", "7", "11", "14", "41", "49"],
"echo_fields": [2, 3, 4, 7, 11, 14, 37, 41, 49],
"response_mti": "0210",
"response_fields": {
"38": "auth_code",
"39": "00"
},
"latency_ms": 100,
"jitter_ms": 25,
"drop_connection": false
}| Key | Type | Description |
|---|---|---|
match_fields |
object | Fields to match against incoming requests. Empty or omitted matches any request. |
required_fields |
array | Fields that must be present in the request; missing fields trigger RC 30 (Format Error). |
echo_fields |
array | Field IDs to copy from request to response. |
response_mti |
string | MTI for the response message. |
response_fields |
object | Static or dynamic response field values. "auth_code" generates a random 6-char code. |
delay_ms / latency_ms |
integer | Base response delay in milliseconds. delay_ms takes precedence if both are set. |
jitter_ms |
integer | Random variation applied to the base delay: ±jitter_ms. |
drop_connection |
boolean | If true, closes the TCP connection without sending a response (chaos testing). |
JISO parses raw PCAP / raw-stream captures, groups ISO8583 traffic by MTI +
Processing Code + POS Entry Mode, and auto-generates reusable configuration
items — transaction templates, dataset pools, and mock_route definitions.
One engine drives both the interactive TUI wizard (page 7) and the headless CLI.
The analyze command never prompts. A headless selection is required: --yes
to auto-pick the busiest flow, or an explicit --flow/--mode. Unknown ports
exit 3 and list the available ones.
# Analyze the busiest flow; print the AnalyzeOutput report as JSON
jiso analyze captures/switch.pcap --header visa --mode tx --yes --json -o report.json
# Dry-run: print the flow table and the plan, write nothing
jiso analyze captures/switch.pcap --header ascii4 --yes --dry-runDry-run (human) prints the discovered flows and the plan without touching disk
(real run on visaonlnode1.pcap, visa header):
selected flow 4005 (320 msgs)
Flows in capture (destination port -> messages):
4005 320 msgs
dry-run: would analyze flow 4005 (320 msgs) of 'visaonlnode1.pcap' (header visa) in tx mode
dry-run: generated items would be written to transactions/transaction.json
dry-run: nothing was written
--json prints the full AnalyzeOutput (real output; flows and the generated
name lists trimmed for brevity):
{
"mode": "transactions",
"stream_file": "visaonlnode1.pcap",
"header_type": "visa",
"direction_mode": "dst",
"direction_label": "-> Dst Port 4005 (320 pkts, 53989 bytes)",
"target_port": 4005,
"packet_count": 320,
"byte_count": 53989,
"unsecure": false,
"extracted_messages": 333,
"flow_count": 10,
"flows": [
{ "key": "0110_0", "mti": "0110", "de3": "0", "de22": "", "count": 195 },
{ "key": "0110_100000", "mti": "0110", "de3": "100000", "de22": "", "count": 8 }
],
"pair_count": 0,
"scenario_step_count": 0,
"output_file": "transactions/transaction.json",
"generated_transaction_names": [
"Captured Flow 0110_0", "Captured Flow 0110_100000", "Captured Flow 0110_110000"
],
"generated_dataset_names": [ "dataset_0110_0", "dataset_0110_100000" ]
}Four steps, advanced with enter, backed with esc, jumped with
pgup/pgdown:
- capture — type a path or press
fto browse (./,./captures/,./pcap/,./dumps/are scanned for.pcap/.pcapng). - spec — pick a discovered
*.jsonspec or enter a path (j/kmove,spaceselects). - header — the TCP length framing:
binary2,ascii4,binary4,bcd2,NAPS,visa. - run — enumerate the flows, select, analyze, and write.
On the run step the enumerated flows appear as paired dst (requests) and
src (responses) rows, each showing the peer port (from :47772 /
to :47772) so the origin is clear. The cursor reaches every row and space
toggles one direction — dst and src select independently, because the
analysis unit is a flow direction, not the conversation port (tx/routes
analyze exactly the picked directions; scenario correlates a whole port, so a
pick on either half pulls the port in). Requests (dst) are selected by default.
t/r/s set the goal (transactions / mock routes / scenario), m toggles
PAN/track masking, / filters flows, o edits the output path, u opens the
unparsable-message reviewer, and w writes:
flows 570 msgs parsed, 96 unparsable · [u] review
▸ ● → dst :4005 from :47772 333 msgs 0110(209) 0302(95) 0630(26) 0810(2) 0410(1) signon
○ ← src :4005 to :47772 237 msgs 0100(113) 0312(95) 0620(26) 0800(2) 0400(1) signon
ready - Enter starts the analysis
[Enter] run [t/r/s] goal [m] security [/] filter [w] write [Esc] back
Framed messages that will not unpack are counted, not hidden. The run line
offers [u] review; u opens a read-only two-pane browser over capped samples
(first 50 of N): the failure roster on the left, and the sample under the cursor
on the right — the fields that unpacked before the failure (describe form)
above a hexdump of the raw message with the unparsed bytes painted in the
error colour, so the tester sees what parsed and exactly where it stopped (the
captured head is 128 bytes):
UNPARSABLE MESSAGES showing first 50 of 96 SAMPLE AT 138 (128 bytes)
OFFSET LEN REASON reason: failed to unpack field 44 …
▸ 138 439 failed to unpack field 44 (Addit… PARSED BEFORE FAILURE · 12 fields
697 439 failed to unpack field 44 (Addit… 0 Message Type 0100
2309 439 failed to unpack field 44 (Addit… 11 System Trace Audit No. 123456
… …
HEXDUMP
marked = unparsed from byte 62
0000008a 01 00 f6 64 66 81 28 f0 … |..…d f.(|
0000009a 00 20 10 40 85 65 30 77 … |. . @.e0w|
[j/k] sample · [pgup/pgdn] page · [esc] close
j/k walk samples, PgUp/PgDn page, Esc closes. The OFFSET locates the
sample in the capture for an external hex tool; the marked region is where the
message stopped unpacking.
enter on the run step runs the analysis and auto-presents the generated-item
picker. Every generated transaction / dataset / mock route is listed with the
cursor item's file form beside it — fields in numeric ISO8583 order, byte-for-byte
what w will write — so the operator chooses exactly which items land in the
file. A transaction and the dataset it draws from share one toggle group, so
selecting one selects the other and a dataset is never written without its
transaction:
ITEMS 15 of 15 included
NAME KIND PREVIEW Captured Flow 0110_0 (transaction)
▸ ✓ Captured Flow 0110_0 transaction {
✓ dataset_0110_0 dataset "type": "transaction",
✓ Captured Flow 0110_100000 transaction "name": "Captured Flow 0110_0",
✓ dataset_0110_100000 dataset "spec": "specs/visa.json", …
[space] include · [a] all/none · [enter] apply · [esc] close
space toggles a row, a all-or-none, enter applies the selection, esc
applies it too and closes (it no longer discards), and x reopens the picker.
There is no separate dry-run step in the wizard — the picker is the review, and
w writes exactly the selected set (with a §N3 overwrite confirm when the target
file already exists). An all-deselected picker is an error, never a silent empty
write.
Each generated transaction records the spec it was analyzed with (its "spec"
key), so the written file reloads on the Transactions screen even when the
session's global spec differs; and if a tx-file a pick selects cannot be loaded,
the Transactions screen now names the reason (transaction file rejected: …)
instead of showing nothing.
The stress command performs stress testing with gradual TPS ramp-up:
jiso stress --tx "Sign On,Purchase Template" --tps 10 --ramp 30s --duration 1m --workers 1During the test, transactions are randomly selected from the chosen types. On completion, a comprehensive summary is printed:
================================================================================
STRESS TEST SUMMARY - Worker a1b2c3d4
================================================================================
Start Time: 2026-07-05 17:44:30 MST
End Time: 2026-07-05 17:45:30 MST
Selected Transactions: Sign On, Balance Inquiry, Purchase
--------------------------------------------------------------------------------
ALL TESTING SUMMARY
--------------------------------------------------------------------------------
Target TPS: 10 Concurrency (Workers): 1
Actual TPS: 9.8 Total Test Duration: 1m0s
--------------------------------------------------------------------------------
Transaction Counts:
Total Executions: 588
Successful: 588 (100.00%)
Failed: 0 ( 0.00%)
--------------------------------------------------------------------------------
Response Code Breakdown:
Code "00": 588 (100.00%)
--------------------------------------------------------------------------------
Latency Profile:
Min Latency: 1.2ms Median (p50): 2.5ms
Max Latency: 12.4ms p90 Percentile: 4.8ms
Mean Latency: 2.8ms p95 Percentile: 5.5ms
p99 Percentile: 8.2ms
--------------------------------------------------------------------------------
Latency Budget (Timeout: 5s):
Satisfactory (<= 50% of timeout): 588 (100.00%)
Tolerable (51%-100% of timeout): 0 ( 0.00%)
Exceeded (> 100% of timeout): 0 ( 0.00%)
--------------------------------------------------------------------------------
Latency Histogram:
[ 0ms - 10ms]: ██████████████████████████████ 580 (98.64%)
[ 10ms - 50ms]: █ 8 ( 1.36%)
================================================================================
PER TRANSACTION TYPE DETAILS
================================================================================
Transaction: Sign On
Total Executions: 196
...
================================================================================
The stats command monitors active stress tests and workers in real-time during execution. (The headless jiso stress command drives the same worker manager without a terminal; add -R/--report to export the summary JSON.)
JISO supports zero-trust Mutual TLS (mTLS) client connections and embedded mock server hosting to comply with scheme security standards such as Visa Secure Messaging Controller (SMC).
- Consolidated Configuration File: Pass all TLS options via
--tls-config <path>(pointing to atls_config.jsonfile). - Strict PEM Certificate Validation: Validates PEM-encoded client certificates, private keys, and Root/Intermediate CA bundles.
- Automated Visa SMC Heartbeat: Automatically sends periodic Visa
0800Network Connection Status keep-alive messages (DE 70 =0301, DE 63 =0002). Active ONLY when connecting with thevisaheader format. - Test Certificate Generator: Includes an interactive tool (
scripts/gen-test-certs.sh) to generate X.509 Root CA, Server, and Client test certificates in PEM format.
For complete setup instructions, JSON schema parameters, and CLI examples, see the Mutual TLS & Visa SMC Guide.
JISO supports multiple TCP message length header formats:
| Type | Description |
|---|---|
ascii4 |
4-byte ASCII decimal length header |
binary2 |
2-byte big-endian binary length header |
binary4 |
4-byte big-endian binary length header |
bcd2 |
2-byte BCD-encoded length header |
NAPS |
NAPS (National Australian Payment Switch) framing |
visa |
VISA Base I header with station ID, session control, and reject/accept data |
When connecting with the visa header type, JISO prompts for or uses the Local Station ID (configurable via --visa-station-id flag or $JISO_VISA_STATION_ID).
When establishing a connection (connect), JISO can optionally process unsolicited incoming messages (server-initiated requests) by matching them against mock_route definitions:
Open the TUI connect dialog (c) and answer the unsolicited-message
handling prompt, or use jiso send / jiso scenario run / jiso stress,
which connect on demand and load mock_route items from the transaction
file for unsolicited incoming message handling.
This enables JISO to act as both client and responder — useful for testing bidirectional payment flows.
When launched with --db, JISO logs every transaction to a SQLite database for post-test analysis:
jiso tui --db ./sessions.dbEach session gets a unique UUID. View session statistics from the CLI
(jiso db stats -d ./sessions.db [--json], plus jiso db tx <id> for the
reconstructed message view) or in the TUI Sessions page (6): totals,
success/failure counts, average processing time, and response-code
distribution, with per-transaction review.
JISO includes production-grade networking features:
- Client Listener Mode — Option to act as a TCP/mTLS listener waiting for a remote switch to connect while remaining an active client (see Listener Mode Guide)
- Automatic Reconnection — Configurable retry attempts with exponential backoff (Caller Mode) and Auto Re-Listen (Listener Mode)
- Connection Health Checks — Background workers verify connection status before sending
- Retry Mechanisms — Failed send operations are retried with exponential backoff, distinguishing temporary from permanent errors
- Circuit Breakers — Background workers auto-stop after 10 consecutive failures
- Message Validation — Transactions are validated before sending to catch configuration errors early
- STAN Correlation — Request/response STAN matching verified for every transaction
- Configurable Timeouts — Connection, total connection, and response timeouts adjustable for different network conditions
Specification files define the message format, field types, encodings, and composite field structures. JISO ships with several example specs in the specs/ directory:
| File | Description |
|---|---|
spec.json |
Generic ISO8583 ASCII specification |
spec_bcp.json |
BCP (Base Communication Protocol) spec |
mastercard.json |
Mastercard specification |
visa.json |
VISA specification |
flex.json |
Flexible specification |
tsys_dhi.json |
TSYS DHI specification |
example_composed_emv.json |
Example demonstrating all composite patterns (positional, TLV, BER-TLV, bitmap) |
See also: docs/specifications.md for the complete specification authoring guide covering field types, encoders, prefixes, padding, composite fields, tag spec keywords, and unknown-tag handling.
jiso/
├── cmd/main.go # Application entry point
├── internal/
│ ├── cli/ # v2 cobra command tree, worker management, display helpers
│ ├── client/ # Client configuration and target management
│ ├── command/ # All CLI commands (connect, send, stress, serve, analyze, etc.)
│ │ └── templates/ # Embedded default spec/transaction JSON templates
│ ├── config/ # Global configuration and flag parsing
│ ├── connection/ # ISO8583 connection wrapper and STAN normalization
│ ├── db/ # SQLite session logging and async batch writer
│ ├── metrics/ # Transaction and networking statistics collectors
│ ├── cli/lexer/ # Shlex lexer (command palette tokenization)
│ ├── reporter/ # Test report formatting
│ ├── server/ # Embedded mock server engine, route matcher, stats
│ ├── service/ # Service layer (spec loading, connection lifecycle)
│ ├── transactions/ # Transaction collection, scenario runner, compose/interpolate
│ ├── utils/ # Header adapters, spec loader, RRN/STAN generators
│ └── view/ # ISO message rendering
├── specs/ # ISO8583 specification JSON files
├── transactions/ # Transaction configuration JSON files
├── docs/ # Documentation
│ ├── SCHEMA.md # Polymorphic configuration schema reference
│ ├── scenarios.md # Scenario testing documentation
│ └── specifications.md # ISO8583 specification authoring guide
└── Makefile # Build targets
go test -v ./...All packages include comprehensive test suites covering transaction composition, validation, configuration parsing, network utilities, RRN/STAN generation, server route matching, and more.
- Verify the ISO8583 server is running and reachable
- Confirm the correct TCP header format is selected (
ascii4,binary2,bcd2,NAPS,visa) - Check that the specification file matches the server's message format
- Check firewall and network connectivity
- Adjust timeouts for high-latency networks:
--connect-timeout,--total-connect-timeout,--response-timeout - Increase retries for unreliable networks:
--reconnect-attempts
- Monitor worker status with
stats - Workers auto-stop after 10 consecutive failures (circuit breaker)
- Workers skip transactions when the connection goes offline (health checks)
- Use
stop-allorstop <id>to manage workers manually - Use
reloadto reinitialize the entire service without restarting the application
- Use
infoto inspect a transaction's composed message with hex dump - Run with
-hexflag for byte-level request/response inspection - Check spec file loading errors — the error message identifies the problematic field and keyword
- Verify
autokeywords are applied to correct field IDs (see Autogenerated Field Keywords) - For composite fields, verify that subfield lengths sum to the parent composite length
This project is licensed under the Apache 2.0 License — see the LICENSE file for details.
- Built on moov-io/iso8583 for message parsing and encoding
- Uses moov-io/iso8583-connection for network connectivity
- Interactive prompts powered by AlecAivazis/survey; command palette tokenization via kballard/go-shellquote











