---
category: Reference
title: Terraform Provider Reference
description: Technical specification for the openstatus Terraform Provider.
---
The openstatus Terraform provider lets you manage your monitoring infrastructure programmatically using HashiCorp Terraform. Define monitors, notification channels, and status pages as code — with full support for version control, automated deployments, and IaC workflows.
**Key capabilities:**
- Manage HTTP, TCP, DNS, and ICMP monitors with assertions.
- Configure notification channels (Slack, PagerDuty, email, webhooks, and more).
- Create and manage status pages with component groups.
- Provision private locations and assign monitors to them.
- Import existing resources into Terraform state.
## Installation
Declare the provider in your Terraform configuration. Terraform will automatically download it when you run `terraform init`.
```terraform
terraform {
required_providers {
openstatus = {
source = "openstatusHQ/openstatus"
version = "~> 0.1"
}
}
}
```
For the latest version, refer to the [Terraform Registry](https://registry.terraform.io/providers/openstatusHQ/openstatus/latest).
## Provider configuration
```terraform
provider "openstatus" {
api_token = "YOUR_OPENSTATUS_API_TOKEN" # or set OPENSTATUS_API_TOKEN env var
}
```
| Argument | Type | Required | Description |
| :---------- | :------- | :------- | :-------------------------------------------------------------------------- |
| `api_token` | `string` | Yes | Your openstatus API token. Can also be set via the `OPENSTATUS_API_TOKEN` environment variable. |
| `base_url` | `string` | No | Base URL for the openstatus API. Defaults to `https://api.openstatus.dev/rpc`. |
## Resources
### `openstatus_http_monitor`
Manages an HTTP monitor with support for custom headers, request bodies, and response assertions.
**Arguments:**
| Argument | Type | Required | Default | Description |
| :----------------- | :-------------- | :------- | :------- | :-------------------------------------------------------------------------- |
| `name` | `string` | Yes | | Monitor name (max 256 chars). |
| `url` | `string` | Yes | | URL to monitor (max 2048 chars). |
| `periodicity` | `string` | Yes | | Check frequency: `30s`, `1m`, `5m`, `10m`, `30m`, `1h`. |
| `method` | `string` | No | `"GET"` | HTTP method: `GET`, `POST`, `HEAD`, `PUT`, `PATCH`, `DELETE`, `OPTIONS`, `TRACE`, `CONNECT`. |
| `body` | `string` | No | `""` | Request body for `POST`, `PUT`, `PATCH` methods. |
| `timeout` | `number` | No | `45000` | Timeout in milliseconds (0–120000). |
| `degraded_at` | `number` | No | computed | Response time threshold (ms) after which the monitor is considered degraded. |
| `retry` | `number` | No | `3` | Number of retries on failure (0–10). |
| `follow_redirects` | `bool` | No | `true` | Whether to follow HTTP redirects. |
| `active` | `bool` | No | `false` | Whether the monitor is active. |
| `public` | `bool` | No | `false` | Whether the monitor is visible on your public status page. |
| `description` | `string` | No | | Monitor description (max 1024 chars). |
| `regions` | `set(string)` | No | | Regions to monitor from. See [Available Regions](#available-regions). |
**Blocks:**
- **`headers`** (max 20) — Custom HTTP headers to include with each request.
- `key` (string, required) — Header name.
- `value` (string, required) — Header value.
- **`status_code_assertions`** (max 10) — Assert on response status codes.
- `target` (number, required) — Expected status code (100–599).
- `comparator` (string, required) — One of: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`.
- **`body_assertions`** (max 10) — Assert on response body content.
- `target` (string, required) — Expected value.
- `comparator` (string, required) — One of: `contains`, `not_contains`, `eq`, `neq`, `empty`, `not_empty`, `gt`, `gte`, `lt`, `lte`.
- **`header_assertions`** (max 10) — Assert on response headers.
- `key` (string, required) — Header name to assert on.
- `target` (string, required) — Expected value.
- `comparator` (string, required) — Same comparators as `body_assertions`.
- **`open_telemetry`** — Export this monitor's metrics to an OTLP endpoint (HTTP only).
- `endpoint` (string, optional) — OTLP metrics endpoint URL.
- `headers` (block list, optional) — Headers sent with each export; each has a required `key` and `value`.
**Read-only attributes:** `id` (string), `status` (string: `active`, `degraded`, `error`, `unknown`), `private_location_ids` (set of string — managed from `openstatus_private_location.monitor_ids`).
**Example — Basic health check:**
```terraform
resource "openstatus_http_monitor" "website" {
name = "Website Availability"
url = "https://www.example.com"
periodicity = "1m"
active = true
public = true
regions = ["fly-iad", "fly-ams", "fly-syd"]
}
```
**Example — API monitor with assertions and headers:**
```terraform
resource "openstatus_http_monitor" "api" {
name = "API Health Check"
description = "Monitors the /health endpoint with full assertions."
url = "https://api.example.com/health"
periodicity = "5m"
method = "GET"
timeout = 30000
active = true
regions = ["fly-iad", "fly-ams", "fly-nrt"]
headers {
key = "Authorization"
value = "Bearer ${var.api_token}"
}
headers {
key = "Accept"
value = "application/json"
}
status_code_assertions {
target = 200
comparator = "eq"
}
body_assertions {
target = "ok"
comparator = "contains"
}
header_assertions {
key = "Content-Type"
target = "application/json"
comparator = "contains"
}
}
```
**Example — POST monitor with request body:**
```terraform
resource "openstatus_http_monitor" "webhook" {
name = "Webhook Endpoint"
url = "https://api.example.com/webhooks/health"
periodicity = "10m"
method = "POST"
active = true
regions = ["fly-iad"]
headers {
key = "Content-Type"
value = "application/json"
}
body = jsonencode({
type = "health_check"
})
status_code_assertions {
target = 202
comparator = "eq"
}
}
```
**Import:**
```bash
terraform import openstatus_http_monitor.website
```
---
### `openstatus_tcp_monitor`
Manages a TCP connection monitor to verify that a port is open and reachable.
**Arguments:**
| Argument | Type | Required | Default | Description |
| :------------ | :------------ | :------- | :------- | :----------------------------------------------------------------- |
| `name` | `string` | Yes | | Monitor name (max 256 chars). |
| `uri` | `string` | Yes | | Target in `host:port` format (max 2048 chars). |
| `periodicity` | `string` | Yes | | Check frequency: `30s`, `1m`, `5m`, `10m`, `30m`, `1h`. |
| `timeout` | `number` | No | `45000` | Timeout in milliseconds (0–120000). |
| `degraded_at` | `number` | No | computed | Degradation threshold in milliseconds. |
| `retry` | `number` | No | `3` | Number of retries on failure (0–10). |
| `active` | `bool` | No | `false` | Whether the monitor is active. |
| `public` | `bool` | No | `false` | Whether the monitor is publicly visible. |
| `description` | `string` | No | | Monitor description (max 1024 chars). |
| `regions` | `set(string)` | No | | Regions to monitor from. See [Available Regions](#available-regions). |
**Blocks:**
- **`open_telemetry`** — Export this monitor's metrics to an OTLP endpoint (HTTP only).
- `endpoint` (string, optional) — OTLP metrics endpoint URL.
- `headers` (block list, optional) — Headers sent with each export; each has a required `key` and `value`.
**Read-only attributes:** `id` (string), `status` (string), `private_location_ids` (set of string — managed from `openstatus_private_location.monitor_ids`).
**Example — Database port check:**
```terraform
resource "openstatus_tcp_monitor" "database" {
name = "PostgreSQL Port Check"
description = "Ensures the database port is open and reachable."
uri = "db.example.com:5432"
periodicity = "1m"
timeout = 10000
active = true
regions = ["fly-iad", "fly-fra"]
}
```
**Example — Redis monitor:**
```terraform
resource "openstatus_tcp_monitor" "redis" {
name = "Redis Connection"
uri = "redis.example.com:6379"
periodicity = "30s"
active = true
regions = ["fly-iad", "fly-ams", "fly-nrt"]
}
```
**Import:**
```bash
terraform import openstatus_tcp_monitor.database
```
---
### `openstatus_dns_monitor`
Manages a DNS monitor with support for record type assertions.
**Arguments:**
| Argument | Type | Required | Default | Description |
| :------------ | :------------ | :------- | :------- | :----------------------------------------------------------------- |
| `name` | `string` | Yes | | Monitor name (max 256 chars). |
| `uri` | `string` | Yes | | Domain name to monitor (max 2048 chars). |
| `periodicity` | `string` | Yes | | Check frequency: `30s`, `1m`, `5m`, `10m`, `30m`, `1h`. |
| `timeout` | `number` | No | `45000` | Timeout in milliseconds (0–120000). |
| `degraded_at` | `number` | No | computed | Degradation threshold in milliseconds. |
| `retry` | `number` | No | `3` | Number of retries on failure (0–10). |
| `active` | `bool` | No | `false` | Whether the monitor is active. |
| `public` | `bool` | No | `false` | Whether the monitor is publicly visible. |
| `description` | `string` | No | | Monitor description (max 1024 chars). |
| `regions` | `set(string)` | No | | Regions to monitor from. See [Available Regions](#available-regions). |
**Blocks:**
- **`record_assertions`** (max 10) — Assert on DNS record values.
- `record` (string, required) — DNS record type: `A`, `AAAA`, `CNAME`, `MX`, `TXT`.
- `target` (string, required) — Expected value.
- `comparator` (string, required) — One of: `eq`, `neq`, `contains`, `not_contains`.
- **`open_telemetry`** — Export this monitor's metrics to an OTLP endpoint (HTTP only).
- `endpoint` (string, optional) — OTLP metrics endpoint URL.
- `headers` (block list, optional) — Headers sent with each export; each has a required `key` and `value`.
**Read-only attributes:** `id` (string), `status` (string), `private_location_ids` (set of string — managed from `openstatus_private_location.monitor_ids`).
**Example — A record validation:**
```terraform
resource "openstatus_dns_monitor" "main_domain" {
name = "DNS A Record Check"
description = "Verifies that example.com resolves to the correct IP."
uri = "example.com"
periodicity = "10m"
active = true
regions = ["fly-iad", "fly-ams"]
record_assertions {
record = "A"
comparator = "eq"
target = "93.184.216.34"
}
}
```
**Example — MX record validation:**
```terraform
resource "openstatus_dns_monitor" "email" {
name = "Email MX Record Check"
uri = "example.com"
periodicity = "30m"
active = true
regions = ["fly-iad"]
record_assertions {
record = "MX"
comparator = "contains"
target = "mail.example.com"
}
}
```
**Import:**
```bash
terraform import openstatus_dns_monitor.main_domain
```
---
### `openstatus_icmp_monitor`
Manages an ICMP (ping) monitor that checks host reachability and round-trip latency.
**Arguments:**
| Argument | Type | Required | Default | Description |
| :------------ | :------------ | :------- | :------- | :----------------------------------------------------------------- |
| `name` | `string` | Yes | | Monitor name (max 256 chars). |
| `uri` | `string` | Yes | | Target host or IP address to ping, without a port. |
| `periodicity` | `string` | Yes | | Check frequency: `30s`, `1m`, `5m`, `10m`, `30m`, `1h`. |
| `timeout` | `number` | No | `45000` | Budget in milliseconds for the whole check (0–120000). |
| `degraded_at` | `number` | No | computed | Average-latency threshold in milliseconds. |
| `retry` | `number` | No | `3` | Number of retries on a fully failed check (0–10). |
| `active` | `bool` | No | `false` | Whether the monitor is active. |
| `public` | `bool` | No | `false` | Whether the monitor is publicly visible. |
| `description` | `string` | No | | Monitor description (max 1024 chars). |
| `regions` | `set(string)` | No | | Regions to monitor from. See [Available Regions](#available-regions). |
**Blocks:**
- **`open_telemetry`** — Export this monitor's metrics to an OTLP endpoint (HTTP only).
- `endpoint` (string, optional) — OTLP metrics endpoint URL.
- `headers` (block list, optional) — Headers sent with each export; each has a required `key` and `value`.
**Read-only attributes:** `id` (string), `status` (string), `private_location_ids` (set of string — managed from `openstatus_private_location.monitor_ids`).
See the [ICMP monitor reference](/docs/reference/icmp-monitor) for how a check is run (three echo requests, average latency, packet loss).
**Example — Gateway reachability:**
```terraform
resource "openstatus_icmp_monitor" "gateway" {
name = "Gateway Ping"
description = "Round-trip latency to the upstream gateway."
uri = "8.8.8.8"
periodicity = "1m"
timeout = 10000
active = true
regions = ["fly-iad", "fly-fra"]
open_telemetry {
endpoint = "https://otel.example.com/v1/metrics"
}
}
```
**Import:**
```bash
terraform import openstatus_icmp_monitor.gateway
```
---
### `openstatus_notification`
Manages a notification channel. Supports 13 provider types: Discord, Email, Slack, PagerDuty, OpsGenie, Webhook, Telegram, SMS, WhatsApp, Google Chat, Grafana OnCall, Microsoft Teams, and ntfy.
**Arguments:**
| Argument | Type | Required | Description |
| :-------------- | :------------ | :------- | :------------------------------------------------------ |
| `name` | `string` | No | Notification channel name. |
| `provider_type` | `string` | Yes | Provider type (see supported values below). |
| `monitor_ids` | `set(string)` | No | Set of monitor IDs to associate with this notification. |
**Supported `provider_type` values:** `discord`, `email`, `slack`, `pagerduty`, `opsgenie`, `webhook`, `telegram`, `sms`, `whatsapp`, `google_chat`, `grafana_oncall`, `ntfy`.
**Provider-specific blocks** — use exactly one block matching your `provider_type`:
| Block | Arguments |
| :-------------- | :----------------------------------------------------------------------------------------------------- |
| `discord` | `webhook_url` (string, required, sensitive) |
| `email` | `email` (string, required) |
| `slack` | `webhook_url` (string, required, sensitive) |
| `pagerduty` | `integration_key` (string, required, sensitive) |
| `opsgenie` | `api_key` (string, required, sensitive), `region` (string, required: `us` or `eu`) |
| `webhook` | `endpoint` (string, required), `headers` (optional list of `key`/`value` objects) |
| `telegram` | `chat_id` (string, required) |
| `sms` | `phone_number` (string, required) |
| `whatsapp` | `phone_number` (string, required) |
| `google_chat` | `webhook_url` (string, required, sensitive) |
| `grafana_oncall` | `webhook_url` (string, required, sensitive) |
| `ntfy` | `topic` (string, required), `server_url` (string, optional), `token` (string, optional, sensitive) |
**Read-only attributes:** `id` (string), `created_at` (string), `updated_at` (string).
**Example — Slack notification:**
```terraform
resource "openstatus_notification" "slack_alerts" {
name = "Slack Alerts"
provider_type = "slack"
monitor_ids = [openstatus_http_monitor.api.id]
slack {
webhook_url = var.slack_webhook_url
}
}
```
**Example — PagerDuty notification:**
```terraform
resource "openstatus_notification" "pagerduty" {
name = "PagerDuty Escalation"
provider_type = "pagerduty"
monitor_ids = [
openstatus_http_monitor.api.id,
openstatus_tcp_monitor.database.id,
]
pagerduty {
integration_key = var.pagerduty_key
}
}
```
**Example — Email notification:**
```terraform
resource "openstatus_notification" "email" {
name = "On-Call Email"
provider_type = "email"
monitor_ids = [openstatus_http_monitor.api.id]
email {
email = "oncall@example.com"
}
}
```
**Example — Custom webhook:**
```terraform
resource "openstatus_notification" "custom_webhook" {
name = "Custom Webhook"
provider_type = "webhook"
webhook {
endpoint = "https://api.example.com/alerts"
headers {
key = "Authorization"
value = "Bearer ${var.webhook_token}"
}
headers {
key = "Content-Type"
value = "application/json"
}
}
}
```
**Example — Discord notification:**
```terraform
resource "openstatus_notification" "discord" {
name = "Discord Alerts"
provider_type = "discord"
discord {
webhook_url = var.discord_webhook_url
}
}
```
**Import:**
```bash
terraform import openstatus_notification.slack_alerts
```
---
### `openstatus_status_page`
Manages a status page with access control and branding.
**Arguments:**
| Argument | Type | Required | Description |
| :------------------- | :------------- | :------- | :----------------------------------------------------------------------------- |
| `title` | `string` | Yes | Page title (1–256 chars). |
| `slug` | `string` | Yes | URL slug (1–256 chars). Used in the status page URL. |
| `description` | `string` | No | Page description (max 1024 chars). |
| `homepage_url` | `string` | No | Link to your homepage. |
| `contact_url` | `string` | No | Link to your contact page. |
| `icon` | `string` | No | URL of the icon to display. |
| `custom_domain` | `string` | No | Custom domain (DNS must point to openstatus first). |
| `access_type` | `string` | No | Access control: `public`, `password`, `email-domain`, or `ip-restriction`. |
| `password` | `string` | No | Required when `access_type` is `password`. Sensitive. |
| `auth_email_domains` | `list(string)` | No | Required when `access_type` is `email-domain`. |
| `allowed_ip_ranges` | `string` | No | Comma-separated IPv4 CIDR ranges. Required when `access_type` is `ip`. |
| `theme` | `string` | No | Theme key applied to the page. |
| `custom_theme` | `object` | No | Per-mode CSS variable overrides merged over `theme`, with `light` and `dark` maps. Requires the custom-theme plan feature. |
| `default_locale` | `string` | No | Default language for the page. |
| `locales` | `list(string)` | No | Locales offered in the language switcher. |
| `allow_index` | `bool` | No | Whether search engines may index the page. |
**Read-only attributes:** `id` (string), `published` (bool), `created_at` (string), `updated_at` (string).
**Example — Public status page:**
```terraform
resource "openstatus_status_page" "main" {
title = "Example Inc. Status"
slug = "example-status"
description = "Real-time status for all Example Inc. services."
homepage_url = "https://example.com"
contact_url = "https://example.com/support"
}
```
**Example — Password-protected status page:**
```terraform
resource "openstatus_status_page" "internal" {
title = "Internal Status"
slug = "internal-status"
description = "Status page for internal services."
access_type = "password"
password = var.status_page_password
}
```
**Example — Email-domain restricted status page:**
```terraform
resource "openstatus_status_page" "company" {
title = "Company Status"
slug = "company-status"
access_type = "email-domain"
auth_email_domains = ["example.com", "subsidiary.com"]
}
```
**Example — IP-restricted status page:**
```terraform
resource "openstatus_status_page" "internal" {
title = "Internal Status"
slug = "internal-status"
access_type = "ip-restriction"
allowed_ip_ranges = "10.0.0.0/8,192.168.0.0/16"
}
```
**Import:**
```bash
terraform import openstatus_status_page.main
```
---
### `openstatus_status_page_component`
Manages a component on a status page. Components can be linked to a monitor or be static.
**Arguments:**
| Argument | Type | Required | Description |
| :------------ | :------- | :------- | :--------------------------------------------------------------------------- |
| `page_id` | `string` | Yes | Status page ID this component belongs to. Forces replacement if changed. |
| `type` | `string` | Yes | Component type: `monitor` or `static`. Forces replacement if changed. |
| `monitor_id` | `string` | No | Required when `type` is `monitor`. The monitor ID to display. |
| `name` | `string` | No | Component display name (max 256 chars). |
| `description` | `string` | No | Component description (max 1024 chars). |
| `order` | `number` | No | Display order on the status page. |
| `group_id` | `string` | No | Component group ID this belongs to. |
| `group_order` | `number` | No | Display order within its group. |
**Read-only attributes:** `id` (string), `created_at` (string), `updated_at` (string).
**Example — Monitor component:**
```terraform
resource "openstatus_status_page_component" "api" {
page_id = openstatus_status_page.main.id
type = "monitor"
monitor_id = openstatus_http_monitor.api.id
name = "API"
order = 1
}
```
**Example — Static component:**
```terraform
resource "openstatus_status_page_component" "third_party" {
page_id = openstatus_status_page.main.id
type = "static"
name = "Third-party Services"
description = "Status of external dependencies."
order = 2
}
```
**Import:**
```bash
terraform import openstatus_status_page_component.api /
```
---
### `openstatus_status_page_component_group`
Manages a component group on a status page, allowing you to organize components visually.
**Arguments:**
| Argument | Type | Required | Description |
| :-------- | :------- | :------- | :----------------------------------------------------------------------- |
| `page_id` | `string` | Yes | Status page ID this group belongs to. Forces replacement if changed. |
| `name` | `string` | Yes | Group name (1–256 chars). |
**Read-only attributes:** `id` (string), `created_at` (string), `updated_at` (string).
**Example:**
```terraform
resource "openstatus_status_page_component_group" "infrastructure" {
page_id = openstatus_status_page.main.id
name = "Infrastructure"
}
resource "openstatus_status_page_component_group" "applications" {
page_id = openstatus_status_page.main.id
name = "Applications"
}
```
**Import:**
```bash
terraform import openstatus_status_page_component_group.infrastructure /
```
---
### `openstatus_private_location`
Manages a private location: a self-hosted checker agent that runs the monitors you assign to it.
Terraform owns `monitor_ids` and `metadata` — removing either from the configuration clears it on the next apply. Liveness (`status`, `last_seen_at`) is only available on the `openstatus_private_location` data source.
**Arguments:**
| Argument | Type | Required | Description |
| :------------ | :------------ | :------- | :----------------------------------------------------------- |
| `name` | `string` | Yes | Display name for the private location. |
| `monitor_ids` | `set(string)` | No | IDs of the monitors this private location runs. |
| `metadata` | `map(string)` | No | User-defined key/value labels attached to this location. |
**Read-only attributes:** `id` (string), `token` (string, sensitive), `created_at` (string), `updated_at` (string).
```terraform
resource "openstatus_private_location" "eu_dc" {
name = "EU Datacenter"
monitor_ids = [openstatus_http_monitor.api.id]
metadata = {
env = "prod"
region = "eu-west-1"
}
}
# The agent token is generated by openstatus. Pass it to the checker agent.
output "agent_token" {
value = openstatus_private_location.eu_dc.token
sensitive = true
}
```
## Data Sources
### `openstatus_monitor`
Look up a single monitor by ID. Works for HTTP, TCP, DNS, and ICMP monitors.
```terraform
data "openstatus_monitor" "existing" {
id = "123"
}
output "monitor_name" {
value = data.openstatus_monitor.existing.name
}
output "monitor_type" {
value = data.openstatus_monitor.existing.type
}
```
**Computed attributes:** `type` (`http`, `tcp`, `dns`, `icmp`), `name`, `url` (HTTP only), `uri` (TCP/DNS/ICMP only), `periodicity`, `method` (HTTP only), `active`, `public`, `description`, `timeout`, `status`, `private_location_ids`.
---
### `openstatus_monitors`
List all monitors with pagination.
```terraform
data "openstatus_monitors" "all" {
limit = 100
offset = 0
}
output "total_monitors" {
value = length(data.openstatus_monitors.all.monitors)
}
```
| Argument | Type | Required | Default | Description |
| :------- | :------- | :------- | :------ | :----------------------- |
| `limit` | `number` | No | `50` | Max results (1–100). |
| `offset` | `number` | No | `0` | Pagination offset. |
**Computed:** `monitors` — list of objects with `id`, `name`, `type`.
---
### `openstatus_notification`
Look up a notification channel by ID.
```terraform
data "openstatus_notification" "existing" {
id = "456"
}
output "notification_provider" {
value = data.openstatus_notification.existing.provider_type
}
```
**Computed attributes:** `name`, `provider_type`, `monitor_ids`, `created_at`, `updated_at`.
---
### `openstatus_status_page`
Look up a status page by ID.
```terraform
data "openstatus_status_page" "existing" {
id = "789"
}
output "status_page_url" {
value = data.openstatus_status_page.existing.slug
}
```
**Computed attributes:** `title`, `slug`, `description`, `homepage_url`, `contact_url`, `icon`, `custom_domain`, `published`, `access_type`, `password` (sensitive), `auth_email_domains`, `theme`, `created_at`, `updated_at`.
---
### `openstatus_private_location`
Look up a single private location by ID. Unlike the resource, this data source exposes agent liveness.
```terraform
data "openstatus_private_location" "eu_dc" {
id = "12"
}
output "agent_last_seen" {
value = data.openstatus_private_location.eu_dc.last_seen_at
}
```
**Computed attributes:** `name`, `monitor_ids`, `metadata`, `status` (`active`, `error`, or `unknown`), `last_seen_at` (RFC 3339, null if the agent has never reported), `token` (sensitive), `created_at`, `updated_at`.
---
### `openstatus_private_locations`
List all private locations with pagination.
```terraform
data "openstatus_private_locations" "all" {
limit = 100
}
output "private_location_names" {
value = [for l in data.openstatus_private_locations.all.private_locations : l.name]
}
```
| Argument | Type | Required | Default | Description |
| :------- | :------- | :------- | :------ | :----------------- |
| `limit` | `number` | No | `50` | Max results. |
| `offset` | `number` | No | `0` | Pagination offset. |
**Computed:** `private_locations` — list of objects with `id`, `name`, `metadata`, `status`, `last_seen_at`, `monitor_count`, `created_at`, `updated_at`. Agent tokens are not returned by the list endpoint; use the singular data source to fetch one.
## Available Regions
Monitors can run from any of the following 28 regions:
**Fly.io:**
`fly-ams`, `fly-arn`, `fly-bom`, `fly-cdg`, `fly-dfw`, `fly-ewr`, `fly-fra`, `fly-gru`, `fly-iad`, `fly-jnb`, `fly-lax`, `fly-lhr`, `fly-nrt`, `fly-ord`, `fly-sjc`, `fly-sin`, `fly-syd`, `fly-yyz`
**Koyeb:**
`koyeb-fra`, `koyeb-par`, `koyeb-sfo`, `koyeb-sin`, `koyeb-tyo`, `koyeb-was`
**Railway:**
`railway-us-west2`, `railway-us-east4`, `railway-europe-west4`, `railway-asia-southeast1`
## Full End-to-End Example
This example sets up a complete monitoring stack: HTTP and TCP monitors, Slack notifications, and a public status page with grouped components.
```terraform
terraform {
required_providers {
openstatus = {
source = "openstatusHQ/openstatus"
version = "~> 0.1"
}
}
}
provider "openstatus" {
api_token = var.openstatus_api_token
}
# --- Variables ---
variable "openstatus_api_token" {
type = string
sensitive = true
}
variable "slack_webhook_url" {
type = string
sensitive = true
}
# --- Monitors ---
resource "openstatus_http_monitor" "api" {
name = "API Health"
description = "Monitors the main API health endpoint."
url = "https://api.example.com/health"
periodicity = "5m"
method = "GET"
timeout = 30000
active = true
public = true
regions = ["fly-iad", "fly-ams", "fly-nrt"]
status_code_assertions {
target = 200
comparator = "eq"
}
body_assertions {
target = "ok"
comparator = "contains"
}
}
resource "openstatus_http_monitor" "website" {
name = "Website"
url = "https://www.example.com"
periodicity = "1m"
active = true
public = true
regions = ["fly-iad", "fly-ams", "fly-syd"]
status_code_assertions {
target = 200
comparator = "eq"
}
}
resource "openstatus_tcp_monitor" "database" {
name = "PostgreSQL"
uri = "db.example.com:5432"
periodicity = "1m"
timeout = 10000
active = true
regions = ["fly-iad"]
}
resource "openstatus_dns_monitor" "domain" {
name = "DNS Resolution"
uri = "example.com"
periodicity = "10m"
active = true
regions = ["fly-iad", "fly-ams"]
record_assertions {
record = "A"
comparator = "eq"
target = "93.184.216.34"
}
}
# --- Notifications ---
resource "openstatus_notification" "slack" {
name = "Slack Alerts"
provider_type = "slack"
monitor_ids = [
openstatus_http_monitor.api.id,
openstatus_http_monitor.website.id,
openstatus_tcp_monitor.database.id,
]
slack {
webhook_url = var.slack_webhook_url
}
}
# --- Status Page ---
resource "openstatus_status_page" "main" {
title = "Example Inc. Status"
slug = "example-status"
description = "Real-time status for all Example Inc. services."
homepage_url = "https://example.com"
contact_url = "https://example.com/support"
}
resource "openstatus_status_page_component_group" "web" {
page_id = openstatus_status_page.main.id
name = "Web Services"
}
resource "openstatus_status_page_component_group" "infra" {
page_id = openstatus_status_page.main.id
name = "Infrastructure"
}
resource "openstatus_status_page_component" "api_component" {
page_id = openstatus_status_page.main.id
type = "monitor"
monitor_id = openstatus_http_monitor.api.id
name = "API"
group_id = openstatus_status_page_component_group.web.id
order = 1
group_order = 1
}
resource "openstatus_status_page_component" "website_component" {
page_id = openstatus_status_page.main.id
type = "monitor"
monitor_id = openstatus_http_monitor.website.id
name = "Website"
group_id = openstatus_status_page_component_group.web.id
order = 1
group_order = 2
}
resource "openstatus_status_page_component" "db_component" {
page_id = openstatus_status_page.main.id
type = "monitor"
monitor_id = openstatus_tcp_monitor.database.id
name = "Database"
group_id = openstatus_status_page_component_group.infra.id
order = 2
group_order = 1
}
```
## Related Resources
- **[HTTP Monitor Reference](/docs/reference/http-monitor)** — Detailed specification for HTTP monitor configuration.
- **[TCP Monitor Reference](/docs/reference/tcp-monitor)** — Detailed specification for TCP monitor configuration.
- **[DNS Monitor Reference](/docs/reference/dns-monitor)** — Detailed specification for DNS monitor configuration.
- **[CLI Reference](/docs/reference/cli-reference)** — Manage monitors using the openstatus command-line interface.
- **[Terraform Registry](https://registry.terraform.io/providers/openstatusHQ/openstatus/latest)** — Official provider page with version history.
- **[Provider Source Code](https://github.com/openstatusHQ/terraform-provider-openstatus)** — GitHub repository for the Terraform provider.