Skip to main content
sajn delivers only to public HTTPS URLs, so it can’t reach 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 environment set to SANDBOX.

Expose your local server

Start a tunnel to your local port. Each tool prints a public HTTPS URL that forwards to your machine.
The URL is shown on the Forwarding line, such as https://TUNNEL_ID.ngrok-free.app.
On free plans, the URL changes every time you restart the tunnel. When it changes, update the webhook’s URL.

Create a test endpoint

In the sandbox, create a webhook that points at the tunnel:
Replace the following:
  • SANDBOX_API_KEY: an API key from your sandbox.
  • TUNNEL_HOST: the host name that your tunnel printed.
Store the 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 a POST 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 a webhook.test event:
Replace WEBHOOK_ID with the id of your test endpoint. sajn sends a signed event to this endpoint only, with the following body:
The response is the delivery, with 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:
Your receiver gets a 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 event id. 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 through GET /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 id and returns 2xx within 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.