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:

  1. Provider -- github. Identifies the provider profile for parsing and verification.
  2. Name -- "repo-events". A human-readable label for this webhook endpoint. The runtime generates a stable URL from this.
  3. 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:

ProviderSignature MethodEvent Header/FieldNotes
githubHMAC-SHA256X-GitHub-Event headerSupports event.action sub-events
stripeStripe signature (v1)type field in payloadUses Stripe-Signature header
slackSigning secrettype field in payloadHandles URL verification challenge
gitlabToken-basedX-Gitlab-Event headerSupports 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

ConcernWebhookRoute
Signature verificationAutomatic (per provider profile)Manual (verify block)
Payload parsingProvider-awareRaw HTTP body
Event routingDeclarative (on event -> target)Imperative (apply block logic)
Provider supportBuilt-in profilesAny HTTP client
Use caseKnown providers with standard webhooksCustom 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