Webhooks (Inbound)
Pulsabase exposes a public inbound webhook endpoint for each edge function. Use it to receive events from external services — Stripe payment confirmations, GitHub push events, Twilio SMS replies, and so on.
Webhook Endpoint
Section titled “Webhook Endpoint”POST https://api.yourproject.pulsabase.io/webhooks/{project_id}/{function-slug}- No
X-Api-Keyrequired — this endpoint is intentionally public so external services can call it - The request body (the external event payload) is passed as the function’s
input - The full HTTP request headers are also available via
{{input.headers}}
Setting Up a Webhook
Section titled “Setting Up a Webhook”Step 1 — Create the Function
Section titled “Step 1 — Create the Function”Create an edge function that handles the incoming payload. Name it something descriptive (e.g., stripe-payment-handler).
Function: stripe-payment-handler
Step 1: verify_signature → [Transform] // Validate Stripe webhook signature from headers (see below) {{input.headers['stripe-signature']}} !== null
Step 2: get_order → [Database] SELECT * FROM orders WHERE stripe_payment_id = {{input.body.data.object.id}}
Step 3: update_order → [Database] UPDATE orders SET status = 'paid' WHERE id = {{steps.get_order.body.id}}
Step 4: notify_user → [HTTP] POST https://push.example.com/notify Body: { "userId": "{{steps.get_order.body.user_id}}", "message": "Payment confirmed!" }Step 2 — Register in External Service
Section titled “Step 2 — Register in External Service”Copy the webhook URL from the Dashboard → Edge Functions → Webhooks page and paste it into your external service’s webhook configuration (e.g., Stripe Dashboard → Webhooks → Add Endpoint).
Step 3 — Verify the Signature (Security)
Section titled “Step 3 — Verify the Signature (Security)”Always verify the webhook signature from the external service. Use a before hook or the first step of your function:
Step 1: verify → [Transform]Compute HMAC-SHA256 of request body using your Stripe signing secret.Compare with {{input.headers['stripe-signature']}}.If mismatch → return { "error": "INVALID_SIGNATURE", "status": 401 }Without signature verification, anyone can call your webhook URL with a fake payload. Always verify the signature before processing the event.
Available Input Variables
Section titled “Available Input Variables”Inside a webhook-triggered function, the following variables are available:
| Variable | Description |
|---|---|
{{input.body}} | The full JSON body of the incoming request |
{{input.body.<field>}} | A specific field from the body |
{{input.headers}} | All HTTP request headers |
{{input.headers['x-signature']}} | A specific header (case-insensitive) |
{{input.method}} | The HTTP method (POST, GET, etc.) |
{{input.query.<param>}} | Query string parameters |
Common Webhook Integrations
Section titled “Common Webhook Integrations”| Service | Event | Use Case |
|---|---|---|
| Stripe | payment_intent.succeeded | Mark order as paid |
| Stripe | customer.subscription.deleted | Downgrade user plan |
| GitHub | push | Trigger a deployment |
| Twilio | IncomingMessage | Process SMS reply |
| SendGrid | bounced | Mark email as undeliverable |
| Lemon Squeezy | order_created | Provision user account |
Response
Section titled “Response”Your function’s final step output is returned as the HTTP response to the external service. Most services (Stripe, GitHub) expect a 200 OK response quickly. If your function takes more than a few seconds, consider running heavy processing asynchronously:
// Acknowledge the webhook immediately — process asyncreturn { "received": true }; // 200 OK to external serviceThen dispatch the actual work via an after-hook or a separate async invocation.