Terraform provider v0.5.1
The official Terraform provider for LastPing.
Published on the public Terraform Registry as lastping-dev/lastping. Declare your cron, CI/CD and AI-agent monitors as code, import the ones you already have, and let an AI agent generate them.
- 7 managed resources
- 1 ephemeral resource
- 6 data sources
- Free for individuals, no monitor caps
Install in three steps
A normal registry provider: nothing to vendor, nothing to build. Terraform 1.5 or later; 1.10 or later if you want the ephemeral API key.
-
Declare the provider
Leave
api_keyout: the provider readsLASTPING_API_KEYfrom the environment, so the credential never sits in a file you might commit.terraform { required_providers { lastping = { source = "lastping-dev/lastping" version = "~> 0.5" } } } provider "lastping" { # Set LASTPING_API_KEY in your environment instead of hardcoding it. } -
Authenticate
Create a key at app.lastping.dev, Settings, API Keys. One key, one project, no ambiguity about what a plan is about to change.
export LASTPING_API_KEY="lp_…" # Targeting a different LastPing environment (e.g. staging)? export LASTPING_ENDPOINT="https://staging.lastping.dev" -
Initialise and apply
terraform initdownloads the provider and verifies its signature. Then plan, review, apply.$ terraform init - Finding lastping-dev/lastping versions matching "~> 0.5"... - Installing lastping-dev/lastping v0.5.1... - Installed lastping-dev/lastping v0.5.1 (self-signed, key ID E863B1802B5C1E64) Terraform has been successfully initialized! $ terraform apply
A complete monitor, end to end
Monitor, destination, routing and alert wording in one file. It applies as-is against the real API.
grace_sis required and validated to [60, 31536000].- One
lastping_routeper monitor and event type. - Template placeholders are
{token}, not Go templates.
terraform apply creates five resources. The monitor's ping_url comes back for whatever runs the job.
# The Slack incoming-webhook URL is itself the credential. Keep it out of the
# repo: pass it with TF_VAR_slack_webhook_url or a secrets manager.
variable "slack_webhook_url" {
type = string
sensitive = true
}
# 1: the monitor. It expects a ping every night at 03:00 UTC and waits
# grace_s seconds past that before opening an incident.
resource "lastping_monitor" "nightly_backup" {
name = "Nightly backup"
slug = "nightly-backup"
schedule_kind = "cron"
cron_expr = "0 3 * * *"
tz = "UTC"
grace_s = 1800
tags = ["env:prod", "team:platform"]
}
# 2: where alerts go.
resource "lastping_destination" "oncall_slack" {
kind = "slack"
name = "#oncall"
webhook_url = var.slack_webhook_url
}
# 3: which events go there. One resource per (monitor, event type).
resource "lastping_route" "backup_down" {
monitor_id = lastping_monitor.nightly_backup.id
event_type = "down"
destination_ids = [lastping_destination.oncall_slack.id]
}
resource "lastping_route" "backup_recovery" {
monitor_id = lastping_monitor.nightly_backup.id
event_type = "recovery"
destination_ids = [lastping_destination.oncall_slack.id]
}
# 4: what the alert says. Placeholders are {token}, not Go templates.
resource "lastping_alert_template" "nightly_backup" {
monitor_id = lastping_monitor.nightly_backup.id
templates = {
"down" = "{check_name} has not checked in. Last ping {last_ping}, expected {schedule}. {incident_url}"
"recovery" = "{check_name} recovered."
}
}
Export as Terraform: adopt, don't recreate
LastPing writes the HCL for monitors you already have, and pairs every resource with an import block, so the first plan adopts them instead of replacing them.
- A monitor imports by its slug, a destination by UUID, a route by
<monitor-id>:<event-type>. - Secrets come out as
var.references withsensitive = truevariables and a loud TODO, never an empty string. - A clean plan,
0 to add, 0 to change, 0 to destroy, means your monitoring is in version control and nothing changed.
Still on another tool? Write the resource blocks directly: moving off Opsgenie heartbeats before April 2027 has the field mapping.
# from the dashboard, or straight from the API with the same key:
$ curl -fsS -H "Authorization: Bearer $LASTPING_API_KEY" \
https://app.lastping.dev/api/v1/export/terraform > lastping.tf# Generated by LastPing.
# Secrets are not exported: the API never returns them. Every `var.`
# reference below has a matching variable block you must fill in.
# Import blocks adopt your existing resources instead of recreating them.
import {
to = lastping_monitor.nightly_backup
id = "nightly-backup"
}
resource "lastping_monitor" "nightly_backup" {
name = "Nightly backup"
slug = "nightly-backup"
schedule_kind = "cron"
cron_expr = "0 3 * * *"
tz = "UTC"
grace_s = 1800
tags = ["env:prod", "team:platform"]
}
import {
to = lastping_destination.oncall
id = "29145b3c-64c7-4b7f-91b7-a09c0eecaee1"
}
resource "lastping_destination" "oncall" {
kind = "slack"
name = "#oncall"
webhook_url = var.slack_webhook_url_oncall
}
import {
to = lastping_route.nightly_backup_down
id = "abbb8a64-dc85-4cbb-bf22-af13bfaf64bc:down"
}
resource "lastping_route" "nightly_backup_down" {
monitor_id = lastping_monitor.nightly_backup.id
event_type = "down"
destination_ids = [lastping_destination.oncall.id]
}
variable "slack_webhook_url_oncall" {
# Set this: secrets are never exported.
type = string
sensitive = true
description = "webhook_url for destination \"#oncall\""
}$ terraform plan
Plan: 0 to add, 0 to change, 0 to destroy.The agent writes the monitoring in the same pull request
When an agent builds a scheduled job, nobody files the "add monitoring" ticket. So make the monitoring part of the diff.
A public schema
Every resource and validation rule is on the Terraform Registry, so an agent can add the lastping_monitor in the same commit as the job.
CI applies it
The pipeline that deploys the job runs terraform apply: rename the job and you rename its monitor.
Or act now over MCP
For a monitor right now, mid-conversation, the MCP server reaches the same API. Export as Terraform turns it into code later.
The concept, at length: what monitoring as code means and why it matters more with agents.
A credential that does not outlive the run
The ephemeral lastping_api_key mints a key for one run and revokes it when the run ends. Nothing about it is written to plan or state. Requires Terraform 1.10 or later.
- The
ttlis the safety net: a killed run's key still expires server-side. Set it above your longest apply; a key cannot be renewed in place. - The managed
lastping_api_keystill exists for credentials that must outlive the run; its plaintext lands in state.
# Mints a key that exists only for this run and is revoked when the run ends.
# Nothing about it is written to plan or state. Requires Terraform 1.10+.
ephemeral "lastping_api_key" "run" {
name = "terraform-run"
ttl = "30m"
}
provider "lastping" {
alias = "run"
api_key = ephemeral.lastping_api_key.run.key
}
resource "lastping_monitor" "nightly_backup" {
provider = lastping.run
name = "Nightly backup"
slug = "nightly-backup"
schedule_kind = "cron"
cron_expr = "0 3 * * *"
tz = "UTC"
grace_s = 1800
}
Reference
Seven managed resources, one ephemeral resource, six data sources. The full schema for each is on the Terraform Registry.
Resource reference
Every row links to its page on the Terraform Registry.
| Resource | What it manages |
|---|---|
| lastping_agent | An agent whose monitors roll up into one live state. Attach monitors to it with agent_id on lastping_monitor. Creating an agent whose slug already exists fails rather than adopting it: import it instead. |
| lastping_monitor | A heartbeat, CI or HTTP probe monitor. Cron or simple-interval schedule, tags, runaway ceiling, pause state. Nested assertion blocks check the ping body, and metric_guard blocks alert when a reported number crosses a ceiling. Creating a monitor whose slug already exists fails loudly rather than taking it over silently: import it instead. |
| lastping_destination | Where alerts are delivered: Slack, email, custom webhook, Telegram, Discord, ntfy, Pushover, Microsoft Teams, Google Chat. Credentials are write-only: stored, never returned. |
| lastping_route | One monitor's alerts for one event type (down, recovery, fail, every-run, success, started) routed to a list of destinations. One resource per event type; an empty list mutes that event without deleting the route. |
| lastping_alert_template | Custom alert message bodies for one monitor, overriding the built-in wording. One resource owns the monitor's whole template map, because the API replaces the set rather than merging into it. |
| lastping_status_page | A public or private status page over a chosen set of monitors. Public slugs are globally unique across every LastPing account: see the note below. |
| lastping_api_key | A long-lived API key for automation that outlives the run. The plaintext is stored in Terraform state; prefer the ephemeral resource below when you can. |
| ephemeral lastping_api_key | A short-lived key minted for one run and revoked when it ends. Never written to plan or state. Requires Terraform 1.10 or later. |
| data lastping_project | The project the configured key belongs to. Doubles as a credential smoke-test: a revoked key fails here at plan time rather than partway through an apply. |
| data lastping_monitors | Every monitor in the project, optionally filtered by tag. Useful for building a status page from a tag instead of a hand-maintained list of ids, and for auditing monitors created outside Terraform. |
| data lastping_monitor | A single monitor by id or slug: how you attach a route to a monitor Terraform does not manage, without importing it. |
| data lastping_destination | A single destination by id or name. Reports only the non-secret target hint; a name matching more than one destination is an error, not an arbitrary pick. |
| data lastping_incidents | One monitor's incident history, newest first. For outputs and reports: incident history moves without Terraform doing anything, so do not feed it into a managed resource. |
| data lastping_metrics | The project's monitors as Prometheus gauges, exactly as the metrics endpoint returns them. For writing a scrape snapshot to disk or feeding a dashboard module. |
Four things worth knowing before your first apply
Alert templates use {token}, not Go templates
Placeholders: {check_name}, {status}, {event}, {cause}, {last_ping}, {schedule}, {incident_url}, {run_url}, {branch}, {commit}, {actor}, {failing_stage}, {duration}, {latency}, {status_code} and {url}. {failing_stage} is CI-only: always on GitLab, on GitHub only with the workflow_job event, never on Jenkins. {{.CheckName}} is accepted and renders literally; an unrecognised {check_nam} is rejected at apply time.
grace_s is required
Omit it and the API returns 400, grace 0s outside [60, 31536000]: how late a job may be is a decision about that job. For monitor_type = "http" the server floors grace at 2 × probe_interval_s; a smaller value is rejected at plan time.
Status page slugs are global
A slug is unique across every LastPing account, so a slug you have never seen may be taken. slug forces replacement, so add lifecycle { create_before_destroy = true } to public status pages.
Terraform will not adopt what it did not create
Routes and alert templates are whole-set writes, so creating either over existing ones would overwrite someone's alerting. The provider refuses and tells you to terraform import them, which is why Export as Terraform emits import blocks.
CI binding is declarable with ci_provider, ci_workflow and ci_branch; changing or removing ci_provider replaces the monitor. ci_webhook_url is reported by every read. ci_workflow and ci_branch cannot be refreshed: an imported monitor starts with them empty and the first apply writes them. The webhook secret is write-once: Terraform keeps the value captured at creation, and an imported CI monitor has none. The export emits the binding, with a comment on what import cannot carry.
Questions
Does LastPing have a Terraform provider?
Yes. The official provider is published on the public Terraform Registry as lastping-dev/lastping. Add source = "lastping-dev/lastping" and version = "~> 0.5" to your required_providers block and terraform init downloads and signature-verifies it like any other registry provider. It covers seven managed resources, one ephemeral resource and six data sources, and needs Terraform 1.5 or later, 1.10 or later if you use the ephemeral API key.
Can I import monitors I already created in the dashboard?
Yes, and you do not have to write the HCL yourself. Export as Terraform renders your existing monitors, destinations, routes, alert templates and status pages as HCL, and pairs every resource with a Terraform import block, so the first plan adopts what you already have rather than proposing to recreate it. Secrets are the one thing it cannot include: the API never returns them, so each secret attribute is emitted as a var. reference with a matching sensitive variable block for you to fill in.
Is the LastPing Terraform provider free?
Yes. LastPing is free for individuals, no monitor cap and no feature gate, and the Terraform provider is part of that. The provider itself is open source and adds no cost of its own. The one free-tier limit that shows up in Terraform is status pages: one public status page per project, with private pages unlimited.
The provider is MPL-2.0: source on GitHub.
Which LastPing resources can Terraform manage?
Seven managed resources (lastping_agent, lastping_monitor, lastping_destination, lastping_route, lastping_alert_template, lastping_status_page and lastping_api_key) plus an ephemeral lastping_api_key and six data sources for reading monitors, a single monitor, a destination, incidents, Prometheus metrics and the project. Binding a monitor to a CI provider is declarable too (ci_provider, ci_workflow and ci_branch). Its webhook secret is write-once, so Terraform keeps the value captured at creation and an imported CI monitor has none.
See the resource reference for the full list.
Can an AI agent write the Terraform for me?
Yes, and this is the intended path. The provider's schema and documentation are public on the Terraform Registry, so a coding agent can write correct HCL for a monitor in the same pull request that adds the job it watches: no separate ticket, no dashboard visit, and the reviewer sees both changes together.
Agents that prefer to act on the live API rather than write files can use the LastPing MCP server instead. Both paths reach the same monitors, and Export as Terraform is how one created over MCP later becomes code.
How do I keep a LastPing API key out of Terraform state?
Use the ephemeral lastping_api_key resource, which requires Terraform 1.10 or later. It mints a key for the duration of the run, hands it to a provider configuration, and revokes it when the run ends: nothing about it is written to plan or state. The key also carries a server-side expiry as a safety net, so a run that is killed before it can revoke its key still leaves a credential that stops working on its own.
Can I point the provider at a different LastPing environment?
Yes. Set LASTPING_ENDPOINT in the environment, or the endpoint argument on the provider block, to target a different LastPing deployment (for example a staging project). It defaults to https://app.lastping.dev. LastPing is a hosted product, not self-hostable software.
Start monitoring in minutes
Free for individuals. One URL to ping, or let your AI assistant set it up.