Checkmk MCP Server — 125 tools
contains code
The Checkmk DADL turns Checkmk's API into an MCP server that Claude, GPT or any MCP-compatible agent can consume directly. One YAML file declares all 125 tools — host, service, downtime, folder, rule, user, and more — and ToolMesh serves them at runtime. No Python boilerplate, no per-endpoint code, no separate MCP server process.
Below: the endpoint coverage matrix, a two-block ToolMesh setup, the full tool reference grouped by Checkmk feature area, required credential scopes.
Source: Checkmk REST API
Which Checkmk endpoints are covered?
54% (125 of ~230 endpoints)
Focus: Checkmk 2.4 REST API v1: host status and service status via Livestatus queries, downtimes for hosts and host groups, downtimes for services and service groups, downtime modification and deletion, acknowledgements, comments, host configuration, host clusters, host bulk operations, folders with attribute inheritance, folder moves, service discovery, service phase updates, rules, rulesets, rule ordering, activation of pending changes, host groups, service groups, contact groups, roles and user accounts, passwords, time periods, host tags, aux tags, notification rules, site connections, agent download, metrics, audit log, background jobs, parent scan.
Missing: HW/SW inventory trees, agent registration, BI (business intelligence) aggregations and packs, event console (current and historical events), LDAP connections, broker connections, quick setup wizards, configuration entities (notification parameters), DCD (dynamic host configuration), licensing, certificate management, custom host attributes, autocomplete helpers, graph timerange and icon endpoints, agent baking and signature keys (CEE), bulk update/delete for the three group types, deprecated GET variants of the status collections. NOT a gap: Checkmk's global settings have no REST endpoint in any 2.x version (see domain notes).
How do you configure the Checkmk DADL?
- 1. Log into the Checkmk GUI of the site you want to automate
- 2. Go to Setup > Users > Add user
- 3. Set 'Username' to e.g. 'automation' and enable 'Automation secret for machine accounts'
- 4. Click the dice icon to generate a secret, or paste your own, and copy it
- 5. Assign roles: 'Monitoring user' for read-only, 'Administrator' for Setup writes
- 6. Save the user, then click 'Activate on selected sites' -- a new user is a pending change
- 7. Set CREDENTIAL_CHECKMK_AUTOMATION_SECRET to the string '<username> <secret>' -- the
- username, ONE space, then the secret (e.g. 'automation ABCdef123...'). The Checkmk
- bearer token consists of both values; a bare secret results in HTTP 401.
- 8. Point the backends.yaml url at the SITE, not the server: https://<host>/<site>/check_mk/api/1.0
- 9. Verify with the get_version tool -- it needs no parameters and no permissions.
Environment variable: CREDENTIAL_CHECKMK_AUTOMATION_SECRET
The interactive, always-up-to-date API reference lives inside every Checkmk site under Help > REST API documentation (and the raw spec under /<site>/check_mk/api/1.0/openapi-swagger-ui/). Self-hosted: the url MUST contain the site name -- the shape is <proto>://<host>/<SITE>/check_mk/api/1.0. Getting this wrong is the most common setup failure and it looks confusing: EVERY tool then returns the same HTTP 404 carrying an Apache HTML error page instead of Checkmk JSON. Diagnose it by requesting <url>/version by hand -- the correct site answers with JSON ({"title": "Unauthorized"} when unauthenticated), a wrong path answers with Apache's HTML. If you do not know the site name, `omd sites` on the server lists it. An automation user must be activated once (step 6) before the API accepts it. For a read-only integration, give the user the 'Monitoring user' role only: every Setup tool in this backend then fails with HTTP 403 instead of silently changing configuration.
How do you install the Checkmk MCP server with ToolMesh?
Add to your backends.yaml:
- name: checkmk
transport: rest
dadl: checkmk.dadl
url: "https://monitoring.example.com/prod/check_mk/api/1.0"
Set the credential:
CREDENTIAL_CHECKMK_AUTOMATION_SECRET=your-token-here What 125 tools does the Checkmk DADL expose?
POST list_hosts_status Live status of monitored hosts, filtered with a Livestatus query. POST is used only to carry the query payload -- this is a read-only call. Returns one entry per host with exactly the columns requested. Example query for all non-UP hosts: {"op": "!=", "left": "state", "right": "0"}. Useful columns: name, address, alias, state (0=UP, 1=DOWN, 2=UNREACHABLE), state_type, acknowledged, scheduled_downtime_depth, last_check, last_state_change, plugin_output, num_services_crit, num_services_warn, tag_names, groups. Without a query this returns EVERY host -- always filter on large sites. Requires Checkmk 2.4+ (on 2.3 and older this URL only exists as GET).
GET get_host_status Live status of ONE monitored host. Returns name, alias and address by default. Because ToolMesh cannot send repeated query parameters, only a single extra column can be selected here -- for a full column set call list_hosts_status with {"op": "=", "left": "name", "right": "<host>"} instead. Answers HTTP 404 when the host is not monitored (a host that exists in Setup but was never activated is NOT monitored).
POST list_services_status Live status of monitored services across all hosts, filtered with a Livestatus query. Read-only despite POST. The single most useful monitoring call: unacknowledged problems are {"op": "and", "expr": [{"op": "!=", "left": "state", "right": "0"}, {"op": "=", "left": "acknowledged", "right": "0"}, {"op": "=", "left": "scheduled_downtime_depth", "right": "0"}]}. Useful columns: host_name, description, state (0=OK, 1=WARN, 2=CRIT, 3=UNKNOWN), state_type, acknowledged, scheduled_downtime_depth, plugin_output, last_check, last_state_change, current_attempt, max_check_attempts, perf_data, host_state. Unfiltered this returns every service of every host -- easily tens of thousands of rows. Requires Checkmk 2.4+.
POST list_host_services Live status of all monitored services of ONE host. Read-only despite POST. Same column and query semantics as list_services_status, but scoped to the host in the path -- the cheapest way to answer "what is wrong on host X". Requires Checkmk 2.4+.
GET get_service_status Live status of ONE service on ONE host. Returns host_name, description, state, state_type and last_check by default -- a sensible set without further parameters. The service is addressed by its display name ("Filesystem /", "CPU utilization", "Check_MK"), which is what the `description` column contains. HTTP 404 when host or service is not monitored.
GET list_downtimes All scheduled downtimes, host and service. Each entry carries the downtime id (as `id`), host_name, author, comment, start_time, end_time, is_service and recurring. The id is what delete_downtime(delete_type "by_id") and modify_downtime need. Note the `query` parameter is a JSON STRING here (GET), not an object.
GET get_downtime Show a single downtime by its numeric id. site_id is required in distributed setups to locate the downtime. POST create_downtime_host Schedule a downtime for hosts. `downtime_type` selects how the targets are addressed: "host" (single host_name), "hostgroup" (all hosts of hostgroup_name) or "host_by_query" (all hosts matching query). start_time/end_time are ISO 8601 with timezone. A FIXED downtime (duration 0, the default) simply spans start..end. With duration > 0 the downtime is FLEXIBLE: it lasts `duration` SECONDS starting at the first problem inside the window. `recur` makes it repeat: fixed (default, no repeat), hour, day, week, second_week, fourth_week, weekday_start, weekday_end, day_of_month. Takes effect immediately, no activation needed. Returns 204 with no body on success.
POST create_downtime_service Schedule a downtime for services. `downtime_type` selects the addressing: "service" (host_name plus service_descriptions), "servicegroup" (all services of servicegroup_name) or "service_by_query" (all services matching query). Same time, duration and recur semantics as create_downtime_host. To silence a whole host INCLUDING its services, schedule a host downtime and additionally a service downtime by query on that host -- a host downtime alone does not suppress service notifications.
PUT modify_downtime Change end time and/or comment of existing downtimes. Select the downtimes exactly like delete_downtime does, via `modify_type`: by_id, params (host_name plus optional service_descriptions), query, hostgroup or servicegroup. `end_time` is an object: {"modify_type": "absolute", "value": "2026-08-12T22:00:00Z"} or {"modify_type": "relative", "value": 30} where value is a non-zero number of MINUTES added to (or, if negative, subtracted from) the current end time.
POST delete_downtime Remove scheduled downtimes -- POST, not DELETE. `delete_type` selects the targets: "by_id" (downtime_id plus site_id), "params" (host_name, optionally narrowed by service_descriptions -- without them ALL downtimes of that host go away), "query" (Livestatus filter on the downtimes table), "hostgroup" or "servicegroup". Returns 204 with no body. Deleting a non-existent downtime is not an error.
POST create_acknowledgement_host Acknowledge host problems, which stops notifications until the host recovers. `acknowledge_type`: "host" (host_name), "hostgroup" (hostgroup_name) or "host_by_query" (query on the hosts table). `sticky` keeps the acknowledgement until the host is UP again (not just until it improves), `notify` informs the contacts, `persistent` keeps the comment after recovery. Effective immediately. Returns 204. There is NO endpoint to remove an acknowledgement in this API version.
POST create_acknowledgement_service Acknowledge service problems. `acknowledge_type`: "service" (host_name plus service_description -- exactly one service), "servicegroup" (servicegroup_name) or "service_by_query" (query on the services table; the way to acknowledge many services at once). Same sticky/notify/persistent semantics as create_acknowledgement_host. Effective immediately, returns 204, and cannot be undone via the API.
GET list_comments List monitoring comments. The collection in the path selects the scope: "host" for host comments, "service" for service comments, "all" for both. Acknowledgements and downtimes also show up here, because Checkmk stores their text as comments. `query` is a JSON STRING (GET), filtering the Livestatus comments table.
GET get_comment Show a single monitoring comment by its numeric id. site_id is required to locate the comment. POST create_comment_host Add a comment to hosts. `comment_type` is "host" (single host_name) or "host_by_query" (all hosts matching query). Non-persistent comments vanish when the monitoring core restarts; set persistent true to keep them. Comments do not suppress notifications -- use create_acknowledgement_host or a downtime for that.
POST create_comment_service Add a comment to services. `comment_type` is "service" (host_name plus service_description) or "service_by_query" (all services matching query). Same persistence semantics as create_comment_host.
POST delete_comments Delete monitoring comments -- POST, not DELETE. `delete_type`: "by_id" (comment_id plus site_id), "query" (Livestatus filter) or "params" (host_name, optionally narrowed by service_descriptions). Deleting the comment of an acknowledgement removes the acknowledgement -- this is the only indirect way to un-acknowledge a problem via the API.
GET list_hosts All hosts configured in Setup, with their folder and attributes. This is the CONFIGURATION view -- a host listed here is not necessarily monitored yet (it becomes monitored after activate_changes). For live state use list_hosts_status. Set effective_attributes to see the attributes inherited from the folder tree as well. Returns every host of the site; there is no paging.
GET get_host Setup configuration of a single host: its folder, its explicitly set attributes and, on request, the effective attributes inherited from the folder tree. Cluster hosts additionally carry cluster_nodes. HTTP 404 if the host does not exist in Setup.
POST create_host Create a host in Setup. `folder` uses tilde notation ("~" for the root folder, "~datacenter~racks" for a nested one). `attributes` holds the host attributes, most commonly {"ipaddress": "10.0.0.5", "site": "prod", "tag_agent": "cmk-agent", "tag_address_family": "ip-v4-only", "alias": "...", "labels": {"env": "prod"}, "parents": ["gateway"]}. The host is created but NOT monitored until you run service discovery and activate_changes -- see the add_host_monitored composite for the full flow.
POST create_host_cluster Create a CLUSTER host -- a virtual host whose services are provided jointly by its nodes (e.g. a failover pair). Identical to create_host plus the mandatory `nodes` list, which must contain host names that already exist in Setup.
PUT update_host Change the attributes of a host in Setup. Pick exactly ONE strategy: `attributes` REPLACES the whole attribute set (everything not listed is lost), `update_attributes` merges the given keys into the existing ones (the usual choice), `remove_attributes` deletes the listed attribute names. Requires If-Match; "*" is sent by default -- pass the ETag from get_host for real optimistic locking.
PUT update_host_nodes Replace the node list of a CLUSTER host. The given list is authoritative -- nodes not included are detached from the cluster. Fails with HTTP 400 on a non-cluster host.
PUT rename_host Rename a host, carrying over its historic data, downtimes and comments. This starts a BACKGROUND JOB and requires that there are NO pending changes (activate first, otherwise HTTP 409) and that the monitoring core is stopped for the rename window. Poll wait_host_rename_completion afterwards.
GET wait_host_rename_completion Poll the currently running host-rename background job. HTTP 204 = finished, HTTP 302 = still running (call again), HTTP 404 = no rename job exists. Empty body in all cases.
POST move_host Move a host to another folder. The host then inherits the attributes of the new folder, which can change how it is monitored (site, agent type, check intervals). Explicitly set host attributes are kept.
DELETE delete_host Delete a host from Setup, including its services and its historic data reference. Returns 204. The host keeps being monitored until the next activate_changes.
POST create_hosts_bulk Create many hosts in one request. `entries` is a list of create_host bodies: [{"host_name": "h1", "folder": "~linux", "attributes": {"ipaddress": "10.0.0.1"}}, ...]. Far cheaper than a loop for onboarding whole racks. The response contains the created hosts; entries that fail validation abort the request.
PUT update_hosts_bulk Update many hosts in one request. `entries` is a list of {"host_name": "h1", "update_attributes": {...}} objects; `attributes` and `remove_attributes` work per entry exactly as in update_host. No If-Match is required for the bulk variant.
POST delete_hosts_bulk Delete many hosts in one request -- POST, not DELETE. `entries` is a plain list of host names. Returns 204. Irreversible once activated.
GET list_folders List folders of the Setup tree. By default only the direct children of the root folder are returned -- set recursive true for the whole tree, or point `parent` at a sub-folder. Each entry carries its path, title and attributes. Folder attributes are inherited by every host below, which makes folders the primary place to configure sites, agent types and check intervals.
GET get_folder Show one folder with its title, path and attributes. `folder` uses tilde notation ("~" is the root folder, "~linux~web" a nested one) or the folder's 32-character hex id. Slashes do not work in the URL, not even percent-encoded.
POST create_folder Create a folder. `name` is the directory name used in the path, `title` the label shown in the GUI, `parent` the containing folder in tilde notation ("~" for top level). `attributes` are inherited by all hosts and sub-folders below, e.g. {"site": "prod", "tag_agent": "cmk-agent", "snmp_community": "public"}.
PUT update_folder Change title and/or attributes of a folder. Same three mutually exclusive strategies as update_host: `attributes` replaces everything, `update_attributes` merges, `remove_attributes` deletes named keys. Changing folder attributes silently reconfigures every host below.
DELETE delete_folder Delete a folder. delete_mode "recursive" (the DEFAULT) removes the folder with all sub-folders and all hosts inside it -- pass "abort_on_nonempty" to refuse unless the folder is empty. Returns 204.
POST move_folder Move a folder (with everything inside it) under a different parent. All hosts below inherit the attributes of the new parent chain.
PUT update_folders_bulk Update several folders in one request. `entries` is a list of {"folder": "~linux~web", "title": ..., "update_attributes": {...}} objects, with the same attribute strategies as update_folder. No If-Match needed.
GET list_folder_hosts List the hosts stored directly in one folder (not recursive). Cheaper and clearer than get_folder with show_hosts, and it returns full host_config objects including attributes.
GET list_pending_changes All configuration changes that are staged but not yet activated. Each entry is a FLAT object {id, user_id, action_name, text, time} -- no extensions wrapper; `time` is an ISO 8601 string here (unlike the audit log, which returns epoch integers). An empty result means the running configuration matches Setup. Call this before activate_changes to see what you are about to publish, and above all to spot FOREIGN changes: any entry whose user_id is not your API user makes activate_changes fail unless force_foreign_changes is set. Note the `text` field is HTML-escaped by Checkmk (' for apostrophes).
POST activate_changes Publish all pending Setup changes to the monitoring core -- nothing configured via the host_config/folder_config/rule/... tools takes effect before this runs. `sites` restricts the activation to certain sites (default: all sites with pending changes). `force_foreign_changes` is required when another user has staged changes as well. Without it Checkmk answers **HTTP 401** "There are changes from other users and foreign changes are not allowed in this API call" -- that reads like an auth failure and is mapped to `unauthorized`, but the credential is fine; check list_pending_changes for entries with a foreign user_id. Other status codes: 200 = accepted, 303 = started and still running, 422 = nothing to activate, 423 = another activation is already running, 409 = a site failed. The response carries {id, is_running, changes, sites, time_started} -- `id` feeds wait_activation_completion. Requires If-Match; "*" is sent by default -- pass the ETag from list_pending_changes to be sure that nothing changed in between.
GET wait_activation_completion Block until an activation run finishes. HTTP 204 = completed, HTTP 302 = still running (call again), HTTP 404 = unknown activation id. Empty body. Use get_activation_run afterwards to see whether every site succeeded.
GET get_activation_run Status of one activation run: {id, is_running, changes, sites, status_per_site, time_started, title}. Completion is `is_running: false` -- there is NO top-level "status" field. The outcome sits in `status_per_site`, an ARRAY of {site, state, phase, status_text, status_details, start_time, end_time} where state is "success"/"error" and phase reaches "done". ALWAYS check state per site: a finished run does not mean every site succeeded, and in a distributed setup one remote site can fail while the local one reports done.
GET list_activation_runs All activation runs currently in progress. Non-empty means a subsequent activate_changes would fail with HTTP 423 (locked) -- check this first when automating.
POST start_service_discovery Run a service discovery on one host as a background job. `mode` decides what happens to the result: "fix_all" (default -- add all undecided services and remove all vanished ones, the usual choice after creating a host), "new" (only add newly found services), "remove" (only drop vanished ones), "refresh" (re-scan and refresh labels/parameters), "only_host_labels", "only_service_labels", "tabula_rasa" (throw everything away and rediscover from scratch). The result is a pending Setup change -- run activate_changes afterwards. On 2.5 this returns the discovery RESULT directly ({id, title, check_table, host_labels, vanished_labels, changed_labels}) rather than a job handle, and a fast scan can finish before a job record exists -- wait_service_discovery_completion then answers HTTP 404, which means "already done", not "failed". Treat that 404 as success and read get_service_discovery.
GET wait_service_discovery_completion Block until the discovery job of a host finishes. HTTP 204 = done, HTTP 302 = still running (call again), HTTP 404 = no discovery job for that host. Empty body.
GET get_service_discovery_run Status and log output of the last service discovery job of a host -- use it to find out WHY a discovery produced nothing (unreachable agent, SNMP timeout, wrong credentials).
GET get_service_discovery The discovery result of a host: every service the agent offers, grouped by phase -- "monitored" (active), "undecided" (found but not added), "vanished" (configured but no longer reported), "ignored" (disabled by rule). This is the read side that tells you what update_service_phase can act on. Shape: `check_table` is an OBJECT keyed by "<plugin>-<item>", each value being {value: "<phase>", extensions: {check_plugin_name, service_item, service_name, host_name, ...}} -- the phase sits in `value`, the display name in extensions.service_name. An empty check_table means the agent returned nothing (ping-only host, unreachable agent, wrong credentials) -- check get_service_discovery_run for the log.
PUT update_service_phase Move a single discovered service into another phase -- the API equivalent of clicking one service in the discovery view. `target_phase` is usually "monitored" (accept an undecided service), "undecided" or "ignored" (disable it). `check_type` is the check plugin name (e.g. "df", "cpu_utilization") and `service_item` the item within that plugin (e.g. "/boot"), both as shown by get_service_discovery. Creates a pending change.
POST start_discovery_bulk Run service discovery on MANY hosts as one background job -- the right tool after a bulk host import. `options` selects what to apply, e.g. {"monitor_undecided_services": true, "remove_vanished_services": true, "update_service_labels": false, "update_service_parameters": false, "update_host_labels": true} (all default to false). `do_full_scan` forces a fresh agent contact instead of using cached data, `bulk_size` is the number of hosts per worker batch, and `ignore_errors` keeps going when single hosts fail. Track it with get_background_job.
GET list_rulesets Search the available rulesets -- the ~1700 configuration knobs of Checkmk (thresholds, check parameters, notification settings, agent options). The ruleset name (e.g. "checkgroup_parameters:filesystem", "host_groups", "active_checks:http") is what list_rules and create_rule expect. TRAP: `used` defaults to TRUE on the server, so without it you only see rulesets that ALREADY have rules -- on a fresh site that is a handful, and `fulltext`/`name` searches come back empty even for rulesets that plainly exist (verified on 2.5.0p11: no filter = 15 hits, used=false = 1674). To search the CATALOGUE, always pass used=false. That response is large (~400 KB), so combine it with `fulltext` or `group`.
GET get_ruleset Show one ruleset with its title, help text, item form and the number of rules it holds. Read this before writing rules into it -- it tells you what the value structure has to look like.
GET list_rules All rules of ONE ruleset, in evaluation order (the first matching rule wins). Each rule carries its id, folder, properties (description, comment, disabled), value_raw and conditions. `ruleset_name` is mandatory -- there is no "all rules of the site" call.
GET get_rule Show one rule by its id, including value_raw and its conditions. POST create_rule Create a rule in a ruleset. `value_raw` is the rule value as a PYTHON REPRESENTATION STRING, not JSON -- e.g. "{'levels': (80.0, 90.0)}" for filesystem levels. Copy the exact shape from an existing rule via list_rules. `conditions` limits where the rule applies, e.g. {"host_name": {"match_on": ["web01"], "operator": "one_of"}, "host_tags": [{"key": "agent", "operator": "is", "value": "cmk-agent"}]}. `properties` holds {"description": "...", "comment": "...", "disabled": false}. New rules are inserted at the TOP of the folder's rule list; use move_rule to reposition.
PUT update_rule Replace value, properties and conditions of an existing rule. The ruleset and folder of a rule cannot be changed here -- use move_rule for the folder, or delete and recreate.
POST move_rule Change the evaluation position of a rule, which decides precedence. `position`: "top_of_folder" / "bottom_of_folder" (needs `folder`), "before_specific_rule" / "after_specific_rule" (needs the other rule's id in `rule_id`).
DELETE delete_rule Delete a rule. Returns 204. Takes effect after activate_changes. GET list_host_groups All host groups with name and alias. Host groups are used as downtime/acknowledgement targets and as notification conditions. GET get_host_group Show one host group -- returns its name and alias. HTTP 404 if it does not exist, which is the cheapest existence check before referencing the group in a downtime or a rule.
POST create_host_group Create a host group. `name` is the internal id used everywhere in the API, `alias` the label shown in the GUI. Assigning hosts to the group is done with a rule in the "host_groups" ruleset, not here.
PUT update_host_group Change the alias of a host group. The name itself cannot be changed -- delete and recreate instead. DELETE delete_host_group Delete a host group. Fails while rules still reference it. Returns 204. POST create_host_groups_bulk Create several host groups in one request. `entries` is a list of {name, alias} objects. GET list_service_groups All service groups with name and alias. Used as downtime/acknowledgement targets and in notification rules. GET get_service_group Show one service group -- returns its name and alias. HTTP 404 if it does not exist, which is the cheapest existence check before using it as a downtime or acknowledgement target.
POST create_service_group Create a service group. Membership is assigned via a rule in the 'service_groups' ruleset, not here. PUT update_service_group Change the alias of a service group. The name itself is immutable -- delete and recreate to rename it. DELETE delete_service_group Delete a service group. Fails while rules in the 'service_groups' ruleset still assign services to it. Returns 204 and takes effect after activate_changes.
POST create_service_groups_bulk Create several service groups in one request. `entries` is a list of {name, alias} objects. GET list_contact_groups All contact groups. Contact groups are Checkmk's authorization unit: a user sees exactly the hosts and services whose contact groups they belong to, and notifications are routed by them.
GET get_contact_group Show one contact group -- returns its name, alias and inventory path restrictions. It does NOT list the members: users carry their contact groups, hosts get them from an attribute or a rule.
POST create_contact_group Create a contact group. Users are added to it via create_user/update_user (contactgroups), hosts via the 'host_contactgroups' ruleset or the host attribute 'contactgroups'.
PUT update_contact_group Change alias and inventory path restrictions of a contact group. DELETE delete_contact_group Delete a contact group. Fails while users or rules still reference it. Returns 204. POST create_contact_groups_bulk Create several contact groups in one request. `entries` is a list of {name, alias} objects. GET list_users All configured users with their roles, contact groups and contact options. Passwords and secrets are never returned. GET get_user Show one user: full name, roles, contact groups, contact options and interface settings. Passwords and automation secrets are never returned -- there is no way to read a secret back out of Checkmk, only to set a new one via update_user.
POST create_user Create a user. `auth_option` decides the login type: {"auth_type": "password", "password": "..."} for humans (they are forced to change it), or {"auth_type": "automation", "secret": "..."} for machine accounts used with this very API. `roles` is a list of role ids (["user"], ["admin"], ["guest"] or custom ones), `contactgroups` decides which hosts/services the user sees and is notified about, and `contact_options` holds {"email": "...", "fallback_contact": false}. A new user only works after activate_changes.
PUT update_user Change a user. All fields are optional -- only what you pass is modified. Sending `auth_option` with a new password or secret rotates the credential (this is how you rotate the automation secret this backend itself uses). Roles and contactgroups are REPLACED, not merged.
DELETE delete_user Delete a user. Returns 204. Takes effect after activate_changes. GET list_user_roles All user roles, built-in (admin, user, guest, agent_registration) and custom clones, with their permission sets. GET get_user_role Show one role with its alias, base role and permission overrides. POST create_user_role Clone an existing role -- roles are always derived, never created from nothing. `role_id` is the role to copy (admin, user, guest, agent_registration), `new_role_id` and `new_alias` name the clone. Adjust its permissions afterwards with update_user_role.
PUT update_user_role Change a role: rename it (new_role_id/new_alias), re-base it (new_basedon, only for custom roles) or override single permissions. `new_permissions` is a map of permission name to "yes"/"no"/"default", e.g. {"general.server_side_requests": "no"}.
DELETE delete_user_role Delete a custom user role. Built-in roles cannot be deleted. Returns 204. GET list_passwords All entries of the password store -- the shared secrets that rules reference by id instead of embedding them (SNMP communities, API tokens for active checks, agent credentials). The password VALUES are never returned, only the metadata.
GET get_password Show one password store entry (metadata only, no secret). POST create_password Store a shared secret. `ident` is the id that rules reference. `owned_by` is the contact group owning the entry ("admin" or a contact group name), `editable_by` the group allowed to change it. Storing a secret here is much better than putting it into a rule value.
PUT update_password Change a password store entry, including rotating the secret itself via `password`. DELETE delete_password Delete a password store entry. Rules referencing it break. Returns 204. GET list_time_periods All time periods. Time periods define when checks run and when notifications are sent (e.g. "workhours", "24X7"). Note the domain type is singular: time_period.
GET get_time_period Show one time period with its active ranges, exceptions and exclusions. POST create_time_period Create a time period. `active_time_ranges` is a list of {"day": "monday"|...|"all", "time_ranges": [{"start": "08:00", "end": "17:00"}]}. `exceptions` overrides single dates: [{"date": "2026-12-24", "time_ranges": [{"start": "08:00", "end": "12:00"}]}]. `exclude` lists other time period names to subtract.
PUT update_time_period Change a time period. Fields left out stay as they are; `active_time_ranges` is replaced as a whole when given. DELETE delete_time_period Delete a time period. Fails while rules or users still reference it. Returns 204. GET list_host_tag_groups All host tag groups. Host tags are Checkmk's classification mechanism: every host carries one tag per group (e.g. criticality: prod/test), and rules use them as conditions.
GET get_host_tag_group Show one host tag group with its possible tags. POST create_host_tag_group Create a host tag group. `tags` is the list of choices: [{"id": "prod", "title": "Production", "aux_tags": []}, {"id": "test", "title": "Test"}]. A tag with id null becomes the "no choice" option. Hosts then set the attribute "tag_<group id>" to one of these ids.
PUT update_host_tag_group Change a host tag group. `tags` replaces the whole choice list -- removing a tag that hosts still use fails unless `repair` is true, which then reassigns those hosts.
DELETE delete_host_tag_group Delete a host tag group. Fails when hosts or rules still use it unless `repair` is set. Returns 204.
GET list_aux_tags All auxiliary tags. Aux tags are attached to host tags and add a second, orthogonal dimension for rule conditions (e.g. tag 'snmp-v2' implies aux tag 'snmp').
GET get_aux_tag Show one auxiliary tag with its title, topic and help text. HTTP 404 if the id does not exist. POST create_aux_tag Create an auxiliary tag that host tags can reference in their aux_tags list. PUT update_aux_tag Change title, topic or help of an auxiliary tag. The id is immutable. POST delete_aux_tag Delete an auxiliary tag -- POST on the delete action, NOT the DELETE method. Fails while host tag groups still reference it.
GET list_notification_rules All notification rules in evaluation order. Notification rules decide who is informed about which problem through which channel; they are evaluated top to bottom and all matching rules contribute unless one cancels the others.
GET get_notification_rule Show one notification rule with its full rule_config. POST create_notification_rule Create a notification rule. Everything lives in the single nested `rule_config` object: {"rule_properties": {"description": "...", "comment": "", "documentation_url": "", "do_not_notify": {"state": "disabled"}, "allow_users_to_deactivate": {"state": "enabled"}}, "notification_method": {"notify_plugin": {"option": "create_notification_with_the_following_parameters", "plugin_params": {"plugin_name": "mail"}}}, "contact_selection": {...}, "conditions": {...}}. The structure is deep and version-specific -- read an existing rule with get_notification_rule first and modify a copy rather than writing one from scratch.
PUT update_notification_rule Replace the configuration of a notification rule. `rule_config` must be complete -- this is not a merge. POST delete_notification_rule Delete a notification rule -- POST on the delete action, NOT the DELETE method. Returns 204. GET list_site_connections All configured site connections of this distributed monitoring setup, including their status host and socket configuration. GET get_site_connection Show one site connection: its basic settings, the Livestatus status connection (socket, proxy, timeouts, status host) and the configuration connection used for replication.
POST create_site_connection Add a remote site to the distributed setup. Everything sits in the nested `site_config` object: {"basic_settings": {"site_id": "remote1", "alias": "Remote 1", "customer": "..."}, "status_connection": {"connection": {"socket_type": "tcp", "host": "10.0.0.9", "port": 6557, "encrypted": true, "verify": true}, "proxy": {"use_livestatus_daemon": "direct"}, "connect_timeout": 2, "status_host": {"status_host_set": "disabled"}, ...}, "configuration_connection": {"enable_replication": true, "url_of_remote_site": "https://10.0.0.9/remote1/check_mk/", ...}}. After creating the connection you still have to call login_site_connection.
PUT update_site_connection Replace the configuration of an existing site connection. `site_config` must be complete. POST login_site_connection Log into a remote site to establish the configuration replication. Needs the credentials of an ADMIN user ON THE REMOTE SITE; Checkmk exchanges them for a permanent automation secret and does not store the password. Required once after create_site_connection.
POST logout_site_connection Drop the replication credentials of a remote site. The connection stays configured but can no longer replicate. POST delete_site_connection Remove a site connection -- POST on the delete action, NOT the DELETE method. Log out first. GET get_version Version and edition of the site: {"site", "group", "rest_api": {"revision"}, "versions": {"checkmk", "python", "apache", ...}, "edition"}. Needs no parameters and almost no permissions -- the ideal connectivity and credential smoke test, and the way to find out which edition you are talking to before using edition-specific features. Edition strings: "community" (the former Raw/cre, renamed in 2.5), "enterprise"/"cee", "cloud"/"cce", "managed"/"cme". A 404 with an Apache error page instead of JSON means the configured URL misses the site segment -- see setup.notes.
GET list_audit_log Audit log entries of ONE day -- `date` is required and expects YYYY-MM-DD. Every Setup change is recorded here with user, time, object and the diff text. Filter further by object_type (e.g. "Host", "Folder", "Rule"), object_id, user_id or a regular expression on the text.
POST archive_audit_log Move all current audit log entries into the archive, clearing the active log. Irreversible via the API. Returns 204. GET get_background_job State of any background job by id: whether it is active or finished, its state and its log output. Use it for the jobs that have no dedicated wait tool, above all bulk discovery and parent scan. The job id is part of the response of the tool that started the job.
POST get_metric Read the RRD time series behind a service graph. Read-only despite POST. `type` is "single_metric" (plus metric_id, e.g. "cmk_time_agent") or "predefined_graph" (plus graph_id, e.g. "cmk_cpu_time_by_phase"); both ids become visible in the GUI after enabling "Show internal IDs" in the service view's display options. `time_range` takes ISO 8601 start/end, `reduce` how a segment is condensed (average, min, max). The answer is {"time_range": {"start", "end"}, "step": <seconds>, "metrics": [{"title", "color", "line_type", "data_points": [...]}]} -- data_points is a bare value array spaced `step` seconds apart, with nulls for gaps. Passing `site` is strongly recommended in distributed setups.
GET download_agent Download one of the vanilla agent packages shipped with Checkmk. `os_type` is linux_rpm, linux_deb or windows_msi. These are the UNBAKED generic agents -- individually baked agents with per-host configuration are an Enterprise feature and are not available here. The binary is stored in the ToolMesh file broker and returned as a time-limited download URL, not as inline data. This endpoint serves ONLY application/octet-stream, so it overrides the backend-wide `Accept: application/json` via its own Accept parameter -- without that override Checkmk answers HTTP 406 (verified on 2.5.0p11).
POST start_parent_scan Start a parent scan background job: Checkmk traceroutes to the given hosts and derives their network parents, which makes the monitoring suppress notifications for hosts that are merely UNREACHABLE behind a broken router. `gateway_hosts` decides what happens to gateways that are not yet monitored ({"state": "monitor_in_folder"|"do_not_monitor", "folder": "~", "alias": ...}), `performance` tunes the probing ({"responses_timeout", "hop_probes", "max_gateway_distance", "ping_probes"}) and `configuration` holds {"force_explicit_parents": true}. Track it with get_background_job.
What composite workflows does the Checkmk DADL provide? ⚠ contains code
FN get_problems The "what is broken right now" call. Returns {hosts, services, summary} with all hosts that are not UP and all services that are not OK, by default hiding everything that is already acknowledged or in a scheduled downtime. Set include_handled true to see those as well, or limit the scope to a single host with host_name. This is one round trip instead of two hand-written Livestatus queries and is the right entry point for any triage question.
FN apply_pending_changes Activate all pending Setup changes and wait until the activation has really finished -- activate_changes alone only STARTS the job. Returns {activated, activation_id, changes, state, sites}. Answers {activated: false, reason: "no_pending_changes"} when there is nothing to do, so it is safe to call unconditionally at the end of a configuration session. Set force_foreign true when other users have staged changes as well, otherwise Checkmk refuses to activate them.
FN add_host_monitored Create a host and take it all the way to "actually monitored": create_host, then a service discovery in fix_all mode, then activation of the pending changes. Returns {host, folder, discovered, activated, services}. This is the complete onboarding flow -- doing only create_host leaves a host that exists in Setup but is never checked. Set activate false to stage the change and activate later together with other work.