Webhooks
Status: [Designed] -- Area 2 of the Grove language. Syntax and semantics are defined; implementation is in progress.
Webhooks declare system-managed endpoints for receiving events from external services. Unlike manually coded routes, webhooks handle provider-specific concerns automatically -- signature verification, payload parsing, event filtering, and routing. Grove supports built-in provider profiles for common services, and you declare which external events map to which internal targets.
Prerequisites: Routes, Triggers, Services. What you'll learn: How to declare webhooks, use built-in provider profiles, configure signature verification, and route external events to workflows or actions.
Declaring a Webhook
A webhook binds a provider profile to event routing rules:
webhook github "repo-events" {
on push -> start ci_pipeline v1
on pull_request.opened -> start pr_review v1
on pull_request.merged -> start deploy_staging v1
}
The declaration has:
- Provider --
github. Identifies the provider profile for parsing and verification. - Name --
"repo-events". A human-readable label for this webhook endpoint. The runtime generates a stable URL from this. - Event rules --
on event -> target. Maps provider events to internal actions.
Built-In Provider Profiles
Grove includes profiles for common webhook providers. Each profile knows how to verify signatures, parse payloads, and extract event types:
| Provider | Signature Method | Event Header/Field | Notes |
|---|---|---|---|
github | HMAC-SHA256 | X-GitHub-Event header | Supports event.action sub-events |
stripe | Stripe signature (v1) | type field in payload | Uses Stripe-Signature header |
slack | Signing secret | type field in payload | Handles URL verification challenge |
gitlab | Token-based | X-Gitlab-Event header | Supports merge request, push, etc. |
GitHub
webhook github "deployments" {
on push -> start run_tests v1
on pull_request.opened -> start lint_check v1
on pull_request.merged -> start deploy v1
on release.published -> start release_pipeline v1
}
GitHub events support dot notation for sub-events: pull_request.opened, release.published, issues.labeled. The part before the dot is the event type (from the X-GitHub-Event header), and the part after is the action field in the payload.
Stripe
webhook stripe "payment-events" {
on payment_intent.succeeded -> start fulfill_order v1
on payment_intent.payment_failed -> start handle_failure v1
on customer.subscription.deleted -> start cancel_subscription v1
}
Stripe event types use their standard dotted format: payment_intent.succeeded, invoice.paid, customer.subscription.deleted.
Slack
webhook slack "bot-commands" {
on event_callback -> start process_message v1
on url_verification -> start handle_verification v1
}
The Slack profile automatically handles the URL verification challenge that Slack sends when registering a webhook endpoint.
GitLab
webhook gitlab "ci-events" {
on push -> start run_pipeline v1
on merge_request -> start review_pipeline v1
on tag_push -> start release_build v1
}
Signature Verification
Each provider profile has a built-in signature verification method. The runtime automatically verifies incoming requests using the configured secret before processing:
webhook stripe "payments" {
secret: credentials.stripe_webhook_secret
on payment_intent.succeeded -> start process_payment v1
on charge.refunded -> start process_refund v1
}
The secret field references a credential declared in a service or provided through runtime configuration. If the signature does not match, the request is rejected with a 401 response.
For providers without a built-in profile, use routes with a verify block instead.
Event Routing
To Workflows
The most common target. The webhook starts a workflow, and the provider's parsed payload is passed as the workflow input:
on push -> start ci_pipeline v1
Wildcard Matching
Use * to catch all events from a provider:
webhook github "audit-log" {
on * -> start log_github_event v1
}
The wildcard matches every event type. This is useful for auditing or forwarding all events to a single processing workflow.
Multiple Webhooks
A module can declare multiple webhooks for different providers or different logical groupings:
webhook github "code-events" {
on push -> start ci_pipeline v1
on pull_request.merged -> start deploy v1
}
webhook stripe "billing-events" {
on invoice.paid -> start record_payment v1
on customer.subscription.deleted -> start cancel_access v1
}
webhook slack "notifications" {
on event_callback -> start process_slack_event v1
}
Webhooks vs. Routes
| Concern | Webhook | Route |
|---|---|---|
| Signature verification | Automatic (per provider profile) | Manual (verify block) |
| Payload parsing | Provider-aware | Raw HTTP body |
| Event routing | Declarative (on event -> target) | Imperative (apply block logic) |
| Provider support | Built-in profiles | Any HTTP client |
| Use case | Known providers with standard webhooks | Custom integrations or non-standard APIs |
Use webhooks when integrating with a supported provider. Use routes when you need full control over request handling or when the provider is not covered by a built-in profile.
See Also
- Routes -- Custom HTTP endpoints with manual verification
- Triggers -- Event-driven workflow starts from internal events
- Services -- Outbound API contracts (the complement to inbound webhooks)
- Full Language Reference -- Webhook grammar (section 6.16)