Terraform Provider
Overview
Section titled “Overview”The official okstatus Terraform provider lets you manage monitors, monitor groups, incidents, status pages, alert channels, and maintenance windows as code — useful for provisioning monitoring alongside the infrastructure it watches, or keeping a fleet of monitors in version control instead of clicking through the dashboard.
The provider is published on the Terraform Registry and its full resource/data-source reference lives there. This guide only covers getting started — see the registry docs for every field.
Install
Section titled “Install”terraform { required_providers { okstatus = { source = "clearcloud-fr/okstatus" version = "~> 1.6" } }}
provider "okstatus" { # api_key can also come from the OKSTATUS_API_KEY environment variable. # api_key = "oks_live_..."}Prefer the environment variable over hardcoding the key in your .tf files:
export OKSTATUS_API_KEY="oks_live_..."A first monitor
Section titled “A first monitor”resource "okstatus_monitor" "api" { name = "Production API" url = "https://api.example.com/health" type = "http" interval = 60 regions = ["fr-dc3", "de-fra", "es-mad"] accepted_status_codes = ["200-299"]
tags = ["prod", "payments"] keyword = "\"status\":\"ok\"" follow_redirects = false}Which regions values are actually allowed depends on your plan — a region your plan doesn’t include fails at apply with a 400, not at plan. See Regions and intervals for the per-plan list.
An HTTP check can send its own request — method, body and headers:
resource "okstatus_monitor" "webhook" { name = "Order webhook" url = "https://api.example.com/orders/ping" http_method = "POST" http_body = jsonencode({ ping = true }) http_body_encoding = "json" http_headers = { Authorization = "Bearer ${var.probe_token}" }}http_headers is sensitive and write-only: OKStatus never returns request headers, so Terraform sends them when the attribute changes and cannot see a header edited in the dashboard. ignore_tls = true accepts a self-signed certificate.
Other check types take their own settings:
resource "okstatus_monitor" "spf" { name = "SPF record" url = "example.com" type = "dns" dns_record_type = "TXT" dns_expected_value = "v=spf1"}
resource "okstatus_monitor" "database" { name = "Database port" url = "db.example.com" type = "tcp" port = 5432}Databases, heartbeats and other types
Section titled “Databases, heartbeats and other types”type takes every check type of OKStatus except AI models (which have okstatus_llm_monitor): grpc, push, group, postgres, mysql, mongodb, smtp, imap and redis.
resource "okstatus_monitor" "orders_db" { name = "Orders database" url = "postgres://db.example.com:5432/orders" type = "postgres" db_query = "SELECT 1" basic_auth_user = "okstatus_ro" basic_auth_password = var.orders_db_password}
resource "okstatus_monitor" "backup" { name = "Nightly backup" url = "nightly-backup" type = "push" interval = 86400 grace_period = 3600}A push monitor exposes its push_token (sensitive) — the token of the ping URL your job calls. Changing type or grace_period replaces the monitor.
Authenticating to the monitored endpoint
Section titled “Authenticating to the monitored endpoint”resource "okstatus_monitor" "partner_api" { name = "Partner API" url = "https://partner.example.com/health"
auth = { type = "oauth2" token_url = "https://login.example.com/oauth/token" client_id = "okstatus-probe" client_secret = var.partner_client_secret }}auth.type is bearer, apikey, cookie, oauth2 or mtls — see Authentication for what each one does. Basic auth, and the account of a database, SMTP, IMAP or Redis monitor, go in basic_auth_user / basic_auth_password.
Credentials are write-only: OKStatus never returns them, so Terraform sends them when they change and cannot see an edit made in the dashboard. Removing them from the configuration removes them from the monitor. Never write user:password@ in url — the provider refuses it.
Pausing and muting
Section titled “Pausing and muting”resource "okstatus_monitor" "staging" { name = "Staging" url = "https://staging.example.com" paused = true # no checks muted = true # checks, but no alerts}What you leave out stays as it is
Section titled “What you leave out stays as it is”tags, paused, muted, keyword, follow_redirects, port, the HTTP request options and the DNS settings have no default. An attribute you do not write keeps the value the monitor already has, including one set in the dashboard — so adding the provider to existing monitors, or upgrading it, never resets them. To remove a value, say so: tags = [], keyword = "", paused = false.
Attaching alert channels
Section titled “Attaching alert channels”Alert channel config uses the backend’s own field names (camelCase), not Terraform’s usual snake_case — see the okstatus_alert_channel reference for the shape of every channel type.
resource "okstatus_alert_channel" "team_discord" { type = "discord" config = { webhookUrl = "https://discord.com/api/webhooks/..." }}
resource "okstatus_monitor" "checkout" { name = "Checkout" url = "https://shop.example.com/checkout/health" alert_channel_ids = [okstatus_alert_channel.team_discord.id]}alert_channel_ids is the complete list of the monitor’s channels; [] detaches them all. Without the attribute, Terraform does not manage the monitor’s channels at all. To attach a channel created in the dashboard, look it up with data.okstatus_alert_channels.
Grouping monitors
Section titled “Grouping monitors”resource "okstatus_monitor_group" "payments" { name = "Payments" description = "Everything on the checkout path"
monitor_ids = [ okstatus_monitor.api.id, okstatus_monitor.checkout.id, ]}A monitor belongs to one group at most, and monitor_ids is the group’s complete membership. Destroying the group keeps its monitors.
A group can carry alert_channel_ids of its own: a monitor that joins the group gets them attached. If you also set alert_channel_ids on that monitor, repeat the group’s channels there — otherwise the next apply detaches them from the monitor.
Running a monitor on a private agent
Section titled “Running a monitor on a private agent”Private agents are enrolled from the dashboard. Terraform reads them and gives you the region value that runs a monitor on one of them:
data "okstatus_private_agents" "all" {}
locals { paris_agent = one([for a in data.okstatus_private_agents.all.agents : a if a.name == "dc-paris"])}
resource "okstatus_monitor" "intranet" { name = "Intranet" url = "https://intranet.example.com" regions = [local.paris_agent.region]}regions = ["private"] lets any of your agents run the check.
What’s covered
Section titled “What’s covered”| Resource / data source | Manages |
|---|---|
okstatus_monitor | Every monitor type except AI models, with credentials and alert channels |
okstatus_llm_monitor | AI model (LLM) monitors (Max and above) |
okstatus_monitor_group | Monitor groups (the folders of the Monitors page) |
okstatus_alert_channel | Email, Discord, webhook, Slack, Telegram, and more |
okstatus_incident | Incidents and their timestamped updates |
okstatus_maintenance | Scheduled maintenance windows |
okstatus_status_page | Public status pages |
data.okstatus_monitors | Look up existing monitors (e.g. to reference by name) |
data.okstatus_monitor_groups | Look up existing groups and their monitors |
data.okstatus_alert_channels | Look up existing alert channels |
data.okstatus_private_agents | Your private agents and the region value of each |
data.okstatus_org | Read the current organization’s plan and settings |
slo_target on okstatus_monitor and okstatus_monitor_group sets an SLO (Max and Enterprise). Terraform manages the objective; the budget is read with the API (GET /api/v1/slos) or the MCP connector (list_slos).
Not managed by Terraform: enrolling a private agent, and SLA reports.
Full schema, every field, and defaults: registry.terraform.io/providers/clearcloud-fr/okstatus.
Importing existing resources
Section titled “Importing existing resources”Resources created through the dashboard can be brought under Terraform management with terraform import, using the resource’s ID (visible in the dashboard URL or via the REST API):
terraform import okstatus_monitor.api <monitor-id>terraform import okstatus_monitor_group.payments <group-id>An imported monitor keeps its tags, keyword and paused state until you write those attributes.