Insights API
Summaries, diary audits, exports and analysis ratings. 12 ops: get_diary, get_nutrition_summary, query_foods, audit_diary, export_data, get_goals, set_goals, get_survey, answer_survey, get_query_privacy, update_query_privacy, get_query_report.
Summaries, diary audits, exports and analysis ratings.
get_diary
readGet the diary · POST /api/v1/get_diary · scope insights:read or GET …?input=
The food and symptom diary over a range of days (default the last 7, at most 31 per call), for reading or auditing: every day (empty ones too, so gaps show) with its meals, items (match, grams, nutrients, confidence, source), ingredients (tier, confidence, status) and symptom logs, each with who logged it and from where. Use get_day for one day, get_nutrition_summary for totals, query_foods for "what have I eaten", export_data for everything. Nutrients are integers: energy in millikilocalories, macros and most minerals in milligrams, some vitamins in micrograms; *_display has kcal and grams. The data dictionary (every column, unit and provenance field) is the MCP resource gutlog://data-dictionary and the README.md of export_data. May include `survey`: one optional question to ask the person once (record the answer with answer_survey).
curl -X POST https://getgutlog.com/api/v1/get_diary \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog get_diary{
"type": "object",
"properties": {
"from": {
"description": "First day, YYYY-MM-DD in the person's timezone (inclusive).",
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
"to": {
"description": "Last day, YYYY-MM-DD (inclusive); default today.",
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
"include_ingredients": {
"default": true,
"description": "Each item's ingredients with tier, confidence and status (default true).",
"type": "boolean"
},
"include_symptoms": {
"default": true,
"description": "Each day's symptom logs (default true).",
"type": "boolean"
},
"include_empty_days": {
"default": true,
"description": "List days with nothing logged (default true).",
"type": "boolean"
}
}
}Get a nutrition summary · POST /api/v1/get_nutrition_summary · scope insights:read or GET …?input=
Calories, macros or any nutrient over any range (default the last 7 days, up to a year): totals, the average per logged day, a breakdown by day, week, month or meal type, and each goal (set_goals) with the average as a percent and how many days met it. For "how much protein did I average this month", "am I under my sodium limit", "calories by week". Averages count only days with meals; audit_diary finds the missing ones. Nutrients are integers: energy in millikilocalories, macros and most minerals in milligrams, some vitamins in micrograms; *_display has kcal and grams. May include `survey`: one optional question to ask the person once (record the answer with answer_survey).
curl -X POST https://getgutlog.com/api/v1/get_nutrition_summary \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog get_nutrition_summary{
"type": "object",
"properties": {
"from": {
"description": "First day, YYYY-MM-DD in the person's timezone (inclusive).",
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
"to": {
"description": "Last day, YYYY-MM-DD (inclusive); default today.",
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
"nutrients": {
"description": "Nutrient keys to report (default the core panel: energy, protein, carbs, fat, fiber, sugar, added_sugar, sodium, saturated_fat). Every key: energy, protein, carbs, fat, saturated_fat, trans_fat, fiber, sugar, added_sugar, sodium, cholesterol, potassium, calcium, iron, magnesium, zinc, vitamin_c, vitamin_a, vitamin_d, vitamin_b12, folate, caffeine.",
"maxItems": 22,
"type": "array",
"items": {
"type": "string",
"enum": [
"energy",
"protein",
"carbs",
"fat",
"saturated_fat",
"trans_fat",
"fiber",
"sugar",
"added_sugar",
"sodium",
"cholesterol",
"potassium",
"calcium",
"iron",
"magnesium",
"zinc",
"vitamin_c",
"vitamin_a",
"vitamin_d",
"vitamin_b12",
"folate",
"caffeine"
]
}
},
"group_by": {
"default": "day",
"description": "How to break the range down: day (default), week (ISO, Monday first), month, meal_type, or total only.",
"type": "string",
"enum": [
"day",
"week",
"month",
"meal_type",
"total"
]
}
}
}query_foods
readQuery the foods eaten · POST /api/v1/query_foods · scope insights:read or GET …?input=
What the person has eaten, grouped by food (default the last 90 days): how many times, on how many days, when last, grams and nutrients contributed. Filter by name (query), by an ingredient the items contained (ingredient, e.g. garlic or gluten-containing wheat), or meal type; sort by times, recent, grams or a nutrient (protein → top protein sources). Each food lists meal_ids to open with get_diary. Nutrients are integers: energy in millikilocalories, macros and most minerals in milligrams, some vitamins in micrograms; *_display has kcal and grams. May include `survey`: one optional question to ask the person once (record the answer with answer_survey).
curl -X POST https://getgutlog.com/api/v1/query_foods \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog query_foods{
"type": "object",
"properties": {
"from": {
"description": "First day, YYYY-MM-DD in the person's timezone (inclusive).",
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
"to": {
"description": "Last day, YYYY-MM-DD (inclusive); default today.",
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
"query": {
"description": "Only foods whose name contains this text (case-insensitive).",
"type": "string",
"maxLength": 200
},
"ingredient": {
"description": "Only items that contained this canonical ingredient (included or confirmed).",
"type": "string",
"minLength": 1,
"maxLength": 100
},
"meal_type": {
"type": "string",
"enum": [
"breakfast",
"lunch",
"dinner",
"snack",
"drink"
]
},
"sort": {
"default": "times",
"description": "times (default), recent, grams, or a nutrient key such as protein (most contributed first).",
"type": "string",
"enum": [
"times",
"recent",
"grams",
"energy",
"protein",
"carbs",
"fat",
"saturated_fat",
"trans_fat",
"fiber",
"sugar",
"added_sugar",
"sodium",
"cholesterol",
"potassium",
"calcium",
"iron",
"magnesium",
"zinc",
"vitamin_c",
"vitamin_a",
"vitamin_d",
"vitamin_b12",
"folate",
"caffeine"
]
},
"limit": {
"default": 50,
"type": "integer",
"minimum": 1,
"maximum": 200
}
}
}audit_diary
readAudit the diary · POST /api/v1/audit_diary · scope insights:read or GET …?input=
Checks the diary before you trust it (default the last 14 days, at most 92): days with missing meals, meals flagged for review and possible ingredients nobody confirmed, low-confidence matches, implausible portions, days with meals but no symptom log, and likely duplicate meals. Each finding has a severity, the day, the meal or item, and fix: {op, input, how} naming the op to call (fill in what the person tells you); fix.available is false for an op this server does not offer yet. Work top down, then run it again. A Gutlog Plus feature: on Free it answers 402 with the upgrade link, and get_diary has everything to check by hand. May include `survey`: one optional question to ask the person once (record the answer with answer_survey).
curl -X POST https://getgutlog.com/api/v1/audit_diary \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog audit_diary{
"type": "object",
"properties": {
"from": {
"description": "First day, YYYY-MM-DD in the person's timezone (inclusive).",
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
"to": {
"description": "Last day, YYYY-MM-DD (inclusive); default today.",
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
"checks": {
"description": "Which checks to run (default all): missing_meals: A day in the range with fewer than two meals logged (from the first logged day on). unconfirmed_items: A meal flagged for review, or possible ingredients still waiting for a yes or no. low_confidence: An item matched with low confidence (under 0.5): the food may be wrong. implausible_portions: An item over 3× its food's typical serving, over 2 kg, or zero grams. missing_symptoms: A day with meals but no symptom log (gut analysis needs \"fine\" days too). duplicates: Two meals with the same items within 15 minutes of each other.",
"type": "array",
"items": {
"type": "string",
"enum": [
"missing_meals",
"unconfirmed_items",
"low_confidence",
"implausible_portions",
"missing_symptoms",
"duplicates"
]
}
},
"limit": {
"default": 100,
"description": "At most this many findings, most important first.",
"type": "integer",
"minimum": 1,
"maximum": 500
}
}
}export_data
writeExport the data · POST /api/v1/export_data · scope insights:write
Exports the diary (default everything) as files: export.json (meals → items → ingredients, symptom logs, corrections and the data dictionary), meals.csv, items.csv, ingredients.csv, symptoms.csv, corrections.csv, daily.csv and README.md (the data dictionary: every file, column and unit). delivery "links" (default) returns signed download URLs that expire in an hour: give them only to the person. delivery "inline" returns README.md and export.json in the response for small ranges. Free on every plan.
curl -X POST https://getgutlog.com/api/v1/export_data \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog export_data{
"type": "object",
"properties": {
"from": {
"description": "First day, YYYY-MM-DD in the person's timezone (inclusive).",
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
"to": {
"description": "Last day, YYYY-MM-DD (inclusive); default today.",
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
"delivery": {
"default": "links",
"description": "links (default): signed download URLs valid 60 minutes. inline: the README and export.json in the response, for ranges under 512 KB.",
"type": "string",
"enum": [
"links",
"inline"
]
}
}
}get_goals
readGet nutrition goals · POST /api/v1/get_goals · scope insights:read or GET …?input=
The person's daily nutrition goals (calories, protein, carbs, fat, fiber, sugars, saturated fat, sodium) as stored integers and in kcal and grams. get_nutrition_summary compares against them. Nutrients are integers: energy in millikilocalories, macros and most minerals in milligrams, some vitamins in micrograms; *_display has kcal and grams.
curl -X POST https://getgutlog.com/api/v1/get_goals \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog get_goals{
"type": "object",
"properties": {}
}set_goals
writeSet nutrition goals · POST /api/v1/set_goals · scope insights:write
Sets daily goals in the units people use: calories (kcal), protein_g, carbs_g, fat_g, fiber_g, sugar_g, added_sugar_g, saturated_fat_g, sodium_mg. Fields you leave out stay as they are (replace: true clears them); null removes one. Sugars, saturated fat and sodium are limits, the rest targets. Only the person's own numbers: never invent goals, and suggest a registered dietitian for medical diets.
curl -X POST https://getgutlog.com/api/v1/set_goals \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog set_goals{
"type": "object",
"properties": {
"calories": {
"description": "Daily energy goal in kcal; null removes it.",
"anyOf": [
{
"type": "number",
"minimum": 0,
"maximum": 20000
},
{
"type": "null"
}
]
},
"protein_g": {
"description": "Daily protein goal in g; null removes it.",
"anyOf": [
{
"type": "number",
"minimum": 0,
"maximum": 1000
},
{
"type": "null"
}
]
},
"carbs_g": {
"description": "Daily carbs goal in g; null removes it.",
"anyOf": [
{
"type": "number",
"minimum": 0,
"maximum": 2000
},
{
"type": "null"
}
]
},
"fat_g": {
"description": "Daily fat goal in g; null removes it.",
"anyOf": [
{
"type": "number",
"minimum": 0,
"maximum": 1000
},
{
"type": "null"
}
]
},
"fiber_g": {
"description": "Daily fiber goal in g; null removes it.",
"anyOf": [
{
"type": "number",
"minimum": 0,
"maximum": 500
},
{
"type": "null"
}
]
},
"sugar_g": {
"description": "Daily sugar goal in g; null removes it.",
"anyOf": [
{
"type": "number",
"minimum": 0,
"maximum": 1000
},
{
"type": "null"
}
]
},
"added_sugar_g": {
"description": "Daily added sugar goal in g; null removes it.",
"anyOf": [
{
"type": "number",
"minimum": 0,
"maximum": 1000
},
{
"type": "null"
}
]
},
"saturated_fat_g": {
"description": "Daily saturated fat goal in g; null removes it.",
"anyOf": [
{
"type": "number",
"minimum": 0,
"maximum": 500
},
{
"type": "null"
}
]
},
"sodium_mg": {
"description": "Daily sodium goal in mg; null removes it.",
"anyOf": [
{
"type": "number",
"minimum": 0,
"maximum": 50000
},
{
"type": "null"
}
]
},
"replace": {
"default": false,
"description": "Clear every goal not given in this call (default: keep them).",
"type": "boolean"
}
}
}get_survey
readGet the survey to ask · POST /api/v1/get_survey · scope insights:read or GET …?input=
The one-question survey due for this person, if any (at most one a week, never one they answered): {survey: {id, question, kind, scale | choices, how}} or {survey: null}. Ask it in your own words when it fits the conversation, then record the answer with answer_survey. Reads that are due one include it as `survey` already.
curl -X POST https://getgutlog.com/api/v1/get_survey \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog get_survey{
"type": "object",
"properties": {}
}answer_survey
writeAnswer a survey · POST /api/v1/answer_survey · scope insights:write
Records the person's answer to a survey (logging_ease, accuracy, pmf, next_improvement, nps, cancel): a number on the survey's scale or one of its choice ids, plus anything else they said as comment. Only their answer, never yours; if they declined, do not call it.
curl -X POST https://getgutlog.com/api/v1/answer_survey \ -H "Authorization: Bearer gutlog_…" \ -H "Content-Type: application/json" \ -d '{"survey":"logging_ease","answer":-9007199254740991}'npx @meterapp/gutlog answer_survey --json '{"survey":"logging_ease","answer":-9007199254740991}'{
"type": "object",
"properties": {
"survey": {
"type": "string",
"enum": [
"logging_ease",
"accuracy",
"pmf",
"next_improvement",
"nps",
"cancel"
],
"description": "The survey id from get_survey (or a read's `survey`)."
},
"answer": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "string",
"minLength": 1,
"maxLength": 100
}
],
"description": "A whole number on the scale, or a choice id."
},
"comment": {
"description": "Anything else they said, in their words.",
"type": "string",
"maxLength": 2000
}
},
"required": [
"survey",
"answer"
]
}Get query privacy · POST /api/v1/get_query_privacy · scope insights:read or GET …?input=
Whether Gutlog keeps the words of free-text requests (keep_raw_queries, off by default) and what it keeps either way.
curl -X POST https://getgutlog.com/api/v1/get_query_privacy \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog get_query_privacy{
"type": "object",
"properties": {}
}update_query_privacy
writeUpdate query privacy · POST /api/v1/update_query_privacy · scope insights:write
Whether Gutlog may keep the words of free-text requests (a search, a meal description) to improve how it understands them. Off by default: without it only the op, the client, timing, outcome and an intent category are kept, never the words. Only the person may turn it on; never on your own.
curl -X POST https://getgutlog.com/api/v1/update_query_privacy \ -H "Authorization: Bearer gutlog_…" \ -H "Content-Type: application/json" \ -d '{"keep_raw_queries":false}'npx @meterapp/gutlog update_query_privacy --json '{"keep_raw_queries":false}'{
"type": "object",
"properties": {
"keep_raw_queries": {
"type": "boolean",
"description": "true keeps the words of free-text requests; false (default) never stores them."
}
},
"required": [
"keep_raw_queries"
]
}get_query_report
readGet the query analytics report · POST /api/v1/get_query_report · scope insights:read or GET …?input=
Gutlog team only. How people query their data, across every organization, for the last week by default: op calls by op, surface, client (chatgpt, claude, cursor, cli…) and intent, latency, failures by error code, empty and rephrased calls, the ops nobody called, analysis ratings and survey results (NPS, product-market fit), plus highlights for the weekly post. Counts only: never anyone's food, symptoms or words.
curl -X POST https://getgutlog.com/api/v1/get_query_report \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog get_query_report{
"type": "object",
"properties": {
"days": {
"default": 7,
"description": "How many days back from `until` (default 7: the weekly report).",
"type": "integer",
"minimum": 1,
"maximum": 90
},
"until": {
"description": "End of the window (exclusive), ISO 8601; default now.",
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
}
}
}