Opis Nutrition API
From a meal photo to nutrients you can defend.
Identify foods and portions from photos, let a person confirm them if you want, and get 53 nutrients with their provenance — through one asynchronous REST API, hosted in London.
- UK CoFID + USDA + Open Food Facts
- 53 nutrients, UCUM units
- AWS eu-west-2 (London)
- Standard Webhooks
- Free test mode
Three capabilities, metered separately
Use them together as a meal analysis, or buy just the part you need.
Analysis
Photo → itemsUp to four photos of one meal in; identified foods and drinks out, each with estimated grams, confidence and alternative names.
POST /v1/meal-analyses
Meter: identification
Confirmation
OptionalLet a person accept, edit or reject the identified items before nutrition runs — or skip it. Your choice, per project or per request.
POST /v1/meal-analyses/{id}/confirm
Meter: not metered
Nutrition
Items → nutrientsItems and grams in; 53 nutrients per item and per meal out, with the matched food and its source. Also sold on its own.
POST /v1/nutrition-estimates
Meter: nutrition
How the asynchronous flow works
Every request returns 202 with a resource you can poll, wait on with Prefer: wait, or follow by webhook. Automatic and manual confirmation run on the same state machine; manual mode simply stops at requires_confirmation until your user answers.
Automatic confirmation
The default. Identified items go straight to nutrition.
- queuedYou
POST /v1/meal-analyses; we answer 202. - processing· identificationFoods, portions and confidence are identified from the photo.
- processing· nutritionConfirmation is recorded as automatic; nutrients are computed.
- succeededWebhook
meal_analysis.succeeded; fetch the result.
Manual confirmation
A person reviews the items before nutrition runs. The wait is durable state — nothing sits in a queue.
- queuedSame create, with confirmation
mode: "manual". - processing· identificationFoods and portions are identified.
- requires_confirmationWebhook
meal_analysis.requires_confirmation. Your user accepts, edits or rejects; youPOST …/confirmwithIf-Match. - processing· nutritionNutrients are computed for the confirmed items.
- succeededThe result keeps both the AI view and the human view.
- Rejected →
canceled(rejected_at_confirmation). - No answer by
confirmation.expires_at→ youron_expirypolicy:cancel(default) orauto_confirm(recorded asauto_on_expiry).
Why opis
UK CoFID first, with fallbacks you can see
Foods are matched to the UK Composition of Foods Integrated Dataset, with USDA and Open Food Facts as fallbacks. Every item reports its source, food code and whether the match is approximate.
53 nutrients with provenance
Energy, macronutrients, sugars, fat quality, vitamins and minerals in UCUM units — each value says whether it was analysed, calculated, imputed or borrowed.
Null means “not measured”, never zero
Missing values stay null. Meal totals sum only known values and report completeness per nutrient, so you never mistake a gap for an absence.
A full audit trail
Every workflow keeps an append-only timeline: who confirmed, what changed and when, plus the pinned pipeline release and profile hash that produced the result.
Hosted in London
Platform, storage and databases run in AWS eu-west-2. Image analysis uses OpenAI as a listed sub-processor; we never train on your data.
Signed webhooks
Standard Webhooks signatures (HMAC-SHA256) with thin payloads — verify with the official libraries in a few lines, and replay from the console.
Five minutes with a test key
- Sign in to the console with Google and create an organization.
- Create a test API key (
opis_test_…). Test mode is free and deterministic. - Upload a photo, create an analysis, and poll it until it settles.
- Add a webhook endpoint when you are ready to stop polling.
# 1. Upload a photo (test keys never reach the live engine)
curl https://platform.opis.health/v1/files \
-H "Authorization: Bearer $OPIS_API_KEY" \
-F file=@lunch.jpg
# → { "id": "file_01j9…", "status": "processing" }
# 2. Start the analysis
curl https://platform.opis.health/v1/meal-analyses \
-H "Authorization: Bearer $OPIS_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{ "images": [{ "file_id": "file_01j9…" }] }'
# → 202 { "id": "mna_01j9…", "status": "queued" }
# 3. Poll until it settles (or use a webhook)
curl https://platform.opis.health/v1/meal-analyses/mna_01j9… \
-H "Authorization: Bearer $OPIS_API_KEY"
# → { "status": "succeeded", "nutrition": { "totals": { "nutrients": { "energy_kcal": { "value": 341.2, "unit": "kcal" } } } } }Start in test mode today
Test keys work as soon as you create an organization. Live keys are enabled after opis activates it.