Announcing api.dottxt.ai
Almost three years ago we released Outlines, the first open-source library that made it practical to enforce structured outputs at generation time.
For a year and a half the field was skeptical. Then everyone copied the surface. Structured outputs became table stakes. Outlines has been downloaded more than 65M times. Every provider, every frontier lab, every open-source serving engine shipped its own version. Problem solved.
Or is it?
We've spent the past year talking to the people who actually run these models at scale. Hospitals extracting clinical data. Banks processing financial documents. Agent builders chaining tool calls. Model aggregators routing across providers. All with the same frustration: what was supposed to make models reliable isn't.
Current implementations handle the basic types, but they diverge on everything that encodes real constraints:
- String validation. Length bounds, regex patterns, formats. Partially supported, sometimes silently ignored.
- Optional fields. Fields the model can genuinely omit. Often forced to be required.
- Composition.
anyOf,oneOf,allOf. Partially supported at best, outright rejected at worst. - Conditionals.
if/then/else,dependentRequired. The keywords that encode business logic: "if payment method is credit card, require card number." Unsupported everywhere.
Without them, your schema describes the shape of your data, not the rules. So the rules end up in your application code instead.
Take a payment object. The shape is easy: a method enum and a few optional fields. The rule is that the required field depends on the method. JSON Schema has if/then/else and dependentRequired for exactly this. No provider enforces them. So you end up writing this:
from typing import Literal, Optional
from pydantic import BaseModel, model_validator
class Payment(BaseModel):
method: Literal["card", "bank_transfer", "cash"]
card_number: Optional[str] = None
iban: Optional[str] = None
received_by: Optional[str] = None
@model_validator(mode="after")
def check_required_fields(self):
if self.method == "card" and not self.card_number:
raise ValueError("card_number required for card payments")
if self.method == "bank_transfer" and not self.iban:
raise ValueError("iban required for bank transfers")
if self.method == "cash" and not self.received_by:
raise ValueError("received_by required for cash payments")
return selfAnd then you wrap the LLM call in a retry loop, because the validator will fail often enough to matter (even with large models). Every business constraint you can't express in the schema is a retry loop waiting to be run.
Worst of all, we've reproduced bugs in every major provider's implementation, and the open-source libraries they're built on have measurable, persistent issues. It's probably affecting you.
And that is understandable. Getting 90% of the way there is simple. The last 10% is edge cases, heavy testing, and performance. All painful, unglamorous, resource-intensive work. That's why we exist. And it matters, because with structured outputs, 90% is failure. The whole point is deterministic control over the model's output. Anything less is just another layer of indirection.
This stops today.
Announcing the dottxt API
An OpenAI-compatible endpoint that enforces your complete JSON Schema. Built with our technology, served by our inference partner DoubleWord.
If your structured output pipeline has retry logic, normalization code, or a validation layer that you feel shouldn't exist, this is for you.
How it works
Change two lines:
client = OpenAI(
base_url="<https://api.dottxt.ai/v1>",
api_key=os.environ["DOTTXT_API_KEY"],
)Everything else stays the same. What changes is what comes back.
The validation code, the date normalization, the currency cleanup, the empty-string-to-None conversion, the retry loop, all the code that exists because the schema wasn't enforced? Delete it.
The schema is the contract. We enforce it.
Get started
Quickstart - first request in five minutes.
What you can build - learn about structured outputs.
Provider comparison - see where implementations diverge.
JSON Schema features - full list of what's enforced.
Get better results
Most schemas we see in production are too loose. They define the shape but not the boundaries: no length limits on strings, no bounds on arrays, no patterns on identifiers. The model fills in reasonable values most of the time, and then once in a dozen requests, something breaks downstream.
Send us your schemas. We'll tell you where the low-hanging fruit are.
For inference providers
Are you an inference provider and want to offer real structured output guarantees to your customers? Reach out.
The .txt Team