for developers
The ingredient layer
for your app.
Barcode or raw INCI in. Marks, allergens, pregnancy, skin-fit and the source on every field out. Charge-on-match billing means you pay for a real result, never for a miss.
# authenticate with your key, then read a label
curl https://api.reva.dev/v1/analyze \
-H "X-API-Key: sk_live_..." \
-d '{ "inci": ["Aqua","Niacinamide","Retinol"] }'the response
Honest intelligence, typed.
# POST /v1/analyze → 200 matched
{
"rawInci": ["Niacinamide", "Retinol"],
"overallSafetyScore": 7.8,
"safetyLevel": "low_risk",
"cleanBeautyScore": 88,
"comedogenicityScore": 1,
"coverage": 1.0,
"parsedIngredients": [
{ "inciName": "Niacinamide", "safetyLevel": "low_risk",
"safetyScore": 9, "isAllergen": false, "found": true },
{ "inciName": "Retinol", "safetyLevel": "moderate_risk",
"safetyScore": 4, "pregnancySafe": false, "found": true }
],
"allergenFlags": [],
"pregnancySafe": false,
"pregnancyUnsafeIngredients": ["Retinol"],
"flags": { "lowConfidence": false },
"applicability": { "skinBound": true }
}Every field is typed and parsed against a versioned contract, so an integration breaks loudly rather than quietly. Nothing hides behind an average.
- coverage is the honest one. It reports how much of the formula we could actually read. Below
0.3it flipslowConfidencetotrue, the scores are held, and nothing is faked green. - safetyLevel carries the same reading you see in the app, alongside
safetyScore, so you can render a word rather than a bare number. - found is per ingredient, so a miss is visible rather than silently scored. Per-field provenance is not in the public contract yet; it is on the roadmap, and we would rather say so than imply it ships today.
- pregnancySafe and the allergen flags come straight off the Australian rules, dated to when they were in force.
the api
Every route, one safety graph.
Barcode or raw INCI in, marks and a source out. Every route reads from the one graph, so a score on /analyze and a score on /products always line up. Two routes are live today; the rest are marked as planned. We would rather lose you at the evaluation stage than at the integration stage.
the same graph, in your stack
four reasons
Why build on it.
Charge-on-match
You pay for answers, and only answers - a 404 or a held score is free. A miss earns us nothing, so coverage is what we optimise.
Australia-aware
The AICIS inventory and the ten SUSMP schedules as data, not EU-with-exceptions bolted on at the end.
Provenance on every field
A citation and the date the rule was in force, on each value, signed. It cannot be re-skinned into a scarier verdict.
Honest confidence signals
Coverage below a third holds the score - we tell you when we don't know, instead of inventing a green.
resources
Start building.
API Reference
Every endpoint, payload and schema.
Explore →Quickstart
Your first call in five minutes.
Start →Status
Uptime and incidents.
View →Changelog
What shipped, dated.
Read →SDKs for TypeScript, Python, Ruby and Go, plus a native MCP server.
on the roadmap
Shipping to the API next.
The graph keeps getting deeper and more honest. A few of the endpoints and capabilities landing next.
Audit-grade chat
Epistemic-typed answers over the graph: a tipping-point, prove-it-or-concede citations, and a hard fail to "not in our evidence."
VLM label reader
Read INCI, batch and PAO off a packaging photo, so you can score the long tail whose list is an image, a partial "key ingredients" teaser, or missing text - the ones a plain scraper can't read.
Data-gap bounty market
Post a priced bounty on a coverage miss; it settles by webhook when the filled score clears human approval.
Ship it this afternoon.
20,000 matched calls a month on the free tier, no credit card.