CORTEX api developer reference
Introduction
What the API does and the typical workflow.
The CORTEX api by Fitshield lets your application search our food database, calculate the full nutrition of a cooked or raw dish, send dishes for certified-nutritionist verification, track their status, download nutrition fact sheets, and raise support requests.
It is a JSON-over-HTTPS API. All request and response bodies are application/json (UTF-8), unless a binary file is being downloaded.
Typical workflow
- 1Search for each ingredient and get its
food_code. - 2Calculate the dish, sending ingredients + cooking info, and receive a
dish_idand the nutrition result. - 3Send to nutritionist for verification.
- 4Check status until it is
approvedorrejected. - 5Get the fact sheet once the dish is approved.
Base URL & versioning
Where requests go.
All endpoints are relative to the versioned base URL:
https://api.fitshield.in/v1Example: the Search endpoint is GET /foods/search, i.e. GET https://api.fitshield.in/v1/foods/search.
Proposed. The host name is a placeholder. Replace it with the URLs issued for your test and live environments.
Authentication
Bearer API keys for test and live.
The API is a paid service. Each account is issued API keys from the developer dashboard: a test key (sk_test_…) and a live key (sk_live_…). Send the key as a Bearer token on every request:
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx- Keep keys secret; use them server-side only.
- Requests with a missing or invalid key return 401 Unauthorized.
- Test-key requests operate on sandbox data and are not billed.
Conventions
Response envelope, IDs, units and timestamps.
Response envelope
Every JSON response uses a consistent envelope. On success:
{
"success": true,
"data": {}
}On failure:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Human-readable explanation.",
"details": [
{
"field": "ingredients",
"issue": "required"
}
]
}
}General
- IDs are opaque strings (e.g.
dsh_8f3a2b). Do not parse them. - Timestamps are ISO 8601 UTC (e.g.
2026-09-09T10:22:31Z). - Quantities use units
g,ml, orpiece. - Nutrient values are returned as a nutrition-label object with
{ value, unit }leaves. - All requests should send
Accept: application/json.
Error handling
HTTP status plus a precise error code.
The HTTP status code gives the broad outcome; error.code gives the precise reason.
| Code | HTTP | Meaning |
|---|---|---|
INVALID_REQUEST | 400 | Malformed request, bad JSON or missing/incorrect parameters. |
MISSING_API_KEY / INVALID_API_KEY | 401 | No key, or an invalid/revoked key. |
FORBIDDEN | 403 | Key valid but not permitted for this action. |
RESOURCE_NOT_FOUND | 404 | The dish or food does not exist. |
ALREADY_SUBMITTED | 409 | Dish is already under verification. |
NOT_APPROVED | 409 | Fact sheet requested before approval. |
VALIDATION_ERROR | 422 | A field failed validation. |
RATE_LIMITED | 429 | Too many requests / quota exceeded, see Retry-After. |
INTERNAL_ERROR | 500 | Server error. Safe to retry later. |
Example error
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The dish must contain at least one ingredient.",
"details": [
{
"field": "ingredients",
"issue": "required"
}
]
}
}Rate limits & quota
Per-key limits and the headers to watch.
Requests are limited per API key according to your plan. When exceeded, the API returns 429 Too Many Requests with a Retry-After header (seconds). Every response includes:
X-RateLimit-Limit, requests allowed per windowX-RateLimit-Remaining, requests left in the current window
Proposed. Default suggestion: 60 requests/minute per key, with a monthly quota by plan. Confirm final limits.
Search foods
Autocomplete foods from the database.
/foods/searchReturns database suggestions matching a typed name (autocomplete). For example, q=pan returns items such as Paneer, Pan, Panne. Results can be ingredients or packaged foods. Use the returned food_code when calculating a dish.
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
q | string | Yes | The (partial) name to search for. Minimum 2 characters. |
type | string | No | Filter by ingredient, packaged, or dish. If omitted, all types are returned. |
limit | integer | No | Max suggestions. Default 10, maximum 50. |
Example request
curl -X GET "https://api.fitshield.in/v1/foods/search?q=pan&limit=5" \
-H "Authorization: Bearer sk_live_xxx"Example response (200 OK)
{
"success": true,
"data": {
"query": "pan",
"results": [
{
"food_code": "F1024",
"food_name": "Paneer",
"type": "ingredient",
"source": "ICMR"
},
{
"food_code": "F2210",
"food_name": "Panne (pasta)",
"type": "ingredient",
"source": "USDA"
},
{
"food_code": "P5567",
"food_name": "Amul Paneer (200 g)",
"type": "packaged",
"source": "Amul"
}
]
}
}Response fields
| Field | Type | Description |
|---|---|---|
results[].food_code | string | Unique code for the food. Pass this to the Calculate endpoint. |
results[].food_name | string | Display name. |
results[].type | string | ingredient, packaged, or dish. |
results[].source | string | Data source / provider: a database such as ICMR or USDA, or the brand for packaged foods (e.g. Amul). |
Calculate dish nutrition
Compute nutrition, claims & allergens.
/dishes/calculateCalculates the nutrition of a dish from its ingredients and quantities. Ingredients may be identified by food_code (from Search) or by a plain name.
Cooking is optional and can be given at two independent levels:
- Per ingredient: an ingredient carries its own
cookingobject, applied to just that ingredient. - Whole dish: a top-level
cookingobject, applied to the combined dish.
If an ingredient has its own cooking and a dish-level cooking is also provided, both are applied in sequence: the ingredient is cooked first, then the whole-dish cooking is applied on top (cooking is applied twice). Omit cooking entirely for a raw dish.
The result is saved and returned with a dish_id used by all later endpoints.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
dish_name | string | Yes | Name of the dish. |
cooking | object | No | Whole-dish cooking, applied to the combined dish. Omit for no dish-level cooking. |
cooking.method | string | Conditional | Required inside any cooking object. raw, boil, steam, fry, deep_fry, saute, simmer, bake, roast, grill, pressure_cook. |
cooking.time_minutes | number | No | Cooking time in minutes. |
cooking.temperature_c | number | No | Cooking temperature in °C. |
ingredients | array | Yes | One or more ingredients (at least one). |
ingredients[].food_code | string | Conditional | Preferred identifier (from Search). Provide this or name. |
ingredients[].name | string | Conditional | Ingredient name, used if food_code is absent. |
ingredients[].quantity | number | Yes | Amount of the ingredient. |
ingredients[].unit | string | Yes | g, ml, or piece. |
ingredients[].cooking | object | No | Cooking applied to just this ingredient. Same shape as the top-level cooking. |
Example request (whole-dish cooking)
curl -X POST "https://api.fitshield.in/v1/dishes/calculate" \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"dish_name": "Paneer Butter Masala",
"cooking": {
"method": "simmer",
"time_minutes": 20,
"temperature_c": 150
},
"ingredients": [
{
"food_code": "F1024",
"quantity": 250,
"unit": "g"
},
{
"name": "Butter",
"quantity": 30,
"unit": "g"
},
{
"name": "Tomato puree",
"quantity": 150,
"unit": "ml"
}
]
}'Example request (per-ingredient cooking + whole-dish cooking)
Here each ingredient is cooked on its own, then the whole dish is simmered, so the fried ingredient is effectively cooked twice.
curl -X POST "https://api.fitshield.in/v1/dishes/calculate" \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"dish_name": "Mixed Veg Sabzi",
"cooking": {
"method": "simmer",
"time_minutes": 8
},
"ingredients": [
{
"food_code": "F3001",
"quantity": 100,
"unit": "g",
"cooking": {
"method": "fry",
"time_minutes": 5,
"temperature_c": 180
}
},
{
"food_code": "F3002",
"quantity": 120,
"unit": "g",
"cooking": {
"method": "boil",
"time_minutes": 10
}
}
]
}'Example response (201 Created)
{
"success": true,
"data": {
"dish_id": "dsh_8f3a2b",
"dish_name": "Paneer Butter Masala",
"total_weight_g": 430,
"nutrition": {
"basis": "per_dish",
"energy": {
"value": 892,
"unit": "kcal"
},
"protein": {
"value": 28.6,
"unit": "g"
},
"carbohydrate": {
"total": {
"value": 22.1,
"unit": "g"
},
"added_sugars": {
"value": 3,
"unit": "g"
}
},
"fat": {
"total": {
"value": 71.2,
"unit": "g"
},
"saturated": {
"value": 36,
"unit": "g"
},
"trans": {
"value": 0.4,
"unit": "g"
}
},
"sodium": {
"value": 410,
"unit": "mg"
}
},
"government_claims": [
"High in Protein",
"Source of Calcium"
],
"allergen_claims": {
"contains": [
"Milk"
],
"may_contain": [
"Tree nuts"
]
},
"verification_status": "not_submitted",
"created_at": "2026-09-09T10:22:31Z"
}
}Response fields
| Field | Type | Description |
|---|---|---|
dish_id | string | Use this in all later endpoints. |
total_weight_g | number | Total finished weight of the dish. |
nutrition | object | Nutrition-label panel. See the Nutrition model. |
nutrition.basis | string | What the values represent: per_dish (default) or per_100g. |
government_claims | string[] | Regulatory nutrition/health claims the dish qualifies for (e.g. FSSAI). Empty if none. |
allergen_claims | object | Allergen declarations: contains and may_contain lists. |
verification_status | string | not_submitted until sent to a nutritionist. |
Edit dish
Update a dish and recalculate.
/dishes/{dish_id}Update a previously calculated dish (change its name, cooking details, or ingredients) and recalculate its nutrition. Send the full updated dish definition (same body as Calculate); it replaces the stored definition.
Editing recalculates nutrition, government claims and allergen claims. If the dish was already submitted or approved, editing resets verification_status to not_submitted and invalidates any existing fact sheet. You must send it for verification again.
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
dish_id | string | Yes | The dish to edit. |
Request body
Identical to POST /dishes/calculate. Send the full, updated dish_name, optional cooking, and ingredients (each with optional per-ingredient cooking).
Example request
curl -X PUT "https://api.fitshield.in/v1/dishes/dsh_8f3a2b" \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"dish_name": "Paneer Butter Masala (less oil)",
"cooking": {
"method": "simmer",
"time_minutes": 18,
"temperature_c": 150
},
"ingredients": [
{
"food_code": "F1024",
"quantity": 250,
"unit": "g"
},
{
"name": "Butter",
"quantity": 15,
"unit": "g"
},
{
"name": "Tomato puree",
"quantity": 150,
"unit": "ml"
}
]
}'Example response (200 OK)
Returns the same object as Calculate, with recalculated nutrition, government_claims, allergen_claims, and verification_status reset to not_submitted.
{
"success": true,
"data": {
"dish_id": "dsh_8f3a2b",
"dish_name": "Paneer Butter Masala (less oil)",
"total_weight_g": 415,
"nutrition": {
"basis": "per_dish",
"energy": {
"value": 804,
"unit": "kcal"
},
"protein": {
"value": 28.4,
"unit": "g"
},
"carbohydrate": {
"total": {
"value": 21.6,
"unit": "g"
},
"added_sugars": {
"value": 3,
"unit": "g"
}
},
"fat": {
"total": {
"value": 60.1,
"unit": "g"
},
"saturated": {
"value": 30.2,
"unit": "g"
},
"trans": {
"value": 0.3,
"unit": "g"
}
},
"sodium": {
"value": 395,
"unit": "mg"
}
},
"government_claims": [
"High in Protein"
],
"allergen_claims": {
"contains": [
"Milk"
],
"may_contain": [
"Tree nuts"
]
},
"verification_status": "not_submitted",
"updated_at": "2026-09-09T12:05:00Z"
}
}Send to nutritionist
Submit a dish for verification.
/dishes/{dish_id}/send-to-nutritionistSubmits a calculated dish for verification by a certified nutritionist. Verification is asynchronous, so poll the status endpoint. The dish_id comes from the Calculate response.
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
dish_id | string | Yes | The dish to submit. |
Request body (optional)
| Field | Type | Required | Description |
|---|---|---|---|
note | string | No | A message for the nutritionist. |
Example request
curl -X POST "https://api.fitshield.in/v1/dishes/dsh_8f3a2b/send-to-nutritionist" \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"note": "Please confirm the oil quantity."
}'Example response (202 Accepted)
{
"success": true,
"data": {
"dish_id": "dsh_8f3a2b",
"verification_status": "pending",
"submitted_at": "2026-09-09T10:25:00Z"
}
}A dish already under review returns 409 with code ALREADY_SUBMITTED.
Check verification status
Status of a single dish.
/dishes/{dish_id}/verification-statusReturns the current verification status of a dish previously sent for review.
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
dish_id | string | Yes | The dish whose status you want. |
Example request
curl -X GET "https://api.fitshield.in/v1/dishes/dsh_8f3a2b/verification-status" \
-H "Authorization: Bearer sk_live_xxx"Example response (200 OK)
{
"success": true,
"data": {
"dish_id": "dsh_8f3a2b",
"verification_status": "approved",
"remarks": "Values verified against standard recipe.",
"reviewed_by": "Dr. A. Sharma",
"updated_at": "2026-09-09T11:40:00Z"
}
}verification_status values
| Value | Description |
|---|---|
not_submitted | Calculated but not yet sent for verification. |
pending | Submitted, awaiting review. |
approved | Verified. The fact sheet can now be downloaded. |
rejected | Not approved; see remarks. |
View all dishes & status
List all dishes with status (filter + paginate).
/dishesLists all dishes created under your account, each with its current verification status. Supports filtering and pagination.
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
status | string | No | Filter by not_submitted, pending, approved, or rejected. |
q | string | No | Filter by dish name (partial match). |
page | integer | No | Page number, starting at 1. Default 1. |
limit | integer | No | Results per page. Default 20, maximum 100. |
Example request
curl -X GET "https://api.fitshield.in/v1/dishes?status=pending&page=1&limit=20" \
-H "Authorization: Bearer sk_live_xxx"Example response (200 OK)
{
"success": true,
"data": {
"dishes": [
{
"dish_id": "dsh_8f3a2b",
"dish_name": "Paneer Butter Masala",
"verification_status": "pending",
"created_at": "2026-09-09T10:22:31Z",
"updated_at": "2026-09-09T10:25:00Z"
},
{
"dish_id": "dsh_44c1d0",
"dish_name": "Mixed Veg Sabzi",
"verification_status": "approved",
"created_at": "2026-09-07T09:10:00Z",
"updated_at": "2026-09-07T14:02:00Z"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 2,
"total_pages": 1
}
}
}Response fields
| Field | Type | Description |
|---|---|---|
dishes[].dish_id | string | Dish identifier. |
dishes[].dish_name | string | Dish name. |
dishes[].verification_status | string | not_submitted, pending, approved, or rejected. |
dishes[].created_at | string | When the dish was first calculated. |
dishes[].updated_at | string | When the dish or its status last changed. |
pagination | object | page, limit, total, total_pages. |
Get fact sheet
Download the fact sheet (after approval).
/dishes/{dish_id}/fact-sheetDownloads the nutrition fact sheet for a dish. Available only after the dish is approved. By default returns a JSON object with a time-limited download link; pass format=pdf to stream the PDF directly.
Path & query parameters
| Field | Type | Required | Description |
|---|---|---|---|
dish_id | string | Yes | The approved dish. |
format | string | No | json (default) returns a link; pdf streams the file. |
Example request
curl -X GET "https://api.fitshield.in/v1/dishes/dsh_8f3a2b/fact-sheet" \
-H "Authorization: Bearer sk_live_xxx"Example response (200 OK, format=json)
{
"success": true,
"data": {
"dish_id": "dsh_8f3a2b",
"format": "pdf",
"download_url": "https://cdn.fitshield.in/factsheets/dsh_8f3a2b.pdf?token=...",
"expires_at": "2026-09-09T12:40:00Z"
}
}If the dish is not yet approved, the API returns 409 with code NOT_APPROVED. With format=pdf the response body is the file (Content-Type: application/pdf, Content-Disposition: attachment).
Support request
Send a query / request; replied to by email.
/support-requestsSend a request to the Fitshield team. Use it to ask a nutritionist a question about a dish, request that a new packaged food be added to the database, or raise any other query. Our team resolves the request and replies to the email you provide.
- Nutritionist question about a dish: put the dish id and topic in
subject, your question inbody, and (optionally) thedish_id. - Request a new packaged food: describe the product in
subjectandbody. - Anything else: use
subjectandbodyfreely.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Reply-to email address. We respond here once the request is resolved. |
subject | string | Yes | Short summary of the request. |
body | string | Yes | The full message / details of the request. |
dish_id | string | No | Link the request to a specific dish (for nutritionist questions). |
category | string | No | nutritionist_query, new_food_request, or other. Helps route the request. |
Example request
curl -X POST "https://api.fitshield.in/v1/support-requests" \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"email": "dev@example.com",
"subject": "Question on dish dsh_8f3a2b (vitamin C retention)",
"body": "Could a nutritionist confirm the vitamin C retention after cooking for this dish?",
"dish_id": "dsh_8f3a2b",
"category": "nutritionist_query"
}'Example response (201 Created)
{
"success": true,
"data": {
"request_id": "req_9x2k",
"status": "received",
"email": "dev@example.com",
"created_at": "2026-09-09T09:00:00Z"
}
}The team will reply to the email you provided once the request is resolved. A missing email, subject, or body returns 422 VALIDATION_ERROR.
Data models
Ingredient, Cooking, Nutrition, claims.
Ingredient (request)
| Field | Type | Required | Description |
|---|---|---|---|
food_code | string | Conditional | Food code from Search; preferred identifier. |
name | string | Conditional | Used if food_code is not supplied. |
quantity | number | Yes | Amount of the ingredient. |
unit | string | Yes | g, ml, or piece. |
cooking | object | No | Cooking applied to just this ingredient (optional). |
Cooking (request)
Used both at the top level (whole dish) and inside an ingredient. If both are present for an ingredient, they apply in sequence.
| Field | Type | Required | Description |
|---|---|---|---|
method | string | Yes | Required within a cooking object. raw, boil, steam, fry, deep_fry, saute, simmer, bake, roast, grill, pressure_cook. |
time_minutes | number | No | Cooking time in minutes. |
temperature_c | number | No | Cooking temperature in °C. |
Nutrition (response)
A nutrition-label panel. Each leaf is { "value": number, "unit": string }.
| Field | Unit | Description |
|---|---|---|
basis | — | per_dish (default) or per_100g. |
energy | kcal | Energy. |
protein | g | Protein. |
carbohydrate.total | g | Total carbohydrate. |
carbohydrate.added_sugars | g | Added sugars. |
fat.total | g | Total fat. |
fat.saturated | g | Saturated fat. |
fat.trans | g | Trans fat. |
sodium | mg | Sodium. |
Government claims (response)
string[], regulatory claims automatically evaluated from the nutrition values (e.g. High in Protein, Low Fat, Source of Calcium). Empty when the dish qualifies for none.
Allergen claims (response)
| Field | Type | Description |
|---|---|---|
contains | string[] | Allergens definitely present (e.g. Milk, Wheat, Soy). |
may_contain | string[] | Possible cross-contamination allergens. |
Endpoint summary
All eight endpoints at a glance.
| Endpoint | Method & path | Purpose |
|---|---|---|
| Search foods | GET /foods/search | Autocomplete foods from the database. |
| Calculate dish nutrition | POST /dishes/calculate | Compute nutrition, claims & allergens. |
| Edit dish | PUT /dishes/{dish_id} | Update a dish and recalculate. |
| Send to nutritionist | POST /dishes/{dish_id}/send-to-nutritionist | Submit a dish for verification. |
| Check verification status | GET /dishes/{dish_id}/verification-status | Status of a single dish. |
| View all dishes & status | GET /dishes | List all dishes with status (filter + paginate). |
| Get fact sheet | GET /dishes/{dish_id}/fact-sheet | Download the fact sheet (after approval). |
| Support request | POST /support-requests | Send a query / request; replied to by email. |
Need API keys or have a question?
The CORTEX api is a paid service. Talk to our team for access, pricing and integration help, or write to hello@fitshield.in.
© 2026 Fitshield Dietfood Private Limited · CORTEX api v1.0. Developer documentation. Base URL, authentication and rate limits shown are proposed and subject to change.