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.
Raw-body ordering and parser placement issues map to ACCRUE-DX-WEBHOOK-RAW-BODY — see Troubleshooting — ACCRUE-DX-WEBHOOK-RAW-BODY for the fix matrix row.
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