Skip to main content
The devhelm_monitor resource creates and manages monitors of any type. Configure assertions, incident policies, and scheduling in HCL.

Basic example

resource "devhelm_monitor" "api_health" {
  name              = "API Health"
  type              = "HTTP"
  frequency_seconds = 60
  regions           = ["us-east", "eu-west"]

  config = jsonencode({
    url       = "https://api.example.com/health"
    method    = "GET"
    verifyTls = true
  })

  assertions {
    type   = "status_code"
    # `expected` is a STRING — quote it, even for plain numeric codes
    config = jsonencode({ expected = "200", operator = "equals" })
  }
}
JSON value types inside config and assertions[].config must match the API contract exactly — status_code.expected is a string (expected = "200", not expected = 200), while response_time.thresholdMs is a number. Type-mismatched values plan cleanly but fail apply with “Provider produced inconsistent result” because the API normalizes them on the round-trip.

Arguments

Top-level

AttributeTypeRequiredDescription
namestringYesHuman-readable name (also used as import ID)
typestringYesMonitor type: HTTP, DNS, TCP, ICMP, HEARTBEAT, MCP_SERVER. Forces replacement on change.
configstring (JSON)YesType-specific configuration as JSON
frequency_secondsnumberCheck frequency in seconds (30–86400)
enabledboolWhether the monitor is active (default: true)
regionslist(string)Probe regions
environment_idstringEnvironment ID for variable substitution
alert_channel_idslist(string)Alert channel IDs to notify
tag_idslist(string)Tag IDs to attach
authobjectHTTP authentication. Pick exactly one of bearer, basic, header, or api_key; each variant takes a vault_secret_id (UUID of a devhelm_secret). header and api_key also require header_name.

Computed attributes

AttributeDescription
idMonitor ID
ping_urlHeartbeat ping URL (only set for HEARTBEAT type)

assertions block

Repeatable block for pass/fail criteria. The block name is assertions (plural); repeat it once per assertion:
AttributeTypeRequiredDescription
typestringYesAssertion type discriminator in snake_case wire format. 42 types are supported, validated at plan time against the API spec. Common ones: status_code, response_time, body_contains, header_value, regex_body, json_path, ssl_expiry, redirect_count, redirect_target, response_size; plus per-type families dns_* (e.g. dns_resolves, dns_record_equals, dns_ttl_low), tcp_* (tcp_connects, tcp_response_time), icmp_* (icmp_reachable, icmp_packet_loss), heartbeat_* (heartbeat_received, heartbeat_max_interval), mcp_* (mcp_connects, mcp_tool_available), and *_warn variants
configstring (JSON)YesAssertion configuration as JSON; the inner type field is omitted (set via the sibling type attribute). Field names inside config are camelCase and value types must match the API contract exactly, e.g. { expected = "200", operator = "equals" } for status_code (expected is a string) or { thresholdMs = 500 } for response_time (thresholdMs is a number)
severitystringfail or warn (default: fail)

incident_policy attribute

Single nested attribute (use = assignment, not a block) controlling confirmation and recovery behavior. Omit it entirely to adopt server defaults; supplying any field overrides the policy in full.
AttributeTypeRequiredDescription
confirmation_typestringConfirmation strategy (e.g., multi_region)
min_regions_failingnumberMinimum failing regions to confirm
max_wait_secondsnumberMaximum confirmation wait time
consecutive_successesnumberConsecutive passes required for recovery
min_regions_passingnumberMinimum passing regions for recovery
cooldown_minutesnumberMinutes before auto-resolving
trigger_ruleslist of objectsRules that determine when failures escalate to incidents
trigger_rules[*] object:
AttributeTypeRequiredDescription
typestringYesconsecutive_failures, failures_in_window, or response_time
severitystringYesdown or degraded
scopestringper_region or any_region
countnumberYesFailure count threshold (1–10); required for all rule types
window_minutesnumberConditionalTime window in minutes; required when type = "failures_in_window"
threshold_msnumberConditionalResponse time threshold in ms; required when type = "response_time"
aggregation_typestringall_exceed, average, p95, max
The provider enforces these conditional requirements at plan time.

Config by monitor type

The config attribute accepts JSON. The shape depends on type:
config = jsonencode({
  url           = "https://api.example.com/health"
  method        = "GET" # required: GET, POST, PUT, PATCH, DELETE, or HEAD
  verifyTls     = true
  customHeaders = { Accept = "application/json" }
  # also: contentType, requestBody (for POST/PUT/PATCH)
})
config = jsonencode({
  hostname    = "example.com"
  recordTypes = ["A", "AAAA"] # A, AAAA, CNAME, MX, NS, TXT, SRV, SOA, CAA, PTR
  nameservers = ["8.8.8.8"]
  timeoutMs   = 5000
  # also: totalTimeoutMs
})
config = jsonencode({
  host      = "db.example.com"
  port      = 5432
  timeoutMs = 5000
})
config = jsonencode({
  host        = "10.0.1.5"
  packetCount = 3
  timeoutMs   = 5000
})
config = jsonencode({
  expectedInterval = 86400
  gracePeriod      = 3600
})
config = jsonencode({
  command = "npx"
  args    = ["-y", "@modelcontextprotocol/server-everything"]
  # also: env (map of environment variables)
})

Full example with assertions and incident policy

resource "devhelm_monitor" "api_health" {
  name              = "API Health"
  type              = "HTTP"
  frequency_seconds = 60
  enabled           = true
  regions           = ["us-east", "eu-west"]

  config = jsonencode({
    url       = "https://api.example.com/health"
    method    = "GET"
    verifyTls = true
  })

  assertions {
    type   = "status_code"
    config = jsonencode({ expected = "200", operator = "equals" })
  }

  assertions {
    type     = "response_time"
    config   = jsonencode({ thresholdMs = 2000 })
    severity = "warn"
  }

  incident_policy = {
    confirmation_type     = "multi_region"
    min_regions_failing   = 2
    max_wait_seconds      = 120
    consecutive_successes = 2

    trigger_rules = [
      {
        type     = "consecutive_failures"
        severity = "down"
        scope    = "per_region"
        count    = 3
      },
    ]
  }

  tag_ids           = [devhelm_tag.production.id]
  alert_channel_ids = [devhelm_alert_channel.slack.id]
}

Import

terraform import devhelm_monitor.api_health "API Health"
Import accepts the monitor name or its UUID. If multiple monitors share the same name, the import fails with an ambiguity error listing the candidate UUIDs — import by UUID in that case.

Next steps

Alert channels

devhelm_alert_channel resource reference.

Tags

devhelm_tag resource reference.

Data sources

Reference existing resources without managing them.