From Chat Response to Valid JSON in Your Terminal
Make a chat response safe for your next script
A chat response becomes much more useful when your next command can parse it. For this walkthrough, we’ll turn a bug report into an object containing a summary, a severity, and reproduction steps. We’ll request structured output, extract the assistant’s content, and validate it locally before another program consumes it.
Fluxo gives you one key and one base URL, https://api.fluxorelay.com, for multiple model providers. We’ll use GPT-6 Astra as the example selection. Structured-output support depends on the selected model and route, so check that your selection accepts the response_format option used below. An OpenAI-compatible request shape does not guarantee identical feature support everywhere.
Prepare curl, jq, and a local schema validator
Run these commands in Bash with curl, jq, and Python 3 installed. Use a fresh directory because the commands create local files. The Python environment keeps the validation dependency separate from your application.
mkdir fluxo-json-demo && cd fluxo-json-demo — python3 -m venv .venv && .venv/bin/python -m pip install jsonschema
If you need a key, you can create a Fluxo account and follow along. Read the key silently into your shell so its value does not appear in shell history. Then enter the exact API model identifier for GPT-6 Astra from Fluxo’s model listing; the display name and API identifier may differ.
read -rsp 'Fluxo API key: ' FLUXO_API_KEY; printf '\n'; export FLUXO_API_KEY
read -rp 'API model identifier for GPT-6 Astra: ' FLUXO_MODEL; export FLUXO_MODEL
Define the bug-report JSON Schema
The schema is the contract your application expects. Here, every field is required, severity has three allowed values, and extra properties are forbidden. Keeping the first schema small makes failures easier to diagnose.
printf '%s\n' '{"type":"object","properties":{"summary":{"type":"string"},"severity":{"type":"string","enum":["low","medium","high"]},"steps":{"type":"array","items":{"type":"string"}}},"required":["summary","severity","steps"],"additionalProperties":false}' > schema.json
JSON mode and schema-constrained output are different features. JSON mode requests valid JSON; a supported strict JSON Schema mode also constrains its structure. Neither establishes whether the generated content is factually correct.
Send response_format to the chat endpoint
Build the request with jq so shell quoting cannot corrupt the nested schema. The prompt supplies the task and evidence; response_format supplies the machine-readable contract.
jq -n --arg model "$FLUXO_MODEL" --slurpfile schema schema.json '{model:$model,messages:[{role:"user",content:"Extract a bug report. After signing in, clicking Export returns HTTP 500 every time. Reproduction: sign in, open Reports, click Export. Assign severity using low, medium, or high."}],response_format:{type:"json_schema",json_schema:{name:"bug_report",strict:true,schema:$schema[0]}}}' > request.json
curl --fail-with-body --silent --show-error https://api.fluxorelay.com/v1/chat/completions -H "Authorization: Bearer $FLUXO_API_KEY" -H 'Content-Type: application/json' --data-binary @request.json -o response.json
If the endpoint rejects json_schema or strict, inspect the returned error. Choose a route that supports the feature, or deliberately implement a separate JSON-mode workflow with validation and bounded retries. Removing the option silently would change your application’s guarantees.
Validate the assistant content before using it
The HTTP response is an envelope. Its assistant content contains the JSON document you requested. Check the finish reason and content type before extracting that document; a refusal, missing content, or truncated response must stop this workflow.
jq -e '.choices[0] | .finish_reason == "stop" and (.message.refusal == null) and (.message.content | type == "string")' response.json > /dev/null && jq -er '.choices[0].message.content' response.json > result.json && .venv/bin/python -c 'import json; from jsonschema import validate; validate(instance=json.load(open("result.json")), schema=json.load(open("schema.json"))); print("Schema valid")' && jq . result.json
This chain stops when a check fails. Keep that behavior when integrating it into a worker: parsing and schema validation belong before database writes or tool execution. Add business checks too, such as whether the reproduction steps actually reflect the supplied report.
Reuse the JSON contract from your editor
Once this terminal request works, move the same schema into your application using an OpenAI SDK. Fluxo also works with Claude Code, Codex, and Gemini CLI, keeping access convenient across editor and terminal workflows. Billing follows actual token usage, including cache reads and writes, with no monthly fee. Users also earn a referral share when people they invite pay.
Keep request.json, schema.json, and a sanitized failing response when debugging. If you need help, leave a note on the contact page after signing in.