# Terraform provider

The official **Terraform provider** manages HostTracker as code: monitors, contacts, contact groups, alert and report
subscriptions, maintenance windows, webhooks and status pages, reconciled through the
[REST API v2](/integrations/rest-api/). It is published on the Terraform Registry as
[`HostTracker/hosttracker`](https://registry.terraform.io/providers/HostTracker/hosttracker/latest) (current version
0.1.0), works with Terraform 1.0 or newer and OpenTofu, and is built on the [Go SDK](/integrations/sdks/). Every
attribute is documented in the
[registry documentation](https://registry.terraform.io/providers/HostTracker/hosttracker/latest/docs).

:::note[Plan requirement]
The provider uses the API, so your plan must include API access - see
[Rate limits and quotas](/integrations/rate-limits/#which-plans-include-the-api).
:::

## Install

```hcl
terraform {
  required_providers {
    hosttracker = {
      source  = "HostTracker/hosttracker"
      version = "~> 0.1"
    }
  }
}

provider "hosttracker" {}
```

Provider settings (all optional):

| Setting | Environment variable | Default | What it does |
|---|---|---|---|
| `token` | `HT_TOKEN` | - | The API token. Keep it in the environment, not in a `.tf` file - a token in configuration ends up in version control and in state. |
| `base_url` | `HT_BASE_URL` | `https://api2.host-tracker.com` | The API root. |
| `timeout` | - | 30 | Seconds per request attempt. |
| `retry_max` | - | 2 | Retries for throttled or retryable requests; `Retry-After` is honoured. |

## Authenticate

Mint a token under **Integrations -> API** (`/integrations/api`) - see
[API authentication](/integrations/api-authentication/). Give it the scopes your configuration uses:
`monitor:read` + `monitor:write` for monitors, subscriptions and maintenance; `contact:read` + `contact:write` for
contacts and groups; `webhook:read` + `webhook:write`; `statuspage:read` + `statuspage:write`; `account:read` for the
account data source. Family scopes (`monitor`, `contact`, ...) cover both leaves.

```sh
export HT_TOKEN="your-api-token"
terraform plan
```

## Example

An HTTP monitor with a keyword, attached certificate and blacklist checks, an email contact subscribed to its
alerts, a weekly maintenance window and a status page:

```hcl
resource "hosttracker_monitor" "shop" {
  type     = "http"
  url      = "https://shop.example.com/"
  name     = "Shop"
  interval = 300
  tags     = ["prod", "web"]

  locations = {
    pools    = ["allworld"]
    fallback = "world"
  }

  recheck = {
    strategy = "fullAgreement"
  }

  settings = {
    http = {
      keywords        = "Add to cart"
      follow_redirect = true
      timeout         = 20000
      attached = {
        ssl_exp = { enabled = true }
        dnsbl   = { enabled = true }
      }
      cert_watch_days = [7, 30]
    }
  }
}

resource "hosttracker_contact" "ops" {
  type    = "email"
  address = "ops@example.com"
  name    = "Ops"
}

resource "hosttracker_alert_subscription" "shop_ops" {
  monitor_id  = hosttracker_monitor.shop.id
  contact_id  = hosttracker_contact.ops.id
  alert_types = ["down", "up"]
}

resource "hosttracker_maintenance" "weekly_deploy" {
  name         = "Weekly deploy"
  from         = 1790056800
  duration_sec = 3600
  timezone     = "Europe/London"
  recurrence   = { week_days = ["Tuesday"] }
  monitor_ids  = [hosttracker_monitor.shop.id]
  suppress     = { alerts = true, stats = true }
}

resource "hosttracker_status_page" "public" {
  slug  = "example-shop"
  title = "Example Shop status"

  components = [
    { monitor_id = hosttracker_monitor.shop.id, name = "Shop", group = "Web" },
  ]

  settings = {
    theme       = "light"
    show_groups = true
    features    = ["barCharts", "uptimePercent", "detailsPages", "subscribe"]
  }
}
```

`interval` is in seconds and must be allowed by your plan. The email contact is created unconfirmed; its owner
confirms it with the code they receive before alerts are delivered.

## Resources

| Resource | Manages |
|---|---|
| `hosttracker_monitor` | One monitor. Typed `settings` blocks for `http`, `ping`, `port`, `dnsbl`, `ssl_exp`, `domain_exp`, `web_risk`; other types (`waterfall`, `tran`, `api`, `database`, `counter`, `cntCheck`, `snmp`) use `settings_json`. |
| `hosttracker_contact` | An `email`, `sms` or `voiceCall` contact, with active hours, language, alert delay and grouped alerts. |
| `hosttracker_contact_group` | A named set of contacts with the events each receives. |
| `hosttracker_alert_subscription` | Which state changes (`up`, `down`, `repeatedlyDown`) of one monitor reach one contact. |
| `hosttracker_report_subscription` | How often (`daily` ... `yearly`) one contact gets a report about one monitor. |
| `hosttracker_maintenance` | A one-time or weekly maintenance window, suppressing alerts, statistics or both, uniformly (`monitor_ids` + `suppress`) or per monitor (`monitors`). |
| `hosttracker_webhook` | A signed webhook: url, events, scope, headers, and its secret (`rotate_secret` rotates it). |
| `hosttracker_status_page` | A status page: settings and, optionally, its whole component list. |

## Data sources

| Data source | Reads |
|---|---|
| `hosttracker_monitor`, `hosttracker_monitors` | One monitor by id or lookup; a filtered list (state, type, tag, text). |
| `hosttracker_monitor_types` | The type catalogue with your plan's interval floors. |
| `hosttracker_locations` | Location pools and locations - use it for `locations.pools`. |
| `hosttracker_account` | Your package, limits and remaining API quota. |
| `hosttracker_contact`, `hosttracker_contacts` | One contact by id or lookup; a filtered list. |
| `hosttracker_contact_group` | One group by id or name. |
| `hosttracker_contact_types` | The channels and the alert delays each accepts. |
| `hosttracker_webhook`, `hosttracker_webhooks` | One webhook by id or url; all webhooks. |
| `hosttracker_status_page`, `hosttracker_status_pages` | One page by id or slug; all pages. |
| `hosttracker_maintenance_windows` | Maintenance windows filtered by span, state, monitor and name. |

## Import existing objects

A monitor created in the app is adopted by its id (shown in its page address, or listed by the
`hosttracker_monitors` data source):

```sh
terraform import hosttracker_monitor.shop 8e2d4c8b-7a41-4a2b-9d0e-2f3a5c6b7d8e
```

Creating a monitor for an address that already has one of the same type is refused with `409 duplicate_monitor`,
and the error names the existing id so you can import it instead.

## Things worth knowing

- **Removing an attribute keeps its value.** The API reads an absent member as "leave it alone", so deleting an
  attribute from configuration does not clear it. Write the empty value (`""`, `[]`) to clear.
- **`type` and `slug` are immutable** - changing them replaces the monitor or page.
- **Status page components are a whole set.** If you write `components`, every apply replaces the page's component
  list with yours; a component added in the app is removed on the next apply. Leave `components` out to manage them
  in the app, and keep `auto_add_monitors` off when Terraform owns the list.
- **Status page password and custom domain** are managed in the app only (`has_password` and `custom_domain` are
  read-only).
- **`hide_branding` has no effect** - the "Powered by HostTracker" credit shows on every status page.
- **Not in 0.1.0:** the maintenance window `showOnStatusPage` switch (windows created by Terraform show on status
  pages, the API default) and new typed settings blocks for the remaining monitor types.
- **Monitor `updated`** moves only on creation, up/down changes and plan-limit disabling, not on configuration
  edits.
- **Rate limits.** The default parallelism of 10 is comfortable on a paid plan's quota; on a trial token use
  `terraform apply -parallelism=3`. The provider retries `429 rate_limited` honouring `Retry-After`.
- **Timestamps are Unix seconds** (`from`, `created`, `since`); some resources add `*_rfc3339` read-only twins.

## Related

- [REST API v2](/integrations/rest-api/)
- [API authentication, tokens and scopes](/integrations/api-authentication/)
- [Create a maintenance window](/maintenance/create/)
- [Create a status page](/status-pages/create/)
