{"openapi":"3.1.0","info":{"title":"HACCP Control API","version":"1.0.0","description":"REST API exposing the actions of the HACCP Control product. Authenticate with a Kavaro API key as a bearer token."},"servers":[{"url":"https://kavaro.ai"}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","description":"A Kavaro API key (user- or organization-scoped)."}}},"security":[{"ApiKeyAuth":[]}],"paths":{"/api/rest/actions/list_sites":{"post":{"operationId":"list_sites","summary":"List sites","description":"List the food business's sites/locations with their id, name, address, country, branchekode/ATECO and status.","tags":["actions"],"security":[{"ApiKeyAuth":[]}],"x-required-permissions":["sites:view"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"additionalProperties":false}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object","properties":{"result":{}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key may not invoke this action"},"404":{"description":"Unknown action"}}}},"/api/rest/actions/get_site":{"post":{"operationId":"get_site","summary":"Inspect site","description":"Get one site with all its fields and the count of its check-library templates.","tags":["actions"],"security":[{"ApiKeyAuth":[]}],"x-required-permissions":["sites:view"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"siteId":{"type":"string","description":"The site to inspect"}},"required":["siteId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object","properties":{"result":{}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key may not invoke this action"},"404":{"description":"Unknown action"}}}},"/api/rest/actions/list_templates":{"post":{"operationId":"list_templates","summary":"List checks","description":"List the check-library templates for a site (its HACCP checklist) with id, name, category, frequency, spec and required flag. Optionally filter by category.","tags":["actions"],"security":[{"ApiKeyAuth":[]}],"x-required-permissions":["templates:view"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"siteId":{"description":"Only templates for this site","type":"string"},"category":{"description":"Only checks of this category","type":"string","enum":["receiving","storage","cold_chain","cooking","cleaning","allergen","hygiene","pest","calibration","other"]},"limit":{"description":"Max to return; defaults to 200","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"additionalProperties":false}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object","properties":{"result":{}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key may not invoke this action"},"404":{"description":"Unknown action"}}}},"/api/rest/actions/get_template":{"post":{"operationId":"get_template","summary":"Inspect check","description":"Get one check-library template with all its fields.","tags":["actions"],"security":[{"ApiKeyAuth":[]}],"x-required-permissions":["templates:view"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"templateId":{"type":"string","description":"The check to inspect"}},"required":["templateId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object","properties":{"result":{}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key may not invoke this action"},"404":{"description":"Unknown action"}}}},"/api/rest/actions/list_daily_logs":{"post":{"operationId":"list_daily_logs","summary":"List daily logs","description":"List logged days (the egenkontrol binder) for a site, newest first, with each log's id, date, pass/fail tally, status and when it was exported/signed.","tags":["actions"],"security":[{"ApiKeyAuth":[]}],"x-required-permissions":["logs:view"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"siteId":{"description":"Only logs for this site","type":"string"},"limit":{"description":"Max to return; defaults to 30","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"additionalProperties":false}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object","properties":{"result":{}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key may not invoke this action"},"404":{"description":"Unknown action"}}}},"/api/rest/actions/get_daily_log":{"post":{"operationId":"get_daily_log","summary":"Inspect daily log","description":"Get one logged day with every check in it: result, measured value, notes, corrective action and whether a photo was attached.","tags":["actions"],"security":[{"ApiKeyAuth":[]}],"x-required-permissions":["logs:view"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"dailyLogId":{"type":"string","description":"The daily log to inspect"}},"required":["dailyLogId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object","properties":{"result":{}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key may not invoke this action"},"404":{"description":"Unknown action"}}}},"/api/rest/actions/list_check_logs":{"post":{"operationId":"list_check_logs","summary":"List check entries","description":"List the individual check entries in a logged day, or the entries for one template across time.","tags":["actions"],"security":[{"ApiKeyAuth":[]}],"x-required-permissions":["logs:view"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"dailyLogId":{"description":"Only entries in this logged day","type":"string"},"templateId":{"description":"Only entries for this check","type":"string"},"limit":{"description":"Max to return; defaults to 100","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"additionalProperties":false}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object","properties":{"result":{}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key may not invoke this action"},"404":{"description":"Unknown action"}}}},"/api/rest/actions/create_site":{"post":{"operationId":"create_site","summary":"Add site","description":"Add a food business's site/location with its address, country and (optionally) its DK branchekode or IT ATECO code, which seed the check library.","tags":["actions"],"security":[{"ApiKeyAuth":[]}],"x-required-permissions":["sites:edit"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"name":{"type":"string","description":"e.g. 'Main restaurant' or 'Bageriet på Strandvejen'"},"addressLine":{"type":"string"},"country":{"description":"ISO country code; defaults to DK","type":"string"},"branchekode":{"description":"DK CVR branchekode, e.g. 561010","type":"string"},"ateco":{"description":"IT ATECO code, e.g. 56.11.11","type":"string"}},"required":["name"],"additionalProperties":false}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object","properties":{"result":{}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key may not invoke this action"},"404":{"description":"Unknown action"}}}},"/api/rest/actions/update_site":{"post":{"operationId":"update_site","summary":"Update site","description":"Update a site's details or status.","tags":["actions"],"security":[{"ApiKeyAuth":[]}],"x-required-permissions":["sites:edit"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"siteId":{"type":"string"},"name":{"type":"string"},"addressLine":{"type":"string"},"country":{"type":"string"},"branchekode":{"type":"string"},"ateco":{"type":"string"},"status":{"type":"string","enum":["active","inactive"]}},"required":["siteId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object","properties":{"result":{}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key may not invoke this action"},"404":{"description":"Unknown action"}}}},"/api/rest/actions/delete_site":{"post":{"operationId":"delete_site","summary":"Delete site","description":"Permanently delete a site and everything logged for it.","tags":["actions"],"security":[{"ApiKeyAuth":[]}],"x-required-permissions":["sites:delete"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"siteId":{"type":"string"}},"required":["siteId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object","properties":{"result":{}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key may not invoke this action"},"404":{"description":"Unknown action"}}}},"/api/rest/actions/apply_preset":{"post":{"operationId":"apply_preset","summary":"Load check presets","description":"Seed a site's check library from a HACCP preset: a DK branchekode, an IT ATECO, or the default EU core (Reg. 852/2004). Checks that already exist for the site are left untouched; this only adds the missing ones. Use it right after creating a site so the mandatory daily checks exist.","tags":["actions"],"security":[{"ApiKeyAuth":[]}],"x-required-permissions":["templates:edit"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"siteId":{"type":"string","description":"The site to load presets into"},"source":{"description":"Preset source; defaults to the site's branchekode/ATECO, else the EU core","type":"string","enum":["eu_core","branchekode","ateco"]}},"required":["siteId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object","properties":{"result":{}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key may not invoke this action"},"404":{"description":"Unknown action"}}}},"/api/rest/actions/create_template":{"post":{"operationId":"create_template","summary":"Add check","description":"Add a new check to a site's check library.","tags":["actions"],"security":[{"ApiKeyAuth":[]}],"x-required-permissions":["templates:edit"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"siteId":{"type":"string","description":"The site whose checklist this check belongs to"},"name":{"type":"string","description":"Short name, e.g. 'Fridge temperature'"},"category":{"description":"Defaults to other","type":"string","enum":["receiving","storage","cold_chain","cooking","cleaning","allergen","hygiene","pest","calibration","other"]},"frequency":{"description":"How often it is required; defaults to every service","type":"string","enum":["each_service","daily","weekly","monthly"]},"spec":{"description":"The acceptance criterion, e.g. 'Refrigerator below 8 °C'","type":"string"},"guidance":{"description":"Optional plain-language guidance as JSON {what, why, how}: what to check, why it matters, how to record","type":"string"},"required":{"description":"Must be logged each time it is due; defaults to true","type":"boolean"}},"required":["siteId","name"],"additionalProperties":false}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object","properties":{"result":{}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key may not invoke this action"},"404":{"description":"Unknown action"}}}},"/api/rest/actions/update_template":{"post":{"operationId":"update_template","summary":"Update check","description":"Update a check-library template.","tags":["actions"],"security":[{"ApiKeyAuth":[]}],"x-required-permissions":["templates:edit"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"templateId":{"type":"string"},"name":{"type":"string"},"category":{"type":"string","enum":["receiving","storage","cold_chain","cooking","cleaning","allergen","hygiene","pest","calibration","other"]},"frequency":{"type":"string","enum":["each_service","daily","weekly","monthly"]},"spec":{"type":"string"},"guidance":{"description":"Plain-language guidance as JSON {what, why, how}: what to check, why it matters, how to record","type":"string"},"required":{"type":"boolean"},"status":{"type":"string","enum":["active","archived"]}},"required":["templateId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object","properties":{"result":{}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key may not invoke this action"},"404":{"description":"Unknown action"}}}},"/api/rest/actions/delete_template":{"post":{"operationId":"delete_template","summary":"Delete check","description":"Permanently remove a check from a site's check library.","tags":["actions"],"security":[{"ApiKeyAuth":[]}],"x-required-permissions":["templates:delete"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"templateId":{"type":"string"}},"required":["templateId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object","properties":{"result":{}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key may not invoke this action"},"404":{"description":"Unknown action"}}}},"/api/rest/actions/record_check":{"post":{"operationId":"record_check","summary":"Record a check","description":"Log the result of one check into a site's daily log for a given day (creating/opening that day's log as needed). This is the core 30-second action: staff records pass/fail, an optional measured value, notes and a corrective action. Pass checkLogId to update an already-logged entry in place instead of appending a new one.","tags":["actions"],"security":[{"ApiKeyAuth":[]}],"x-required-permissions":["logs:edit"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"siteId":{"type":"string","description":"The site the check belongs to"},"templateId":{"type":"string","description":"The check (check-library template) being logged"},"result":{"type":"string","enum":["pass","fail","na"],"description":"The result: pass, fail or not applicable"},"measuredValue":{"description":"A measured value or short observation, e.g. '5 °C'","type":"string"},"notes":{"type":"string"},"correctiveAction":{"description":"Corrective action taken or planned (for a failed check)","type":"string"},"logDate":{"description":"The day being logged (ISO date); defaults to today","type":"string"},"checkLogId":{"description":"An existing entry for this check on this day to update in place; omit to append a new entry","type":"string"}},"required":["siteId","templateId","result"],"additionalProperties":false}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object","properties":{"result":{}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key may not invoke this action"},"404":{"description":"Unknown action"}}}},"/api/rest/actions/complete_daily_log":{"post":{"operationId":"complete_daily_log","summary":"Complete the day's log","description":"Mark a site's daily log for a day as complete (all due checks recorded). If any checks that were due that day are still unlogged, the day is marked as partially logged instead, and the response reports how many (dueCount). Use after the day's checks have been logged; call it again after logging the rest to upgrade a partial day to complete.","tags":["actions"],"security":[{"ApiKeyAuth":[]}],"x-required-permissions":["logs:edit"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"siteId":{"type":"string","description":"The site whose log is being completed"},"logDate":{"description":"The day to complete (ISO date); defaults to today","type":"string"}},"required":["siteId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object","properties":{"result":{}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key may not invoke this action"},"404":{"description":"Unknown action"}}}},"/api/rest/actions/export_inspection_report":{"post":{"operationId":"export_inspection_report","summary":"Export inspection report","description":"Generate an inspection-ready PDF of a site's logged days over a date range (the inspection export). Returns the stored file's id and URL. Marks the days in range as exported.","tags":["actions"],"security":[{"ApiKeyAuth":[]}],"x-required-permissions":["reports:export"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"siteId":{"type":"string","description":"The site to export"},"from":{"description":"Start of the range (ISO date); defaults to 30 days ago","type":"string"},"to":{"description":"End of the range (ISO date); defaults to today","type":"string"}},"required":["siteId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object","properties":{"result":{}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key may not invoke this action"},"404":{"description":"Unknown action"}}}},"/api/rest/actions/sign_daily_log":{"post":{"operationId":"sign_daily_log","summary":"Send a day for signature","description":"Generate the PDF for one logged day and send it for electronic signature (the native in-house signature by default). Returns the signature envelope's status.","tags":["actions"],"security":[{"ApiKeyAuth":[]}],"x-required-permissions":["reports:export"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"dailyLogId":{"type":"string","description":"The logged day to sign"},"signers":{"description":"Who signs; defaults to the site's owner/owner email","type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":"string"}},"required":["name","email"],"additionalProperties":false}}},"required":["dailyLogId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Action result","content":{"application/json":{"schema":{"type":"object","properties":{"result":{}}}}}},"400":{"description":"Invalid input"},"401":{"description":"Missing or invalid API key"},"403":{"description":"The key may not invoke this action"},"404":{"description":"Unknown action"}}}}}}