# Voynich manuscript — JSON API > Version 9.11.0 (August 2026) This page documents every JSON endpoint of the Voynich decipherment system API in a format optimized for LLM-based retrieval systems. ## Overview Base URL: `https://voynich.kiltau.com` | Category | Endpoints | Description | |---|---|---| | **Core tests** | 9 | Statistical tests validating the morphology hypothesis | | **Lexicon** | 4 | Access to the Voynich lexicon with filter and search functions | | **Grammar** | 3 | EVA→Hebrew mapping and grammar rules | | **Folios** | 2 | Transcription data of the folio pages | | **Services** | 2 | Translation and backtest | ## General notes - **CORS:** All endpoints set `Access-Control-Allow-Origin: *`. - **Content-Type:** `application/json; charset=utf-8` - **Fehler/Errors:** `400` on invalid parameters, `500` on internal errors. The error object contains an `error` field. - **Caching:** Deterministic endpoints (`/api/cut`, `/api/gibberish/protocol`, `/api/gibberish/run`) cache results per `(seed, parameter)` combination in an in-memory cache (max. 50 entries). - **Determinismus/Determinism:** Same `seed` + same parameters = identical result (cacheable). --- ## Core tests Statistical tests validating the morphology hypothesis ### `GET` /api/cut Runs the **Candidate Uniqueness Test (CUT)** — the central test of the morphology hypothesis: it checks whether the proposed prefix/suffix segmentation actually yields unique readings, or whether competing segmentations would be equally plausible. Three phases run in sequence: phase 1 (lexicon CUT) and phase 2 (generative CUT) over a weighted sample from the token index, phase 2b (sequence-based CUT, R19) over real paragraph sequences. The result is deterministic for a given `seed`/`sampleSize` combination and is cached server-side. **Parameters:** | Name | Type | In | Required | Default | Description | |---|---|---|---|---|---| | `seed` | number | query | no | — | Seed for the Mulberry32 PRNG. Same seed + same sampleSize = identical result (cacheable). Default: Date.now() | | `sampleSize` | number | query | no | 300 | Number of tokens to draw (weighted sample from the corpus for phase 1/2; token budget for the paragraph sample in phase 2b). Allowed range: 50–1000. | | `perToken` | boolean | query | no | true | If false, the perToken arrays (phase 1/2) and the perParagraph array (phase 2b) are omitted (response becomes much smaller). | **Response (example):** ```json { "meta": { "seed": 42, "sampleSize": 300, "distinctTypeCount": 87, "date": "2026-07-04" }, "phase1": { "topGapMedian": 7, "top1Quote": 12, "ambiguityIndex": 3.5, "hotspotRules": [ { "id": "R19", "count": 45 }, { "id": "R2", "count": 32 }, { "id": "R43", "count": 28 }, { "id": "R41", "count": 15 }, { "id": "R40", "count": 10 } ], "verdict": "fail", "perToken": [ { "token": "qokoldm", "candidateCount": 3, "topGap": 25, "winner": { "prefix": "qo-", "root": "koldm", "suffix": "", "score": 40, "entry": { "eva": "koldm", "heb": "כֹּל+דָּם", "de": "alles Blut", "confidenceStars": 4, "rulesApplied": [ "R2", "R43" ] } }, "candidates": [ { "prefix": "qo-", "root": "koldm", "suffix": "", "score": 40, "entry": null }, { "prefix": "", "root": "qokoldm", "suffix": "", "score": -25, "entry": null } ] } ] }, "phase2": { "rejectRate": 12.5, "r41RejectCount": 30, "r65RejectCount": 8, "meanBranchCount": 1.2, "tokensWithBranching": 35, "truncatedCount": 2, "coverage": { "rulesFormalized": [ "R1", "R2", "R3", "R4", "R40", "R41", "R45", "R65", "D1-D2" ], "rulesTotal": 60, "coverageRatio": 0.15 }, "perToken": [ { "token": "qokoldm", "candidate": { "prefixes": [ "qo-" ], "root": "koldm", "r40": "pass", "d1": false, "d2": false, "branchCount": 0, "truncated": false, "readings": [ "קוֹכֹּלדם" ] }, "reject": null } ] }, "phase2b": { "paragraphCount": 48, "tokenCount": 302, "intensificationCount": 6, "coverage": { "rulesFormalized": [ "R19" ], "rulesTotal": 60 }, "perParagraph": [ { "folio": "f1r", "para": "P1", "words": [ "qokedy", "qokedy", "shol" ], "intensification": [ { "words": "qokedy qokedy", "type": "×2" } ] } ] } } ``` **Examples:** - _Standard (random seed, 300 tokens, incl. perToken):_ ``` curl http://localhost:5173/api/cut ``` - _Deterministic (seed 42, 500 tokens):_ ``` curl 'http://localhost:5173/api/cut?seed=42&sampleSize=500' ``` - _Aggregates only (without perToken/perParagraph arrays):_ ``` curl 'http://localhost:5173/api/cut?seed=42&perToken=false' ``` - _Invalid parameter:_ ``` curl http://localhost:5173/api/cut?sampleSize=10 # → 400 { "error": "sampleSize must be between 50 and 1000" } ``` ### `GET` /api/entropy Returns the **saved results of the OP3 entropy audit**: the conditional entropy H2 (and H1) of the Voynich manuscript (H layer, word-internal) compared with the WLC reference (Hebrew + Aramaic, each fully vocalized / only Niqqud / unvocalized), plus a generator control value from `/api/gibberish/protocol` (Ø 3 seeds). The values come from the reproducible entropy toolkit (`op3_entropy_test.py`) — **static measurements, not computed live**. Key finding: with H2 = 2.122 bit the manuscript lies about 1.22 bit below the vocalized WLC; vowel marking alone therefore does not sufficiently explain the low entropy. `toolkit.downloadUrl` in the response points to the ZIP with the analysis scripts. No parameters required. **Response (example):** ```json { "version": "9.9.6", "title": "Konditionalentropie H2 (OP3-Audit)", "method": "Methode: Konditionalentropie H(cᵢ|cᵢ₋₁), ausschließlich wortintern …", "headline": [ { "value": "2,122 bit", "label": "Voynich H-Layer H2" }, { "value": "3,338 bit", "label": "WLC Hebr. vokalisiert (Niqqud) H2" }, { "value": "3,896 bit", "label": "WLC Hebr. unvokalisiert H2" }, { "value": "+0,33 bit", "label": "Generator-Abstand zum Manuskript" } ], "stats": [ { "label": "Voynich H-Layer — EVA (wortintern)", "h1": "3,860", "h2": "2,122", "highlight": "voynich" }, { "label": "WLC Hebräisch — vokalisiert (Niqqud, ohne Kantillation)", "h1": "4,833", "h2": "3,338", "highlight": "ref" }, { "label": "WLC Hebräisch — unvokalisiert", "h1": "4,232", "h2": "3,896", "highlight": "ref" }, { "label": "WLC Aramäisch — vokalisiert (Niqqud)", "h1": "4,757", "h2": "3,150", "highlight": "ref" }, { "label": "WLC Aramäisch — unvokalisiert", "h1": "4,242", "h2": "3,647", "highlight": "ref" }, { "label": "Generator /api/gibberish/protocol (Ø 3 Seeds)", "h1": "3,811", "h2": "2,451", "highlight": "control" } ], "note": "Niqqud-Vokalisierung senkt H2 im Referenzkorpus um 0,56 bit (3,896 → 3,338). …", "sources": [ { "name": "Westminster Leningrad Codex (WLC)", "license": "Text: Public Domain · Annotation: CC BY 4.0", "href": "https://github.com/openscriptures/morphhb" } ], "toolkit": { "name": "Entropie-Toolkit", "downloadUrl": "https://voynich.kiltau.com/downloads/entropy-validation.zip", "scripts": [ "op3_entropy_test.py", "fetch_wlc.py", "stolfi.py" ], "note": "Reproduzierbare Analyse (op3_entropy_test.py); WLC-Referenzkorpus nicht enthalten — Download per Skript (fetch_wlc.py), siehe Toolkit-README." } } ``` **Examples:** - _Fetch saved OP3 entropy metrics:_ ``` curl http://localhost:5173/api/entropy ``` ### `GET` /api/word-length Returns the **saved results of the OP1 word-length audit**: compares the word-length distribution of the Voynich manuscript (H/C/F layers, EVA and Hebrew letters) with Semitic references (Mishnah, WLC Hebrew/Aramaic) and Italian/Latin control texts — each with metrics (n, mean, sd, CV, QCD, skewness, excess kurtosis, entropy H), window concentration, length histogram, shifted binomial fit (TVD), and affixation depth. Measured with the reproducible OP1 toolkit (`op1_length_test.py`) — **static measurements, not computed live**. Key finding: the Voynich coefficient of variation (CV 0.347) lies within the reference range (0.326–0.363), and the 4–8 glyph window covers 79.69% of all tokens. `toolkit.downloadUrl` in the response points to the ZIP with the analysis scripts. No parameters required. **Response (example):** ```json { "version": "9.9.6", "title": "Wortlängenverteilung (OP1-Audit)", "corpusNote": "226 lokale Stolfi-Transkriptionen (224 Folios), H-/C-/F-Layer, …", "method": "Methode: EVA-Tokens über stolfi.tokenize() …", "headline": [ { "value": "0,347", "label": "CV Voynich H-Layer (EVA)" }, { "value": "0,331", "label": "CV Mischna" }, { "value": "0,326 / 0,363", "label": "CV WLC Hebr. / Aram." }, { "value": "79,69 %", "label": "4–8-Fenster (Voynich)" } ], "distStats": { "columns": [ "Verteilung", "n", "Mittel", "sd", "CV", "QCD", "Schiefe", "ExKurt", "H (bit)" ], "rows": [ { "label": "Voynich H-Layer — EVA-Glyphen", "n": "37.049", "mean": "5,05", "sd": "1,75", "cv": "0,347", "qcd": "0,200", "skew": "+0,088", "kurt": "+0,245", "h": "2,836", "highlight": "voynich" }, { "label": "WLC Hebräisch — Token, Buchstaben", "n": "284.635", "mean": "3,92", "sd": "1,28", "cv": "0,326", "qcd": "0,250", "skew": "+0,393", "kurt": "−0,094", "h": "2,345", "highlight": "ref" }, { "label": "Mischna (Sefaria) — Token, Buchstaben", "n": "187.055", "mean": "4,02", "sd": "1,33", "cv": "0,331", "qcd": "0,250", "skew": "+0,409", "kurt": "−0,080", "h": "2,409", "highlight": "ref" } ], "note": "Der Variationskoeffizient (CV) des Voynich-Korpus liegt oberhalb des mischnischen …" }, "windowConcentration": { "columns": [ "Verteilung", "bestes 3er-Fenster", "bestes 5er-Fenster" ], "rows": [ { "label": "Voynich H-Layer — EVA-Glyphen", "best3": "4–6: 63,19 %", "best5": "3–7: 84,43 %" }, { "label": "WLC Hebräisch — Token, Buchstaben", "best3": "3–5: 74,27 %", "best5": "2–6: 97,32 %", "highlight": "ref" } ], "note": "Das in OP1 genannte Fenster 4–8 EVA-Glyphen fasst 79,69 % der Tokens …" }, "lengthHistogram": { "columns": [ "Voynich EVA", "Voynich hebr.", "Mischna", "WLC Hebr." ], "rows": [ { "length": "1", "values": [ "2,11", "3,64", "0,05", "0,00" ] }, { "length": "5", "values": [ "25,27", "14,82", "19,98", "19,67" ] } ] }, "binomialFit": { "columns": [ "Verteilung", "Fit", "TVD" ], "rows": [ { "label": "Voynich — EVA-Glyphen", "fit": "Binomial(11; 0,459)", "tvd": "0,0509" }, { "label": "Mischna", "fit": "Binomial(8; 0,378) + 1", "tvd": "0,0396", "highlight": "ref" } ], "note": "Die oft zitierte Binomialnähe …" }, "affixDepth": { "columns": [ "Voynich (R41-Kette, Obergrenze)", "WLC Hebräisch (Proklitika)" ], "rows": [ { "label": "Mittel je Wort", "values": [ "0,81", "0,43" ] }, { "label": "Maximaltiefe", "values": [ "5", "4" ] } ], "note": "Voynich-Werte sind eine Obergrenze …" }, "remaining": [ "Im Konsonantenskelett sind Voynich-Wörter im Mittel 0,54 Buchstaben (≈13 %) kürzer als mischnische.", "3,64 % der Tokens sind einbuchstabig …" ], "sources": [ { "name": "Westminster Leningrad Codex (WLC)", "license": "Text: Public Domain · Annotation: CC BY 4.0", "href": "https://github.com/openscriptures/morphhb" } ], "toolkit": { "name": "OP1-Toolkit", "downloadUrl": "https://voynich.kiltau.com/downloads/word-length-validation.zip", "scripts": [ "op1_length_test.py", "fetch_all.py", "fetch_wlc.py", "fetch_mishnah.py", "fetch_italian.py", "fetch_latin.py", "stolfi.py" ], "note": "Reproduzierbare Analyse (op1_length_test.py); Referenzkorpora nicht enthalten — Download per Skript (fetch_*.py), siehe Toolkit-README." } } ``` **Examples:** - _Fetch saved OP1 word-length metrics:_ ``` curl http://localhost:5173/api/word-length ``` ### `GET` /api/slot-grammar Returns the **saved results of the OP2 slot-grammar audit**: how strongly EVA glyphs are bound to word positions (INI/MED/FIN), on the glyph level (`I(Glyph;Position)`) and, length-stratified, on the word/root level — calibrated against two independent Hebrew references, Biblical Hebrew (WLC) and Mishnaic Hebrew (Sefaria, the project's core-hypothesis target language). Includes a second, independent measure (restrictiveness of a formal slot-constraint model) for cross-checking. Measured with the reproducible slot toolkit (`op2_slots.py`, `op2_model.py`, `op2_mishnah.py` among others) — **static measurements, not computed live**. Key finding: word-level binding is 2.4–2.5× the Hebrew references and robust across both measures; root-level binding is unsettled — mutual information and restrictiveness disagree there. `toolkit.downloadUrl` in the response points to the ZIP with the analysis scripts. No parameters required. **Response (example):** ```json { "version": "9.10.0", "title": "Slot-Grammatik-Positionsbindung (OP2-Audit)", "method": "Methode: Glyph = Einheit der projekteigenen Mapping-Tabelle (longest-match-first) …", "headline": [ { "value": "0,713 bit", "label": "I(Glyph;Position), Glyphebene" }, { "value": "2,4–2,5×", "label": "Faktor Voynich/Referenz, Wortebene" }, { "value": "41,7 %", "label": "Restriktivität Volltoken (Mischna 68,6 %)" }, { "value": "offen", "label": "Wurzelebene — MI und Restriktivität widersprüchlich" } ], "glyphPositions": { "columns": [ "Glyph", "Gruppe", "N", "INI %", "MED %", "FIN %", "KL (bit)" ], "rows": [ { "glyph": "q", "group": "cons", "n": 5025, "ini": "99,4", "med": "0,6", "fin": "0,0", "kl": "2,074", "single": "INI" }, { "glyph": "aiin", "group": "compound", "n": 1859, "ini": "0,1", "med": "0,8", "fin": "99,1", "kl": "2,044", "single": "FIN" }, { "glyph": "e", "group": "vowel", "n": 8893, "ini": "0,5", "med": "99,1", "fin": "0,3", "kl": "0,806", "single": "MED" } ], "note": "I(Glyph;Position) = 0,713 bit bei H(Pos) = 1,450 bit …" }, "miStrata": { "columns": [ "Länge", "Voyn. voll", "Voyn. Wz.", "Misch. voll", "Misch. Wz.", "WLC voll", "WLC Wz." ], "rows": [ { "length": "3", "voynFull": "0,871", "voynRoot": "0,833", "mishFull": "0,313", "mishRoot": "0,397", "wlcFull": "0,326", "wlcRoot": "0,318" }, { "length": "gepoolt", "voynFull": "0,785", "voynRoot": "0,685", "mishFull": "0,323", "mishRoot": "0,368", "wlcFull": "0,312", "wlcRoot": "0,294", "pooled": true } ], "note": "Faktor Voynich/Mischna: Vollwort 2,43× · Wurzel 1,86× …" }, "restrictiveness": { "columns": [ "Ebene", "n", "Cov %", "Restr %", "Cov/Restr" ], "rows": [ { "label": "Voynich Volltoken", "n": "27 493", "cov": "98,9", "restr": "41,7", "ratio": "2,37", "highlight": "voynich" }, { "label": "Mischna Vollwörter", "n": "162 094", "cov": "100,0", "restr": "68,6", "ratio": "1,46", "highlight": "ref" } ], "note": "Restriktivität = Durchlassquote zufälliger Umstellungen desselben Glyph-Multisets …" }, "sources": [ { "name": "Westminster Leningrad Codex (WLC)", "license": "Text: Public Domain · Annotation: CC BY 4.0", "href": "https://github.com/openscriptures/morphhb" }, { "name": "Mischna, Vilna-Ausgabe 1913 (Sefaria-Export)", "license": "Text: Public Domain", "href": "https://github.com/Sefaria/Sefaria-Export" } ], "toolkit": { "name": "Slot-Toolkit", "downloadUrl": "https://voynich.kiltau.com/downloads/slot-validation.zip", "scripts": [ "op2_slots.py", "op2_strip.py", "op2_hebrew.py", "op2_hebrew2.py", "op2_fix.py", "op2_mishnah.py", "op2_model.py", "op2_ch.py", "stolfi.py", "cut.py" ], "note": "Reproduzierbare Analyse (op2_*.py); WLC- und Mischna-Referenzkorpora nicht enthalten — Download per Skript (fetch_wlc_zip.py, fetch_mishnah.py), siehe Toolkit-README." } } ``` **Examples:** - _Fetch saved OP2 slot-grammar metrics:_ ``` curl http://localhost:5173/api/slot-grammar ``` ### `GET` /api/gibberish/protocol Runs the multi-run **gibberish test (GPA-1)** — a control test that checks how easily randomly generated pseudo-words would pass as valid lexicon entries: in `runCount` runs it generates `wordCount` pseudo-words each via a Markov chain, checks them against the lexicon (false-positive rate) and computes entropy metrics for validation — H1 (unigram entropy, `graphH`/`graphH_raw`) and H2 (conditional entropy, `graphH2`; OP3 benchmark against the manuscript reference 2.122 bit). The result is deterministic for `seed` + `wordCount` + `runCount`. **Parameters:** | Name | Type | In | Required | Default | Description | |---|---|---|---|---|---| | `seed` | number | query | no | — | PRNG seed. Same seed + same parameters = identical result. Default: Date.now() | | `wordCount` | number | query | no | 50 | Pseudo-words per run. Range: 10–500. | | `runCount` | number | query | no | 10 | Number of runs. Range: 1–100. | | `perWord` | boolean | query | no | false | If true, the generated words are output per run as full analysis objects (otherwise only a string array). | **Response (example):** ```json { "meta": { "seed": 42, "wordCount": 50, "runCount": 10 }, "protocol": { "mean": 8.6, "sd": 3.2, "min": 4, "max": 14, "meanGraphH": 3.55, "meanGraphH2": 2.54, "meanGraphH_raw": 3.82, "meanWordH": 8.12, "genValidation": { "lengthDelta": -0.2, "entropyDelta": 0.05, "genMeanLength": 5.2, "corpusMeanLength": 5.4, "genEntropy": 3.65, "corpusEntropy": 3.6 }, "runs": [ { "run": 1, "fpRate": 8, "total": 50, "lexhits": 4, "passed": 0, "capped": 2, "invalid": 1, "d1count": 3, "d2count": 1, "graphH": 3.55, "graphH2": 2.57, "wordH": 8.1 }, { "run": 2, "fpRate": 6, "total": 50, "lexhits": 3, "passed": 0, "capped": 1, "invalid": 0, "d1count": 2, "d2count": 1, "graphH": 3.61, "graphH2": 2.64, "wordH": 8.22 } ] } } ``` **Examples:** - _Standard (seed 42, 50 words, 10 runs):_ ``` curl 'http://localhost:5173/api/gibberish/protocol?seed=42' ``` - _With perWord analysis:_ ``` curl 'http://localhost:5173/api/gibberish/protocol?seed=42&perWord=true' ``` ### `GET` /api/gibberish/run Runs a single **gibberish test (GPA-1)** pass: generates `wordCount` pseudo-words and returns the aggregated statistics. Intended for quick single tests. **Parameters:** | Name | Type | In | Required | Default | Description | |---|---|---|---|---|---| | `seed` | number | query | no | — | PRNG seed. Default: Date.now() | | `wordCount` | number | query | no | 50 | Number of pseudo-words to generate. Range: 10–500. | | `perWord` | boolean | query | no | true | If true, the generated words are output as full analysis objects (otherwise only a string array). | **Response (example):** ```json { "meta": { "seed": 42, "wordCount": 50 }, "run": { "fpRate": 8, "total": 50, "lexhits": 4, "passed": 0, "capped": 2, "invalid": 1, "d1count": 3, "d2count": 1, "graphH": 3.55, "graphH2": 2.57, "wordH": 8.1 } } ``` **Examples:** - _Single test (seed 42, 100 words):_ ``` curl 'http://localhost:5173/api/gibberish/run?seed=42&wordCount=100' ``` ### `GET` /api/gibberish/analyze Analyzes a single **EVA word**: checks lexicon membership, performs prefix stripping, validates R40/R41 and determines D1/D2 phonotactics flags. Intended for quick word analyses without a UI. **Parameters:** | Name | Type | In | Required | Default | Description | |---|---|---|---|---|---| | `word` | string | query | yes | — | EVA word to analyze. | **Response (example):** ```json { "word": { "word": "qokoldm", "inLexicon": true, "lexEntry": { "eva": "koldm", "heb": "כֹּל+דָּם", "de": "alles Blut", "morph": "qo+", "confidenceStars": 4 }, "prefixes": [], "root": "qokoldm", "rootCons": null, "r40": "lexikon", "r41": { "valid": true }, "d1": false, "d2": false, "maxStars": "★★★★" } } ``` **Examples:** - _Analyze a known lexeme:_ ``` curl 'http://localhost:5173/api/gibberish/analyze?word=qokoldm' ``` ### `GET` /api/gibberish/stats Returns corpus statistics: mean word length, grapheme entropy (H1, `graphEntropy`), conditional entropy (H2, `conditionalEntropy` — OP3 benchmark against the manuscript reference 2.122 bit, see `/api/entropy`) and total number of lexicon entries. No parameters required. **Response (example):** ```json { "stats": { "meanLength": 5.4, "graphEntropy": 3.6, "conditionalEntropy": 2.81, "wordCount": 486 } } ``` **Examples:** - _Fetch corpus statistics:_ ``` curl http://localhost:5173/api/gibberish/stats ``` ### `GET` /api/segmentation Learns word building blocks purely from corpus frequency (frequency-weighted byte-pair encoding + trie branching factor), matches the discovered prefix/suffix candidates against the manually derived grammar table and clusters the remaining stems by Jaccard similarity (complete linkage) into stem families. Before clustering, suffix-dominant units (e.g. `dy`, `ol`, `ey` — bound suffix share ≥ `suffixDominance`) are recognized as function-morpheme hubs and excluded (suffix-dominance prefilter, section-C test 1), otherwise they would merge independent stem families into one cluster via the Jaccard chain. In addition to prefix/suffix context, the dominant positional role of each word (phrase/paragraph end, possibly immediately before a `{plant}` illustration — `@phraseEnd`, `@paragraphEnd`, `@phraseEndPlant`, `@lineEndPlant`, `@paragraphEndPlant`) flows into the clustering as a context feature. BPE training is cached server-side per `numMerges`. **Parameters:** | Name | Type | In | Required | Default | Description | |---|---|---|---|---|---| | `numMerges` | number | query | no | 250 | Number of BPE merge steps. Range: 10–2000. | | `minBranchingFactor` | number | query | no | 5 | Minimum branching factor for a prefix/suffix candidate to count as statistically conspicuous. | | `minSupport` | number | query | no | 10 | Minimum attestation count for a candidate. | | `minSimilarity` | number | query | no | 0.3 | Jaccard threshold for the stem-family clustering (complete linkage). | | `minStemSupport` | number | query | no | 15 | Minimum attestation count of a stem to participate in clustering. | | `excludeSuffixDominant` | boolean | query | no | true | Excludes suffix-dominant candidate stems (suffix-dominance prefilter) from clustering. | | `suffixDominance` | number | query | no | 0.8 | Threshold for the bound suffix share above which a stem counts as suffix-dominant (only when excludeSuffixDominant=true). | | `detail` | boolean | query | no | false | If true, the full novelPrefixes/novelSuffixes/suffixCandidates arrays are output (can run into the hundreds); otherwise only the counters. | **Response (example):** ```json { "meta": { "numMerges": 250, "minBranchingFactor": 5, "minSupport": 10, "minSimilarity": 0.3, "minStemSupport": 15, "excludeSuffixDominant": true, "suffixDominance": 0.8, "wordCount": 7492, "suffixCandidateCount": 110 }, "comparison": { "matchRate": 1, "confirmedPrefixes": [ { "form": "qo", "position": "prefix", "branchingFactor": 85, "support": 567 }, { "form": "sh", "position": "prefix", "branchingFactor": 97, "support": 479 } ], "confirmedSuffixes": [ { "form": "dy", "position": "suffix", "branchingFactor": 96, "support": 752 } ], "unconfirmedPrefixes": [], "unconfirmedSuffixes": [], "novelPrefixCount": 210, "novelSuffixCount": 201 }, "clusters": [ { "stems": [ "ch", "cho", "ed" ], "totalSupport": 566, "sharedPrefixes": [ "qo", "o" ], "sharedSuffixes": [ "dy" ], "sharedBoundaryTags": [ "@phraseEnd" ], "exampleWords": [ "qokedy", "ochedy" ] } ] } ``` **Examples:** - _Standard (250 merges, counters instead of full novel lists):_ ``` curl http://localhost:5173/api/segmentation ``` - _With full novel candidates:_ ``` curl 'http://localhost:5173/api/segmentation?detail=true' ``` - _Stricter clustering:_ ``` curl 'http://localhost:5173/api/segmentation?minSimilarity=0.5&minStemSupport=25' ``` - _Invalid parameter:_ ``` curl http://localhost:5173/api/segmentation?numMerges=5 # → 400 { "error": "numMerges must be between 10 and 2000" } ``` --- ## Lexicon Access to the Voynich lexicon with filter and search functions ### `GET` /api/lexicon Returns the full, enriched lexicon as an array — the same data basis the lexicon page of the application shows. Each entry contains among others `eva` (transcription), `heb` (Hebrew reading), `de` (German translation), `confidenceStars`, `rulesApplied` (applied grammar rules), `isAnchor` and `evidence`. **Parameters:** | Name | Type | In | Required | Default | Description | |---|---|---|---|---|---| | `fields` | string | query | no | — | Comma-separated field list for filtering (e.g. eva,heb,de). | | `minStars` | number | query | no | — | Minimum confidenceStars (e.g. 3). | **Examples:** - _Filtered by fields & confidence:_ ``` curl 'http://localhost:5173/api/lexicon?fields=eva,heb,de&minStars=5' curl http://localhost:5173/api/lexicon?fields=eva,heb ``` ### `GET` /api/lexicon/:eva Returns a single lexicon entry by its EVA name, enriched with everything in the compiled snapshot that belongs to this entry: `data` (the lexicon entry including compiled `rulesApplied`), `frequency` (corpus count like `/api/lexicon/frequencies`), `segmentation` (affix/cluster membership from the standard segmentation analysis like `/api/segmentation`, or `null`), `citingRules` (grammar rules whose diagnostic tokens cite this EVA), `backtest` (live executed backtest result if the EVA is a prediction), `alias` (alias relationships in both directions) and `neighbors` (the 8 most frequent immediate left and right neighbors in the corpus). 404 if not found. **Parameters:** | Name | Type | In | Required | Default | Description | |---|---|---|---|---|---| | `eva` | string | path | yes | — | EVA name of the lexicon entry. | **Response (example):** ```json { "version": "9.7.10", "data": { "eva": "koldm", "heb": "כֹּל+דָּם", "de": "alles Blut", "confidenceStars": 4 }, "frequency": { "count": 307, "folioCount": 87, "lineStart": 12, "lineEnd": 133 }, "neighbors": { "left": [ { "word": "ot", "count": 28 }, { "word": "qo", "count": 15 } ], "right": [ { "word": "dy", "count": 56 }, { "word": "shey", "count": 12 } ] }, "segmentation": null, "citingRules": [ "R2", "R15" ], "backtest": null, "alias": null } ``` **Examples:** - _Direct lookup:_ ``` curl http://localhost:5173/api/lexicon/koldm curl http://localhost:5173/api/lexicon/qokoldm ``` ### `GET` /api/lexicon/search Searches the lexicon by substring match on `eva`, `heb`, `de`. Returns all hits as an array. **Parameters:** | Name | Type | In | Required | Default | Description | |---|---|---|---|---|---| | `q` | string | query | yes | — | Search term (case-insensitive). | **Examples:** - _Substring search:_ ``` curl 'http://localhost:5173/api/lexicon/search?q=koldm' curl 'http://localhost:5173/api/lexicon/search?q=blut' ``` ### `GET` /api/lexicon/frequencies Returns frequency lists from the corpus: `type=words` for whole word forms — with positional counters per occurrence: `lineStart`/`lineEnd` (line/locus unit like "P1.3"), `phraseStart`/`phraseEnd` (Stolfi phrase boundary `-`) and `paragraphEnd` (Stolfi paragraph boundary `=`), plus their `*Plant` variants (`lineEndPlant`, `phraseEndPlant`, `paragraphEndPlant`) for boundaries immediately before a `{plant}` illustration marker — plus folio count; `type=letters` for letter combinations of any length (from an index computed once at module load). **Parameters:** | Name | Type | In | Required | Default | Description | |---|---|---|---|---|---| | `type` | string | query | no | words | words or letters. | | `min` | number | query | no | 1 | Minimum total frequency. | | `limit` | number | query | no | 1000 | Maximum number of results. | | `maxLength` | number | query | no | — | Maximum word length (only type=words). | | `length` | number | query | no | 1 | Exact length of the letter combination (only type=letters). | | `minLineStart` | number | query | no | 0 | Minimum number of line-initial occurrences (only type=words). | | `minLineEnd` | number | query | no | 0 | Minimum number of line-final occurrences (only type=words). | | `minPrefix` | number | query | no | 0 | Minimum number of word-initial occurrences of the letter combination (only type=letters). | | `minSuffix` | number | query | no | 0 | Minimum number of word-final occurrences of the letter combination (only type=letters). | | `minWord` | number | query | no | 0 | Minimum number as a standalone word (only type=letters). | | `search` | string | query | no | — | Substring filter. | | `sort` | string | query | no | — | Sort field. type=words: count, lineStart, lineEnd, lineEndPlant, phraseStart, phraseEnd, phraseEndPlant, paragraphEnd, paragraphEndPlant, folioCount, item. type=letters: total, prefix, suffix, word, item. | | `order` | string | query | no | desc | asc or desc. | **Response (example):** ```json { "version": "9.7.5", "type": "words", "total": 1, "meta": { "longestWordLength": 14, "maxUsefulNgramLength": 13, "lineCount": 5449, "paragraphCount": 512, "tokenCount": 40060 }, "data": [ { "item": "daiin", "count": 817, "folioCount": 211, "lineStart": 163, "lineEnd": 148, "lineEndPlant": 45, "phraseStart": 195, "phraseEnd": 135, "phraseEndPlant": 61, "paragraphEnd": 41, "paragraphEndPlant": 9 } ] } ``` **Examples:** - _Most frequent words:_ ``` curl 'http://localhost:5173/api/lexicon/frequencies?type=words&limit=10' ``` - _Letter combinations of length 2:_ ``` curl 'http://localhost:5173/api/lexicon/frequencies?type=letters&length=2&limit=20' ``` --- ## Grammar EVA→Hebrew mapping and grammar rules ### `GET` /api/mapping Returns the underlying EVA→Hebrew character table — the basis for transliteration and translation throughout the application — as well as the list of known prefixes. **Parameters:** | Name | Type | In | Required | Default | Description | |---|---|---|---|---|---| | `group` | string | query | no | — | Filter by group: cons, vowel, digraph, compound. | **Examples:** - _Full mapping / filtered by group:_ ``` curl http://localhost:5173/api/mapping curl 'http://localhost:5173/api/mapping?group=cons' ``` ### `GET` /api/rules Returns all grammar rules of the morphology hypothesis as an array, enriched with folio attestations, validation status and R43 metadata. **Parameters:** | Name | Type | In | Required | Default | Description | |---|---|---|---|---|---| | `status` | string | query | no | — | Filter: validiert or kandidat. | **Examples:** - _All rules / filtered by status:_ ``` curl http://localhost:5173/api/rules curl 'http://localhost:5173/api/rules?status=validiert' ``` ### `GET` /api/rules/:id Returns a single grammar rule by its ID (e.g. R1, R42). Case-insensitive. 404 if not found. **Parameters:** | Name | Type | In | Required | Default | Description | |---|---|---|---|---|---| | `id` | string | path | yes | — | Rule ID, case-insensitive. | **Examples:** - _Rule by ID:_ ``` curl http://localhost:5173/api/rules/R1 curl http://localhost:5173/api/rules/r40 ``` --- ## Folios Transcription data of the folio pages ### `GET` /api/folios Returns all folio pages grouped by quire. Each entry contains the quire label and the page IDs. **Parameters:** | Name | Type | In | Required | Default | Description | |---|---|---|---|---|---| | `lang` | string | query | no | — | Filter: A (quires 1–7) or B (quires 7–20). | **Examples:** - _All folios / filtered by language:_ ``` curl http://localhost:5173/api/folios curl 'http://localhost:5173/api/folios?lang=A' ``` ### `GET` /api/folio/:slug Returns the compiled snapshot of a folio page — the same one the UI and the Markdown export (`/folio/:slug.md`) show, not just the raw JSON data: `iconographic.rules` additionally contains automatically derived rule attestations — from structural generators and from diagnostic token occurrences of the rules (manual entries take precedence), `iconographic.layoutStructure` contains the automatically derived TOTUS hint when all four plant zones are text-free. Besides the metadata, the response provides two text representations: `paragraphs` (derived majority-vote consensus with tokens, agreement scores) and `transcription` (raw interlinear mirror of voynich.nu, multilayered H/C/F/…) — both serve purely for visual inspection; for corpus statements only the local scripts remain authoritative. `starSide` (`left` as default, or `right`) gives the side of the margin stars; `stars` (margin stars per paragraph with `points` and `color`) is `null` except for folios with astronomy/star diagrams. 404 if no JSON exists; `lacuna: true` for physically missing folios. **Parameters:** | Name | Type | In | Required | Default | Description | |---|---|---|---|---|---| | `slug` | string | path | yes | — | Folio slug, e.g. f103r. | **Examples:** - _Fetch a folio page:_ ``` curl http://localhost:5173/api/folio/f103r curl http://localhost:5173/api/folio/f57r ``` --- ## Services Translation and backtest ### `GET` /api/translate Translates EVA text into Hebrew. One sentence per line, words separated by spaces or `·`. For each word a lexicon lookup (direct and prefix fallback) as well as a grammar check (R41/R65/R40/D1/D2) is performed. Structural markers at the end of words are stripped and returned as `postMarkers` (`-` = line end, `=` = colophon); line-final prognosis terms carry an `r6` field (`death` for sheol/shol, `heal` for or — rule applies to language B). **Parameters:** | Name | Type | In | Required | Default | Description | |---|---|---|---|---|---| | `text` | string | query | yes | — | EVA text (URL-encoded). | **Examples:** - _Translate EVA text:_ ``` curl 'http://localhost:5173/api/translate?text=qokoldm+daiin' curl 'http://localhost:5173/api/translate?text=sheol+daiin' ``` ### `GET` /api/backtest Runs the complete backtest — the stress test of the morphology hypothesis against real attestations: checks all type-I predictions (on already transcribed folios) and type-II predictions (previously predicted word forms that were still unobserved at the time of prediction) against the folio transcriptions. Returns aggregated statistics (pass rate per type) and the list of all existing entries (`entries`, incl. `pred`) — the entries enable the double-entry check. With `perEntry=true` the individual per-check results are additionally listed on each entry. The result is cached server-side. **Parameters:** | Name | Type | In | Required | Default | Description | |---|---|---|---|---|---| | `perEntry` | boolean | query | no | false | If true, the individual per-check results are listed on each entry. | **Examples:** - _Run the backtest:_ ``` curl http://localhost:5173/api/backtest curl 'http://localhost:5173/api/backtest?perEntry=true' ``` --- Generated on August 2026 from Voynich decipherment system v9.11.0.