StreamFix is a drop-in replacement for the OpenAI API. It proxies your requests to OpenRouter (or your own key), repairing broken JSON and validating schemas in real-time.
from openai import OpenAI
client = OpenAI(
base_url="https://streamfix.dev/v1",
api_key="sk_YOUR_KEY"
)
# Use normally - works with any model
resp = client.chat.completions.create(
model="openai/gpt-4o-mini",
messages=[{"role": "user", "content": "Hello!"}]
)
Authenticate requests via the Authorization header using your Bearer token.
Authorization: Bearer sk_YOUR_API_KEY
Note: You can also Bring Your Own Key (BYOK) for upstream providers using the X-Provider-Authorization header.
Standard OpenAI-compatible chat completion endpoint. Supports JSON mode, streaming, and function calling. All standard OpenAI parameters (temperature, max_tokens, top_p, etc.) are passed through to the upstream provider.
| Param | Type | Required | Description |
|---|---|---|---|
| model | string | Yes | Target model (e.g. openai/gpt-4o) |
| messages | array | Yes | Chat history |
| stream | boolean | No | Enable streaming response |
| tools | array | No | Tool definitions for function calling |
| schema | object | No | JSON Schema for Contract Mode (3 credits). Use extra_body wrapper for OpenAI SDK. |
StreamFix supports Server-Sent Events (SSE) with token-by-token repair. The FSM engine buffers only the minimum tokens needed (approximately 10 characters) to apply repairs without delaying the stream.
Real-Time Repair: Unquoted keys, trailing commas, and <think> tags are fixed/stripped on-the-fly. The client receives valid JSON chunks with sub-millisecond overhead.
from openai import OpenAI client = OpenAI( base_url="https://streamfix.dev/v1", api_key="sk_YOUR_KEY" ) stream = client.chat.completions.create( model="openai/gpt-4o", messages=[{"role": "user", "content": "List 3 items as JSON"}], stream=True ) # Chunks arrive repaired in real-time for chunk in stream: delta = chunk.choices[0].delta.content if delta: print(delta, end="", flush=True)
Every response passes through a multi-stage pipeline. Each stage is independent and applies only when needed.
Isolates JSON from surrounding prose, markdown fences, and reasoning tags.
| Repair Name | Description |
|---|---|
| fence_strip | Removes markdown code fences (```json ... ```) |
| think_tag_strip | Strips <think>...</think> reasoning tags (DeepSeek, etc.) |
| prose_extract | Extracts JSON object/array from surrounding prose text |
Fixes common JSON syntax violations produced by LLMs.
| Repair Name | Description |
|---|---|
| remove_trailing_comma | Removes trailing commas before } or ] |
| quote_unquoted_keys | Wraps unquoted object keys in double quotes |
| fix_single_quotes | Converts single-quoted strings to double-quoted |
| close_truncated_json | Closes unclosed braces/brackets from truncated output |
| fix_python_literals | Converts Python True/False/None to JSON equivalents |
| fix_leading_zeros | Removes invalid leading zeros from numbers (e.g. 007 to 7) |
| insert_null_for_empty_values | Replaces empty values with null (e.g. {"key": }) |
Applied when a schema is provided (Contract Mode).
| Repair Name | Description |
|---|---|
| type_coerce | Coerces values to match schema types (see Type Coercion) |
Enforce strict adherence to a JSON Schema. When a schema is provided, StreamFix runs the full pipeline: repair the syntax, coerce types to match, validate against the schema, and auto-retry with a schema-aware prompt if validation fails.
Auto-Retry: On validation failure, StreamFix re-prompts the model with a schema-aware system message that includes enum values, min/max constraints, and required fields. Maximum 1 retry per request.
resp = client.chat.completions.create(
model="openai/gpt-4o",
messages=[{"role": "user", "content": "Extract the order info"}],
extra_body={
"schema": {
"type": "object",
"required": ["order_id", "total", "status"],
"properties": {
"order_id": {"type": "integer"},
"total": {"type": "number"},
"status": {"type": "string", "enum": ["pending", "shipped", "delivered"]}
}
}
}
)
Strict Mode guarantees that a response is parseable JSON or returns a structured error. Enable it by setting the X-StreamFix-Strict header.
X-StreamFix-Strict: true
stream: true is set alongside Strict Mode.from openai import OpenAI client = OpenAI( base_url="https://streamfix.dev/v1", api_key="sk_YOUR_KEY", default_headers={"X-StreamFix-Strict": "true"} ) # 200 = valid JSON, 422 = parse failure resp = client.with_raw_response.chat.completions.create( model="openai/gpt-4o", messages=[{"role": "user", "content": "Return a JSON object"}] ) print(resp.status_code) # 200 or 422
{
"error": {
"type": "parse_failure",
"message": "Failed to extract or repair valid JSON from response",
"request_id": "req_abc123def456",
"extraction_status": "FAILED",
"raw_content_preview": "Sure! Here is some info..."
}
}
When a schema is provided, StreamFix automatically coerces values to match the declared types before validation. This fixes the most common schema violations from LLMs without requiring a retry.
| Input | Schema Type | Output |
|---|---|---|
| "30" | integer | 30 |
| "true" | boolean | true |
| 30.0 | integer | 30 |
| "3.14" | number | 3.14 |
Note: Coercion is recorded as type_coerce in the x-streamfix-applied response header, so you can track how often your chosen model returns the wrong type.
Retrieve the repaired JSON and validation metadata for any request (streaming or non-streaming).
{
"request_id": "req_abc123",
"status": "REPAIRED",
"repairs_applied": ["remove_trailing_comma"],
"repaired_content": "{\"status\": \"ok\"}",
"schema_valid": true,
"response_time_ms": 450
}
StreamFix automatically repairs broken JSON in tool_calls[].function.arguments for non-streaming requests.
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Call test_function"}],
tools=[{
"type": "function",
"function": {
"name": "test_function",
"parameters": {
"type": "object",
"properties": {"arg": {"type": "string"}}
}
}
}]
)
# Tool call arguments are automatically repaired if broken
tool_calls = response.choices[0].message.tool_calls
if tool_calls:
args = tool_calls[0].function.arguments # Already repaired JSON
Note: For streaming requests, tool call arguments are passed through as-is to ensure low latency. Use non-streaming for guaranteed tool call repair.
We support all models via OpenRouter. Here are our recommended defaults for reliability.
Best balance of speed and cost ($0.000005/req)
Excellent for structured data extraction
High performance open-source model
StreamFix returns all repair and validation metadata in HTTP headers to maintain 100% OpenAI API compatibility in the response body.
x-streamfix-request-id: req_abc123def456 x-streamfix-status: repaired x-streamfix-applied: fence_strip,remove_trailing_comma x-streamfix-credits-used: 1 x-streamfix-credits-remaining: 999 x-streamfix-mode: shared
x-streamfix-contract-mode: active
x-streamfix-schema-valid: true
x-streamfix-schema-errors: 0
x-streamfix-retry-count: 1 # If retry was triggered
x-streamfix-tool-args-repaired: 1 # Non-streaming only
| Header | Values | Description |
|---|---|---|
| x-streamfix-status | pass | repaired | failed | Overall repair status for this request |
| x-streamfix-applied | comma-separated names | Repair names applied (e.g. fence_strip,remove_trailing_comma) |
| x-streamfix-repair-status | applied | none | passthrough | Whether repairs were applied to the response |
| x-streamfix-repairs-applied | 0-N | Number of repairs made |
| x-streamfix-contract-mode | active | Present when Contract Mode is enabled |
| x-streamfix-schema-valid | true | false | Schema validation result (Contract Mode only) |
| x-streamfix-artifact-stored | true | false | Whether repair artifact was saved (requires opt-in) |
| x-streamfix-tool-args-repaired | 0-N | Number of tool call arguments repaired (non-streaming only) |
| x-streamfix-retry-count | 0-1 | Number of retries attempted (Contract Mode only) |
| x-streamfix-client-request-id | string | Echoed correlation ID from X-Request-Id header |
The x-streamfix-applied header contains a comma-separated list of repair names. Use this to monitor which models produce which errors.
| Stage | Name | Example |
|---|---|---|
| Extraction | fence_strip | ```json{...}``` → {...} |
| Extraction | think_tag_strip | <think>...</think>{...} → {...} |
| Extraction | prose_extract | Here is the JSON: {...} → {...} |
| Syntax | remove_trailing_comma | {"a":1,} → {"a":1} |
| Syntax | quote_unquoted_keys | {key:"v"} → {"key":"v"} |
| Syntax | fix_single_quotes | {'a':'b'} → {"a":"b"} |
| Syntax | close_truncated_json | {"a":1 → {"a":1} |
| Syntax | fix_python_literals | {"ok":True} → {"ok":true} |
| Syntax | fix_leading_zeros | {"n":007} → {"n":7} |
| Syntax | insert_null_for_empty_values | {"a":} → {"a":null} |
| Contract | type_coerce | "30" → 30 (integer) |
| Code | Meaning | Solution |
|---|---|---|
| 401 | Unauthorized | Check your API Key in the Authorization header. |
| 402 | Payment Required | Insufficient credits. Top up at /account/purchase. |
| 422 | Unprocessable Entity | Strict Mode: JSON could not be parsed after all repair stages. |
| 429 | Rate Limited | You exceeded 60 requests/minute. Slow down. |
| 408 | Request Timeout | Streaming timeout exceeded (300 seconds). |
| 413 | Payload Too Large | Request exceeds 10MB limit. |
| 502 | Bad Gateway | Upstream provider (e.g. OpenAI) error. Retry. |
Create a new account and receive an API key with 1000 free credits.
POST /account/create?email=user@example.com
{
"api_key": "sk_abc123...",
"email": "user@example.com",
"credits": 1000,
"message": "Account created! Save your API key - it won't be shown again."
}
Note: If the email already exists, the API key is rotated and existing credits are preserved.
Check your remaining credits. Requires authentication.
GET /account/balance Authorization: Bearer sk_YOUR_API_KEY
{
"credits_remaining": 997,
"is_active": true
}
Create a Stripe checkout session for purchasing credits. User-friendly: uses email instead of API key.
POST /account/purchase-by-email
Content-Type: application/json
{
"email": "user@example.com"
}
{
"checkout_url": "https://checkout.stripe.com/...",
"credits": 10000,
"price_usd": 10.0
}
Use your own provider API keys to avoid using the shared pool.
from openai import OpenAI client = OpenAI( base_url="https://streamfix.dev/v1", api_key="sk_YOUR_STREAMFIX_KEY", default_headers={ "X-Provider-Authorization": "Bearer YOUR_OPENROUTER_KEY" } )
Benefits: Use your own OpenRouter account, avoid shared pool rate limits, more control over costs. StreamFix credits are still deducted (1 per request, 3 for Contract Mode), but upstream costs use your account.
| Item | Cost |
|---|---|
| Basic request (repair only) | 1 credit |
| Contract Mode (schema validation + retry) | 3 credits |
| Free tier on signup | 1,000 credits |
| Credit purchase | $10 = 10,000 credits |
X-StreamFix-Applied: This header tells you exactly which repairs were needed. Use it to understand which models produce bad output and to track repair rates over time.X-Provider-Authorization to separate upstream LLM costs from StreamFix credits.response_format: {"type": "json_object"} when possible. StreamFix repairs what breaks, but starting with valid intent helps.X-Request-Id or X-Client-Request-Id header to track requests across your system logs.