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"] }'
charge-on-matchAICIS + TGA awaretyped DTOsMCP-ready

the response

Honest intelligence, typed.

# POST /v1/analyze → 200 matched { "overallSafetyScore": 7.8, "safetyLevel": "low_risk", "cleanBeautyScore": 88, "coverage": 1.0, "parsedIngredients": [ { "inci": "Niacinamide", "mark": "clear", "score": 9 }, { "inci": "Retinol", "mark": "for_you", "score": 4, "pregnancySafe": false } ], "allergenFlags": ["-"], "epistemic": "per-field", "flags": { "lowConfidence": false } }

Every field is typed, and every field carries its source. Nothing hides behind an average.

  • coverage is the honest one. It reports how much of the formula we could actually read. Below 0.3 it flips lowConfidence to true, the scores are held, and nothing is faked green.
  • mark is the same shape and word you see in the app - clear, for_you or held - not a bare number to argue with.
  • epistemic tells you what each value rests on, per field, so an AU rule and a graded study never get blended into one figure.
  • 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.

POST/v1/analyzeINCI list → marks + sources
GET/v1/products/:barcodethe whole read for a product
GET/v1/products/:barcode/safetyjust the safety score
GET/v1/products/:barcode/allergensthe EU 80-allergen report
GET/v1/products/:barcode/pregnancypregnancy and feeding flags
GET/v1/products/:barcode/compatibilityskin-type fit
GET/v1/ingredients/:incithe 40-field record
GET/v1/ingredients/searchfind by name or CAS
POST/v1/analyze/basketvet a whole basket before checkout
POST/v1/verifya claim → supported / refuted / graph-silent, with citations
POST/v1/products/submitadd a product to the moderation queue
POST/v1/webhooks/reformulationget pinged when a formula changes
GET/v1/products/:barcode/provenancethe signed provenance card
A warm oak desk with a closed laptop, a ceramic mug, a brass pen and an open notebook. 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. Our incentive is coverage, not your bill.

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.

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.

See the full roadmap

Ship it this afternoon.

20,000 matched calls a month on the free tier, no credit card.