Skip to main content
Headless login runs the authentication in your interface instead of sajn’s hosted page. You show the QR code and the button that opens the BankID app. Your server starts the attempt, polls it, and reads the result. sajn talks to BankID.
Headless login needs a client that uses your own BankID certificate, so the BankID app shows your company name. Clients in a sandbox organization run against the BankID mock instead. The calls use your sajn API key with the login:write and login:read scopes.

1. Create a session

Create the session as in the Session API. Keep the id. Headless login doesn’t use loginUrl.

2. Start an attempt

Call this from your server when the user chooses to log in. Send the user’s IP address as your server sees it, never your server’s own address.
Response

3. Show the QR code or the button

  • Another device: render qrCode as a QR code. It changes every second, so show the new value from each poll.
  • The same device: open autoStartUrl from a tap. iOS blocks an app switch that no tap started. To build your own link, use autoStartToken.

4. Poll until the attempt ends

Poll every 1 to 2 seconds and show the new qrCode while status is PENDING.
Pending
The login completes even if you stop polling, and login.completed fires. Calling start again while an attempt runs returns that attempt with its current qrCode.

5. Read the result

When status is COMPLETED, read the claims with GET /api/v1/login/sessions/{id}. The poll response carries no identity. The authenticated read is the only place your server learns who logged in.

Cancel an attempt

When the user presses Cancel, cancel the attempt so the BankID app stops waiting:
The response has the same shape as a poll. The session stays open, so the user can start a new attempt. If the user finished in the BankID app just before the cancel, status is COMPLETED.

Errors

Reference

Start

POST …/start

Poll

POST …/poll

Cancel

POST …/cancel