Keep webhook setup on the public host boundary. The recommended shape is:
- mount
/webhooks/stripein a dedicated raw-body pipeline - implement a host handler with
use Accrue.Webhook.Handler - configure the signing secret in
config/runtime.exs - use replay through the supported admin and task surfaces
Route and raw body
Stripe signatures are checked against the original request body, so the webhook scope must use a parser pipeline with a raw body reader:
pipeline :accrue_webhook_raw_body do
plug Plug.Parsers,
parsers: [:json],
pass: ["*/*"],
json_decoder: Jason,
body_reader: {Accrue.Webhook.CachingBodyReader, :read_body, []}
end
scope "/webhooks" do
pipe_through :accrue_webhook_raw_body
accrue_webhook "/stripe", :stripe
endHost handler boundary
Use use Accrue.Webhook.Handler in a host-owned module:
defmodule MyApp.BillingHandler do
use Accrue.Webhook.Handler
@impl Accrue.Webhook.Handler
def handle_event(type, event, ctx) do
MyApp.Billing.handle_webhook(type, event, ctx)
end
endSignature failures and generic HTTP failures
Invalid signatures should return a generic 400. Host misconfiguration should
surface as a generic server failure, with the actionable detail carried by the
stable diagnostic code and linked fix path in the troubleshooting guide.
Replay
Replay is for reprocessing persisted webhook events after you fix host setup or handler code. Verify the end-to-end proof path with:
mix test test/accrue_host_web/webhook_ingest_test.exs