Surfaces: Webhooks
Ce contenu n’est pas encore disponible dans votre langue.
The webhook surface turns a machine into a receiver for external events. When Stripe sends a payment notification, GitHub sends a push event, or Microsoft Graph sends a mail notification, the webhook surface receives it, validates the signature, and runs the machine.
Declaring a webhook surface
machine stripe_handler
accepts event_type as text, is required data as map, is required
responds with status as text action_taken as text
ensures permissions allowed to reason, http
implements decide route_event when input.event_type is "payment_intent.succeeded" ask process_payment, using: "anthropic:claude-haiku-4-5" with task "Summarize this payment and decide next actions" returns status as text action_taken as text assuming status: "processed" action_taken: "receipt sent" when input.event_type is "charge.failed" compute handle_failure {status: "failed", action_taken: "alert sent to billing team"} otherwise compute skip {status: "ignored", action_taken: "none"}
expresses webhook path: "/hooks/stripe" authentication: "hmac_sha256" provider: "stripe"Configuration options
| Config | Required | Default | Description |
|---|---|---|---|
path | Yes | - | URL path for the webhook receiver |
authentication | No | "none" | Signature verification: "hmac_sha256", "none" |
provider | No | - | Named provider for pre-configured signature verification |
Providers
When you specify a provider, mashin knows the signature format:
| Provider | Signature header | Algorithm |
|---|---|---|
"stripe" | Stripe-Signature | HMAC-SHA256 with timestamp |
"github" | X-Hub-Signature-256 | HMAC-SHA256 |
"microsoft" | Client state validation | Token-based |
"slack" | X-Slack-Signature | HMAC-SHA256 with timestamp |
For providers not in this list, use authentication: "hmac_sha256" and configure the secret in your cell’s credentials.
Registering webhooks with external services
After declaring a webhook surface, you need a public URL for the external service to deliver to. Two options:
Cloud cell
If your cell is deployed to mashin.live, the webhook URL is:
https://myorg.mashin.live/hooks/stripeLocal cell with tunnel
For local development, the tunnel provides a public URL:
mashin tunnel stripe_handler.mashinThe CLI shows the public URL. Use it when registering the webhook with the external service.
Automatic registration example
A machine can register its own webhook URL using context.cell.webhook_urls:
machine outlook_bridge
accepts event as map
expresses webhook path: "/outlook" provider: microsoft
implements ask register, from: "@mashin/actions/http/post" url: "https://graph.microsoft.com/v1.0/subscriptions" body: { changeType: "created", notificationUrl: context.cell.webhook_urls["/outlook"], resource: "me/mailFolders('Inbox')/messages", expirationDateTime: "2026-06-01T00:00:00Z" } returns subscription_id as text assuming subscription_id: "sub_123"context.cell.webhook_urls resolves to the correct URL regardless of whether the cell is local (tunnel URL) or cloud (direct URL).
Payload mapping
The webhook payload is mapped to the machine’s accepts section. The mapping depends on the provider:
Stripe
// Incoming webhook payload{ "type": "payment_intent.succeeded", "data": { "object": { "amount": 5000, "currency": "usd" } }}Maps to:
event_type="payment_intent.succeeded"data={"object": {"amount": 5000, "currency": "usd"}}
GitHub
// Incoming webhook payload (with X-GitHub-Event: push header){ "ref": "refs/heads/main", "commits": [...]}The X-GitHub-Event header value is available as context.webhook.event_type.
Generic
For webhooks without a named provider, the entire request body is passed as input. Define your accepts to match the expected payload shape.
Signature verification
When authentication: "hmac_sha256" is set, the webhook handler:
- Reads the signature from the provider-specific header
- Computes HMAC-SHA256 of the raw request body using the webhook secret from cell credentials
- Compares (constant-time) the computed signature with the received signature
- Rejects the request with HTTP 401 if the signature does not match
Set the webhook secret in your cell:
mashin secrets set stripe_webhook_secret whsec_...Multiple webhook sources
A machine can declare multiple webhook surfaces:
expresses webhook path: "/hooks/stripe" provider: "stripe" webhook path: "/hooks/github" provider: "github"Or a single machine can handle multiple event types from one source using decide steps to route by event type.
Governance
Every webhook delivery is governed:
- Signature is verified (if configured)
- Payload is validated against the
acceptscontract - Governance permissions are checked
- The machine executes
- A
SurfaceAccessevent is recorded with:webhooksurface - The external service receives an HTTP 200 acknowledgment
Rejected webhooks return HTTP 403 (governance denied) or HTTP 401 (signature invalid). Most webhook providers retry on non-2xx responses.
Next steps
- WebSocket - Real-time connections
- REST API - HTTP endpoints
- Surfaces overview - All surface types