localhost directly. To test on your own machine, expose your local server through a tunnel, point a webhook in a sandbox organization at the tunnel, and send test events or trigger real ones.
Before you begin
- Run your receiver locally, for example one of the verification samples on port 3000.
- Create a sandbox and an API key in it. A sandbox behaves like production, but BankID is mocked and nothing is billed, so you can send and sign documents quickly. Its events have
environmentset toSANDBOX.
Expose your local server
Start a tunnel to your local port. Each tool prints a public HTTPS URL that forwards to your machine.- ngrok
- cloudflared
Forwarding line, such as https://TUNNEL_ID.ngrok-free.app.Create a test endpoint
In the sandbox, create a webhook that points at the tunnel:SANDBOX_API_KEY: an API key from your sandbox.TUNNEL_HOST: the host name that your tunnel printed.
secret from the response and start your receiver with it, for example with SAJN_WEBHOOK_SECRET set to that value.
Dashboard save check
When you save a webhook in the dashboard, sajn first sends aPOST request with the body {"test": true} and the user agent sajn-webhook-validator/1.0 to the URL. This request isn’t signed and isn’t an event. The save fails if the URL doesn’t answer within 5 seconds, redirects, returns 404 Not Found, or returns a 2xx HTML page. Any other answer passes, including the 400 Bad Request that your signature check returns for this unsigned request.
The API runs a lighter check: it sends a GET request and only rejects a 2xx HTML page.
Send a test event
To check that your receiver gets and verifies deliveries, send it awebhook.test event:
WEBHOOK_ID with the id of your test endpoint.
sajn sends a signed event to this endpoint only, with the following body:
status set to PENDING. To see your receiver’s answer, pass its id to GET /api/v1/webhooks/{id}/deliveries/{deliveryId}. The test event is retried like any other event if your receiver fails, and GET /api/v1/events doesn’t list it.
To test your receiver without sajn, sign a request yourself with the openssl script.
Trigger a real event
To test how your receiver handles real data, trigger an event in the sandbox. Creating a contact is the quickest:contact.created delivery within seconds. For the request, see Create a contact. To test the signing flow, send a document to yourself in the sandbox and sign it with the mocked BankID; the endpoint gets document.completed after sajn seals the PDF.
Resend a real delivery to your machine
To test with an event that your endpoint received before, retry its delivery. A retry goes only to the endpoint that the delivery belongs to, with its original body, and it keeps the eventid. To test with an event from another endpoint, read it with GET /api/v1/events/{id} and pass the response to your handler directly.
Inspect deliveries
Every delivery, with each attempt’s request headers, your status code, and your response body, appears in Inställningar > Utvecklare > Loggar in the workspace, and throughGET /api/v1/webhooks/{id}/deliveries. To find the delivery for a request that your receiver logged, pass its webhook-id as the eventId filter. To send a logged delivery again, open it and click Sänd om (Resend).
Go to production
Before you point a production endpoint at your receiver, check the following:- The receiver verifies signatures against the raw body with the production endpoint’s secret.
- It deduplicates on the event
idand returns2xxwithin 30 seconds. For both, see How delivery behaves. - It runs on a stable public HTTPS URL, not a tunnel.
- You deleted the tunnel endpoints that you no longer use, so they don’t fail and get paused.

