{"openapi":"3.1.0","info":{"title":"Gutlog API","version":"1","summary":"The food and gut database your AI assistant writes to","description":"Gutlog logs what you eat from a photo in ChatGPT or Claude: calories, macros, nutrients and ingredients with a confidence score you can fix in one tap. Clean-ingredient verdicts, organic advice, a barcode index, tummy scores, trigger analysis and elimination diets, from the web app, MCP, the CLI or the API.\n\nEvery op is POST /api/v1/{op} with its input as a JSON body. The same ops are MCP tools at https://getgutlog.com/api/mcp and CLI commands (npx @meterapp/gutlog). Errors are RFC 9457 problem details; see https://getgutlog.com/docs/errors.","contact":{"name":"Meter","email":"jonathan@getgutlog.com","url":"https://getgutlog.com/docs"}},"servers":[{"url":"https://getgutlog.com"}],"externalDocs":{"description":"API reference","url":"https://getgutlog.com/docs/api"},"security":[{"bearerAuth":[]}],"tags":[{"name":"meta","description":"The API catalog."},{"name":"meals","description":"Meals and diary: Log meals from a draft, a photo, text or a barcode; read and fix the diary."},{"name":"foods","description":"Foods: Search the food database and your personal foods; nutrients per portion."},{"name":"products","description":"Products: The barcode index: look up, scan labels and submit products."},{"name":"clean","description":"Clean and organic: Clean-ingredient verdicts, profiles, swaps and organic advice."},{"name":"gut","description":"Gut: Symptoms, tummy scores, exposures and suspected triggers."},{"name":"programs","description":"Programs: Elimination diet programs: safety screen, phases and challenges."},{"name":"insights","description":"Insights: Summaries, diary audits, exports and analysis ratings."},{"name":"events","description":"Events: Your account's event stream."},{"name":"organization","description":"Account: Settings, onboarding and the activity log."},{"name":"members","description":"Members and sharing: Members, teams and the audit log."},{"name":"keys","description":"API keys: Keys for the CLI, scripts and MCP clients without OAuth."},{"name":"billing","description":"Billing: Plans, prices, checkout links and the subscription."},{"name":"profile","description":"Profile: Your own name and email preferences."},{"name":"feedback","description":"Feedback: Request features, report issues and upvote what matters to you."}],"paths":{"/api/v1":{"get":{"operationId":"list_ops","summary":"List every op","description":"The machine-readable catalog of every op with its input JSON Schema. Public; needs no credential.","tags":["meta"],"security":[],"responses":{"200":{"description":"The op catalog.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpsManifest"}}}}}}},"/api/v1/get_organization":{"post":{"operationId":"get_organization","summary":"Get organization","description":"The organization this credential acts in (a person's own diary is their personal organization): id, slug, name, timezone (the diary day boundary) and language, and the caller's role. Call first to orient yourself; get_account adds the plan and usage.","tags":["organization"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"organization:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_organization_get","summary":"Get organization (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. The organization this credential acts in (a person's own diary is their personal organization): id, slug, name, timezone (the diary day boundary) and language, and the caller's role. Call first to orient yourself; get_account adds the plan and usage.","tags":["organization"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/update_organization":{"post":{"operationId":"update_organization","summary":"Update organization","description":"Change the organization's name, default timezone (IANA, e.g. Europe/Madrid: where a diary day starts and ends, reminder times) or default language (BCP 47: emails and reports). Owners and admins.","tags":["organization"],"x-read-only":false,"x-admin-only":true,"x-min-role":"admin","x-scope":"organization:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"timezone":{"type":"string","maxLength":64},"default_locale":{"type":"string","minLength":2,"maxLength":35}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/list_activity":{"post":{"operationId":"list_activity","summary":"List activity","description":"Every change made through the platform, newest first: who (a person, an API key, an AI agent, a worker), from which surface (dashboard, api, mcp, cli, worker, ai) and what. The audit log (list_audit_log) has the sensitive changes with their details.","tags":["organization"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"organization:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"limit":{"default":50,"description":"Page size, at most 200.","type":"integer","minimum":1,"maximum":200},"offset":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"list_activity_get","summary":"List activity (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Every change made through the platform, newest first: who (a person, an API key, an AI agent, a worker), from which surface (dashboard, api, mcp, cli, worker, ai) and what. The audit log (list_audit_log) has the sensitive changes with their details.","tags":["organization"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_onboarding":{"post":{"operationId":"get_onboarding","summary":"Get onboarding checklist","description":"The person's setup checklist, in order: connect their AI assistant (MCP), log a first meal, scan a barcode, log symptoms, start an elimination program. Each step has done, a one-line how-to for an agent (which op or command does it) and the dashboard path. Use it to tell a person what to do next in Gutlog.","tags":["organization"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"organization:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_onboarding_get","summary":"Get onboarding checklist (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. The person's setup checklist, in order: connect their AI assistant (MCP), log a first meal, scan a barcode, log symptoms, start an elimination program. Each step has done, a one-line how-to for an agent (which op or command does it) and the dashboard path. Use it to tell a person what to do next in Gutlog.","tags":["organization"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_referral_stats":{"post":{"operationId":"get_referral_stats","summary":"Acquisition by channel (staff)","description":"Gutlog team only. Signups and paying organizations by first-touch acquisition channel, in total and for organizations created within the last `days`. Channels: `ref:<slug>` (a link we published with ?ref=, docs/attribution.md), `utm:<source>/<medium>`, `ai` (ChatGPT, Claude, Gemini, Perplexity, Copilot), `search`, `social`, `referral:<host>`, `direct` (landed with no referrer, ref or utm) and `unknown` (opted out with DNT/GPC, signed up on another device, or before attribution existed). Paying means a live subscription on a paid plan. Also returns `refs` (signups per ?ref= slug) and `sources` (per ref, utm_source and utm_medium). Reads every organization (the only cross-organization read besides the feedback board), returns counts only, never organization names.","tags":["organization"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"organization:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"days":{"default":30,"description":"Window for the *_since counts. Default 30.","type":"integer","minimum":1,"maximum":3650}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_referral_stats_get","summary":"Acquisition by channel (staff) (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Gutlog team only. Signups and paying organizations by first-touch acquisition channel, in total and for organizations created within the last `days`. Channels: `ref:<slug>` (a link we published with ?ref=, docs/attribution.md), `utm:<source>/<medium>`, `ai` (ChatGPT, Claude, Gemini, Perplexity, Copilot), `search`, `social`, `referral:<host>`, `direct` (landed with no referrer, ref or utm) and `unknown` (opted out with DNT/GPC, signed up on another device, or before attribution existed). Paying means a live subscription on a paid plan. Also returns `refs` (signups per ?ref= slug) and `sources` (per ref, utm_source and utm_medium). Reads every organization (the only cross-organization read besides the feedback board), returns counts only, never organization names.","tags":["organization"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/list_members":{"post":{"operationId":"list_members","summary":"List members","description":"Everyone in this organization with their email, role (owner, admin, member, viewer) and teams. Read-only: inviting, removing people and changing roles are done by a person in the dashboard (Settings → Members).","tags":["members"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"members:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"list_members_get","summary":"List members (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Everyone in this organization with their email, role (owner, admin, member, viewer) and teams. Read-only: inviting, removing people and changing roles are done by a person in the dashboard (Settings → Members).","tags":["members"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/list_invites":{"post":{"operationId":"list_invites","summary":"List invites","description":"Pending invitations to this organization (email, role, teams, who invited, when it expires). Owners and admins.","tags":["members"],"x-read-only":true,"x-admin-only":true,"x-min-role":"admin","x-scope":"members:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"include_closed":{"default":false,"description":"Also list accepted, revoked and expired invites.","type":"boolean"}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"list_invites_get","summary":"List invites (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Pending invitations to this organization (email, role, teams, who invited, when it expires). Owners and admins.","tags":["members"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/list_teams":{"post":{"operationId":"list_teams","summary":"List teams","description":"Teams in this organization with their members (maintainer or member) and the resources (programs) shared with each team.","tags":["members"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"members:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"list_teams_get","summary":"List teams (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Teams in this organization with their members (maintainer or member) and the resources (programs) shared with each team.","tags":["members"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/create_team":{"post":{"operationId":"create_team","summary":"Create team","description":"Create a team (a group of members to share programs with). You become its maintainer. Members and above.","tags":["members"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"members:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"slug":{"description":"URL-safe id; derived from the name when omitted.","type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,47}$"},"description":{"default":"","type":"string","maxLength":1000}},"required":["name"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/update_team":{"post":{"operationId":"update_team","summary":"Update team","description":"Rename a team or change its description. Its maintainers, owners and admins.","tags":["members"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"members:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"team":{"type":"string","minLength":1,"maxLength":100,"description":"Team slug or id."},"name":{"type":"string","minLength":1,"maxLength":100},"description":{"type":"string","maxLength":1000}},"required":["team"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/delete_team":{"post":{"operationId":"delete_team","summary":"Delete team","description":"Delete a team. Its members stay in the organization but lose what was shared with the team.","tags":["members"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"members:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"team":{"type":"string","minLength":1,"maxLength":100,"description":"Team slug or id."}},"required":["team"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/set_team_member":{"post":{"operationId":"set_team_member","summary":"Add to team","description":"Add an organization member to a team, or change their team role (maintainer manages the team; member is in it). Its maintainers, owners and admins.","tags":["members"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"members:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"team":{"type":"string","minLength":1,"maxLength":100,"description":"Team slug or id."},"user":{"type":"string","minLength":3,"maxLength":320,"description":"An organization member's user id or email address."},"role":{"default":"member","type":"string","enum":["maintainer","member"]}},"required":["team","user"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/remove_team_member":{"post":{"operationId":"remove_team_member","summary":"Remove from team","description":"Take someone out of a team (they stay in the organization). Its maintainers, owners and admins; anyone can leave a team themselves.","tags":["members"],"x-read-only":false,"x-admin-only":false,"x-min-role":"viewer","x-scope":"members:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"team":{"type":"string","minLength":1,"maxLength":100,"description":"Team slug or id."},"user":{"type":"string","minLength":3,"maxLength":320,"description":"An organization member's user id or email address."}},"required":["team","user"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/list_resource_access":{"post":{"operationId":"list_resource_access","summary":"List resource access","description":"Who can see a shareable resource (an elimination program): its visibility (org or restricted), its creator, and every grant to a team or person with its access (read, write, admin). Owners and admins always have admin.","tags":["members"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"members:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"resource_type":{"type":"string","enum":["program"],"description":"program."},"resource_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)$"}},"required":["resource_type","resource_id"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"list_resource_access_get","summary":"List resource access (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Who can see a shareable resource (an elimination program): its visibility (org or restricted), its creator, and every grant to a team or person with its access (read, write, admin). Owners and admins always have admin.","tags":["members"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/set_resource_visibility":{"post":{"operationId":"set_resource_visibility","summary":"Set resource visibility","description":"org: every organization member sees the resource (viewers read, members write). restricted: only its creator, owners and admins, and the teams and people it is shared with (share_resource). Works on programs. Needs admin access to the resource.","tags":["members"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"members:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"resource_type":{"type":"string","enum":["program"],"description":"program."},"resource_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)$"},"visibility":{"type":"string","enum":["org","restricted"]}},"required":["resource_type","resource_id","visibility"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/share_resource":{"post":{"operationId":"share_resource","summary":"Share resource","description":"Give a team or a person read, write or admin access to a program (replacing what that team or person had). read: see it and its data; write: change it (log check-ins, advance phases); admin: also change its settings and who it is shared with. Viewers never get past read. Needs admin access to the resource.","tags":["members"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"members:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"resource_type":{"type":"string","enum":["program"],"description":"program."},"resource_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)$"},"team":{"type":"string","minLength":1,"maxLength":100,"description":"Team slug or id."},"user":{"type":"string","minLength":3,"maxLength":320,"description":"An organization member's user id or email address."},"access":{"type":"string","enum":["read","write","admin"]}},"required":["resource_type","resource_id","access"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/unshare_resource":{"post":{"operationId":"unshare_resource","summary":"Unshare resource","description":"Remove a team's or person's grant on a program. They keep whatever their organization role gives them (nothing, on a restricted resource). Needs admin access to the resource.","tags":["members"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"members:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"resource_type":{"type":"string","enum":["program"],"description":"program."},"resource_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)$"},"team":{"type":"string","minLength":1,"maxLength":100,"description":"Team slug or id."},"user":{"type":"string","minLength":3,"maxLength":320,"description":"An organization member's user id or email address."}},"required":["resource_type","resource_id"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/list_audit_log":{"post":{"operationId":"list_audit_log","summary":"List audit log","description":"Membership, role, team, invite, API key, billing, settings and sharing changes in this organization, newest first: who (a person, an API key, an OAuth client or the system), what, to what, and when. Owners and admins. The activity log (list_activity) has content changes.","tags":["members"],"x-read-only":true,"x-admin-only":true,"x-min-role":"admin","x-scope":"members:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"description":"Only this action or prefix, e.g. member. or invite.accepted.","type":"string","maxLength":100},"limit":{"default":50,"description":"Page size, at most 200.","type":"integer","minimum":1,"maximum":200},"offset":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"list_audit_log_get","summary":"List audit log (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Membership, role, team, invite, API key, billing, settings and sharing changes in this organization, newest first: who (a person, an API key, an OAuth client or the system), what, to what, and when. Owners and admins. The activity log (list_activity) has content changes.","tags":["members"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/list_api_keys":{"post":{"operationId":"list_api_keys","summary":"List API keys","description":"API keys of this organization (prefix only; the full key is shown once at creation), each with the role it acts with, its scopes and who created it. Owners and admins see every key; members see their own. Also returns available_scopes.","tags":["keys"],"x-read-only":true,"x-admin-only":false,"x-min-role":"member","x-scope":"keys:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"list_api_keys_get","summary":"List API keys (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. API keys of this organization (prefix only; the full key is shown once at creation), each with the role it acts with, its scopes and who created it. Owners and admins see every key; members see their own. Also returns available_scopes.","tags":["keys"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/create_api_key":{"post":{"operationId":"create_api_key","summary":"Create API key","description":"Create an organization API key for your backend, the CLI, an MCP host or CI. It acts with your role (an owner's key acts as admin), optionally narrowed to scopes, and keeps working if you leave the organization; admins can revoke it. The full key (gutlog_…) is returned only once; store it as a secret and never ship it to a browser or app.","tags":["keys"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"keys:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"scopes":{"default":[],"description":"Narrow the key to these scopes: `<group>:read`, `<group>:write`, `<group>:*`, `*:read`, or `billing:purchase` (groups: meals, foods, products, clean, gut, programs, insights, billing…). Empty (default): everything the key's role allows.","maxItems":64,"type":"array","items":{"type":"string"}},"expires_in_days":{"description":"Expire the key after this many days. Default: never.","type":"integer","minimum":1,"maximum":3650}},"required":["name"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/revoke_api_key":{"post":{"operationId":"revoke_api_key","summary":"Revoke API key","description":"Revoke an API key immediately; every backend, CLI, CI job or MCP host using it stops working. Owners and admins revoke any key; members their own.","tags":["keys"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"keys:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"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)$"}},"required":["key"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_pricing":{"post":{"operationId":"get_pricing","summary":"Get pricing","description":"The plans (Free, Plus): price {monthly, yearly} in USD, photo/text analyses on our model included per day (logging a meal you analyzed yourself, barcode scans and edits are free and unlimited), limits (members, history days; null is unlimited), features, a checkout_url per paid plan, and how_to_buy. The same document as GET /api/v1/pricing; needs no credential (REST, the catalog MCP server at /api/mcp/catalog, `gutlog pricing`). Call before recommending or buying a plan.","tags":["billing"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"billing:read","security":[{},{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_pricing_get","summary":"Get pricing (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. The plans (Free, Plus): price {monthly, yearly} in USD, photo/text analyses on our model included per day (logging a meal you analyzed yourself, barcode scans and edits are free and unlimited), limits (members, history days; null is unlimited), features, a checkout_url per paid plan, and how_to_buy. The same document as GET /api/v1/pricing; needs no credential (REST, the catalog MCP server at /api/mcp/catalog, `gutlog pricing`). Call before recommending or buying a plan.","tags":["billing"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_account":{"post":{"operationId":"get_account","summary":"Get account","description":"Who this credential acts for and what it may use: the organization, your role in it (viewer, member, admin, owner) and whether you are a person, an OAuth client or an API key (acting_as, with the key's scopes), the plan in force (status, interval, renewal or end date), today's usage against the daily allowance (analyses) with what remains and when it resets, and next_tier: what the next plan adds, its price and a checkout_url. Same data as GET /api/v1/account and `gutlog account`. Call when a human asks about their plan or an analysis was refused for the daily limit.","tags":["billing"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"billing:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_account_get","summary":"Get account (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Who this credential acts for and what it may use: the organization, your role in it (viewer, member, admin, owner) and whether you are a person, an OAuth client or an API key (acting_as, with the key's scopes), the plan in force (status, interval, renewal or end date), today's usage against the daily allowance (analyses) with what remains and when it resets, and next_tier: what the next plan adds, its price and a checkout_url. Same data as GET /api/v1/account and `gutlog account`. Call when a human asks about their plan or an analysis was refused for the daily limit.","tags":["billing"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_billing":{"post":{"operationId":"get_billing","summary":"Get billing","description":"This organization's plan, subscription status, renewal or end date, whether a card is saved (so subscribe can charge it), and today's usage against the plan (analyses, members). Pass refresh: true right after a human finished a checkout to pull the latest state from Stripe.","tags":["billing"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"billing:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"refresh":{"default":false,"description":"Re-read the subscription from Stripe instead of the stored copy.","type":"boolean"}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_billing_get","summary":"Get billing (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. This organization's plan, subscription status, renewal or end date, whether a card is saved (so subscribe can charge it), and today's usage against the plan (analyses, members). Pass refresh: true right after a human finished a checkout to pull the latest state from Stripe.","tags":["billing"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/create_checkout_link":{"post":{"operationId":"create_checkout_link","summary":"Create checkout link","description":"A Stripe Checkout URL where a human pays for a plan; hand it to them (or open it in their browser). Works before signup: with no credential (REST, the catalog MCP server, `gutlog upgrade` before login) the human pays first, then signs in with the same email and the plan attaches to their organization. Nothing is charged and the plan does not change until they complete it; then get_billing {refresh: true} shows the new plan. The link expires after 24 hours. If the organization already has a subscription, the URL is a Stripe page where they confirm the plan change instead. Returns {url, kind: checkout | plan_change, plan, interval, amount_cents, expires_at, session_id}. Never collect card details yourself.","tags":["billing"],"x-read-only":false,"x-admin-only":true,"x-min-role":"admin","x-scope":"billing:write","security":[{},{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"plan":{"type":"string","enum":["plus"],"description":"plus. get_pricing lists what it includes."},"interval":{"default":"month","description":"month ($8), or year ($60).","type":"string","enum":["month","year"]},"ref":{"description":"Optional attribution slug for the link (e.g. agent-cursor). Defaults to the surface: agent-mcp, agent-cli or agent-api.","type":"string","pattern":"^[a-z0-9][a-z0-9_-]{0,39}$"}},"required":["plan"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/subscribe":{"post":{"operationId":"subscribe","summary":"Subscribe","description":"Start or change this organization's paid plan in one call, charging the card already saved for the organization. Only after a human approved this plan and price: confirm must be true. Without a saved card (or if the card needs the human, e.g. 3-D Secure) nothing is charged and it returns status checkout_required with a checkout_url for a human to finish. A plan change is prorated and invoiced immediately. Returns {status: subscribed | changed | unchanged | checkout_required, billing}.","tags":["billing"],"x-read-only":false,"x-admin-only":true,"x-min-role":"admin","x-scope":"billing:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"plan":{"type":"string","enum":["plus"],"description":"plus. get_pricing lists what it includes."},"interval":{"default":"month","description":"month ($8), or year ($60).","type":"string","enum":["month","year"]},"confirm":{"type":"boolean","const":true,"description":"Must be true: a human has seen the plan and price and asked you to buy it. Never set it on your own initiative."}},"required":["plan","confirm"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/cancel_subscription":{"post":{"operationId":"cancel_subscription","summary":"Cancel subscription","description":"Cancel the paid plan at the end of the current period (no refund; the plan stays until then, then the organization is on Free). Only when a human asked: confirm must be true. Every cancellation records why: ask the human for the reason (or prefer_not_to_say) and any comment in their words. resume_subscription undoes it before the period ends.","tags":["billing"],"x-read-only":false,"x-admin-only":true,"x-min-role":"admin","x-scope":"billing:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"confirm":{"type":"boolean","const":true,"description":"Must be true: a human has seen the plan and price and asked you to buy it. Never set it on your own initiative."},"reason":{"type":"string","enum":["too_expensive","not_using","missing_feature","accuracy","logging_effort","switched","privacy","temporary","other","prefer_not_to_say"],"description":"Why they are cancelling: too_expensive (Too expensive), not_using (Not using it enough), missing_feature (Missing a feature I need), accuracy (Nutrition or ingredients were not accurate enough), logging_effort (Logging took too much effort), switched (Switched to another app), privacy (Privacy concerns), temporary (Only needed it for a while), other (Something else), prefer_not_to_say (Prefer not to say)."},"comment":{"description":"Anything else they said about why, in their words.","type":"string","maxLength":2000}},"required":["confirm","reason"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/resume_subscription":{"post":{"operationId":"resume_subscription","summary":"Resume subscription","description":"Undo a cancellation that has not taken effect yet, so the plan renews as before. Nothing is charged until the normal renewal date.","tags":["billing"],"x-read-only":false,"x-admin-only":true,"x-min-role":"admin","x-scope":"billing:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/claim_checkout":{"post":{"operationId":"claim_checkout","summary":"Claim checkout","description":"Attach a checkout paid before signup (create_checkout_link without a credential) to this organization, by its session_id (cs_…). Usually automatic: returning from Stripe, or signing up with the email used at checkout, claims it. Call it when a human paid first and the plan has not appeared. Returns {outcome: claimed | already_yours, billing}.","tags":["billing"],"x-read-only":false,"x-admin-only":true,"x-min-role":"admin","x-scope":"billing:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"session_id":{"type":"string","pattern":"^cs_(live|test)_[A-Za-z0-9]+$","description":"The Checkout Session id create_checkout_link returned (cs_live_… or cs_test_…)."}},"required":["session_id"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/create_billing_portal_link":{"post":{"operationId":"create_billing_portal_link","summary":"Create billing portal link","description":"A private Stripe page where a human downloads invoices, updates the card or billing details, or cancels. The link is for a human and expires after a few minutes of inactivity; never open it on your own.","tags":["billing"],"x-read-only":false,"x-admin-only":true,"x-min-role":"admin","x-scope":"billing:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_billing_link":{"post":{"operationId":"get_billing_link","summary":"Get billing link","description":"The Stripe customer portal for a human: invoices, card and billing details, plan change and cancellation. The same as create_billing_portal_link, under the name every Meter product uses (POST /api/v1/billing/portal, `gutlog billing portal`). The link expires after a few minutes of inactivity; never open it on your own.","tags":["billing"],"x-read-only":false,"x-admin-only":true,"x-min-role":"admin","x-scope":"billing:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/list_feedback":{"post":{"operationId":"list_feedback","summary":"List feature requests and issues","description":"The Gutlog feedback board: feature requests every customer can see, plus your own issue reports (and ones the team published), with status and upvotes, most upvoted first. Each item says whether your organization voted for it or filed it. Call it before request_feature or report_issue to find an existing item to upvote instead of filing a duplicate, or when the human asks what is planned. Works without a credential (public items only).","tags":["feedback"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"feedback:read","security":[{},{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"default":"all","description":"feature = feature requests, issue = bug reports (yours, and ones the team published).","type":"string","enum":["feature","issue","all"]},"status":{"default":"active","description":"active = open, planned, in_progress.","type":"string","enum":["active","all","open","planned","in_progress","done","declined","duplicate"]},"sort":{"default":"top","description":"top = most upvoted, new = most recent, recent_activity = latest vote, comment or status change.","type":"string","enum":["top","new","recent_activity"]},"q":{"description":"Words to find in the title.","type":"string","maxLength":100},"mine":{"default":false,"description":"Only items your organization filed.","type":"boolean"},"limit":{"default":20,"description":"Page size, at most 100.","type":"integer","minimum":1,"maximum":100},"offset":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991},"cursor":{"description":"next_cursor from the previous page (same as offset).","type":"string","pattern":"^\\d+$"}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"list_feedback_get","summary":"List feature requests and issues (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. The Gutlog feedback board: feature requests every customer can see, plus your own issue reports (and ones the team published), with status and upvotes, most upvoted first. Each item says whether your organization voted for it or filed it. Call it before request_feature or report_issue to find an existing item to upvote instead of filing a duplicate, or when the human asks what is planned. Works without a credential (public items only).","tags":["feedback"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_feedback":{"post":{"operationId":"get_feedback","summary":"Get a feature request or issue","description":"One feedback item with its status, upvotes, comments (oldest first; official answers from the Gutlog team are marked `official`) and its timeline of status changes with the team's notes. Your own issues include the context you attached.","tags":["feedback"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"feedback:read","security":[{},{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The item's id from list_feedback, request_feature or report_issue (e.g. 42)."}},"required":["id"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_feedback_get","summary":"Get a feature request or issue (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. One feedback item with its status, upvotes, comments (oldest first; official answers from the Gutlog team are marked `official`) and its timeline of status changes with the team's notes. Your own issues include the context you attached.","tags":["feedback"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/list_my_feedback":{"post":{"operationId":"list_my_feedback","summary":"List my feedback and subscriptions","description":"What your organization filed (every status), the items you get email about (filed, upvoted, commented, followed) with whether you muted them, your organization's review, and whether feedback email reaches you. Use it to follow up on earlier reports.","tags":["feedback"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"feedback:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"list_my_feedback_get","summary":"List my feedback and subscriptions (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. What your organization filed (every status), the items you get email about (filed, upvoted, commented, followed) with whether you muted them, your organization's review, and whether feedback email reaches you. Use it to follow up on earlier reports.","tags":["feedback"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/request_feature":{"post":{"operationId":"request_feature","summary":"Request a feature","description":"Files a feature request on the Gutlog board and upvotes it for your organization. Use it when the human wishes Gutlog did something it cannot do yet (an integration, an op, a Meta feature, a dashboard view). It checks for duplicates first: an identical request gets your vote instead, and when likely matches exist nothing is filed and `similar` lists them (filed: false): upvote_feedback the match, or call again with force: true if yours is different. 10 new items per organization a day. The person behind the call gets a thank-you email and one at every status change. Feature requests and comments are public (never who wrote them beyond a first name): no API keys, message content or customer data.","tags":["feedback"],"x-read-only":false,"x-admin-only":false,"x-min-role":"viewer","x-scope":"feedback:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":3,"maxLength":140,"description":"What you want, in one line."},"details":{"default":"","description":"Why you need it and what you are building; concrete examples help it get planned.","type":"string","maxLength":5000},"body":{"description":"Alias of details.","type":"string","maxLength":5000},"force":{"default":false,"description":"File even when similar items exist.","type":"boolean"}},"required":["title"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/report_issue":{"post":{"operationId":"report_issue","summary":"Report an issue","description":"Reports a problem with Gutlog itself: a failing or wrong call (pass the request_id from the error or the X-Request-Id header, and the op), a meal that matched the wrong food or got the wrong nutrients, a barcode that was not found, a docs error. Attach context (meal_id, program_id, gtin, the error), never what the person ate or how they feel, so the team can reproduce it; ids are checked against your organization. Issues are private: only your organization and the Gutlog team see them, and the team may publish a sanitized title so others can upvote it. Upvote a matching report from list_feedback (kind issue) instead of filing again; likely duplicates are returned in `similar` with filed: false unless force: true. 10 new items per organization a day. The reporter gets an email with what was captured and one at every status change.","tags":["feedback"],"x-read-only":false,"x-admin-only":false,"x-min-role":"viewer","x-scope":"feedback:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":3,"maxLength":140,"description":"What is wrong, in one line."},"details":{"default":"","description":"What you did, what you expected and what happened (status, error code, format).","type":"string","maxLength":5000},"body":{"description":"Alias of details.","type":"string","maxLength":5000},"request_id":{"description":"The request_id of the failing call (shortcut for context.request_id).","type":"string","maxLength":128},"op":{"description":"The op the failing call used, e.g. log_meal (shortcut for context.op).","type":"string","maxLength":80},"context":{"description":"Gutlog identifiers for what failed: request_id, op, meal_id, program_id, gtin, status, error_code, error, client. Never shown publicly; at most 128 KB.","type":"object","properties":{"request_id":{"description":"The request_id of the failing call (X-Request-Id header, or request_id in the error).","type":"string","pattern":"^[A-Za-z0-9._:-]{1,128}$"},"op":{"description":"The op or endpoint that failed, e.g. log_meal.","type":"string","pattern":"^[a-z][a-z0-9_]{1,79}$"},"meal_id":{"description":"The meal involved (meals.id); must be one of your organization's.","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)$"},"program_id":{"description":"The elimination program involved; must be one of your organization's.","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)$"},"gtin":{"description":"The barcode involved (products are public data).","type":"string","pattern":"^[0-9]{8,14}$"},"locale":{"description":"The language involved, e.g. pt_BR.","type":"string","pattern":"^[A-Za-z]{2,8}([-_][A-Za-z0-9]{1,8})*$"},"status":{"description":"The HTTP status the call returned.","type":"integer","minimum":100,"maximum":599},"error_code":{"description":"The error code, e.g. daily_limit_reached.","type":"string","maxLength":100},"error":{"description":"The error message as the client saw it (no keys, no food or symptom text).","type":"string","maxLength":2000},"client":{"description":"Client and version, e.g. gutlog-cli/0.5.0 or Claude Code.","type":"string","maxLength":100},"version":{"type":"string","maxLength":50},"extra":{"description":"Anything else that helps reproduce it (no secrets, no health data).","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"additionalProperties":false},"force":{"default":false,"description":"File even when similar reports exist.","type":"boolean"}},"required":["title"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/upvote_feedback":{"post":{"operationId":"upvote_feedback","summary":"Upvote a feature request or issue","description":"Adds your organization's upvote to a feature request or issue (\"me too\"); votes decide what gets built and fixed first, and you get an email when its status changes. Idempotent: one vote per organization. A vote on a duplicate goes to the original. Returns the item with its new vote count.","tags":["feedback"],"x-read-only":false,"x-admin-only":false,"x-min-role":"viewer","x-scope":"feedback:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The item's id from list_feedback, request_feature or report_issue (e.g. 42)."}},"required":["id"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/remove_feedback_vote":{"post":{"operationId":"remove_feedback_vote","summary":"Remove an upvote","description":"Takes back your organization's upvote on a feature request or issue, and stops its emails unless you filed or commented on it. Returns the item with its new vote count.","tags":["feedback"],"x-read-only":false,"x-admin-only":false,"x-min-role":"viewer","x-scope":"feedback:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The item's id from list_feedback, request_feature or report_issue (e.g. 42)."}},"required":["id"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/comment_on_feedback":{"post":{"operationId":"comment_on_feedback","summary":"Comment on a feature request or issue","description":"Adds context to an existing feature request or issue: your use case, another failing request, a workaround. Prefer it (with upvote_feedback) over filing a near-duplicate. You then get emails about the item; its author gets a daily digest of new comments. 50 comments per organization a day. Feature requests and comments are public (never who wrote them beyond a first name): no API keys, message content or customer data.","tags":["feedback"],"x-read-only":false,"x-admin-only":false,"x-min-role":"viewer","x-scope":"feedback:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The item's id from list_feedback, request_feature or report_issue (e.g. 42)."},"body":{"type":"string","minLength":1,"maxLength":5000,"description":"The comment."}},"required":["id","body"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/set_feedback_subscription":{"post":{"operationId":"set_feedback_subscription","summary":"Start or stop feedback emails","description":"With id: start or stop emails about one feature request or issue. Without id: turn every feedback email (thank-yous, status changes, replies) on or off for the person behind this credential. Lifecycle and product emails are separate.","tags":["feedback"],"x-read-only":false,"x-admin-only":false,"x-min-role":"viewer","x-scope":"feedback:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The item's id from list_feedback, request_feature or report_issue (e.g. 42)."},"subscribed":{"type":"boolean","description":"true to get emails, false to stop them."}},"required":["subscribed"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/submit_review":{"post":{"operationId":"submit_review","summary":"Post or edit a review","description":"Posts your organization's public review of Gutlog (1–5 stars, what you like, what you don't, what you use it for), or edits it (once an hour; earlier versions are kept). Ask the human for the rating and words; never invent a review or post one they did not approve. It publishes on /reviews right away unless an automated check holds it for a quick look (new accounts, links, profanity). marketing_consent: true lets Meter quote it. The reviewer gets a thank-you email and one when the team replies.","tags":["feedback"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"feedback:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"rating":{"type":"integer","minimum":1,"maximum":5,"description":"1 (poor) to 5 (excellent)."},"title":{"default":"","description":"One-line summary.","type":"string","maxLength":120},"body":{"default":"","description":"The review.","type":"string","maxLength":2000},"likes":{"default":"","description":"What works well.","type":"string","maxLength":1000},"dislikes":{"default":"","description":"What should be better.","type":"string","maxLength":1000},"use_case":{"default":"","description":"What you use Gutlog for.","type":"string","maxLength":200},"display_name":{"description":"Name shown with the review; defaults to your first name.","type":"string","maxLength":60},"display_company":{"description":"Company shown with the review, if any.","type":"string","maxLength":80},"marketing_consent":{"default":false,"description":"May Meter quote this review on the site and in marketing.","type":"boolean"}},"required":["rating"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/list_reviews":{"post":{"operationId":"list_reviews","summary":"List reviews","description":"Published reviews of Gutlog with the aggregate (average rating, count and distribution) and the team's responses. Works without a credential.","tags":["feedback"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"feedback:read","security":[{},{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"sort":{"default":"newest","description":"helpful = most detailed first.","type":"string","enum":["newest","helpful","highest","lowest"]},"rating":{"description":"Only reviews with this rating.","type":"integer","minimum":1,"maximum":5},"status":{"default":"published","description":"Gutlog team only: held or hidden reviews too.","type":"string","enum":["published","pending","hidden","all"]},"limit":{"default":20,"type":"integer","minimum":1,"maximum":100},"offset":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"list_reviews_get","summary":"List reviews (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Published reviews of Gutlog with the aggregate (average rating, count and distribution) and the team's responses. Works without a credential.","tags":["feedback"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/update_feedback":{"post":{"operationId":"update_feedback","summary":"Update feedback (staff)","description":"Gutlog team only. Moves an item through open → planned → in_progress → done, or declined, or duplicate (with duplicate_of: votes and subscribers move to the original), with a note every subscriber gets by email. Also publishes or hides an issue (visibility, with a sanitized public_title) and links the GitHub issue or PR (external_ref).","tags":["feedback"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"feedback:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The item's id from list_feedback, request_feature or report_issue (e.g. 42)."},"status":{"type":"string","enum":["open","planned","in_progress","done","declined","duplicate"]},"note":{"description":"Why, or what shipped and how to use it; emailed with the status change.","type":"string","maxLength":5000},"duplicate_of":{"description":"The original, with status duplicate.","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"external_ref":{"description":"GitHub issue or PR URL; empty clears it.","anyOf":[{"type":"string","maxLength":500,"format":"uri"},{"type":"string","const":""}]},"visibility":{"type":"string","enum":["public","private"]},"public_title":{"description":"Sanitized title others see for a published issue.","type":"string","maxLength":140}},"required":["id"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/respond_to_feedback":{"post":{"operationId":"respond_to_feedback","summary":"Respond officially (staff)","description":"Gutlog team only. Posts an official response on an item (emailed to every subscriber), optionally changing its status in the same call.","tags":["feedback"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"feedback:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The item's id from list_feedback, request_feature or report_issue (e.g. 42)."},"body":{"type":"string","minLength":1,"maxLength":5000,"description":"The response, signed as the Gutlog team."},"status":{"type":"string","enum":["open","planned","in_progress","done","declined","duplicate"]},"note":{"type":"string","maxLength":5000},"duplicate_of":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"external_ref":{"type":"string","maxLength":500,"format":"uri"}},"required":["id","body"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/respond_to_review":{"post":{"operationId":"respond_to_review","summary":"Respond to or moderate a review (staff)","description":"Gutlog team only. Replies publicly under a review (the reviewer gets an email), and/or hides or publishes it with a reason. Never hide a review for being negative.","tags":["feedback"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"feedback:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The review id from list_reviews."},"response":{"type":"string","minLength":1,"maxLength":2000},"status":{"type":"string","enum":["published","hidden","pending"]},"reason":{"description":"Why it is hidden; kept internal.","type":"string","maxLength":300}},"required":["id"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_profile":{"post":{"operationId":"get_profile","summary":"Get my profile","description":"Your own settings, the same in every organization: `locale`, the language the dashboard and every email to you are written in (one of en), or null when you never chose one (the dashboard then follows the browser, emails are English). With an API key, the key creator's profile.","tags":["organization"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"organization:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_profile_get","summary":"Get my profile (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Your own settings, the same in every organization: `locale`, the language the dashboard and every email to you are written in (one of en), or null when you never chose one (the dashboard then follows the browser, emails are English). With an API key, the key creator's profile.","tags":["organization"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/update_profile":{"post":{"operationId":"update_profile","summary":"Update my profile","description":"Changes your own settings: `locale` (en) is the language of the dashboard and of every email Gutlog sends you; null forgets it. The dashboard's language picker calls this. Returns the profile.","tags":["organization"],"x-read-only":false,"x-admin-only":false,"x-min-role":"viewer","x-scope":"organization:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"locale":{"anyOf":[{"type":"string","enum":["en"]},{"type":"null"}],"description":"Your language: en, or null for none."}},"required":["locale"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/list_events":{"post":{"operationId":"list_events","summary":"List events","description":"The organization's event log, newest first: every platform event (meal.logged, meal.updated, meal.reviewed, meal.deleted, product.submitted…) with its payload (ids and flags, never food or symptom text), subject, source and time. Filter by type (exact, or a prefix ending in a dot such as \"meal.\") and subject. Use it to see what changed recently or to catch up (pass after_id to read forward).","tags":["events"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"events:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"description":"An event type, or a prefix ending in \".\" (e.g. \"meal.\").","type":"string","maxLength":100},"subject_type":{"description":"meal, product, symptom_log, program…","type":"string","maxLength":50},"subject_id":{"type":"string","maxLength":200},"after_id":{"description":"Only events with a larger id, oldest first: to read forward from the last id you saw.","type":"integer","minimum":0,"maximum":9007199254740991},"limit":{"default":50,"description":"Page size, at most 200.","type":"integer","minimum":1,"maximum":200},"offset":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"list_events_get","summary":"List events (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. The organization's event log, newest first: every platform event (meal.logged, meal.updated, meal.reviewed, meal.deleted, product.submitted…) with its payload (ids and flags, never food or symptom text), subject, source and time. Filter by type (exact, or a prefix ending in a dot such as \"meal.\") and subject. Use it to see what changed recently or to catch up (pass after_id to read forward).","tags":["events"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_event":{"post":{"operationId":"get_event","summary":"Get event","description":"One event from the organization's event log by id, with its payload and how each internal consumer handled it (done, failed with the error, dead after its retries).","tags":["events"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"events:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","minimum":1,"maximum":9007199254740991}},"required":["id"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_event_get","summary":"Get event (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. One event from the organization's event log by id, with its payload and how each internal consumer handled it (done, failed with the error, dead after its retries).","tags":["events"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/search_foods":{"post":{"operationId":"search_foods","summary":"Search foods","description":"Find canonical foods by name in USDA FoodData Central (Foundation, SR Legacy and FNDDS mixed dishes) plus packaged products in the barcode index. Returns foods best first with a 0–1 match score, nutrients per 100 g (integers: energy in millikilocalories, macros and most minerals in milligrams, some vitamins in micrograms), the default serving with kcal and grams for display, household portions (\"1 cup, sliced\" = 165 g) and canonical ingredient ids; and products (brand, name, gtin). Use it to pick the food id before get_food, or to answer \"how many calories in…\". Free; no sign-in needed. log_meal matches foods itself: you do not need this to log.","tags":["foods"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"foods:read","security":[{},{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string","minLength":1,"maxLength":200,"description":"What to look for, e.g. \"banana\", \"chicken breast roasted\", \"cheerios\"."},"limit":{"default":8,"description":"Foods to return (default 8).","type":"integer","minimum":1,"maximum":25},"include_products":{"default":true,"description":"Also search packaged products in the barcode index.","type":"boolean"}},"required":["query"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"search_foods_get","summary":"Search foods (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Find canonical foods by name in USDA FoodData Central (Foundation, SR Legacy and FNDDS mixed dishes) plus packaged products in the barcode index. Returns foods best first with a 0–1 match score, nutrients per 100 g (integers: energy in millikilocalories, macros and most minerals in milligrams, some vitamins in micrograms), the default serving with kcal and grams for display, household portions (\"1 cup, sliced\" = 165 g) and canonical ingredient ids; and products (brand, name, gtin). Use it to pick the food id before get_food, or to answer \"how many calories in…\". Free; no sign-in needed. log_meal matches foods itself: you do not need this to log.","tags":["foods"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_food":{"post":{"operationId":"get_food","summary":"Get a food","description":"One canonical food by id (from search_foods, e.g. usda:171705) or by its page slug: name, category, source and citation, every nutrient per 100 g, all household portions, ingredient ids and its public page. Pass grams or a portion label to also get the nutrients for that amount (integers in stored units, plus a display version in kcal and grams). Free; no sign-in needed.","tags":["foods"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"foods:read","security":[{},{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":100,"description":"Canonical food id from search_foods (e.g. usda:171287 or seed:banana-raw)."},"slug":{"description":"The food's page slug, e.g. bananas-raw (getgutlog.com/foods/<slug>).","type":"string","pattern":"^[a-z0-9-]{1,100}$"},"grams":{"description":"An amount in grams to compute nutrients for.","type":"number","exclusiveMinimum":0,"maximum":10000},"portion":{"description":"A portion label from the food's portions, e.g. \"1 cup, sliced\".","type":"string","minLength":1,"maxLength":120},"quantity":{"default":1,"description":"How many of the portion (default 1).","type":"number","exclusiveMinimum":0,"maximum":100}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_food_get","summary":"Get a food (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. One canonical food by id (from search_foods, e.g. usda:171705) or by its page slug: name, category, source and citation, every nutrient per 100 g, all household portions, ingredient ids and its public page. Pass grams or a portion label to also get the nutrients for that amount (integers in stored units, plus a display version in kcal and grams). Free; no sign-in needed.","tags":["foods"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/lookup_barcode":{"post":{"operationId":"lookup_barcode","summary":"Look up a barcode","description":"Find a packaged food by its barcode: our product index first (instant), then Open Food Facts, then USDA Branded Foods; a product found outside the index is added to it. Returns found, the product (brand, name, serving, nutrients per serving and per 100 g as integers plus display_per_serving in kcal/g, ingredient text, parsed ingredient ids, allergens, status unverified | community_verified | verified, where each field came from and any attribution to show, e.g. Open Food Facts under ODbL) and found_in (index, off, usda_branded). When found is false, ask the person for a photo of the nutrition label and ingredients, then call submit_product with what you read (free) or scan_label with the photos. Free and unlimited. To log the product as eaten, pass the barcode to log_meal instead.","tags":["products"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"products:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","minLength":8,"maxLength":20,"description":"The barcode digits: UPC-A (12), EAN-13, EAN-8 or GTIN-14. Spaces and dashes are ignored."}},"required":["code"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"lookup_barcode_get","summary":"Look up a barcode (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Find a packaged food by its barcode: our product index first (instant), then Open Food Facts, then USDA Branded Foods; a product found outside the index is added to it. Returns found, the product (brand, name, serving, nutrients per serving and per 100 g as integers plus display_per_serving in kcal/g, ingredient text, parsed ingredient ids, allergens, status unverified | community_verified | verified, where each field came from and any attribution to show, e.g. Open Food Facts under ODbL) and found_in (index, off, usda_branded). When found is false, ask the person for a photo of the nutrition label and ingredients, then call submit_product with what you read (free) or scan_label with the photos. Free and unlimited. To log the product as eaten, pass the barcode to log_meal instead.","tags":["products"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_product":{"post":{"operationId":"get_product","summary":"Get a product","description":"A product already in our index by GTIN or id: brand, name, serving, nutrients per serving and per 100 g, ingredient text and parsed ingredient ids, allergens, verification status, the source of every field and the attribution to show, and its public page URL. Never calls outside services (use lookup_barcode for a code we may not have yet). Free; no sign-in needed.","tags":["products"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"products:read","security":[{},{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"gtin":{"type":"string","minLength":8,"maxLength":20,"description":"The barcode digits: UPC-A (12), EAN-13, EAN-8 or GTIN-14. Spaces and dashes are ignored."},"id":{"description":"Product id (products.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)$"}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_product_get","summary":"Get a product (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. A product already in our index by GTIN or id: brand, name, serving, nutrients per serving and per 100 g, ingredient text and parsed ingredient ids, allergens, verification status, the source of every field and the attribution to show, and its public page URL. Never calls outside services (use lookup_barcode for a code we may not have yet). Free; no sign-in needed.","tags":["products"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/scan_label":{"post":{"operationId":"scan_label","summary":"Read a label photo","description":"Read a food package from photos on our model: the nutrition facts panel, serving size, ingredient statement and the barcode digits if visible. Returns the label (nutrients as integers in stored units: energy in millikilocalories, mass in milligrams), per 100 g, a display version, parsed ingredient ids with allergens and what did not match. With gtin (or a readable barcode) and submit true (default), it also submits the label to the product index, like submit_product. Uses one analysis from the daily allowance (402 plan_limit past it). If you can see the photo yourself (ChatGPT, Claude), read it and call submit_product instead: that is free.","tags":["products"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"products:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"images":{"minItems":1,"maxItems":4,"type":"array","items":{"type":"object","properties":{"media_type":{"type":"string","enum":["image/jpeg","image/png","image/webp","image/gif"]},"data":{"type":"string","minLength":100,"maxLength":7000000,"description":"The photo, base64-encoded (no data: prefix), at most ~5 MB."}},"required":["media_type","data"]},"description":"1–4 photos: the nutrition panel and the ingredient list (and the barcode)."},"gtin":{"description":"The product's barcode, if known.","type":"string","minLength":8,"maxLength":20},"submit":{"default":true,"description":"Submit the reading to the product index when a GTIN is known (default true).","type":"boolean"}},"required":["images"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/submit_product":{"post":{"operationId":"submit_product","summary":"Submit a product label","description":"Add or correct a packaged food in the product index from its label: the barcode plus what the label says (brand, name, serving size and grams, the nutrition panel per serving as integers in stored units, the ingredient statement verbatim). A new barcode creates the product (unverified); a label matching ours confirms it, and a second person's matching label verifies it (community_verified); a different label is kept as a pending revision with a diff until another person's label or staff review confirms it. Returns submission_id, status (pending, matched, conflicting, accepted), the product, the diff and a message to relay. Free; uses no analysis.","tags":["products"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"products:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"gtin":{"type":"string","minLength":8,"maxLength":20,"description":"The barcode digits: UPC-A (12), EAN-13, EAN-8 or GTIN-14. Spaces and dashes are ignored."},"label":{"type":"object","properties":{"brand":{"description":"Brand as printed, e.g. \"Kind\".","type":"string","minLength":1,"maxLength":120},"name":{"type":"string","minLength":1,"maxLength":300,"description":"Product name as printed, without the brand, e.g. \"Dark Chocolate Nuts & Sea Salt bar\"."},"serving_label":{"description":"Serving size as printed, e.g. \"1 bar (40g)\" or \"2/3 cup (55g)\".","type":"string","minLength":1,"maxLength":120},"serving_grams":{"description":"Grams (or millilitres for drinks) in one serving.","type":"number","exclusiveMinimum":0,"maximum":5000},"nutrients_per_serving":{"description":"The nutrition panel per serving.","type":"object","properties":{"energy":{"type":"integer","minimum":0,"maximum":1000000000},"protein":{"type":"integer","minimum":0,"maximum":1000000000},"carbs":{"type":"integer","minimum":0,"maximum":1000000000},"fat":{"type":"integer","minimum":0,"maximum":1000000000},"saturated_fat":{"type":"integer","minimum":0,"maximum":1000000000},"trans_fat":{"type":"integer","minimum":0,"maximum":1000000000},"fiber":{"type":"integer","minimum":0,"maximum":1000000000},"sugar":{"type":"integer","minimum":0,"maximum":1000000000},"added_sugar":{"type":"integer","minimum":0,"maximum":1000000000},"sodium":{"type":"integer","minimum":0,"maximum":1000000000},"cholesterol":{"type":"integer","minimum":0,"maximum":1000000000},"potassium":{"type":"integer","minimum":0,"maximum":1000000000},"calcium":{"type":"integer","minimum":0,"maximum":1000000000},"iron":{"type":"integer","minimum":0,"maximum":1000000000},"magnesium":{"type":"integer","minimum":0,"maximum":1000000000},"zinc":{"type":"integer","minimum":0,"maximum":1000000000},"vitamin_c":{"type":"integer","minimum":0,"maximum":1000000000},"vitamin_a":{"type":"integer","minimum":0,"maximum":1000000000},"vitamin_d":{"type":"integer","minimum":0,"maximum":1000000000},"vitamin_b12":{"type":"integer","minimum":0,"maximum":1000000000},"folate":{"type":"integer","minimum":0,"maximum":1000000000},"caffeine":{"type":"integer","minimum":0,"maximum":1000000000}},"additionalProperties":false},"nutrients_per_100g":{"description":"Per 100 g, when the label prints it (EU labels); otherwise derived from per serving and serving_grams.","type":"object","properties":{"energy":{"type":"integer","minimum":0,"maximum":1000000000},"protein":{"type":"integer","minimum":0,"maximum":1000000000},"carbs":{"type":"integer","minimum":0,"maximum":1000000000},"fat":{"type":"integer","minimum":0,"maximum":1000000000},"saturated_fat":{"type":"integer","minimum":0,"maximum":1000000000},"trans_fat":{"type":"integer","minimum":0,"maximum":1000000000},"fiber":{"type":"integer","minimum":0,"maximum":1000000000},"sugar":{"type":"integer","minimum":0,"maximum":1000000000},"added_sugar":{"type":"integer","minimum":0,"maximum":1000000000},"sodium":{"type":"integer","minimum":0,"maximum":1000000000},"cholesterol":{"type":"integer","minimum":0,"maximum":1000000000},"potassium":{"type":"integer","minimum":0,"maximum":1000000000},"calcium":{"type":"integer","minimum":0,"maximum":1000000000},"iron":{"type":"integer","minimum":0,"maximum":1000000000},"magnesium":{"type":"integer","minimum":0,"maximum":1000000000},"zinc":{"type":"integer","minimum":0,"maximum":1000000000},"vitamin_c":{"type":"integer","minimum":0,"maximum":1000000000},"vitamin_a":{"type":"integer","minimum":0,"maximum":1000000000},"vitamin_d":{"type":"integer","minimum":0,"maximum":1000000000},"vitamin_b12":{"type":"integer","minimum":0,"maximum":1000000000},"folate":{"type":"integer","minimum":0,"maximum":1000000000},"caffeine":{"type":"integer","minimum":0,"maximum":1000000000}},"additionalProperties":false},"ingredients_text":{"description":"The ingredient statement exactly as printed, including any \"Contains:\" line.","type":"string","minLength":1,"maxLength":5000}},"required":["name"]}},"required":["gtin","label"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/list_submissions":{"post":{"operationId":"list_submissions","summary":"List product submissions","description":"Gutlog staff: product label submissions waiting for review (pending and conflicting by default, oldest first) with the label, the diff against the product and the revision it proposes.","tags":["products"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"products:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["pending","matched","conflicting","accepted","rejected"]},"limit":{"default":50,"type":"integer","minimum":1,"maximum":200}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"list_submissions_get","summary":"List product submissions (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Gutlog staff: product label submissions waiting for review (pending and conflicting by default, oldest first) with the label, the diff against the product and the revision it proposes.","tags":["products"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/review_submission":{"post":{"operationId":"review_submission","summary":"Review a product submission","description":"Gutlog staff: accept a label submission (its label becomes the product's, recorded as a revision with a diff, and the product is verified) or reject it (a pending revision it proposed is dropped).","tags":["products"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"products:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"submission_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)$"},"decision":{"type":"string","enum":["accept","reject"]},"note":{"description":"Why, for the record.","type":"string","maxLength":2000}},"required":["submission_id","decision"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/log_meal":{"post":{"operationId":"log_meal","summary":"Log a meal","description":"Log what the person ate. It is always stored; nothing is lost when you are unsure.\n\nIn chat, YOU look at the photo or read the message and send items (a draft): free and unlimited. Other inputs, exactly one per call: text (simple text is free; anything harder is one analysis on our model, Plus), image (our model reads a photo, one analysis, Plus: in chat read it yourself instead), barcode (+ servings; free), recipe (ingredients and amounts of a home dish; free).\n\nHow to fill the draft:\n- One item per distinct food or drink (\"grilled chicken breast\", \"white rice\", \"oat milk latte\"), named as a menu or label would. A dish served as one thing (a burrito, a sandwich, a smoothie) is one item; its parts are its ingredients.\n- Amount: grams when you can estimate them (plate ≈ 26 cm, fork ≈ 19 cm, palm of meat ≈ 100 g, fist of rice ≈ 150 g), else portion {quantity, unit} (\"1 cup\", \"2 slice\", \"1 medium\"). For a package with a barcode, send barcode and servings instead.\n- confidence (what it is) and portion_confidence (how much), 0–1: 0.9+ you can see it clearly or were told; 0.7 typical guess; 0.5 hard to tell.\n- ingredients: what is in the item, each with a confidence, most certain first.\n  · ≥ 0.85: visible or stated (\"eggs\" in scrambled eggs).\n  · 0.60–0.85: standard for this dish though not visible (cheese in a quesadilla, rice in sushi).\n  · 0.30–0.60: plausible but hidden. Always consider cooking fat (butter, oil), added sugar, onion and garlic in sauces, dressings and soups: they matter for calories and for gut symptoms, and the person is asked about them.\n  · below 0.30: leave it out.\n- cooking_method when you can tell (grilled, pan_fried, roasted…). Copy any label or ingredient list text you can read into label_text, verbatim.\n- Never invent a barcode or brand you cannot read.\n\nExamples:\n1. Photo of scrambled eggs on toast with a coffee →\n{\"items\":[{\"name\":\"scrambled eggs\",\"grams\":120,\"confidence\":0.9,\"portion_confidence\":0.7,\"cooking_method\":\"pan_fried\",\"ingredients\":[{\"name\":\"eggs\",\"confidence\":0.97,\"visible\":true},{\"name\":\"butter\",\"confidence\":0.5},{\"name\":\"milk\",\"confidence\":0.35}]},{\"name\":\"sourdough toast\",\"portion\":{\"quantity\":1,\"unit\":\"slice\"},\"confidence\":0.85,\"ingredients\":[{\"name\":\"wheat flour\",\"confidence\":0.9}]},{\"name\":\"black coffee\",\"grams\":240,\"confidence\":0.8}]}\n2. \"Chipotle bowl: chicken, white rice, black beans, mild salsa, no cheese\" →\n{\"title\":\"Chipotle bowl\",\"items\":[{\"name\":\"chicken burrito bowl\",\"grams\":520,\"confidence\":0.85,\"portion_confidence\":0.6,\"ingredients\":[{\"name\":\"chicken\",\"confidence\":0.95},{\"name\":\"white rice\",\"confidence\":0.95},{\"name\":\"black beans\",\"confidence\":0.95},{\"name\":\"tomato salsa\",\"confidence\":0.9},{\"name\":\"onion\",\"confidence\":0.7},{\"name\":\"garlic\",\"confidence\":0.45}]}]}\n3. A granola bar wrapper with a readable barcode → {\"items\":[{\"name\":\"granola bar\",\"barcode\":\"0123456789012\",\"servings\":1}]}\n\nWe match each item against the person's own foods, the barcode index, the food database, then recipes; portion it; compute calories and nutrients; and tier ingredients: confirmed (≥0.85 or from a label), likely (0.60–0.85, counted), possible (0.30–0.60, not counted, asked about). needs_review is set under the person's threshold (default 0.80), when a possible ingredient is one of their triggers or allergens, or when a portion is over 3× typical. Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is. Then answer with confirm_ingredients / reject_ingredients by id; fix amounts with update_meal.","tags":["meals"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"meals:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"minItems":1,"maxItems":30,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"The item as it would appear on a menu or label: \"grilled chicken breast\", \"white rice\", \"oat milk latte\"."},"food_id":{"description":"A food id from search_foods or a previous log_meal reply, when you already know the match.","type":"string","maxLength":100},"barcode":{"description":"Barcode digits if you can read them (UPC/EAN); the product's label then wins over estimates.","type":"string","maxLength":20},"brand":{"description":"Brand when packaging shows it.","type":"string","maxLength":120},"grams":{"description":"Your estimate of the edible weight in grams. Prefer this when you can estimate it from the photo (plate size, utensils, hand).","type":"number","exclusiveMinimum":0,"maximum":5000},"portion":{"description":"Instead of grams: \"2 slices\", \"1 cup\", \"1 medium\".","type":"object","properties":{"quantity":{"type":"number","exclusiveMinimum":0,"maximum":100},"unit":{"type":"string","minLength":1,"maxLength":40,"description":"A household measure: \"cup\", \"slice\", \"medium\", \"tbsp\", \"oz\", \"bowl\", \"can\"."}},"required":["quantity","unit"]},"servings":{"description":"Number of the product's servings (with a barcode).","type":"number","exclusiveMinimum":0,"maximum":20},"confidence":{"description":"How sure you are of what this item is, 0–1.","type":"number","minimum":0,"maximum":1},"portion_confidence":{"description":"How sure you are of the amount, 0–1.","type":"number","minimum":0,"maximum":1},"cooking_method":{"type":"string","enum":["raw","boiled","steamed","grilled","roasted","baked","sauteed","pan_fried","deep_fried","air_fried","braised","stewed","microwaved","smoked","unknown"]},"ingredients":{"default":[],"description":"Ingredients with a confidence each, most certain first. Include hidden fats, sugars, onion and garlic when plausible.","maxItems":40,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120,"description":"One ingredient as a person would say it: \"garlic\", \"olive oil\", \"cheddar\"."},"confidence":{"type":"number","minimum":0,"maximum":1,"description":"How sure you are it is in this item, 0–1. ≥0.85 you can see or were told it; 0.60–0.85 very likely for this dish; 0.30–0.60 plausible but hidden (cooking fat, butter, sugar, garlic, onion in a sauce): include these, they are asked about. Omit below 0.30."},"visible":{"description":"You can see it in the photo (true) or inferred it from the dish (false).","type":"boolean"},"ingredient_id":{"description":"Canonical ingredient id if you know it from a previous response; otherwise leave it out.","type":"string","maxLength":80}},"required":["name","confidence"]}},"label_text":{"description":"Any ingredient list or nutrition label text you can read, verbatim.","type":"string","maxLength":4000}},"required":["name"]},"description":"One entry per distinct food or drink on the plate or in the message."},"meal_type":{"description":"Leave out to infer from the time.","type":"string","enum":["breakfast","lunch","dinner","snack","drink"]},"eaten_at":{"description":"When it was eaten, ISO 8601 with offset; 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)))$"},"title":{"description":"A short name for the meal: \"Chipotle bowl\", \"Breakfast\".","type":"string","maxLength":200},"note":{"description":"Anything the person said that is not an item (where, how they felt).","type":"string","maxLength":2000},"client":{"description":"Your client name, e.g. \"chatgpt\", \"claude\", \"cursor\".","type":"string","maxLength":60},"model":{"description":"Your model name, for calibration.","type":"string","maxLength":80},"text":{"description":"What the person said they ate, when you cannot send items: \"chipotle bowl, chicken, white rice, no beans\". Simple text is matched for free; anything else costs one analysis.","type":"string","minLength":1,"maxLength":4000},"image":{"anyOf":[{"type":"object","properties":{"data":{"type":"string","minLength":100,"maxLength":10000000,"description":"Base64 image bytes, no data: prefix."},"media_type":{"type":"string","enum":["image/jpeg","image/png","image/webp","image/gif"]}},"required":["data","media_type"]},{"type":"object","properties":{"url":{"type":"string","maxLength":2000,"format":"starts_with","pattern":"^https:\\/\\/.*","description":"An https URL of the photo."}},"required":["url"]}],"description":"A meal photo our server analyzes (web, CLI, API, email). Costs one analysis (Plus). In chat, read the photo yourself and send items instead: that is free."},"barcode":{"description":"A barcode (UPC/EAN digits) on its own: the product label wins. Free.","type":"string","pattern":"^\\d{8,14}$"},"servings":{"description":"Servings of the barcode product.","type":"number","exclusiveMinimum":0,"maximum":20},"recipe":{"description":"A home recipe: its ingredients and amounts, decomposed into nutrients. Free.","type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"The dish: \"Mum's lentil soup\"."},"ingredients":{"minItems":1,"maxItems":60,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"grams":{"type":"number","exclusiveMinimum":0,"maximum":10000},"portion":{"type":"object","properties":{"quantity":{"type":"number","exclusiveMinimum":0,"maximum":1000},"unit":{"type":"string","minLength":1,"maxLength":40}},"required":["quantity","unit"]}},"required":["name"]},"description":"Everything that went into the whole pot or tray, with amounts."},"servings_made":{"default":1,"description":"How many servings the recipe makes.","type":"number","exclusiveMinimum":0,"maximum":100},"servings_eaten":{"default":1,"description":"How many of those servings were eaten.","type":"number","exclusiveMinimum":0,"maximum":20}},"required":["name","ingredients"]}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_day":{"post":{"operationId":"get_day","summary":"Get a diary day","description":"One day of the food diary in the person's timezone: every meal with its items (match, grams, nutrients, confidence) and ingredients (id, tier, confidence, status), the day's nutrient totals, the person's daily goals and how many meals need review. Nutrients are integers: energy in millikilocalories, macros and most minerals in milligrams, some vitamins in micrograms; totals_display and goals_display have kcal and grams. Defaults to today.","tags":["meals"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"meals:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"date":{"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])))$","description":"A calendar day, YYYY-MM-DD, in the person's timezone."}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_day_get","summary":"Get a diary day (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. One day of the food diary in the person's timezone: every meal with its items (match, grams, nutrients, confidence) and ingredients (id, tier, confidence, status), the day's nutrient totals, the person's daily goals and how many meals need review. Nutrients are integers: energy in millikilocalories, macros and most minerals in milligrams, some vitamins in micrograms; totals_display and goals_display have kcal and grams. Defaults to today.","tags":["meals"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_meal":{"post":{"operationId":"get_meal","summary":"Get a meal","description":"One logged meal with everything an edit needs: item ids, ingredient ids, tiers, statuses and the open questions. Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is.","tags":["meals"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"meals:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"meal_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":"Meal id (meals.id)."}},"required":["meal_id"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_meal_get","summary":"Get a meal (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. One logged meal with everything an edit needs: item ids, ingredient ids, tiers, statuses and the open questions. Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is.","tags":["meals"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/list_review_queue":{"post":{"operationId":"list_review_queue","summary":"List meals to review","description":"Meals flagged needs_review (low confidence, a possible trigger or allergen, an implausible portion), newest first, each as a full meal with its questions. Go through them with the person: ask the questions, then confirm_ingredients / reject_ingredients, update_meal for amounts, or mark_reviewed when a meal looks right.","tags":["meals"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"meals:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"limit":{"default":50,"description":"Page size, at most 200.","type":"integer","minimum":1,"maximum":200},"offset":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"list_review_queue_get","summary":"List meals to review (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Meals flagged needs_review (low confidence, a possible trigger or allergen, an implausible portion), newest first, each as a full meal with its questions. Go through them with the person: ask the questions, then confirm_ingredients / reject_ingredients, update_meal for amounts, or mark_reviewed when a meal looks right.","tags":["meals"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/update_meal":{"post":{"operationId":"update_meal","summary":"Update a meal","description":"Change a logged meal: its title, type, time or note; per item (meal_item_id from the meal) its grams or household portion (\"the chicken was more like 200 g\"), its match (food_id from search_foods: \"it was oat milk\"), its name, or remove it; add_items with the same item shape as log_meal. Edits win over estimates and are kept as corrections. To change a single number directly use set_nutrients. Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is.","tags":["meals"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"meals:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"meal_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":"Meal id (meals.id)."},"title":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"meal_type":{"type":"string","enum":["breakfast","lunch","dinner","snack","drink"]},"eaten_at":{"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)))$"},"note":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"items":{"maxItems":30,"type":"array","items":{"type":"object","properties":{"meal_item_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":"Meal item id (meal_items.id)."},"grams":{"type":"number","exclusiveMinimum":0,"maximum":5000},"portion":{"type":"object","properties":{"quantity":{"type":"number","exclusiveMinimum":0,"maximum":100},"unit":{"type":"string","minLength":1,"maxLength":40}},"required":["quantity","unit"]},"food_id":{"description":"Swap the match to this canonical food.","type":"string","minLength":1,"maxLength":100},"name":{"type":"string","minLength":1,"maxLength":200},"remove":{"type":"boolean"}},"required":["meal_item_id"]}},"add_items":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"The item as it would appear on a menu or label: \"grilled chicken breast\", \"white rice\", \"oat milk latte\"."},"food_id":{"description":"A food id from search_foods or a previous log_meal reply, when you already know the match.","type":"string","maxLength":100},"barcode":{"description":"Barcode digits if you can read them (UPC/EAN); the product's label then wins over estimates.","type":"string","maxLength":20},"brand":{"description":"Brand when packaging shows it.","type":"string","maxLength":120},"grams":{"description":"Your estimate of the edible weight in grams. Prefer this when you can estimate it from the photo (plate size, utensils, hand).","type":"number","exclusiveMinimum":0,"maximum":5000},"portion":{"description":"Instead of grams: \"2 slices\", \"1 cup\", \"1 medium\".","type":"object","properties":{"quantity":{"type":"number","exclusiveMinimum":0,"maximum":100},"unit":{"type":"string","minLength":1,"maxLength":40,"description":"A household measure: \"cup\", \"slice\", \"medium\", \"tbsp\", \"oz\", \"bowl\", \"can\"."}},"required":["quantity","unit"]},"servings":{"description":"Number of the product's servings (with a barcode).","type":"number","exclusiveMinimum":0,"maximum":20},"confidence":{"description":"How sure you are of what this item is, 0–1.","type":"number","minimum":0,"maximum":1},"portion_confidence":{"description":"How sure you are of the amount, 0–1.","type":"number","minimum":0,"maximum":1},"cooking_method":{"type":"string","enum":["raw","boiled","steamed","grilled","roasted","baked","sauteed","pan_fried","deep_fried","air_fried","braised","stewed","microwaved","smoked","unknown"]},"ingredients":{"default":[],"description":"Ingredients with a confidence each, most certain first. Include hidden fats, sugars, onion and garlic when plausible.","maxItems":40,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120,"description":"One ingredient as a person would say it: \"garlic\", \"olive oil\", \"cheddar\"."},"confidence":{"type":"number","minimum":0,"maximum":1,"description":"How sure you are it is in this item, 0–1. ≥0.85 you can see or were told it; 0.60–0.85 very likely for this dish; 0.30–0.60 plausible but hidden (cooking fat, butter, sugar, garlic, onion in a sauce): include these, they are asked about. Omit below 0.30."},"visible":{"description":"You can see it in the photo (true) or inferred it from the dish (false).","type":"boolean"},"ingredient_id":{"description":"Canonical ingredient id if you know it from a previous response; otherwise leave it out.","type":"string","maxLength":80}},"required":["name","confidence"]}},"label_text":{"description":"Any ingredient list or nutrition label text you can read, verbatim.","type":"string","maxLength":4000}},"required":["name"]}},"from_card":{"description":"Set only by the meal card UI: the person tapped it. Agents leave it out.","type":"boolean"}},"required":["meal_id"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/confirm_ingredients":{"post":{"operationId":"confirm_ingredients","summary":"Confirm ingredients","description":"The person says these ingredients were in the meal (\"yes, butter\"): ids from the meal's ingredients or questions, or all_likely: true with meal_id to confirm every likely one at once (\"yes, that's right\"). A confirmed possible ingredient starts counting (a hidden fat or sugar adds its calories). Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is.","tags":["meals"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"meals:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"meal_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":"Meal id (meals.id)."},"ids":{"description":"Ingredient ids (meal_item_ingredients.id).","maxItems":100,"type":"array","items":{"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)$"}},"all_likely":{"type":"boolean"},"from_card":{"description":"Set only by the meal card UI: the person tapped it. Agents leave it out.","type":"boolean"}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/reject_ingredients":{"post":{"operationId":"reject_ingredients","summary":"Reject ingredients","description":"The person says these ingredients were not in the meal (\"no cheese\", \"no garlic\"): ids from the meal's ingredients or questions. A rejected ingredient no longer counts toward nutrients or gut exposures. If the numbers should drop too (the cheese was part of the matched dish), also set_nutrients or swap the match with update_meal. Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is.","tags":["meals"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"meals:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"meal_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":"Meal id (meals.id)."},"ids":{"minItems":1,"maxItems":100,"type":"array","items":{"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":"Ingredient ids (meal_item_ingredients.id)."},"from_card":{"description":"Set only by the meal card UI: the person tapped it. Agents leave it out.","type":"boolean"}},"required":["ids"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/add_ingredients":{"post":{"operationId":"add_ingredients","summary":"Add ingredients","description":"Add ingredients we missed to one item (\"it had onions\", \"cooked in butter\"), confirmed. A hidden fat or sugar adds its usual amount's calories. Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is.","tags":["meals"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"meals:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"meal_item_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":"Meal item id (meal_items.id)."},"ingredients":{"minItems":1,"maxItems":20,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"ingredient_id":{"type":"string","maxLength":100}},"required":["name"]}},"from_card":{"description":"Set only by the meal card UI: the person tapped it. Agents leave it out.","type":"boolean"}},"required":["meal_item_id","ingredients"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/set_nutrients":{"post":{"operationId":"set_nutrients","summary":"Set nutrient values","description":"Override nutrient values of one item directly (\"the protein was more like 45 g\", \"it said 320 kcal\"). Values are in display units: kcal for energy, grams for macros, mg for sodium and other minerals, µg (ug) for vitamins A, D, B12 and folate, unless unit says otherwise. Each field set is locked: later portion changes keep it. value null unlocks a field back to the estimate. Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is.","tags":["meals"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"meals:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"meal_item_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":"Meal item id (meal_items.id)."},"set":{"minItems":1,"maxItems":20,"type":"array","items":{"type":"object","properties":{"nutrient":{"type":"string","minLength":1,"maxLength":40,"description":"A nutrient key: energy, protein, carbs, fat, fiber, sugar, added_sugar, sodium, saturated_fat…"},"value":{"anyOf":[{"type":"number","minimum":0,"maximum":100000},{"type":"null"}]},"unit":{"type":"string","enum":["kcal","g","mg","ug"]}},"required":["nutrient","value"]}},"from_card":{"description":"Set only by the meal card UI: the person tapped it. Agents leave it out.","type":"boolean"}},"required":["meal_item_id","set"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/mark_reviewed":{"post":{"operationId":"mark_reviewed","summary":"Mark a meal reviewed","description":"The person looked at the meal and it is right as it is: it leaves the review queue and stays out. Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is.","tags":["meals"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"meals:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"meal_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":"Meal id (meals.id)."},"from_card":{"description":"Set only by the meal card UI: the person tapped it. Agents leave it out.","type":"boolean"}},"required":["meal_id"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/delete_meal":{"post":{"operationId":"delete_meal","summary":"Delete a meal","description":"Remove a meal from the diary (logged twice, or never eaten). It no longer counts toward totals, the review queue or gut analysis. Confirm with the person first.","tags":["meals"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"meals:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"meal_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":"Meal id (meals.id)."},"from_card":{"description":"Set only by the meal card UI: the person tapped it. Agents leave it out.","type":"boolean"}},"required":["meal_id"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/copy_meal":{"post":{"operationId":"copy_meal","summary":"Copy a meal","description":"Log a meal again (\"same as yesterday's breakfast\"): meal_id, or date + meal_type for the latest meal of that type that day. Logged now unless eaten_at is given; as_meal_type changes its type. Free. Returns the meal: meal_id, needs_review and review_reasons, confidence, totals (integers: energy in millikilocalories, macros in milligrams; totals_display has kcal and grams), items with their match, grams, nutrients and ingredients by tier (each with an id and status), up to three questions (each with the ingredient id to confirm or reject) and reply: say it to the person as is.","tags":["meals"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"meals:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"meal_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":"Meal id (meals.id)."},"date":{"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])))$","description":"A calendar day, YYYY-MM-DD, in the person's timezone."},"meal_type":{"type":"string","enum":["breakfast","lunch","dinner","snack","drink"]},"eaten_at":{"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)))$"},"as_meal_type":{"type":"string","enum":["breakfast","lunch","dinner","snack","drink"]}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/save_personal_food":{"post":{"operationId":"save_personal_food","summary":"Save as my usual","description":"Save a corrected item (meal_item_id) or a whole meal (meal_id, with a name) as one of the person's own foods: \"save this as my usual latte\". Next time that name matches first, with these exact nutrients and ingredients. Saving under an existing name updates it. Items corrected on three different meals are saved automatically.","tags":["meals"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"meals:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"meal_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":"Meal id (meals.id)."},"meal_item_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":"Meal item id (meal_items.id)."},"name":{"description":"What the person calls it; default the item's name (required for a whole meal without a title).","type":"string","minLength":1,"maxLength":200},"aliases":{"description":"Other names it goes by (\"my latte\", \"usual coffee\").","maxItems":10,"type":"array","items":{"type":"string","minLength":1,"maxLength":200}}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/list_personal_foods":{"post":{"operationId":"list_personal_foods","summary":"List personal foods","description":"The person's own foods (saved as usual or learned from corrections), most used first, with nutrients per 100 g, default grams and ingredients. Log one by its name, or with food_id \"personal:<id>\" in a log_meal item.","tags":["meals"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"meals:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"limit":{"default":50,"description":"Page size, at most 200.","type":"integer","minimum":1,"maximum":200},"offset":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"list_personal_foods_get","summary":"List personal foods (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. The person's own foods (saved as usual or learned from corrections), most used first, with nutrients per 100 g, default grams and ingredients. Log one by its name, or with food_id \"personal:<id>\" in a log_meal item.","tags":["meals"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/archive_personal_food":{"post":{"operationId":"archive_personal_food","summary":"Archive a personal food","description":"Stop matching a personal food (it was wrong, or the person no longer eats it). Meals already logged with it keep their numbers.","tags":["meals"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"meals:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"personal_food_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)$"}},"required":["personal_food_id"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/rate_analysis":{"post":{"operationId":"rate_analysis","summary":"Rate an analysis","description":"Thumbs up or down on how well a meal was analyzed, with an optional reason in the person's words. One rating per person per meal; rating again replaces it. Ask what was wrong after a thumbs down and fix it with the edit ops.","tags":["meals"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"meals:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"meal_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":"Meal id (meals.id)."},"rating":{"type":"string","enum":["up","down"]},"reason":{"type":"string","maxLength":1000}},"required":["meal_id","rating"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_calibration":{"post":{"operationId":"get_calibration","summary":"Get confidence calibration","description":"How well ingredient confidences match what the person confirmed and rejected: per 0.1 bucket and source (photo, text, database), how many were answered, the confirm rate and the gap from the bucket's midpoint. A well calibrated 0.8 bucket confirms about 80%.","tags":["meals"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"meals:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"days":{"default":90,"type":"integer","minimum":1,"maximum":365}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_calibration_get","summary":"Get confidence calibration (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. How well ingredient confidences match what the person confirmed and rejected: per 0.1 bucket and source (photo, text, database), how many were answered, the confirm rate and the gap from the bucket's midpoint. A well calibrated 0.8 bucket confirms about 80%.","tags":["meals"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_calibration_all":{"post":{"operationId":"get_calibration_all","summary":"Get calibration across everyone","description":"Calibration across every organization (counts only), for tuning thresholds and the analysis prompt. Gutlog staff only.","tags":["meals"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"meals:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"days":{"default":30,"type":"integer","minimum":1,"maximum":365}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_calibration_all_get","summary":"Get calibration across everyone (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Calibration across every organization (counts only), for tuning thresholds and the analysis prompt. Gutlog staff only.","tags":["meals"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/refresh_global_aliases":{"post":{"operationId":"refresh_global_aliases","summary":"Refresh shared aliases","description":"Promote correction patterns seen from at least 20 different people to shared aliases (and drop ones that fell under). Runs daily on its own; staff only. Only the pattern and a count are kept, never who.","tags":["meals"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"meals:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_logging_settings":{"post":{"operationId":"get_logging_settings","summary":"Get logging settings","description":"The person's review threshold (meals under it are flagged) and daily nutrient goals (integers; goals_display in kcal and grams). Goals default to the FDA Daily Values for 2,000 kcal until set.","tags":["meals"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"meals:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_logging_settings_get","summary":"Get logging settings (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. The person's review threshold (meals under it are flagged) and daily nutrient goals (integers; goals_display in kcal and grams). Goals default to the FDA Daily Values for 2,000 kcal until set.","tags":["meals"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/update_logging_settings":{"post":{"operationId":"update_logging_settings","summary":"Update logging settings","description":"Set the review threshold (0–1; lower flags fewer meals) and daily goals in display units: {\"energy\": 1800, \"protein\": 120, \"sodium\": 2000} (kcal, grams, mg). null removes a goal.","tags":["meals"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"meals:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"review_threshold":{"type":"number","minimum":0,"maximum":1},"goals":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"number","minimum":0,"maximum":100000},{"type":"null"}]}}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/check_clean":{"post":{"operationId":"check_clean","summary":"Check if food is clean","description":"Judge ingredients against Gutlog's published clean-ingredient rubric: pass exactly one of ingredients_text (a label as printed), ingredients (names), barcode (a product in the index) or meal_id (a logged meal). Returns verdict (clean, mostly_clean, not_clean), a 0–100 score, flags (ingredient, category, evidence level: regulatory, strong, mixed or preference, the penalty, a one-line why and a citation), organic advice for Dirty Dozen and Clean Fifteen produce (buy_organic, conventional_ok), and names it did not recognize. Uses the person's profile (Strict, Balanced or Custom) unless profile is given. Tell the person the verdict and the top flags with their evidence level; preference flags are not proven harms. Free and unlimited.","tags":["clean"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"clean:read","security":[{},{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"ingredients_text":{"description":"An ingredient list as printed on a label, e.g. \"Corn, vegetable oil, salt, natural flavors.\"","type":"string","minLength":1,"maxLength":5000},"ingredients":{"description":"Ingredient names or canonical ids, one per entry (instead of ingredients_text).","minItems":1,"maxItems":200,"type":"array","items":{"type":"string","minLength":1,"maxLength":200}},"barcode":{"type":"string","pattern":"^\\d{8,14}$","description":"The product's barcode digits (UPC-A, EAN-13, GTIN-8 or GTIN-14)."},"meal_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":"Meal id (meals.id)."},"profile":{"description":"Judge with this profile instead of the person's saved one: strict, balanced or custom (custom uses their saved category levels).","type":"string","enum":["strict","balanced","custom"]}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"check_clean_get","summary":"Check if food is clean (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Judge ingredients against Gutlog's published clean-ingredient rubric: pass exactly one of ingredients_text (a label as printed), ingredients (names), barcode (a product in the index) or meal_id (a logged meal). Returns verdict (clean, mostly_clean, not_clean), a 0–100 score, flags (ingredient, category, evidence level: regulatory, strong, mixed or preference, the penalty, a one-line why and a citation), organic advice for Dirty Dozen and Clean Fifteen produce (buy_organic, conventional_ok), and names it did not recognize. Uses the person's profile (Strict, Balanced or Custom) unless profile is given. Tell the person the verdict and the top flags with their evidence level; preference flags are not proven harms. Free and unlimited.","tags":["clean"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_clean_rubric":{"post":{"operationId":"get_clean_rubric","summary":"Get the clean rubric","description":"The clean-ingredient rubric as data: version, scoring rules, profiles (strict, balanced, custom) with their thresholds, evidence levels, categories, every rule (ingredient, aliases, category, evidence, penalty, why, citation), additives the EU bans or restricts, and this year's EWG Dirty Dozen and Clean Fifteen with the citation. Filter by category or ingredient id. Use it to explain why something was flagged.","tags":["clean"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"clean:read","security":[{},{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"category":{"description":"Only this category's rules.","type":"string","enum":["natural_flavors","artificial_flavors","artificial_sweeteners","artificial_colors","seed_oils","hydrogenated_fats","added_sugars","preservatives","emulsifiers_gums","flavor_enhancers","refined_starches","bleached_enriched_flours","eu_restricted"]},"ingredient":{"description":"Only the rules on this canonical ingredient id (e.g. natural-flavors).","type":"string","minLength":1,"maxLength":100}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_clean_rubric_get","summary":"Get the clean rubric (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. The clean-ingredient rubric as data: version, scoring rules, profiles (strict, balanced, custom) with their thresholds, evidence levels, categories, every rule (ingredient, aliases, category, evidence, penalty, why, citation), additives the EU bans or restricts, and this year's EWG Dirty Dozen and Clean Fifteen with the citation. Filter by category or ingredient id. Use it to explain why something was flagged.","tags":["clean"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_clean_profile":{"post":{"operationId":"get_clean_profile","summary":"Get the clean profile","description":"The person's clean profile: strict, balanced (the default) or custom, and for custom the level per category (off, balanced or strict). Verdicts from check_clean and clean_summary use it.","tags":["clean"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"clean:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_clean_profile_get","summary":"Get the clean profile (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. The person's clean profile: strict, balanced (the default) or custom, and for custom the level per category (off, balanced or strict). Verdicts from check_clean and clean_summary use it.","tags":["clean"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/set_clean_profile":{"post":{"operationId":"set_clean_profile","summary":"Set the clean profile","description":"Choose how strictly food is judged: strict (every rule, including gums, starches and all added sugars), balanced (the default) or custom. With custom, `categories` sets a level per category (off, balanced or strict); categories not given keep their saved level, or balanced. Returns the saved profile. Ask the person before changing it.","tags":["clean"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"clean:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"profile":{"type":"string","enum":["strict","balanced","custom"],"description":"strict, balanced or custom."},"categories":{"description":"Custom only: a level per category, e.g. {\"natural_flavors\": \"off\", \"added_sugars\": \"strict\"}.","type":"object","propertyNames":{"type":"string","enum":["natural_flavors","artificial_flavors","artificial_sweeteners","artificial_colors","seed_oils","hydrogenated_fats","added_sugars","preservatives","emulsifiers_gums","flavor_enhancers","refined_starches","bleached_enriched_flours","eu_restricted"]},"additionalProperties":{"type":"string","enum":["off","balanced","strict"]}}},"required":["profile"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/clean_summary":{"post":{"operationId":"clean_summary","summary":"Summarize clean eating","description":"How clean the person ate from `from` to `to` (diary days, inclusive, at most 92 days), or over the last `days` days up to today in their timezone (default 7): the overall verdict and mean score, one entry per day with its meals' verdicts and scores, verdict counts, the worst offenders (flagged ingredients by how often and how heavily they appeared, with evidence and why) and Dirty Dozen or Clean Fifteen produce eaten. Use it for weekly check-ins and to suggest one change at a time.","tags":["clean"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"clean:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"from":{"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])))$","description":"A calendar day, YYYY-MM-DD, in the person's timezone."},"to":{"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])))$","description":"A calendar day, YYYY-MM-DD, in the person's timezone."},"days":{"description":"The last N diary days ending at `to` (or today); ignored when `from` is given. Default 7.","type":"integer","minimum":1,"maximum":92},"profile":{"description":"Judge with this profile instead of the person's saved one: strict, balanced or custom (custom uses their saved category levels).","type":"string","enum":["strict","balanced","custom"]}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"clean_summary_get","summary":"Summarize clean eating (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. How clean the person ate from `from` to `to` (diary days, inclusive, at most 92 days), or over the last `days` days up to today in their timezone (default 7): the overall verdict and mean score, one entry per day with its meals' verdicts and scores, verdict counts, the worst offenders (flagged ingredients by how often and how heavily they appeared, with evidence and why) and Dirty Dozen or Clean Fifteen produce eaten. Use it for weekly check-ins and to suggest one change at a time.","tags":["clean"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/suggest_swaps":{"post":{"operationId":"suggest_swaps","summary":"Suggest cleaner swaps","description":"Cleaner products of the same kind from the product index: for one product (barcode) or each indexed product in a logged meal (meal_id). Returns, per product, its verdict, score and flags, and up to `limit` swaps that score higher (brand, name, barcode, verdict, score, improvement and which flags they avoid). Empty when the index has nothing cleaner yet.","tags":["clean"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"clean:read","security":[{},{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"barcode":{"type":"string","pattern":"^\\d{8,14}$","description":"The product's barcode digits (UPC-A, EAN-13, GTIN-8 or GTIN-14)."},"meal_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":"Meal id (meals.id)."},"profile":{"description":"Judge with this profile instead of the person's saved one: strict, balanced or custom (custom uses their saved category levels).","type":"string","enum":["strict","balanced","custom"]},"limit":{"default":3,"description":"Swaps per product, at most 10.","type":"integer","minimum":1,"maximum":10}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"suggest_swaps_get","summary":"Suggest cleaner swaps (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Cleaner products of the same kind from the product index: for one product (barcode) or each indexed product in a logged meal (meal_id). Returns, per product, its verdict, score and flags, and up to `limit` swaps that score higher (brand, name, barcode, verdict, score, improvement and which flags they avoid). Empty when the index has nothing cleaner yet.","tags":["clean"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/log_symptoms":{"post":{"operationId":"log_symptoms","summary":"Log symptoms","description":"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.","tags":["gut"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"gut:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"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."}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/list_symptom_logs":{"post":{"operationId":"list_symptom_logs","summary":"List symptom logs","description":"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).","tags":["gut"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"gut:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"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}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"list_symptom_logs_get","summary":"List symptom logs (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?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).","tags":["gut"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/delete_symptom_log":{"post":{"operationId":"delete_symptom_log","summary":"Delete a symptom log","description":"Delete one symptom log the person logged by mistake, and recompute that day's tummy score.","tags":["gut"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"gut:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"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"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_tummy_scores":{"post":{"operationId":"get_tummy_scores","summary":"Get tummy scores","description":"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.","tags":["gut"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"gut:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"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])))$"}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_tummy_scores_get","summary":"Get tummy scores (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?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.","tags":["gut"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_pending_checkins":{"post":{"operationId":"get_pending_checkins","summary":"Get pending check-ins","description":"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.","tags":["gut"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"gut:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_pending_checkins_get","summary":"Get pending check-ins (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?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.","tags":["gut"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/set_checkin_preferences":{"post":{"operationId":"set_checkin_preferences","summary":"Set check-in preferences","description":"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.","tags":["gut"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"gut:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"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}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_exposures":{"post":{"operationId":"get_exposures","summary":"Get exposures","description":"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.","tags":["gut"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"gut:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"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])))$"}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_exposures_get","summary":"Get exposures (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?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.","tags":["gut"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_triggers":{"post":{"operationId":"get_triggers","summary":"Get suspected triggers","description":"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.","tags":["gut"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"gut:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"include_all":{"default":false,"description":"Also list exposures the person has not eaten yet.","type":"boolean"}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_triggers_get","summary":"Get suspected triggers (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?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.","tags":["gut"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/food_tummy_score":{"post":{"operationId":"food_tummy_score","summary":"Food tummy score","description":"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.","tags":["gut"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"gut:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"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)."}}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"food_tummy_score_get","summary":"Food tummy score (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?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.","tags":["gut"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/check_ingredients":{"post":{"operationId":"check_ingredients","summary":"Check ingredients for triggers","description":"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.","tags":["gut"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"gut:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"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"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"check_ingredients_get","summary":"Check ingredients for triggers (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?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.","tags":["gut"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_low_fodmap_swaps":{"post":{"operationId":"get_low_fodmap_swaps","summary":"Get low-FODMAP swaps","description":"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.","tags":["gut"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"gut:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"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)."}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_low_fodmap_swaps_get","summary":"Get low-FODMAP swaps (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?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.","tags":["gut"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/screen_for_program":{"post":{"operationId":"screen_for_program","summary":"Safety screen for a program","description":"The safety screen every elimination program starts with. Without answers it returns the questions to ask (age, pregnancy or breastfeeding, eating-disorder history, and red flags: blood in stool, unintended weight loss, night-time symptoms, fever, anemia, symptoms starting after 50, family history of colon cancer, celiac or IBD). With answers it returns clear, see_doctor_first (a red flag: a doctor first) or blocked (under 18, pregnant or breastfeeding, or disordered eating: no restrictive diet here). Ask every question; never assume an answer. Nothing is stored. Free.","tags":["programs"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"programs:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"answers":{"type":"object","properties":{"age":{"type":"integer","minimum":1,"maximum":120,"description":"The person's age in years."},"pregnant_or_breastfeeding":{"type":"boolean","description":"Is the person pregnant or breastfeeding?"},"eating_disorder_history":{"type":"boolean","description":"Has the person ever had an eating disorder or disordered eating (restricting, bingeing, purging)?"},"red_flags":{"type":"object","properties":{"blood_in_stool":{"type":"boolean","description":"Blood in your stool, or black, tarry stools?"},"unintended_weight_loss":{"type":"boolean","description":"Losing weight without trying?"},"night_symptoms":{"type":"boolean","description":"Symptoms that wake you up at night (pain or diarrhea)?"},"fever":{"type":"boolean","description":"Fever with your gut symptoms?"},"anemia":{"type":"boolean","description":"Anemia (low iron or low blood count) found on a blood test?"},"onset_after_50":{"type":"boolean","description":"Your gut symptoms first started after age 50?"},"family_history_colon_cancer":{"type":"boolean","description":"A parent, sibling or child with colon (bowel) cancer?"},"celiac_or_ibd":{"type":"boolean","description":"Celiac disease or inflammatory bowel disease (Crohn's or ulcerative colitis), diagnosed or in your close family?"}},"required":["blood_in_stool","unintended_weight_loss","night_symptoms","fever","anemia","onset_after_50","family_history_colon_cancer","celiac_or_ibd"],"description":"Ask each one plainly. Any yes means a doctor first."},"doctor_cleared":{"description":"Only when a red flag is yes: a doctor has assessed these symptoms and agreed a diet trial is appropriate.","type":"boolean"},"celiac_tested":{"description":"Has the person had a celiac blood test while still eating gluten? Cutting wheat first can make that test unreliable.","type":"boolean"}},"required":["age","pregnant_or_breastfeeding","eating_disorder_history","red_flags"],"description":"The safety screen. Ask the person every question; never assume an answer."}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"screen_for_program_get","summary":"Safety screen for a program (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. The safety screen every elimination program starts with. Without answers it returns the questions to ask (age, pregnancy or breastfeeding, eating-disorder history, and red flags: blood in stool, unintended weight loss, night-time symptoms, fever, anemia, symptoms starting after 50, family history of colon cancer, celiac or IBD). With answers it returns clear, see_doctor_first (a red flag: a doctor first) or blocked (under 18, pregnant or breastfeeding, or disordered eating: no restrictive diet here). Ask every question; never assume an answer. Nothing is stored. Free.","tags":["programs"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/start_program":{"post":{"operationId":"start_program","summary":"Start an elimination program","description":"Start an elimination program after the safety screen (pass the same answers as safety_screen). kind low_fodmap: elimination 2–6 weeks with low-FODMAP swaps and a weekly adequate-relief check, then reintroduction of one subgroup at a time (lactose, excess_fructose, sorbitol, mannitol, gos, fructans_wheat, fructans_garlic, fructans_onion; 3 days of increasing doses, then 3 washout days), then personalization. kind single_food with target (dairy, gluten, lactose, caffeine, capsaicin, alcohol, fructans, gos, excess_fructose, sorbitol, mannitol or any taxonomy ingredient id): remove 2–4 weeks, reintroduce over 3 days, compare. If the screen does not clear, nothing starts: the reply has status blocked and the reason to relay. Returns the program, its schedule and the next action. Recommend a registered dietitian. Plus plan.","tags":["programs"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"programs:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["low_fodmap","single_food"]},"target":{"description":"single_food only: dairy, gluten, lactose, caffeine, … or an ingredient id.","type":"string","minLength":1,"maxLength":80},"safety_screen":{"type":"object","properties":{"age":{"type":"integer","minimum":1,"maximum":120,"description":"The person's age in years."},"pregnant_or_breastfeeding":{"type":"boolean","description":"Is the person pregnant or breastfeeding?"},"eating_disorder_history":{"type":"boolean","description":"Has the person ever had an eating disorder or disordered eating (restricting, bingeing, purging)?"},"red_flags":{"type":"object","properties":{"blood_in_stool":{"type":"boolean","description":"Blood in your stool, or black, tarry stools?"},"unintended_weight_loss":{"type":"boolean","description":"Losing weight without trying?"},"night_symptoms":{"type":"boolean","description":"Symptoms that wake you up at night (pain or diarrhea)?"},"fever":{"type":"boolean","description":"Fever with your gut symptoms?"},"anemia":{"type":"boolean","description":"Anemia (low iron or low blood count) found on a blood test?"},"onset_after_50":{"type":"boolean","description":"Your gut symptoms first started after age 50?"},"family_history_colon_cancer":{"type":"boolean","description":"A parent, sibling or child with colon (bowel) cancer?"},"celiac_or_ibd":{"type":"boolean","description":"Celiac disease or inflammatory bowel disease (Crohn's or ulcerative colitis), diagnosed or in your close family?"}},"required":["blood_in_stool","unintended_weight_loss","night_symptoms","fever","anemia","onset_after_50","family_history_colon_cancer","celiac_or_ibd"],"description":"Ask each one plainly. Any yes means a doctor first."},"doctor_cleared":{"description":"Only when a red flag is yes: a doctor has assessed these symptoms and agreed a diet trial is appropriate.","type":"boolean"},"celiac_tested":{"description":"Has the person had a celiac blood test while still eating gluten? Cutting wheat first can make that test unreliable.","type":"boolean"}},"required":["age","pregnant_or_breastfeeding","eating_disorder_history","red_flags"],"description":"The safety screen. Ask the person every question; never assume an answer."},"phase_days":{"description":"Planned length of the elimination (14–42) or removal (14–28) phase; default 28 / 21.","type":"integer","minimum":14,"maximum":42}},"required":["kind","safety_screen"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_program":{"post":{"operationId":"get_program","summary":"Get a program","description":"The running elimination program (or one by id): phase, day, next action in words to relay, the schedule of challenges with doses and results, the tummy-score comparison before and during elimination, low-FODMAP swaps for foods the person actually ate recently, and the dietitian recommendation.","tags":["programs"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"programs:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"program_id":{"description":"Default: the running program.","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)$"}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_program_get","summary":"Get a program (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. The running elimination program (or one by id): phase, day, next action in words to relay, the schedule of challenges with doses and results, the tummy-score comparison before and during elimination, low-FODMAP swaps for foods the person actually ate recently, and the dietitian recommendation.","tags":["programs"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/record_relief_check":{"post":{"operationId":"record_relief_check","summary":"Record the weekly relief check","description":"The weekly question during elimination: \"Over the past 7 days, have you had adequate relief of your gut symptoms?\" Record yes or no. Reintroduction needs adequate relief after at least 2 weeks; no relief by 6 weeks means stop and talk to a doctor or dietitian.","tags":["programs"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"programs:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"program_id":{"description":"Default: the running program.","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)$"},"adequate_relief":{"type":"boolean"}},"required":["adequate_relief"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/record_challenge":{"post":{"operationId":"record_challenge","summary":"Record a challenge dose","description":"During reintroduction: record that the person ate today's challenge dose and how they reacted (none, mild, moderate, severe, or unsure). The first call starts the next challenge (or the one named in challenge). A moderate or severe reaction stops the challenge; after the third dose it is settled as tolerated or symptoms, with the largest dose that was fine, then a 3-day washout. One dose a day. Plus plan.","tags":["programs"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"programs:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"program_id":{"description":"Default: the running program.","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)$"},"challenge":{"description":"Which challenge to start: lactose, excess_fructose, sorbitol, mannitol, gos, fructans_wheat, fructans_garlic, fructans_onion; default the next pending one.","type":"string","maxLength":40},"reaction":{"type":"string","enum":["none","mild","moderate","severe","unsure"],"description":"How the person felt in the hours after the dose."},"notes":{"type":"string","maxLength":2000}},"required":["reaction"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/advance_program":{"post":{"operationId":"advance_program","summary":"Advance a program","description":"Move the running program to its next phase when it is ready: elimination → reintroduction (after 2+ weeks with adequate relief), removal → reintroduce (after 2+ weeks), reintroduction → personalization (every challenge done, or skip_remaining), then finish. Refuses with the reason when it is too early. Returns the program and, at the end, what to limit and what to eat freely. Plus plan.","tags":["programs"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"programs:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"program_id":{"description":"Default: the running program.","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)$"},"skip_remaining":{"default":false,"description":"Leave untested challenges out and move on.","type":"boolean"}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/stop_program":{"post":{"operationId":"stop_program","summary":"Stop a program","description":"Stop the running program (no relief at 6 weeks, too hard to follow, or a doctor's advice). The history stays. Suggest the person returns to a varied diet and talks to a doctor or dietitian if symptoms continue.","tags":["programs"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"programs:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"program_id":{"description":"Default: the running program.","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)$"},"reason":{"type":"string","maxLength":500}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_diary":{"post":{"operationId":"get_diary","summary":"Get the diary","description":"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).","tags":["insights"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"insights:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"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"}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_diary_get","summary":"Get the diary (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?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).","tags":["insights"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_nutrition_summary":{"post":{"operationId":"get_nutrition_summary","summary":"Get a nutrition summary","description":"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).","tags":["insights"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"insights:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"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"]}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_nutrition_summary_get","summary":"Get a nutrition summary (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?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).","tags":["insights"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/query_foods":{"post":{"operationId":"query_foods","summary":"Query the foods eaten","description":"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).","tags":["insights"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"insights:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"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}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"query_foods_get","summary":"Query the foods eaten (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?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).","tags":["insights"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/audit_diary":{"post":{"operationId":"audit_diary","summary":"Audit the diary","description":"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).","tags":["insights"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"insights:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"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}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"audit_diary_get","summary":"Audit the diary (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?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).","tags":["insights"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/export_data":{"post":{"operationId":"export_data","summary":"Export the data","description":"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.","tags":["insights"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"insights:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"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"]}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_goals":{"post":{"operationId":"get_goals","summary":"Get nutrition goals","description":"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.","tags":["insights"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"insights:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_goals_get","summary":"Get nutrition goals (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?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.","tags":["insights"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/set_goals":{"post":{"operationId":"set_goals","summary":"Set nutrition goals","description":"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.","tags":["insights"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"insights:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"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"}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_survey":{"post":{"operationId":"get_survey","summary":"Get the survey to ask","description":"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.","tags":["insights"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"insights:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_survey_get","summary":"Get the survey to ask (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?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.","tags":["insights"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/answer_survey":{"post":{"operationId":"answer_survey","summary":"Answer a survey","description":"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.","tags":["insights"],"x-read-only":false,"x-admin-only":false,"x-min-role":"viewer","x-scope":"insights:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"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"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_query_privacy":{"post":{"operationId":"get_query_privacy","summary":"Get query privacy","description":"Whether Gutlog keeps the words of free-text requests (keep_raw_queries, off by default) and what it keeps either way.","tags":["insights"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"insights:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_query_privacy_get","summary":"Get query privacy (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Whether Gutlog keeps the words of free-text requests (keep_raw_queries, off by default) and what it keeps either way.","tags":["insights"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/update_query_privacy":{"post":{"operationId":"update_query_privacy","summary":"Update query privacy","description":"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.","tags":["insights"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"insights:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"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"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_query_report":{"post":{"operationId":"get_query_report","summary":"Get the query analytics report","description":"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.","tags":["insights"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"insights:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"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)))$"}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_query_report_get","summary":"Get the query analytics report (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?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.","tags":["insights"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/list_locations":{"post":{"operationId":"list_locations","summary":"List pantry locations","description":"The household's storage locations as a tree (e.g. Kitchen fridge › Door, Freezer, Garage freezer, Pantry cupboard, Spice rack, Counter), each with its id, path, type (fridge, freezer, pantry, counter, other: the type decides shelf life), how many items are in it and inside it, and how many expire within 7 days. Call it before adding items to reuse the household's own names.","tags":["pantry"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"pantry:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"list_locations_get","summary":"List pantry locations (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. The household's storage locations as a tree (e.g. Kitchen fridge › Door, Freezer, Garage freezer, Pantry cupboard, Spice rack, Counter), each with its id, path, type (fridge, freezer, pantry, counter, other: the type decides shelf life), how many items are in it and inside it, and how many expire within 7 days. Call it before adding items to reuse the household's own names.","tags":["pantry"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/save_location":{"post":{"operationId":"save_location","summary":"Save pantry locations","description":"Create, rename, retype, nest or archive storage locations. A new one needs a name; its type defaults from the name (\"Garage freezer\" → freezer), then its parent. Archiving needs the location empty. You rarely need this: add_pantry_items creates the locations it is given by path. Batch: pass up to 200 entries; each succeeds or fails on its own (results[i].ok / results[i].error).","tags":["pantry"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"pantry:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"locations":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"object","properties":{"id":{"description":"The location to change. Omit to create one.","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)$"},"name":{"type":"string","minLength":1,"maxLength":80},"type":{"description":"fridge, freezer, pantry, counter or other. Default: from the name, then the parent's type.","type":"string","enum":["fridge","freezer","pantry","counter","other"]},"parent_id":{"description":"The location it is inside, e.g. a shelf in a fridge; null for top level.","anyOf":[{"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)$"},{"type":"null"}]},"position":{"type":"integer","minimum":0,"maximum":1000},"archived":{"description":"true archives it (only when empty).","type":"boolean"}}}}},"required":["locations"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/add_pantry_items":{"post":{"operationId":"add_pantry_items","summary":"Add pantry items","description":"Record food the household has: from a receipt, barcode scans, or a fridge, freezer or pantry photo you read yourself (you list what you see; nothing is analyzed here). Per item: a name (resolved to a canonical ingredient), optional ingredient_id or barcode, quantity and unit, where it is (location path like \"Kitchen fridge › Door\", location_type, or nothing: the place FoodKeeper keeps it), state (fresh, opened, cooked, frozen, thawed), dates, the printed date and its kind, price and store. Returns each item with its estimated expiry (from the printed date or USDA FoodKeeper for its storage and state, with the rule used), how its shelf life was matched, any storage warning, the locations created, and the names that did not resolve (fix with update_pantry_items). Batch: pass up to 200 entries; each succeeds or fails on its own (results[i].ok / results[i].error).","tags":["pantry"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"pantry:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"minItems":1,"maxItems":200,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"What it is, as the person would say it: \"whole milk\", \"chicken thighs\", \"Rao's marinara\". Resolved to a canonical ingredient when possible."},"ingredient_id":{"description":"Canonical ingredient id, when you know it. Omit to resolve from the name.","type":"string","minLength":1,"maxLength":100},"gtin":{"description":"Barcode (UPC/EAN/GTIN, 8–14 digits), when you read one.","type":"string","pattern":"^\\d{8,14}$"},"brand":{"type":"string","minLength":1,"maxLength":120},"quantity":{"default":1,"description":"How much. Default 1.","type":"number","exclusiveMinimum":0,"maximum":1000000},"unit":{"description":"Unit: mass (g, kg, oz, lb), volume (ml, l, tsp, tbsp, cup, fl_oz, pt, qt, gal) or a count (each, can, jar, bottle, bag, box, pack, bunch, head, clove, slice, loaf, carton, dozen, stick, tub, pouch). Plurals and \"lbs\", \"gallon\" are understood.","type":"string"},"location_id":{"description":"A location id from list_locations.","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)$"},"location":{"description":"A location by name or path, e.g. \"Kitchen fridge › Door\", \"Garage freezer\", \"Spice rack\" (› > or / separate levels). Missing levels are created.","type":"string","minLength":1,"maxLength":200},"location_type":{"description":"fridge, freezer, pantry, counter or other. Alone, it means the first location of that type (created as Fridge, Freezer… if there is none); with `location`, the type of a newly created one.","type":"string","enum":["fridge","freezer","pantry","counter","other"]},"state":{"description":"fresh (sealed or whole, the default), opened, cooked (leftovers), frozen (the default in a freezer), thawed.","type":"string","enum":["fresh","opened","cooked","frozen","thawed"]},"purchased_on":{"description":"Day it was bought (YYYY-MM-DD). 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])))$"},"opened_on":{"description":"Day it was opened.","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])))$"},"frozen_on":{"description":"Day it went into the freezer.","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])))$"},"thawed_on":{"description":"Day it came out of the freezer.","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])))$"},"cooked_on":{"description":"Day it was cooked (leftovers, meal prep).","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])))$"},"printed_date":{"description":"The date printed on the package.","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])))$"},"printed_kind":{"description":"What the printed date is: use_by (safety), best_by (quality; the default when a printed date is given), sell_by (for the store), freeze_by.","type":"string","enum":["use_by","best_by","sell_by","freeze_by"]},"expires_on":{"description":"Set the expiry yourself (overrides the estimate until the item is opened, moved or frozen).","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])))$"},"foodkeeper_id":{"description":"Pin the USDA FoodKeeper product its shelf life comes from (get_shelf_life finds one).","type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"price":{"description":"What it cost, in currency units (3.49).","type":"number","minimum":0,"maximum":100000},"currency":{"description":"ISO 4217 code. Default USD.","type":"string","pattern":"^[A-Z]{3}$"},"store":{"description":"Where it was bought.","type":"string","minLength":1,"maxLength":120},"notes":{"type":"string","minLength":1,"maxLength":1000},"source":{"description":"How you captured it: receipt, barcode, photo (you read a fridge or pantry photo), voice, manual. Default manual.","type":"string","enum":["manual","receipt","barcode","photo","voice","shopping_list","meal"]},"client":{"description":"Which assistant is calling (claude, chatgpt, cursor…), for provenance.","type":"string","minLength":1,"maxLength":40}},"required":["name"]},"description":"Up to 200 items, e.g. a whole receipt or everything you saw in a fridge photo."}},"required":["items"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/list_pantry":{"post":{"operationId":"list_pantry","summary":"List pantry items","description":"What is on hand, soonest expiry first. Filters: location_id (and everything inside it), location_type, ingredient_id, state, expiring_before (a day), q (name contains), status (active by default; consumed, discarded or all for history). Each item has its ingredient, quantity and unit, location path, state, dates, printed date, expiry (date, latest, days_left, source, rule, safety), freezable, price and provenance. `unresolved` counts items with no canonical ingredient.","tags":["pantry"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"pantry:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"location_id":{"description":"Only this location and the locations inside it.","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)$"},"location_type":{"type":"string","enum":["fridge","freezer","pantry","counter","other"]},"ingredient_id":{"type":"string","minLength":1,"maxLength":100,"description":"Canonical ingredient id from the taxonomy (e.g. garlic, natural-flavors)."},"state":{"type":"string","enum":["fresh","opened","cooked","frozen","thawed"]},"expiring_before":{"description":"Only items whose estimated expiry is on or before this day.","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])))$"},"q":{"description":"Name contains.","type":"string","minLength":1,"maxLength":100},"status":{"default":"active","description":"active (on hand, the default), consumed, discarded or all.","type":"string","enum":["active","consumed","discarded","all"]},"limit":{"default":200,"type":"integer","minimum":1,"maximum":500},"offset":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"list_pantry_get","summary":"List pantry items (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. What is on hand, soonest expiry first. Filters: location_id (and everything inside it), location_type, ingredient_id, state, expiring_before (a day), q (name contains), status (active by default; consumed, discarded or all for history). Each item has its ingredient, quantity and unit, location path, state, dates, printed date, expiry (date, latest, days_left, source, rule, safety), freezable, price and provenance. `unresolved` counts items with no canonical ingredient.","tags":["pantry"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_pantry_item":{"post":{"operationId":"get_pantry_item","summary":"Get a pantry item","description":"One item with its FoodKeeper shelf-life entry (days per storage, opened, thawed, freezer, tips) and its full history (added, used, moved, frozen, thawed, recounted, discarded: who, when, from which surface). Use it to explain an expiry date.","tags":["pantry"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"pantry:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"item_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":"Pantry item id (pantry_items.id)."}},"required":["item_id"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_pantry_item_get","summary":"Get a pantry item (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. One item with its FoodKeeper shelf-life entry (days per storage, opened, thawed, freezer, tips) and its full history (added, used, moved, frozen, thawed, recounted, discarded: who, when, from which surface). Use it to explain an expiry date.","tags":["pantry"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/update_pantry_items":{"post":{"operationId":"update_pantry_items","summary":"Update pantry items","description":"Change items: resolve what it is (ingredient_id, barcode, foodkeeper_id), recount (quantity: how much is there now), change state (opened, cooked; freezing and thawing is move_pantry_items), dates, the printed date, an expiry you set yourself (expires_on; null returns to the estimate), price, store, notes. The expiry is re-estimated when the state or dates change. For food eaten use consume_pantry_items; thrown out, discard_pantry_items. Batch: pass up to 200 entries; each succeeds or fails on its own (results[i].ok / results[i].error).","tags":["pantry"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"pantry:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"minItems":1,"maxItems":200,"type":"array","items":{"type":"object","properties":{"item_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":"Pantry item id (pantry_items.id)."},"name":{"type":"string","minLength":1,"maxLength":200},"ingredient_id":{"description":"Resolve (or correct) what it is; null clears it.","anyOf":[{"type":"string","minLength":1,"maxLength":100,"description":"Canonical ingredient id from the taxonomy (e.g. garlic, natural-flavors)."},{"type":"null"}]},"gtin":{"anyOf":[{"type":"string","pattern":"^\\d{8,14}$"},{"type":"null"}]},"foodkeeper_id":{"anyOf":[{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},{"type":"null"}]},"brand":{"anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"null"}]},"quantity":{"description":"A recount: how much is there now (an adjust event). Use consume_pantry_items for what was eaten.","type":"number","minimum":0,"maximum":1000000},"unit":{"description":"Unit: mass (g, kg, oz, lb), volume (ml, l, tsp, tbsp, cup, fl_oz, pt, qt, gal) or a count (each, can, jar, bottle, bag, box, pack, bunch, head, clove, slice, loaf, carton, dozen, stick, tub, pouch). Plurals and \"lbs\", \"gallon\" are understood.","type":"string"},"state":{"description":"opened, cooked, thawed… Moving into or out of a freezer is move_pantry_items.","type":"string","enum":["fresh","opened","cooked","frozen","thawed"]},"purchased_on":{"anyOf":[{"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])))$"},{"type":"null"}]},"opened_on":{"description":"Day it was opened; setting state opened without it means today.","anyOf":[{"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])))$"},{"type":"null"}]},"frozen_on":{"anyOf":[{"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])))$"},{"type":"null"}]},"thawed_on":{"anyOf":[{"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])))$"},{"type":"null"}]},"cooked_on":{"anyOf":[{"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])))$"},{"type":"null"}]},"printed_date":{"description":"The printed date; null clears it.","anyOf":[{"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])))$"},{"type":"null"}]},"printed_kind":{"type":"string","enum":["use_by","best_by","sell_by","freeze_by"]},"expires_on":{"description":"Set the expiry yourself; null goes back to the estimate.","anyOf":[{"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])))$"},{"type":"null"}]},"price":{"anyOf":[{"type":"number","minimum":0,"maximum":100000},{"type":"null"}]},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"store":{"anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"null"}]},"notes":{"anyOf":[{"type":"string","minLength":1,"maxLength":1000},{"type":"null"}]}},"required":["item_id"]}}},"required":["items"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/move_pantry_items":{"post":{"operationId":"move_pantry_items","summary":"Move pantry items","description":"Move items to another location (location_id, a path, or a type). Into a freezer the item becomes frozen from today; out of one, thawed from today; either way the expiry is re-estimated (e.g. chicken: 9 months frozen, then 1–2 days in the fridge after thawing). Batch: pass up to 200 entries; each succeeds or fails on its own (results[i].ok / results[i].error).","tags":["pantry"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"pantry:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"minItems":1,"maxItems":200,"type":"array","items":{"type":"object","properties":{"item_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":"Pantry item id (pantry_items.id)."},"location_id":{"description":"A location id from list_locations.","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)$"},"location":{"description":"A location by name or path, e.g. \"Kitchen fridge › Door\", \"Garage freezer\", \"Spice rack\" (› > or / separate levels). Missing levels are created.","type":"string","minLength":1,"maxLength":200},"location_type":{"description":"fridge, freezer, pantry, counter or other. Alone, it means the first location of that type (created as Fridge, Freezer… if there is none); with `location`, the type of a newly created one.","type":"string","enum":["fridge","freezer","pantry","counter","other"]}},"required":["item_id"]},"description":"Each item and where it goes. Into a freezer it becomes frozen; out of one, thawed."}},"required":["items"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/consume_pantry_items":{"post":{"operationId":"consume_pantry_items","summary":"Use pantry items","description":"Record food used: by item_id, or by ingredient_id or name (the soonest-expiring matching items are used first). quantity is optional (all of one item when omitted) and converts between units of the same kind (200 g from a 1 lb pack). Pass meal_id when it went into a logged meal. Items used up leave the pantry and can come back on get_shopping_list. Returns what was used and what is left; `short` when there was not enough. Batch: pass up to 200 entries; each succeeds or fails on its own (results[i].ok / results[i].error).","tags":["pantry"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"pantry:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"minItems":1,"maxItems":200,"type":"array","items":{"type":"object","properties":{"item_id":{"description":"The item used. Or give ingredient_id or name: the soonest-expiring matching items are used first.","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)$"},"ingredient_id":{"type":"string","minLength":1,"maxLength":100,"description":"Canonical ingredient id from the taxonomy (e.g. garlic, natural-flavors)."},"name":{"type":"string","minLength":1,"maxLength":200},"quantity":{"description":"How much was used. Omit to use it all (by item_id: that item; by ingredient: one item).","type":"number","exclusiveMinimum":0,"maximum":1000000},"unit":{"description":"Unit of `quantity`; default the item's own. Mass converts to mass, volume to volume.","type":"string"},"meal_id":{"description":"The logged meal it went into (log_meal).","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)$"}}}}},"required":["items"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/discard_pantry_items":{"post":{"operationId":"discard_pantry_items","summary":"Throw out pantry items","description":"Record food thrown out, all or part, with a reason (expired, spoiled, freezer_burn, didnt_like, too_much, other) for waste tracking; pantry_summary totals it with its cost when the price is known. Batch: pass up to 200 entries; each succeeds or fails on its own (results[i].ok / results[i].error).","tags":["pantry"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"pantry:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"minItems":1,"maxItems":200,"type":"array","items":{"type":"object","properties":{"item_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":"Pantry item id (pantry_items.id)."},"reason":{"default":"expired","description":"expired, spoiled, freezer_burn, didnt_like, too_much or other. Default expired.","type":"string","enum":["expired","spoiled","freezer_burn","didnt_like","too_much","other"]},"quantity":{"description":"Only part of it. Omit to throw it all out.","type":"number","exclusiveMinimum":0,"maximum":1000000},"unit":{"description":"Unit: mass (g, kg, oz, lb), volume (ml, l, tsp, tbsp, cup, fl_oz, pt, qt, gal) or a count (each, can, jar, bottle, bag, box, pack, bunch, head, clove, slice, loaf, carton, dozen, stick, tub, pouch). Plurals and \"lbs\", \"gallon\" are understood.","type":"string"},"notes":{"type":"string","minLength":1,"maxLength":500}},"required":["item_id"]}}},"required":["items"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/list_expiring":{"post":{"operationId":"list_expiring","summary":"List expiring food","description":"Items expiring within `days` (default 7) and, by default, already past their date, soonest first, each with days_left and a suggested action: use, freeze (freezable, not frozen, 2 days or less left) or toss (past a use-by or the safe time for perishable food), with a one-line why. Past a best-by or a freezer quality date the action is use (check it), not toss. Use it to suggest what to cook first.","tags":["pantry"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"pantry:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"days":{"default":7,"description":"Look this many days ahead. Default 7.","type":"integer","minimum":0,"maximum":365},"include_expired":{"default":true,"description":"Also list items already past their date. Default true.","type":"boolean"},"location_type":{"type":"string","enum":["fridge","freezer","pantry","counter","other"]}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"list_expiring_get","summary":"List expiring food (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Items expiring within `days` (default 7) and, by default, already past their date, soonest first, each with days_left and a suggested action: use, freeze (freezable, not frozen, 2 days or less left) or toss (past a use-by or the safe time for perishable food), with a one-line why. Past a best-by or a freezer quality date the action is use (check it), not toss. Use it to suggest what to cook first.","tags":["pantry"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/freeze_suggestions":{"post":{"operationId":"freeze_suggestions","summary":"Suggest what to freeze","description":"Items not frozen that FoodKeeper says freeze well and that expire within `days` (default 3), with how long each would keep if frozen today. Never items already past their date, nor thawed food that did not thaw in the fridge. Freeze them with move_pantry_items to a freezer.","tags":["pantry"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"pantry:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"days":{"default":3,"description":"Items expiring within this many days. Default 3.","type":"integer","minimum":0,"maximum":60}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"freeze_suggestions_get","summary":"Suggest what to freeze (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Items not frozen that FoodKeeper says freeze well and that expire within `days` (default 3), with how long each would keep if frozen today. Never items already past their date, nor thawed food that did not thaw in the fridge. Freeze them with move_pantry_items to a freezer.","tags":["pantry"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_raw_ingredients":{"post":{"operationId":"get_raw_ingredients","summary":"Get raw ingredients on hand","description":"The canonical ingredients on hand, deduplicated across items and locations: total amount (mass in g/kg, volume in ml/l, counts per unit), item ids, states, locations, soonest expiry and days left, soonest first; plus `unresolved` items with no ingredient. This is the list to plan meals or recipes from.","tags":["pantry"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"pantry:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_raw_ingredients_get","summary":"Get raw ingredients on hand (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. The canonical ingredients on hand, deduplicated across items and locations: total amount (mass in g/kg, volume in ml/l, counts per unit), item ids, states, locations, soonest expiry and days left, soonest first; plus `unresolved` items with no ingredient. This is the list to plan meals or recipes from.","tags":["pantry"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/set_par_levels":{"post":{"operationId":"set_par_levels","summary":"Set staple quantities","description":"Staples the household always wants on hand (\"12 eggs\", \"1 gal milk\", \"2 cans tomatoes\"), with an optional usual location and store. quantity 0 removes a staple. get_shopping_list adds staples below their level. Batch: pass up to 200 entries; each succeeds or fails on its own (results[i].ok / results[i].error).","tags":["pantry"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"pantry:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"levels":{"minItems":1,"maxItems":200,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"The staple: \"eggs\", \"milk\", \"canned tomatoes\"."},"ingredient_id":{"type":"string","minLength":1,"maxLength":100,"description":"Canonical ingredient id from the taxonomy (e.g. garlic, natural-flavors)."},"quantity":{"type":"number","minimum":0,"maximum":1000000,"description":"How much to always have. 0 removes the staple."},"unit":{"description":"Unit: mass (g, kg, oz, lb), volume (ml, l, tsp, tbsp, cup, fl_oz, pt, qt, gal) or a count (each, can, jar, bottle, bag, box, pack, bunch, head, clove, slice, loaf, carton, dozen, stick, tub, pouch). Plurals and \"lbs\", \"gallon\" are understood.","type":"string"},"location_id":{"description":"A location id from list_locations.","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)$"},"location":{"description":"A location by name or path, e.g. \"Kitchen fridge › Door\", \"Garage freezer\", \"Spice rack\" (› > or / separate levels). Missing levels are created.","type":"string","minLength":1,"maxLength":200},"location_type":{"description":"fridge, freezer, pantry, counter or other. Alone, it means the first location of that type (created as Fridge, Freezer… if there is none); with `location`, the type of a newly created one.","type":"string","enum":["fridge","freezer","pantry","counter","other"]},"store":{"type":"string","minLength":1,"maxLength":120}},"required":["name","quantity"]}}},"required":["levels"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_shopping_list":{"post":{"operationId":"get_shopping_list","summary":"Get the shopping list","description":"What to buy: items added to the list, staples below their par level (with the amount missing), and items used up in the last `used_up_days` (default 14) that are not on hand. Each line has a key (check it off by key), source (manual, par, used_up) and why; `by_store` groups them by store when known.","tags":["pantry"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"pantry:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"used_up_days":{"default":14,"description":"Suggest items used up in this many days that are not on hand. Default 14; 0 turns it off.","type":"integer","minimum":0,"maximum":90}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_shopping_list_get","summary":"Get the shopping list (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. What to buy: items added to the list, staples below their par level (with the amount missing), and items used up in the last `used_up_days` (default 14) that are not on hand. Each line has a key (check it off by key), source (manual, par, used_up) and why; `by_store` groups them by store when known.","tags":["pantry"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/add_shopping_items":{"post":{"operationId":"add_shopping_items","summary":"Add to the shopping list","description":"Put items on the shopping list (name, optional ingredient_id, quantity and unit, store, notes). Adding something already on the list adds to its quantity. Batch: pass up to 200 entries; each succeeds or fails on its own (results[i].ok / results[i].error).","tags":["pantry"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"pantry:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"minItems":1,"maxItems":200,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"ingredient_id":{"type":"string","minLength":1,"maxLength":100,"description":"Canonical ingredient id from the taxonomy (e.g. garlic, natural-flavors)."},"quantity":{"type":"number","exclusiveMinimum":0,"maximum":1000000},"unit":{"description":"Unit: mass (g, kg, oz, lb), volume (ml, l, tsp, tbsp, cup, fl_oz, pt, qt, gal) or a count (each, can, jar, bottle, bag, box, pack, bunch, head, clove, slice, loaf, carton, dozen, stick, tub, pouch). Plurals and \"lbs\", \"gallon\" are understood.","type":"string"},"store":{"type":"string","minLength":1,"maxLength":120},"notes":{"type":"string","minLength":1,"maxLength":500}},"required":["name"]}}},"required":["items"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/check_off_shopping_items":{"post":{"operationId":"check_off_shopping_items","summary":"Check off shopping items","description":"Mark list lines bought (or removed). By id, or key/name for a suggested line. Bought items go into the pantry (add_to_pantry, default true) at the staple's usual location or where FoodKeeper keeps them, with today's purchase date and any printed date, price and store you give. Batch: pass up to 200 entries; each succeeds or fails on its own (results[i].ok / results[i].error).","tags":["pantry"],"x-read-only":false,"x-admin-only":false,"x-min-role":"member","x-scope":"pantry:write","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"minItems":1,"maxItems":200,"type":"array","items":{"type":"object","properties":{"id":{"description":"A shopping list item id. Suggested rows have none: give their key or name.","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)$"},"key":{"type":"string","minLength":1,"maxLength":200},"name":{"type":"string","minLength":1,"maxLength":200},"status":{"default":"bought","type":"string","enum":["bought","removed"]},"add_to_pantry":{"default":true,"description":"Put a bought item into the pantry. Default true.","type":"boolean"},"quantity":{"description":"How much was bought; default the list's quantity, or 1.","type":"number","exclusiveMinimum":0,"maximum":1000000},"unit":{"description":"Unit: mass (g, kg, oz, lb), volume (ml, l, tsp, tbsp, cup, fl_oz, pt, qt, gal) or a count (each, can, jar, bottle, bag, box, pack, bunch, head, clove, slice, loaf, carton, dozen, stick, tub, pouch). Plurals and \"lbs\", \"gallon\" are understood.","type":"string"},"location_id":{"description":"A location id from list_locations.","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)$"},"location":{"description":"A location by name or path, e.g. \"Kitchen fridge › Door\", \"Garage freezer\", \"Spice rack\" (› > or / separate levels). Missing levels are created.","type":"string","minLength":1,"maxLength":200},"location_type":{"description":"fridge, freezer, pantry, counter or other. Alone, it means the first location of that type (created as Fridge, Freezer… if there is none); with `location`, the type of a newly created one.","type":"string","enum":["fridge","freezer","pantry","counter","other"]},"printed_date":{"description":"The date printed on the package.","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])))$"},"printed_kind":{"description":"What the printed date is: use_by (safety), best_by (quality; the default when a printed date is given), sell_by (for the store), freeze_by.","type":"string","enum":["use_by","best_by","sell_by","freeze_by"]},"price":{"type":"number","minimum":0,"maximum":100000},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"store":{"type":"string","minLength":1,"maxLength":120}}}}},"required":["items"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/pantry_summary":{"post":{"operationId":"pantry_summary","summary":"Pantry summary","description":"Counts on hand by location and state, how many are expired and expiring this week, unresolved items, and this month's use and waste: items thrown out, their cost when known, reasons and the foods most often thrown out.","tags":["pantry"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"pantry:read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"pantry_summary_get","summary":"Pantry summary (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. Counts on hand by location and state, how many are expired and expiring this week, unresolved items, and this month's use and waste: items thrown out, their cost when known, reasons and the foods most often thrown out.","tags":["pantry"],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/get_shelf_life":{"post":{"operationId":"get_shelf_life","summary":"Look up shelf life","description":"How long a food keeps in the pantry, fridge and freezer, sealed, opened and after thawing, from USDA FoodKeeper (public domain), by name, ingredient_id or foodkeeper_id. Days as {min, max} or a marker: package_date, indefinitely, when_ripe, not_recommended. Use the returned foodkeeper_id to pin an item's shelf life. Needs no account.","tags":["pantry"],"x-read-only":true,"x-admin-only":false,"x-min-role":"viewer","x-scope":"pantry:read","security":[{},{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"A food as people say it: \"ketchup\", \"ground beef\".","type":"string","minLength":1,"maxLength":200},"ingredient_id":{"type":"string","minLength":1,"maxLength":100,"description":"Canonical ingredient id from the taxonomy (e.g. garlic, natural-flavors)."},"foodkeeper_id":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"get_shelf_life_get","summary":"Look up shelf life (GET)","description":"Read-only ops also answer GET with the input as URL-encoded JSON in ?input=. How long a food keeps in the pantry, fridge and freezer, sealed, opened and after thawing, from USDA FoodKeeper (public domain), by name, ingredient_id or foodkeeper_id. Days as {min, max} or a marker: package_date, indefinitely, when_ripe, not_recommended. Use the returned foodkeeper_id to pin an item's shelf life. Needs no account.","tags":["pantry"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"input","in":"query","required":false,"description":"The op's input as URL-encoded JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/pricing":{"get":{"operationId":"pricing","summary":"Pricing document","description":"Every plan with price {monthly, yearly} in USD, analyses included per day, limits (history days), features, overage and a checkout_url, plus free_tier and how_to_buy. Public and cacheable; the same shape on every Meter product. ?ref= names the referrer carried on the checkout links.","tags":["billing"],"security":[],"parameters":[{"name":"ref","in":"query","required":false,"description":"Attribution slug, e.g. agent-cursor.","schema":{"type":"string"}}],"responses":{"200":{"description":"The pricing document.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/api/v1/feedback":{"get":{"operationId":"list_feedback_get_api_v_feedback","summary":"List the feedback board","description":"Feature requests and your own issues with status and votes. Public without a credential; ?mine=true returns list_my_feedback instead. Same as POST /api/v1/list_feedback.","tags":["feedback"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"kind","in":"query","required":false,"description":"feature, issue or all.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"active, all, open, planned, in_progress, done, declined or duplicate.","schema":{"type":"string"}},{"name":"sort","in":"query","required":false,"description":"top, new or recent_activity.","schema":{"type":"string"}},{"name":"q","in":"query","required":false,"description":"Words in the title.","schema":{"type":"string"}},{"name":"mine","in":"query","required":false,"description":"true for your items, subscriptions and review (list_my_feedback).","schema":{"type":"boolean"}},{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer"}},{"name":"cursor","in":"query","required":false,"description":"next_cursor from the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/feedback/{id}":{"get":{"operationId":"get_feedback_get_api_v_feedback_id","summary":"Get a feedback item","description":"One item with comments and timeline. Same as POST /api/v1/get_feedback.","tags":["feedback"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The feedback item id.","schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/feedback/features":{"post":{"operationId":"request_feature_post_api_v_feedback_features","summary":"Request a feature","description":"Files a feature request (or returns similar items, filed: false). Same as POST /api/v1/request_feature.","tags":["feedback"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":3,"maxLength":140,"description":"What you want, in one line."},"details":{"default":"","description":"Why you need it and what you are building; concrete examples help it get planned.","type":"string","maxLength":5000},"body":{"description":"Alias of details.","type":"string","maxLength":5000},"force":{"default":false,"description":"File even when similar items exist.","type":"boolean"}},"required":["title"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/feedback/issues":{"post":{"operationId":"report_issue_post_api_v_feedback_issues","summary":"Report an issue","description":"Files a private issue report with request context. Same as POST /api/v1/report_issue.","tags":["feedback"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":3,"maxLength":140,"description":"What is wrong, in one line."},"details":{"default":"","description":"What you did, what you expected and what happened (status, error code, format).","type":"string","maxLength":5000},"body":{"description":"Alias of details.","type":"string","maxLength":5000},"request_id":{"description":"The request_id of the failing call (shortcut for context.request_id).","type":"string","maxLength":128},"op":{"description":"The op the failing call used, e.g. log_meal (shortcut for context.op).","type":"string","maxLength":80},"context":{"description":"Gutlog identifiers for what failed: request_id, op, meal_id, program_id, gtin, status, error_code, error, client. Never shown publicly; at most 128 KB.","type":"object","properties":{"request_id":{"description":"The request_id of the failing call (X-Request-Id header, or request_id in the error).","type":"string","pattern":"^[A-Za-z0-9._:-]{1,128}$"},"op":{"description":"The op or endpoint that failed, e.g. log_meal.","type":"string","pattern":"^[a-z][a-z0-9_]{1,79}$"},"meal_id":{"description":"The meal involved (meals.id); must be one of your organization's.","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)$"},"program_id":{"description":"The elimination program involved; must be one of your organization's.","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)$"},"gtin":{"description":"The barcode involved (products are public data).","type":"string","pattern":"^[0-9]{8,14}$"},"locale":{"description":"The language involved, e.g. pt_BR.","type":"string","pattern":"^[A-Za-z]{2,8}([-_][A-Za-z0-9]{1,8})*$"},"status":{"description":"The HTTP status the call returned.","type":"integer","minimum":100,"maximum":599},"error_code":{"description":"The error code, e.g. daily_limit_reached.","type":"string","maxLength":100},"error":{"description":"The error message as the client saw it (no keys, no food or symptom text).","type":"string","maxLength":2000},"client":{"description":"Client and version, e.g. gutlog-cli/0.5.0 or Claude Code.","type":"string","maxLength":100},"version":{"type":"string","maxLength":50},"extra":{"description":"Anything else that helps reproduce it (no secrets, no health data).","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"additionalProperties":false},"force":{"default":false,"description":"File even when similar reports exist.","type":"boolean"}},"required":["title"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/feedback/{id}/votes":{"post":{"operationId":"upvote_feedback_post_api_v_feedback_id_votes","summary":"Upvote","description":"Adds your organization's vote. Same as POST /api/v1/upvote_feedback.","tags":["feedback"],"parameters":[{"name":"id","in":"path","required":true,"description":"The feedback item id.","schema":{"type":"integer","minimum":1}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The item's id from list_feedback, request_feature or report_issue (e.g. 42)."}},"required":["id"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"delete":{"operationId":"remove_feedback_vote_delete_api_v_feedback_id_votes","summary":"Remove upvote","description":"Takes your organization's vote back. Same as POST /api/v1/remove_feedback_vote.","tags":["feedback"],"parameters":[{"name":"id","in":"path","required":true,"description":"The feedback item id.","schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/feedback/{id}/comments":{"post":{"operationId":"comment_on_feedback_post_api_v_feedback_id_comments","summary":"Comment","description":"Adds a comment ({\"body\": \"…\"}). Same as POST /api/v1/comment_on_feedback.","tags":["feedback"],"parameters":[{"name":"id","in":"path","required":true,"description":"The feedback item id.","schema":{"type":"integer","minimum":1}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"The item's id from list_feedback, request_feature or report_issue (e.g. 42)."},"body":{"type":"string","minLength":1,"maxLength":5000,"description":"The comment."}},"required":["id","body"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/reviews":{"get":{"operationId":"list_reviews_get_api_v_reviews","summary":"List reviews","description":"Published reviews with the aggregate rating. Public. Same as POST /api/v1/list_reviews.","tags":["feedback"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"sort","in":"query","required":false,"description":"newest, helpful, highest or lowest.","schema":{"type":"string"}},{"name":"rating","in":"query","required":false,"description":"Only this rating.","schema":{"type":"integer"}}],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/reviews/me":{"put":{"operationId":"submit_review_put_api_v_reviews_me","summary":"Post or edit your review","description":"Your organization's one review. Same as POST /api/v1/submit_review.","tags":["feedback"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rating":{"type":"integer","minimum":1,"maximum":5,"description":"1 (poor) to 5 (excellent)."},"title":{"default":"","description":"One-line summary.","type":"string","maxLength":120},"body":{"default":"","description":"The review.","type":"string","maxLength":2000},"likes":{"default":"","description":"What works well.","type":"string","maxLength":1000},"dislikes":{"default":"","description":"What should be better.","type":"string","maxLength":1000},"use_case":{"default":"","description":"What you use Gutlog for.","type":"string","maxLength":200},"display_name":{"description":"Name shown with the review; defaults to your first name.","type":"string","maxLength":60},"display_company":{"description":"Company shown with the review, if any.","type":"string","maxLength":80},"marketing_consent":{"default":false,"description":"May Meter quote this review on the site and in marketing.","type":"boolean"}},"required":["rating"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/account":{"get":{"operationId":"get_account_account","summary":"Get account","description":"Plan, renewal, usage against every limit, what remains and what the next plan adds. Same as GET /api/v1/get_account.","tags":["billing"],"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/billing/checkout":{"post":{"operationId":"create_checkout_link_checkout","summary":"Create checkout link","description":"A Stripe Checkout URL for a human, with or without a credential (before signup). Same as POST /api/v1/create_checkout_link.","tags":["billing"],"security":[{},{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"plan":{"type":"string","enum":["plus"],"description":"plus. get_pricing lists what it includes."},"interval":{"default":"month","description":"month ($8), or year ($60).","type":"string","enum":["month","year"]},"ref":{"description":"Optional attribution slug for the link (e.g. agent-cursor). Defaults to the surface: agent-mcp, agent-cli or agent-api.","type":"string","pattern":"^[a-z0-9][a-z0-9_-]{0,39}$"}},"required":["plan"]}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/billing/portal":{"post":{"operationId":"get_billing_link_portal","summary":"Get billing link","description":"The Stripe customer portal for a human: invoices, card, plan change, cancellation. Same as POST /api/v1/get_billing_link.","tags":["billing"],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"The op's output.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Invalid JSON or input that fails the schema (invalid_json, invalid_input).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid credential (unauthorized, invalid_key, invalid_token).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Payment failed or a plan limit was reached; carries checkout_url and the paid plans.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The credential's role or scopes do not allow the op, or no organization is available (forbidden, scope_missing, no_organization).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Unknown op or record (unknown_op, not_found).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"The request conflicts with the current state.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"The input is well-formed but cannot be applied.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limited. Retry after Retry-After seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error. Retry and quote request_id.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An organization API key (gutlog_…) or an OAuth access token. X-Api-Key is accepted as an alternative header."}},"schemas":{"Problem":{"type":"object","description":"RFC 9457 problem details.","required":["type","title","status","detail"],"properties":{"type":{"type":"string","format":"uri","description":"https://getgutlog.com/docs/errors#{status}"},"title":{"type":"string","description":"The error code."},"status":{"type":"integer"},"detail":{"type":"string","description":"What went wrong and what to do about it."},"code":{"type":"string","enum":["invalid_json","invalid_input","invalid_slug","confirm_mismatch","principal_required","same_person","no_person","invalid_grant","expired_token","access_denied","unauthorized","invalid_key","expired_key","invalid_token","payment_failed","plan_limit","forbidden","scope_missing","scope_escalation","dashboard_only","person_required","no_organization","unknown_op","not_found","method_not_allowed","organization_exists","team_exists","already_member","last_owner","already_subscribed","subscription_active","no_subscription","checkout_incomplete","already_claimed","checkout_unavailable","no_email","context_too_large","authorization_pending","rate_limited","internal_error","billing_unavailable"]},"request_id":{"type":"string"},"issues":{"type":"array","items":{"type":"object"},"description":"Schema issues for invalid_input."}}},"OpsManifest":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"mcp":{"type":"string","format":"uri"},"openapi":{"type":"string","format":"uri"},"ops":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"group":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"read_only":{"type":"boolean"},"admin_only":{"type":"boolean"},"input_schema":{"type":"object"}}}}}}}}}