Wine Chemistry & Compliance API
Post a lab panel. Get back which US federal limits it breaches, the arithmetic, and the regulation quoted verbatim. Free, public domain, no key.
Authorised treatment materials and uses, 54 of them with a hard TTB number
Federal composition limits, each served with its verbatim CFR sentence
ppm total SO₂ ceiling — and 10 ppm forces a sulfite declaration
Models. This does not predict wine quality, and says why
What this is
A compliance and chemistry layer for winery QC labs. It answers the question a lab actually asks — “is this wine legal, and by how much am I over” — from the only source that can answer it authoritatively: US federal law, which is public domain and needs no key.
Send the panel you already measured. Each analyte comes back with the governing federal maximum, the citation, the regulation sentence verbatim so you can check this service against eCFR rather than trusting it, and the arithmetic that produced the verdict. Alongside that sit the 79 authorised treatment materials with their TTB limits, and the cellar calculations — molecular SO₂, potential alcohol, unit conversion — that a lab runs by hand every day.
null with a reason, never 0 — a lab reading molecularSO2: 0 would
add sulfur the wine does not need. A wine whose class no federal rule covers comes back
notApplicable with compliant: null, because silence is not a pass. And a
sulfite declaration is reported as a labelling trigger, not a breach, because telling a winery
it broke a rule it did not break is worse than saying nothing.
Live lab check
Edit the panel and check it against the federal limits. The default is a red wine that breaches
both volatile acidity and total SO₂ — try dropping VA to 0.12, or removing pH to see
molecular SO₂ refuse to guess.
Presets: , , .
Endpoints
| Route | What it answers |
|---|---|
POST /chem/v1/lab/check | The product. A lab panel in; per-analyte verdict, limit, citation, verbatim regulation and working out. |
GET /chem/v1/limits | Every federal composition limit. Filter by analyte, wineClass, kind. |
GET /chem/v1/limits/{analyte} | Every rule governing one analyte — VA has six, differing by class, colour and Brix. |
GET /chem/v1/materials | The 79 authorised uses. ?hasLimit=true for the 54 that state a number. |
GET /chem/v1/materials/{id} | One material-and-use. A name with several uses answers 409 with candidates. |
GET /chem/v1/production | Amelioration, sweetening and cellar-treatment sections of part 24. |
POST /chem/v1/calc/molecular-so2 | Free SO₂ + pH → molecular SO₂. Without pH: null and a reason. |
POST /chem/v1/calc/potential-alcohol | °Brix → potential alcohol, as a range. |
GET /chem/v1/sources | Every upstream, and everything rejected with its reason. |
Quick start
# Is this red wine within the federal limits?
curl -X POST https://apis.allanninal.dev/chem/v1/lab/check \
-H 'content-type: application/json' \
-d '{"wineClass":"grape","colour":"red","volatileAcidity":0.15,"totalSO2":372,"freeSO2":28,"pH":3.62}'
# What may I add to wine, and how much?
curl 'https://apis.allanninal.dev/chem/v1/materials?hasLimit=true'
# The molecular SO2 that actually protects the wine
curl -X POST https://apis.allanninal.dev/chem/v1/calc/molecular-so2 \
-H 'content-type: application/json' -d '{"freeSO2":28,"pH":3.62}'
Three things this API will not do
Guess a measurement you did not take
Molecular SO₂ needs pH. Without it the answer is null with a reason — never a default, never 0. Potential alcohol comes back as a range, because every single published Brix-to-alcohol factor is somebody's average.
Treat silence as a pass
A wine class no federal rule covers is reported notApplicable with compliant: null. Saying "compliant" because nothing matched would be the most dangerous answer this service could give.
Predict quality from chemistry
The dataset that needs is CC BY 4.0 and this fleet takes public domain only. There is no model, no prediction endpoint, and the reasoning is published rather than left for you to infer from an endpoint that does not exist.
Reference data (static, free, no auth)
The complete datasets as plain files — cacheable, no key, and the same data the API serves.
| File | Contents |
|---|---|
| index.json | Index of everything below |
| composition-limits.json | The 8 federal limits, each with its verbatim CFR sentence |
| treatment-materials.json | 79 authorised uses across 60 materials · only the 54 with a number |
| production-limits.json | Part 24 amelioration and cellar-treatment sections |
| sources.json | Every upstream used, and everything rejected with its reason |
| plans.json · versions.json | Plan catalogue and version manifest |
Access & rate limits
| Plan | Per minute | Per day | History | Price |
|---|---|---|---|---|
| Free (anonymous) | 60 | 5,000 | 30 days | $0 |
| Free + key | 300 | 50,000 | 30 days | $0 |
| Public interest | 1,200 | 500,000 | full | $0, by application |
| Pro not open yet | 1,200 | 500,000 | full | $19/mo · $190/yr |
| Business not open yet | 6,000 | 5,000,000 | full | $49/mo · $490/yr |
Every plan has every feature. Plans differ only in how much you may use, never in what you may
reach — nothing is behind a paywall. Limits ride on every response as
RateLimit-* headers. The plan catalogue.
FAQ
Does this predict wine quality from chemistry?
No, and there is no model here at all. The dataset that task needs is UCI Wine Quality, which is published under CC BY 4.0 — an attribution obligation this fleet does not accept — and no CC0 equivalent exists. USDA FoodData Central carries wine composition but no sensory quality scores, so there is no training target. The full reasoning is served at /v1/sources.
Do I need an API key?
No. Every read path is anonymous and free at 60 requests a minute and 5,000 a day. A free key raises that to 300 a minute and 50,000 a day; it does not unlock anything, because every plan already reaches every endpoint and every field. Neither source this service uses requires a key either.
Why does molecular SO2 come back as null instead of a number?
Because you did not supply pH, and molecular SO₂ cannot be derived from free SO₂ alone. Assuming a pH
would invent the answer, and a lab reading molecularSO2: 0 would conclude the wine is
microbially unprotected and add sulfur it does not need. Every computed figure here follows the same
rule: a missing input is null with a reason, never a default.
Is this legal advice, or an official TTB determination?
Neither. It reports what the Code of Federal Regulations says, compared against the values you supply, with the regulation quoted verbatim so you can check it yourself against eCFR. It does not verify your laboratory method, and it covers federal limits only — a state may impose stricter ones.
Cost
Free, no signup: 60 requests a minute, 5,000 a day, 30 days of history. Every plan reaches every endpoint and every field; plans differ only in how much you may use. Pro-level access is free, on request, for journalists, academics and nonprofits.
👋 Want an API for your idea?
This API was designed and built by Allan Niñal, an AI & software engineer who ships friendly, well-made, developer-first APIs and data products. Tell me the problem in plain words — compliance, chemistry, public data, or anything else — and I'll turn it into something that works.