Devloop
Test Factuarea webhooks locally without deploying or ngrok — factuarea listen forwards the events of one tax ID to localhost with a signed body, factuarea trigger produces real sandbox events.
Test your webhooks locally without deploying or ngrok, Stripe-CLI style. The
loop has two halves: listen forwards the events of one tax ID to your machine,
trigger produces real sandbox events to forward.
Forward events to localhost
factuarea listen --forward-to http://localhost:3000/webhookslisten polls the event feed, rebuilds the webhook body and signs it with HMAC
(Factuarea-Signature) using an ephemeral whsec_… secret it prints on start.
Configure that secret in your verifier and your verification code runs unchanged
— no code differences between local and production.
For safety, listen only forwards to localhost. To forward to a remote
host, pass --allow-remote-forward explicitly.
listen follows one tax ID, on the company axis: it resolves the company
like any company command (--company, or the only one your credential
reaches). The events of the account itself (account.*) never come through
it; they only arrive at an account webhook. See
Account webhooks.
Produce events to test against
In another terminal, produce real events in the sandbox:
factuarea trigger invoice.paid
factuarea trigger --list # supported eventstrigger only operates in the sandbox — it requires a fact_test_ key.
It never produces events against production data.
How verification stays identical
The signature scheme is the same one the platform uses, so the verifier you ship to production is the verifier you test with locally:
- HMAC-SHA256 over the raw body with a constant-time comparison.
- A timestamp tolerance that rejects replays.
- Both signatures accepted during a secret-rotation grace window.
The only difference is the secret: locally it is the ephemeral whsec_… from
listen; in production it is the endpoint secret. See
Webhooks for the full signature contract and the SDK
verifiers.
A future phase replaces the polling in listen with a WebSocket relay. The
command surface stays the same; only the transport changes.