Agent skill
Terraform Webhooks Skill
Receive and verify HCP Terraform (Terraform Cloud) and Terraform Enterprise notification webhooks. Use when setting up Terraform run notification handlers, debugging X-TFE-Notification-Signature verification, or handling triggers like run:completed, run:errored, run:needs_attention, and assessment:drifted.
Install this skill
npx skills add hookdeck/webhook-skills --skill terraform-webhooks
HCP Terraform (formerly Terraform Cloud) and Terraform Enterprise send workspace notifications to any HTTP endpoint using the generic destination type. This skill covers that destination only; Slack, Microsoft Teams, and email use their own formats.
When to Use This Skill
- How do I receive HCP Terraform / Terraform Cloud run notification webhooks?
- How do I verify the
X-TFE-Notification-Signatureheader? - How do I handle
run:completed,run:errored, orrun:needs_attentionnotifications? - How do I react to drift detection (
assessment:drifted) or failed health assessments? - Why is my Terraform notification configuration failing verification or not enabling?
Verification (core)
The signature is the hex HMAC-SHA512 of the raw request body, keyed with the notification configuration's token, sent in X-TFE-Notification-Signature. The token is optional in HCP Terraform: if you don't set one, no signature is sent, so set one and reject unsigned requests.
const crypto = require('crypto');
function verifyTerraformSignature(rawBody, signatureHeader, token) {
if (!signatureHeader || !token) return false;
const expected = crypto.createHmac('sha512', token).update(rawBody).digest('hex');
try {
const received = Buffer.from(signatureHeader.toLowerCase());
const expectedBuf = Buffer.from(expected);
return received.length === expectedBuf.length && crypto.timingSafeEqual(received, expectedBuf);
} catch {
return false;
}
}
import hmac, hashlib
def verify_terraform_signature(raw_body: bytes, signature_header: str, token: str) -> bool:
if not signature_header or not token:
return False
expected = hmac.new(token.encode(), raw_body, hashlib.sha512).hexdigest()
return hmac.compare_digest(signature_header.lower().encode(), expected.encode())
In Express, read the body with express.raw({ type: '*/*' }) so the signature verifies whatever Content-Type the request carries.
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Verification Request
When you save a configuration with Enabled on, or click Send a test, HCP Terraform POSTs a test payload whose notifications[0].trigger is "verification" (run fields are null). Return any 2xx; the configuration can't be enabled otherwise. The request is signed like any other when a token is set, so the token must already be configured in your handler.
Triggers
Run payloads (payload_version: 1) carry the trigger in notifications[].trigger. Workspace payloads (payload_version: "2") carry it in a top-level trigger.
| Trigger | Fires When |
|---|---|
run:created | A run is created and enters the Pending stage |
run:planning | A run acquires the lock and starts executing |
run:needs_attention | A plan has changes and needs approval or a policy override |
run:applying | A run enters the Apply stage |
run:completed | A run completes successfully |
run:errored | A run ends early from an error or cancellation |
assessment:drifted | Drift detected (health assessments enabled) |
assessment:check_failure | Continuous validation checks failed |
assessment:failed | A health assessment itself failed |
workspace:auto_ | An automatic destroy run is imminent |
workspace:auto_ | An automatic destroy run was attempted |
workspace:deleted | A workspace was deleted |
verification | Test request sent on enable / "Send a test" |
Run payload fields: payload_version, notification_, run_url, run_id, run_message, run_created_at, run_created_by, workspace_id, workspace_name, organization_name, and notifications[] (message, trigger, run_status, run_updated_at, run_updated_by).
For the full payload reference, see Notification configurations API.
Important Headers
| Header | Description |
|---|---|
X-TFE-Notification-Signature | Hex HMAC-SHA512 of the raw body (only when a token is set) |
Environment Variables
# The token entered on the notification configuration (cannot be viewed after saving)
TERRAFORM_NOTIFICATION_TOKEN=your_notification_token
Local Development
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 terraform --path /webhooks/terraform
Use the tunnel URL as the Webhook URL of a generic notification configuration. Enabling the configuration sends the verification request through it.
Reference Materials
- references/overview.md - Notification types, triggers, payloads
- references/setup.md - Creating a notification configuration with a token
- references/verification.md - Signature verification details and gotchas