OpenAI Structured Outputs JSON Schema Converter
Paste a JSON Schema, get one the OpenAI API accepts with strict: true.
Structured Outputs will not accept an ordinary JSON Schema. Every object in it — not just the root, but the ones inside array items, $defs and anyOfbranches — needs additionalProperties: false and a required array naming every one of its properties. Strict mode also has no concept of an optional field, so anything you left out of required has to be re-expressed as a nullable union, and a set of JSON Schema keywords is rejected outright. Miss any one of these in any nested object and the API answers with a 400 that points at a single path, which is why fixing a large schema by hand turns into a loop of paste, call, read error, repeat.
This converter applies every rule recursively in one pass, shows you a diff of exactly what it changed and why, and hands back runnable Python and TypeScript. It is the same tool whether you searched for an OpenAI strict JSON schema converter, wanted toconvert a JSON Schema to OpenAI strict mode, needed anOpenAI structured output schema generator, or just wanted anadditionalProperties false JSON schema converter.
Your data never leaves your browser. All processing happens locally. Nothing you paste is uploaded, logged or stored, and the converter issues no network request of any kind — disconnect the network and it still works.
Convert a JSON Schema to OpenAI strict mode
How it works
The converter parses your schema and walks every node once, rebuilding it in place so the key order you wrote is preserved and the diff stays readable. At each node it applies the rules from OpenAI's Structured Outputs documentation:
- Every object gets
additionalProperties: false. Including objects reached throughitems,anyOfand$defs— the ones a manual fix usually misses. requiredlists every property. Not just the ones you marked; strict mode permits no exceptions.- Anything that was optional becomes nullable.
"string"becomes["string", "null"], ananyOfgains a null branch, and an optional$refis wrapped inanyOfbecause a$refcannot carry a siblingtype. - Unsupported keywords are removed and
oneOfis rewritten.oneOfbecomesanyOf, which keeps your branches instead of discarding them. - Draft-07
definitionsis renamed to$defs, and every$refpointing into it is rewritten so nothing dangles. - The documented size limits are checked. These cannot be auto-fixed, so they are reported rather than silently ignored.
Which JSON Schema keywords are unsupported by OpenAI Structured Outputs
This is the table most write-ups get wrong, because OpenAI moved a whole group of keywords from "not yet supported" to supported during 2025. String patterns and numeric bounds now work on base models.
| Group | Keywords | Status |
|---|---|---|
| Supported types | string, number, integer, boolean, object, array, enum, anyOf, $ref / $defs | SupportedRecursion via $ref: "#" is allowed. |
| String / number / array constraints | minLength, maxLength, pattern, format, minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, minItems, maxItems | SupportedSupported on base models. Not supported on fine-tuned models. |
| Composition | allOf, not, dependentRequired, dependentSchemas, if, then, else, oneOf | Not supportedRejected. oneOf is rewritten to anyOf; the rest are removed. |
| Other object / array keywords | patternProperties, unevaluatedProperties, propertyNames, minProperties, maxProperties, unevaluatedItems, prefixItems, additionalItems, contains, minContains, maxContains, uniqueItems, default, examples, readOnly, writeOnly, deprecated, $schema, $id, $comment | Not supportedAbsent from the supported list — removed. |
Size limits a strict schema must stay inside
These are not fixable by rewriting keywords — if a schema exceeds one, it has to be simplified. The converter reports them so you find out here rather than from a 400.
| Total object properties | 5,000 |
|---|---|
| Object nesting depth | 10 levels |
| Total string length of property names, enum and const values | 120,000 characters |
| Enum values across the whole schema | 1,000 |
| A single enum with more than 250 values | 15,000 characters total |
Optional fields in OpenAI strict mode
The single most common cause of a strict-mode 400 afteradditionalProperties is assuming required is optional. It is not: a property that exists in properties but not in required is invalid, full stop. The fix is not to delete the property — it is to require it and let its value be null. In Pydantic that is Optional[str]with no default; adding = None makes the field optional in the emitted schema and puts you straight back to the same error. The generated Python on this page gets that right.
Where the rules come from
Every rule and limit above is taken from OpenAI'sStructured Outputs documentation. If OpenAI moves another keyword into the supported set, this tool is wrong until its tables are updated — so check the source if something here contradicts a fresh 400.
More utilities: all free developer tools.