Skip to content

Webhook Triggers

Webhook trigger mode lets external services (GitHub, Stripe, Shopify, Linear, Zapier) push events directly to your Wrapd endpoint. The full request body is piped to your command’s stdin as JSON.

endpoints:
- name: github-deploy
command: ./deploy.sh
trigger: webhook
webhook_source: github # github, stripe, shopify, or generic
webhook_events: [push] # filter by event type (optional)
secret: $wrapd:GITHUB_SECRET # HMAC verification secret
public: true # most webhooks can't send API keys
timeout: 60
FieldDefaultDescription
triggerhttpSet to webhook for webhook mode
webhook_sourcegenericProvider type: github, stripe, shopify, or generic
webhook_events[]Event type filter (provider-specific). Empty = accept all
secretSecret reference for HMAC verification
asynctrueReturn 202 immediately (true) or wait for output (false)

Wrapd verifies provider webhook signatures automatically — you don’t need to implement HMAC verification yourself.

SourceVerificationEvent headerSignature format
githubHMAC-SHA256X-GitHub-Eventsha256=<hex>
stripeHMAC-SHA256 + replay protectiontype in bodyt=<ts>,v1=<hex>
shopifyHMAC-SHA256X-Shopify-TopicBase64
genericHMAC-SHA256 (agent-side)sha256=<hex>

Wrapd checks the X-Hub-Signature-256 header against your secret. Events are filtered by X-GitHub-Event header.

- name: on-push
command: ./deploy.sh
trigger: webhook
webhook_source: github
webhook_events: [push, pull_request]
secret: $wrapd:GITHUB_SECRET
public: true

Setup in GitHub:

  1. Go to repo Settings → Webhooks → Add webhook
  2. Payload URL: https://api.wrapd.sh/v1/yourname/on-push
  3. Content type: application/json
  4. Secret: same value as your managed secret
  5. Events: select the events you want

Wrapd parses the Stripe-Signature header, verifies the HMAC, and enforces replay protection (rejects events older than 5 minutes). Events are filtered by the type field in the request body.

- name: payment-received
command: ./fulfill-order.sh
trigger: webhook
webhook_source: stripe
webhook_events: [checkout.session.completed, payment_intent.succeeded]
secret: $wrapd:STRIPE_WEBHOOK_SECRET
public: true

Setup in Stripe:

  1. Go to Developers → Webhooks → Add endpoint
  2. Endpoint URL: https://api.wrapd.sh/v1/yourname/payment-received
  3. Select events to listen for
  4. Copy the signing secret to your Wrapd managed secrets

Wrapd checks the X-Shopify-Hmac-Sha256 header (Base64-encoded HMAC). Events are filtered by X-Shopify-Topic header.

- name: new-order
command: ./notify-team.sh
trigger: webhook
webhook_source: shopify
webhook_events: [orders/create, orders/paid]
secret: $wrapd:SHOPIFY_SECRET
public: true

Setup in Shopify:

  1. Go to Settings → Notifications → Webhooks
  2. Add webhook with your endpoint URL
  3. Copy the HMAC shared secret to your Wrapd managed secrets

The default mode. HMAC verification happens on the agent side using X-Hub-Signature-256 or X-Signature-256 headers. Use this for any webhook provider not explicitly supported.

- name: on-event
command: ./handle.sh
trigger: webhook
secret: $wrapd:MY_SECRET
public: true

When webhook_events is set, Wrapd checks the incoming event type and silently ignores non-matching events (returns 200 OK so the provider doesn’t retry).

This lets you have multiple endpoints listening to the same webhook source but handling different events:

- name: deploy-on-push
command: ./deploy.sh
trigger: webhook
webhook_source: github
webhook_events: [push]
secret: $wrapd:GITHUB_SECRET
public: true
- name: pr-check
command: ./run-tests.sh
trigger: webhook
webhook_source: github
webhook_events: [pull_request]
secret: $wrapd:GITHUB_SECRET
public: true
  1. An external service sends a POST to your endpoint URL
  2. The API verifies the provider signature (for non-generic sources)
  3. The API checks if the event type matches the filter
  4. The request body is forwarded to the agent
  5. The agent pipes the body to your command’s stdin
  6. Response depends on async mode

Async (default) — returns HTTP 202 immediately:

{"status": "accepted", "request_id": "..."}

Use this for GitHub, Stripe, Shopify, and most webhook senders that expect a fast response.

Sync (async: false) — waits for the command to finish and returns stdout:

HTTP 200
<command stdout>

Use this for Slack slash commands or services that read the response body.

Your command receives the full request body on stdin:

#!/bin/bash
# deploy.sh — receives GitHub push payload on stdin
PAYLOAD=$(cat)
REF=$(echo "$PAYLOAD" | jq -r '.ref')
REPO=$(echo "$PAYLOAD" | jq -r '.repository.full_name')
echo "Deploying $REPO ($REF)..."
git pull && make build

The agent also injects convenience environment variables:

VariableValue
WRAPD_WEBHOOK1
WRAPD_ENDPOINTEndpoint name (e.g. on-push)
WRAPD_REQUEST_IDUnique request UUID

Webhook secrets should be stored as managed secrets (not environment variables) for API-side verification:

Terminal window
# In the dashboard: Secrets → Add secret
# Name: GITHUB_SECRET
# Value: your-github-webhook-secret

Then reference it in your endpoint config:

secret: $wrapd:GITHUB_SECRET

For generic source, you can also use local environment variables ($ENV_VAR) since verification happens on the agent side.