> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devhelm.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Terraform Monitors

> Define DevHelm monitors with the devhelm_monitor Terraform resource — all types and configurations

The `devhelm_monitor` resource creates and manages monitors of any type. Configure assertions, incident policies, and scheduling in HCL.

## Basic example

```hcl theme={null}
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" })
  }
}
```

<Warning>
  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.
</Warning>

## Arguments

### Top-level

| Attribute           | Type          | Required | Description                                                                                                                                                                                                 |
| ------------------- | ------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`              | string        | Yes      | Human-readable name (also used as import ID)                                                                                                                                                                |
| `type`              | string        | Yes      | Monitor type: `HTTP`, `DNS`, `TCP`, `ICMP`, `HEARTBEAT`, `MCP_SERVER`. Forces replacement on change.                                                                                                        |
| `config`            | string (JSON) | Yes      | Type-specific configuration as JSON                                                                                                                                                                         |
| `frequency_seconds` | number        | —        | Check frequency in seconds (30–86400)                                                                                                                                                                       |
| `enabled`           | bool          | —        | Whether the monitor is active (default: `true`)                                                                                                                                                             |
| `regions`           | list(string)  | —        | Probe regions                                                                                                                                                                                               |
| `environment_id`    | string        | —        | Environment ID for variable substitution                                                                                                                                                                    |
| `alert_channel_ids` | list(string)  | —        | Alert channel IDs to notify                                                                                                                                                                                 |
| `tag_ids`           | list(string)  | —        | Tag IDs to attach                                                                                                                                                                                           |
| `auth`              | object        | —        | HTTP 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

| Attribute  | Description                                        |
| ---------- | -------------------------------------------------- |
| `id`       | Monitor ID                                         |
| `ping_url` | Heartbeat 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:

| Attribute  | Type          | Required | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| ---------- | ------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `type`     | string        | Yes      | Assertion 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 |
| `config`   | string (JSON) | Yes      | Assertion 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)                                                                                                                                                                                                                                                           |
| `severity` | string        | —        | `fail` 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.

| Attribute               | Type            | Required | Description                                              |
| ----------------------- | --------------- | -------- | -------------------------------------------------------- |
| `confirmation_type`     | string          | —        | Confirmation strategy (e.g., `multi_region`)             |
| `min_regions_failing`   | number          | —        | Minimum failing regions to confirm                       |
| `max_wait_seconds`      | number          | —        | Maximum confirmation wait time                           |
| `consecutive_successes` | number          | —        | Consecutive passes required for recovery                 |
| `min_regions_passing`   | number          | —        | Minimum passing regions for recovery                     |
| `cooldown_minutes`      | number          | —        | Minutes before auto-resolving                            |
| `trigger_rules`         | list of objects | —        | Rules that determine when failures escalate to incidents |

**`trigger_rules[*]` object:**

| Attribute          | Type   | Required    | Description                                                           |
| ------------------ | ------ | ----------- | --------------------------------------------------------------------- |
| `type`             | string | Yes         | `consecutive_failures`, `failures_in_window`, or `response_time`      |
| `severity`         | string | Yes         | `down` or `degraded`                                                  |
| `scope`            | string | —           | `per_region` or `any_region`                                          |
| `count`            | number | Yes         | Failure count threshold (1–10); required for all rule types           |
| `window_minutes`   | number | Conditional | Time window in minutes; required when `type = "failures_in_window"`   |
| `threshold_ms`     | number | Conditional | Response time threshold in ms; required when `type = "response_time"` |
| `aggregation_type` | string | —           | `all_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`:

<CodeGroup>
  ```hcl HTTP theme={null}
  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)
  })
  ```

  ```hcl DNS theme={null}
  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
  })
  ```

  ```hcl TCP theme={null}
  config = jsonencode({
    host      = "db.example.com"
    port      = 5432
    timeoutMs = 5000
  })
  ```

  ```hcl ICMP theme={null}
  config = jsonencode({
    host        = "10.0.1.5"
    packetCount = 3
    timeoutMs   = 5000
  })
  ```

  ```hcl Heartbeat theme={null}
  config = jsonencode({
    expectedInterval = 86400
    gracePeriod      = 3600
  })
  ```

  ```hcl MCP Server theme={null}
  config = jsonencode({
    command = "npx"
    args    = ["-y", "@modelcontextprotocol/server-everything"]
    # also: env (map of environment variables)
  })
  ```
</CodeGroup>

## Full example with assertions and incident policy

```hcl theme={null}
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

```bash theme={null}
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

<CardGroup cols={2}>
  <Card title="Alert channels" icon="bell" href="/mac/terraform/alert-channels">
    devhelm\_alert\_channel resource reference.
  </Card>

  <Card title="Tags" icon="tag" href="/mac/terraform/tags">
    devhelm\_tag resource reference.
  </Card>

  <Card title="Data sources" icon="database" href="/mac/terraform/data-sources">
    Reference existing resources without managing them.
  </Card>
</CardGroup>
