Gut API
Symptoms, tummy scores, exposures and suspected triggers. 11 ops: log_symptoms, list_symptom_logs, delete_symptom_log, get_tummy_scores, get_pending_checkins, set_checkin_preferences, get_exposures, get_triggers, food_tummy_score, check_ingredients, get_low_fodmap_swaps.
Symptoms, tummy scores, exposures and suspected triggers.
log_symptoms
writeLog symptoms · POST /api/v1/log_symptoms · scope gut:write
Record how the person's gut feels: severity 0–10 for bloating, abdominal_pain, gas, nausea, reflux and urgency (only the ones they mention), an overall severity, Bristol stool type 1–7, bowel movements today, energy 0–10, and the time. "Fine" is a valid and valuable log: send fine: true. Best 2–4 hours after a meal and in the evening (get_pending_checkins says which check-in is due; pass its key as prompt). Returns the log id and today's tummy score (0–100, higher is better). Free.
curl -X POST https://getgutlog.com/api/v1/log_symptoms \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog log_symptoms{
"type": "object",
"properties": {
"occurred_at": {
"description": "When the person felt this (ISO 8601 with offset). Default now. For \"after lunch\", use the time they mean.",
"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)))$"
},
"fine": {
"description": "True when the person feels fine: no gut symptoms. A fine log is as useful as a bad one: it is the comparison the trigger analysis needs.",
"type": "boolean"
},
"symptoms": {
"description": "Severity per symptom: bloating, abdominal_pain, gas, nausea, reflux, urgency. Only the ones the person mentioned.",
"type": "object",
"properties": {
"bloating": {
"type": "integer",
"minimum": 0,
"maximum": 10,
"description": "bloating, 0 (none) to 10 (worst imaginable)."
},
"abdominal_pain": {
"type": "integer",
"minimum": 0,
"maximum": 10,
"description": "abdominal pain, 0 (none) to 10 (worst imaginable)."
},
"gas": {
"type": "integer",
"minimum": 0,
"maximum": 10,
"description": "gas, 0 (none) to 10 (worst imaginable)."
},
"nausea": {
"type": "integer",
"minimum": 0,
"maximum": 10,
"description": "nausea, 0 (none) to 10 (worst imaginable)."
},
"reflux": {
"type": "integer",
"minimum": 0,
"maximum": 10,
"description": "reflux, 0 (none) to 10 (worst imaginable)."
},
"urgency": {
"type": "integer",
"minimum": 0,
"maximum": 10,
"description": "urgency, 0 (none) to 10 (worst imaginable)."
}
}
},
"severity": {
"type": "integer",
"minimum": 0,
"maximum": 10,
"description": "Overall gut discomfort right now, 0 (none) to 10 (worst imaginable)."
},
"bristol": {
"description": "Bristol stool form of the latest bowel movement: 1 separate hard lumps … 4 smooth soft sausage … 7 entirely liquid.",
"type": "integer",
"minimum": 1,
"maximum": 7
},
"stool_count": {
"description": "Bowel movements so far today.",
"type": "integer",
"minimum": 0,
"maximum": 30
},
"energy": {
"type": "integer",
"minimum": 0,
"maximum": 10,
"description": "Energy (0 exhausted, 10 great), 0 (none) to 10 (worst imaginable)."
},
"note": {
"description": "The person's own words, if they want them kept.",
"type": "string",
"maxLength": 2000
},
"prompt": {
"description": "The check-in this answers, from get_pending_checkins (e.g. meal:<id> or evening:2026-11-03).",
"type": "string",
"maxLength": 80
}
},
"description": "One symptom check-in."
}List symptom logs · POST /api/v1/list_symptom_logs · scope gut:read or GET …?input=
Symptom logs in a date range (default the last 14 days), newest first: severities per symptom, overall, Bristol type, stool count, energy, fine, and each log's burden (0–10).
curl -X POST https://getgutlog.com/api/v1/list_symptom_logs \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog list_symptom_logs{
"type": "object",
"properties": {
"from": {
"description": "First day, YYYY-MM-DD in the person's timezone.",
"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 (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])))$"
},
"limit": {
"default": 100,
"type": "integer",
"minimum": 1,
"maximum": 500
}
}
}delete_symptom_log
writeDelete a symptom log · POST /api/v1/delete_symptom_log · scope gut:write
Delete one symptom log the person logged by mistake, and recompute that day's tummy score.
curl -X POST https://getgutlog.com/api/v1/delete_symptom_log \ -H "Authorization: Bearer gutlog_…" \ -H "Content-Type: application/json" \ -d '{"symptom_log_id":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'npx @meterapp/gutlog delete_symptom_log --json '{"symptom_log_id":"6f1c2e0a-4b7d-4c2e-9a51-0d3b8e7f9a10"}'{
"type": "object",
"properties": {
"symptom_log_id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "Symptom log id (symptom_logs.id)."
}
},
"required": [
"symptom_log_id"
]
}get_tummy_scores
readGet tummy scores · POST /api/v1/get_tummy_scores · scope gut:read or GET …?input=
Daily tummy scores 0–100 (100 = no gut symptoms) for a date range, default the last 30 days: per day the score, number of logs, fine logs, worst symptom and Bristol types, plus the average and the trend (second half minus first half). Our own score from the person's logs, not a clinical instrument. Free.
curl -X POST https://getgutlog.com/api/v1/get_tummy_scores \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog get_tummy_scores{
"type": "object",
"properties": {
"from": {
"description": "First day, YYYY-MM-DD in the person's timezone.",
"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 (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])))$"
}
}
}Get pending check-ins · POST /api/v1/get_pending_checkins · scope gut:read or GET …?input=
Check-ins due now: one 2–4 hours after each logged meal, an evening check-in, today's reintroduction challenge dose and the weekly adequate-relief question when a program is running. Each has a key and the question to ask. Call it at the start of a chat and ask the person; then log_symptoms with prompt set to the key (or record_challenge / record_relief_check). Empty when nothing is due.
curl -X POST https://getgutlog.com/api/v1/get_pending_checkins \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog get_pending_checkins{
"type": "object",
"properties": {}
}Set check-in preferences · POST /api/v1/set_checkin_preferences · scope gut:write
Turn check-in emails on or off (off, evening only, or also 2–4 h after each meal and program reminders) and set the local hour of the evening check-in (17–23). Emails go to the organization owner's address and carry no food or symptom details. Emails are Plus; turning them off and the hour work on every plan.
curl -X POST https://getgutlog.com/api/v1/set_checkin_preferences \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog set_checkin_preferences{
"type": "object",
"properties": {
"checkin_email": {
"description": "off, evening (one a day), or all (also after meals, at most three a day).",
"type": "string",
"enum": [
"off",
"evening",
"all"
]
},
"evening_hour": {
"description": "Local hour the evening check-in is due; default 20.",
"type": "integer",
"minimum": 17,
"maximum": 23
}
}
}get_exposures
readGet exposures · POST /api/v1/get_exposures · scope gut:read or GET …?input=
What the person was exposed to, per meal and per day, for a date range (default the last 7 days, at most 92): FODMAP subgroups (fructans, GOS, lactose, excess fructose, sorbitol, mannitol), gluten, dairy protein, caffeine, alcohol, fat load, capsaicin, carbonation, sugar alcohols, emulsifiers, insoluble fiber and high-histamine foods, each with the level a typical serving carries and the ingredients that brought it, plus a summary per exposure. From the meals' confirmed and likely ingredients. Free.
curl -X POST https://getgutlog.com/api/v1/get_exposures \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog get_exposures{
"type": "object",
"properties": {
"from": {
"description": "First day, YYYY-MM-DD in the person's timezone.",
"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 (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])))$"
}
}
}get_triggers
readGet suspected triggers · POST /api/v1/get_triggers · scope gut:read or GET …?input=
Which foods look safe for this person and which don't, from their own log: for each exposure, the estimated extra symptom severity (0–10 points) in that exposure's time window after eating, the probability it is a real effect, and how many meals it rests on; or "not_enough_data" (fewer than 5 exposure meals followed by a check-in), "inconclusive", "unlikely", or "confirmed"/"ruled_out" from a reintroduction challenge. Each has an explanation to relay. These are hypotheses to test with an elimination program, never a diagnosis. Plus plan.
curl -X POST https://getgutlog.com/api/v1/get_triggers \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog get_triggers{
"type": "object",
"properties": {
"include_all": {
"default": false,
"description": "Also list exposures the person has not eaten yet.",
"type": "boolean"
}
}
}food_tummy_score
readFood tummy score · POST /api/v1/food_tummy_score · scope gut:read or GET …?input=
Predicted gut-friendliness 0–100 of a food, a barcode product or a list of taxonomy ingredients for this person (100 = nothing we expect to bother them), with the exposures behind it and their citations. With enough logs it uses the person's own trigger estimates; until then population averages (basis says which). A prediction, not a rule. Plus plan.
curl -X POST https://getgutlog.com/api/v1/food_tummy_score \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog food_tummy_score{
"type": "object",
"properties": {
"food_id": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "Canonical food id from search_foods (e.g. usda:171287 or seed:banana-raw)."
},
"barcode": {
"description": "A GTIN/EAN/UPC barcode.",
"type": "string",
"minLength": 6,
"maxLength": 14
},
"ingredient_ids": {
"description": "Taxonomy ingredient ids, e.g. [\"garlic\", \"wheat-flour\"].",
"maxItems": 50,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "Canonical ingredient id from the taxonomy (e.g. garlic, natural-flavors)."
}
}
}
}Check ingredients for triggers · POST /api/v1/check_ingredients · scope gut:read or GET …?input=
Which of these ingredients (taxonomy ids or names) are the person's known or suspected triggers or allergens, with the exposures involved and low-FODMAP swaps. Use it before suggesting a meal, or on a product's ingredient list. Known triggers and allergens come from the person's settings; suspected ones from get_triggers.
curl -X POST https://getgutlog.com/api/v1/check_ingredients \ -H "Authorization: Bearer gutlog_…" \ -H "Content-Type: application/json" \ -d '{"ingredients":["ingredient"]}'npx @meterapp/gutlog check_ingredients --json '{"ingredients":["ingredient"]}'{
"type": "object",
"properties": {
"ingredients": {
"minItems": 1,
"maxItems": 100,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"description": "Ingredient ids (garlic) or names (\"onion powder\")."
}
},
"required": [
"ingredients"
]
}Get low-FODMAP swaps · POST /api/v1/get_low_fodmap_swaps · scope gut:read or GET …?input=
Lower-FODMAP alternatives for an ingredient or a food (its ingredients), with the FODMAP subgroups each one avoids and the published sources. Useful during the elimination phase. Not a substitute for a registered dietitian's plan.
curl -X POST https://getgutlog.com/api/v1/get_low_fodmap_swaps \ -H "Authorization: Bearer gutlog_…"npx @meterapp/gutlog get_low_fodmap_swaps{
"type": "object",
"properties": {
"ingredient": {
"description": "Ingredient id or name.",
"type": "string",
"minLength": 1,
"maxLength": 100
},
"food_id": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "Canonical food id from search_foods (e.g. usda:171287 or seed:banana-raw)."
}
}
}