Skip to content

Webhook

The Webhook events extension receives HTTP webhooks from external services such as GitHub, Stripe, Shopify, internal systems, and low-code tools. The extension parses the request, validates it when configured, and emits one or more EventEnvelopeV1 events for flows.

  1. Configure Provider

    answers.json
    {
    "events-webhook": {
    "enabled": true,
    "public_base_url": "https://your-domain.ngrok-free.app"
    }
    }
  2. Run Setup

    Terminal window
    gtc setup --answers answers.json ./my-bundle
  3. Register Webhook

    Use the generated webhook URL in your external service:

    https://your-domain.com/v1/events/ingress/events-webhook/{tenant}/{team?}/{handler?}
OptionRequiredDescription
enabledYesEnable/disable provider
public_base_urlYesPublic URL for webhooks
secret_headerNoHeader name for simple signature schemes when the installed pack supports it
secret_keyNoSecret used for webhook validation when the installed pack supports it

The standard Greentic event ingress route is:

POST https://your-domain.com/v1/events/ingress/{provider}/{tenant}/{team?}/{handler?}

Example:

POST https://your-domain.com/v1/events/ingress/events-webhook/demo/default/github

Some demo or app-specific packs can declare shorter routes such as /events/webhook/demo/alert. Prefer the URL printed by gtc setup or the route table for the installed pack.

flows/on_webhook.ygtc
name: handle_webhook
version: "1.0"
nodes:
- id: process
type: script
config:
script: |
let data = event.payload;
// Process webhook data
data
to: respond
- id: respond
type: http_response
config:
status: 200
body:
success: true
triggers:
- type: event
event_type: "order.created"
target: process
nodes:
- id: check_event
type: branch
config:
conditions:
- expression: "headers['x-github-event'] == 'push'"
to: handle_push
- expression: "headers['x-github-event'] == 'pull_request'"
to: handle_pr
default: ignore
- id: handle_push
type: script
config:
script: |
let commits = event.payload.commits;
format!("Received {} commits", commits.len())
triggers:
- type: event
event_type: "github"
target: check_event
nodes:
- id: handle_stripe
type: branch
config:
conditions:
- expression: "event.payload.type == 'payment_intent.succeeded'"
to: payment_success
- expression: "event.payload.type == 'payment_intent.failed'"
to: payment_failed
triggers:
- type: event
event_type: "stripe"
target: handle_stripe

Signature configuration is extension-pack specific. Inspect the installed pack with gtc wizard --schema or run gtc setup to see the supported answers.

Common upstream schemes:

  • GitHub signs webhook bodies with X-Hub-Signature-256 using HMAC SHA-256 and the webhook secret.
  • Stripe signs events with Stripe-Signature; Stripe recommends validating against the raw request body and endpoint secret.
  • Twilio signs requests with X-Twilio-Signature using the account Auth Token.

For providers with official SDK signature helpers, prefer the provider’s helper when building a custom extension.

Most webhook providers expect a quick response:

- id: ack
type: http_response
config:
status: 200
to: async_process # Process async after responding

For long-running tasks, acknowledge first:

nodes:
- id: acknowledge
type: http_response
config:
status: 202
body:
message: "Processing"
to: process_async
- id: process_async
type: async
config:
flow: "process_webhook_data"
payload: "{{event.payload}}"
Terminal window
curl -X POST https://your-domain.com/v1/events/ingress/events-webhook/demo/default/test \
-H "Content-Type: application/json" \
-d '{"message": "Hello from webhook"}'
Terminal window
ngrok http 8080
# Visit http://localhost:4040 to inspect requests
  1. Check URL is correct
  2. Verify public URL is accessible
  3. Check firewall/security groups
  4. Review external service logs
  1. Verify secret key matches
  2. Check header name is correct
  3. Ensure raw body is used for validation