Durable webhooks
Restate handlers can be used as durable processors of webhook events.

What does this give you?
- Restate persists all incoming events, and ensures that they are processed exactly once, across failures and restarts. Restate guarantees your handler runs till completion.
- Let Restate deduplicate events on an idempotency key. If the sender of the event retries, Restate will not process the event again.
- Use any of Restate's durable SDK constructs when processing the events: durable calls/messaging to other services, durable timers, scheduling tasks, K/V state, concurrency guarantees etc.
- Any handler can be a durable webhook endpoint. No need to do anything special or extra!
Just point your webhook endpoint to your handler: restate:8080/MyService/myHandler
.
Example
This example processes webhook callbacks from a payment provider.
The payment provider notifies us about payment success or failure of invoices by sending webhook events to our handler. The handler then routes the event to the correct processor via a one-way message.
- TypeScript
- Go
const webhookCallbackRouter = restate.service({name : "WebhookCallbackRouter",handlers: {// Any handler can be a durable webhook processor that never loses events// You don't need to do anything special for this.// Just point your webhook to the handler endpoint: restate:8080/WebhookCallbackRouter/onStripeEventonStripeEvent: async (ctx: restate.Context, event: StripeEvent) => {if (event.type === "invoice.payment_failed") {ctx.objectSendClient(PaymentTracker, event.data.object.id).onPaymentFailed(event);} else if (event.type === "invoice.payment_succeeded") {ctx.objectSendClient(PaymentTracker, event.data.object.id).onPaymentSuccess(event);}}}})restate.endpoint().bind(webhookCallbackRouter).listen(9080);
type WebhookCallbackRouter struct{}// Any handler can be a durable webhook processor that never loses events// You don't need to do anything special for this.// Just point your webhook to the handler endpoint: restate:8080/WebhookCallbackRouter/OnStripeEventfunc (WebhookCallbackRouter) OnStripeEvent(ctx restate.Context, event StripeEvent) error {if event.Type == "invoice.payment_failed" {restate.ObjectSend(ctx, "PaymentTracker", "onPaymentFailed", event.Data.Object.ID).Send(event)} else if event.Type == "invoice.payment_succeeded" {restate.ObjectSend(ctx, "PaymentTracker", "onPaymentSuccess", event.Data.Object.ID).Send(event)}return nil}