Webhooks
Webhooks let DriftWise receive Terraform plan events from your CI system and post analysis results back as PR comments. DriftWise supports Atlantis, GitHub Actions, and GitLab CI as webhook providers.
This page covers inbound webhooks — your CI system sending plan data to DriftWise. For outbound notifications (DriftWise alerting you when scans complete), see Scheduled Scans.
How It Works
- Your CI runs
terraform planand sends the plan JSON to DriftWise via webhook - DriftWise verifies the HMAC signature, parses the plan, and runs analysis
- DriftWise posts a PR comment with risk scoring and narrative
- Returns
202 Acceptedimmediately — analysis runs asynchronously
Creating a Webhook Config
Via the API
curl -X POST "https://app.driftwise.ai/api/v2/orgs/$ORG_ID/webhook-configs" \
-H "x-api-key: $DRIFTWISE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"provider": "atlantis",
"label": "Production Atlantis"
}'
The response includes a raw_secret field — save this immediately. It's only shown once:
{
"id": "config-uuid",
"provider": "atlantis",
"label": "Production Atlantis",
"secret_prefix": "whsec_3a2f9c8e",
"enabled": true,
"raw_secret": "whsec_3a2f9c8e7b1d4f6a..."
}
Configure this secret in your CI system as the webhook signing key.
Supported Providers
| Provider | Value | Signature Header |
|---|---|---|
| Atlantis | atlantis | X-Atlantis-Signature |
| GitHub Actions | github_actions | X-Hub-Signature-256 |
| GitLab CI | gitlab_ci | X-Gitlab-Token |
All three headers carry an sha256=<hex> HMAC value and are interchangeable at the transport layer — pick whichever your CI already produces. X-Gitlab-Token here holds the HMAC your pipeline computes, not GitLab's native constant shared-secret token. GitLab's Settings → Webhooks page uses the same header name but ships a fixed value, which doesn't pass HMAC validation; run the .gitlab-ci.yml script below from inside your pipeline instead.
Webhook URL
Point your CI system to:
https://app.driftwise.ai/webhooks/<provider>/<org_id>
For example:
https://app.driftwise.ai/webhooks/atlantis/1478fe16-d292-4f0f-95fa-d249dda3d7ab
Provider Setup
Atlantis
Add a webhook in your Atlantis server config pointing to DriftWise:
webhooks:
- event: plan
workspace-regex: ".*"
url: "https://app.driftwise.ai/webhooks/atlantis/<org_id>"
secret: "<raw_secret from webhook config>"
See Atlantis Integration for the full workflow setup.
GitHub Actions
Add the webhook secret as a repository secret, then send plan data in your workflow:
- name: Send to DriftWise
run: |
terraform show -json tfplan > plan.json
BODY=$(cat plan.json)
SIGNATURE=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "${{ secrets.DW_WEBHOOK_SECRET }}" | cut -d' ' -f2)
curl -X POST "https://app.driftwise.ai/webhooks/github_actions/${{ vars.DW_ORG_ID }}" \
-H "X-Hub-Signature-256: sha256=$SIGNATURE" \
-H "Content-Type: application/json" \
-d "$BODY"
See GitHub Actions Integration for the full workflow.
GitLab CI
driftwise:
stage: analyze
script: |
terraform show -json tfplan > plan.json
BODY=$(cat plan.json)
SIGNATURE=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "$DW_WEBHOOK_SECRET" | cut -d' ' -f2)
curl -X POST "https://app.driftwise.ai/webhooks/gitlab_ci/$DW_ORG_ID" \
-H "X-Gitlab-Token: sha256=$SIGNATURE" \
-H "Content-Type: application/json" \
-d "$BODY"
See GitLab CI Integration for the full workflow.
Managing Webhook Configs
List configs
curl "https://app.driftwise.ai/api/v2/orgs/$ORG_ID/webhook-configs" \
-H "x-api-key: $DRIFTWISE_API_KEY"
Enable/disable a config
curl -X PATCH "https://app.driftwise.ai/api/v2/orgs/$ORG_ID/webhook-configs/<config_id>" \
-H "x-api-key: $DRIFTWISE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "enabled": false }'
Delete a config
curl -X DELETE "https://app.driftwise.ai/api/v2/orgs/$ORG_ID/webhook-configs/<config_id>" \
-H "x-api-key: $DRIFTWISE_API_KEY"
Security
- Secrets are encrypted at rest with AES-256-GCM — only the
whsec_prefix is stored in plaintext for identification - HMAC-SHA256 signature validation on every inbound webhook — unsigned or mis-signed payloads are rejected with 401
- Replay protection — duplicate payloads (same body hash) are deduplicated to prevent double-processing
- Async processing — webhooks return 202 immediately, so your CI pipeline doesn't block on analysis