Headless flow
This guide shows you how to set up headless authentication for Norwegian BankID. This means that you can provide your own user interface within your app or website.
The headless flow supports the following authentication types:
- Normal
- Payment / Payment 3DS
- Safe Conversation (Call centre)
Please note the following requirements when using the headless flow:
- It only supports the BankID Biometric product type (substantial level of assurance).
- End-users must have the BankID app installed on their device to complete the authentication successfully. If end-users do not have the BankID app, an error message will be returned. In this case we recommend that you direct the end-users to the redirect flow.
- The national identity number (
nin) must be prefilled.
For an introduction to the different authentication types, see the About page.
Prerequisites
- Follow the steps on the Initial preparations page to establish a connection with Norwegian BankID.
-
Before you can start making requests to the Authentication REST API, you need to learn how to connect to it. To do this, see Connect to Signicat APIs Quick start guide.
Ensure that you set the Authentication REST API permission for your API client. When you have obtained an access token and are ready to make an API request, return here to resume this guide.
Learn more about the Signicat Authentication REST API- Authentication REST API for conceptual documentation.
- API Reference for endpoint descriptions.
1. Build the authentication request (Create a new session)
This section describes how to make an HTTP POST request to the /sessions endpoint, to create a new session and start an authentication.
To begin the authentication flow, your application must first start a session by utilising the /sessions endpoint. The endpoint automatically creates a session when you send a request. The flow and resulting information from the transaction depends on the parameters you pass in the body.
The response from the headless authentication request returns the necessary data directly in the idpData object, which you use to drive the authentication in your own custom user interface.
To create a new session, send a POST request to https://api.signicat.com/auth/rest/sessions?signicat-accountId={accountId}.
You can find your accountId in the Signicat Dashboard.
The following sub-sections show examples and descriptions of attributes that you can include in the request.
Request example
Here are some example authentication requests for creating a new session:
- Normal
- Payment
- Safe Conversation
{
"allowedProviders": ["nbid"],
"flow": "headless",
"additionalParameters": {
"nbid_auth_type": "NORMAL"
},
"requestedAttributes": [
"dateOfBirth",
"firstName",
"lastName",
"name",
"nin",
"idpId"
],
"prefilledInput": {
"nin": "17029012345"
}
}
{
"allowedProviders": ["nbid"],
"flow": "headless",
"additionalParameters": {
"nbid_auth_type": "PAYMENT"
},
"requestedAttributes": [
"dateOfBirth",
"firstName",
"lastName",
"name",
"nin",
"idpId",
"nbidAuthType",
"nbidOriginator",
"nbidUpdatedAt",
"nbidSubjectUuid",
"nbidAlternativeSubject",
"nbidSid",
"nbidMethod"
],
"prefilledInput": {
"nin": "17029012345"
},
"paymentPrefillData": {
"reference": "composite-payment-1234",
"payments": [
{
"reference": "individual-payment-56",
"amount": "100",
"currency": "NOK",
"receiver": "ACME AS"
},
{
"reference": "individual-payment-78",
"amount": "200",
"currency": "NOK",
"receiver": "ACME AS"
}
]
}
}
{
"allowedProviders": ["nbid"],
"flow": "headless",
"additionalParameters": {
"nbid_auth_type": "PHONE"
},
"requestedAttributes": [
"dateOfBirth",
"firstName",
"lastName",
"name",
"nin",
"idpId"
],
"prefilledInput": {
"nin": "17029012345"
}
}
If the authentication completes successfully, then the final result contains the attributes that were requested.
Attributes are described in more detail in the following sections.
Initialise authentication
To initialise a headless authentication with Norwegian BankID, you must specify the following required fields in the initial request:
For more detailed field descriptions, see the API reference.
Control the user flow (additionalParameters)
You use additionalParameters to control the headless flow:
Prefill user information (prefilledInput)
When using the headless flow, you must prefill the nin (national identity number) of the user, otherwise the transaction will fail.
"prefilledInput": {"nin": "17029012345"}
For conceptual documentation about prefilling, see the eID and Wallet Hub guide > Prefilling user information.
Payment data (paymentPrefillData)
When you want the end-user to approve a payment before the authentication, you set the additional parameter nbid_auth_type to PAYMENT (as shown shown in the examples above), and you must prefill data about the payment in the paymentPrefillData object.
The paymentPrefillData object is mandatory for payment.
Here is an example of a complete paymentPrefillData object:
{...},
"paymentPrefillData": {
"reference": "composite-payment-1234",
"payments": [
{
"reference": "individual-payment-56",
"amount": "100",
"currency": "NOK",
"receiver": "ACME AS"
},
{
"reference": "individual-payment-78",
"amount": "200",
"currency": "NOK",
"receiver": "ACME AS"
}
]
}
These are the mandatory attributes inside the paymentPrefillData object:
User information (requestedAttributes)
You can request the following user information in the requestedAttributes object:
Response example
Here are example responses for creating a new session for a Norwegian BankID headless flow:
- Normal
- Payment
- Safe Conversation
{
"id": "425cbb48--...",
"accountId": "a-sdge-...",
"status": "CREATED",
"idpData": {
"bindingMessage": "Snedig redning"
},
"allowedProviders": [
"nbid"
],
"flow": "headless",
"requestedAttributes": [
"dateOfBirth",
"firstName",
"lastName",
"name",
"nin",
"idpId"
],
"sessionLifetime": 1200,
"expiresAt": "2026-06-29T11:08:34.9495067+00:00"
}
{
"id": "88fd4d1e-5f9a-4de7-9753-f48d863b771b",
"accountId": "a-sdge-oyNgetJTcOc5ba7Sj5ZR",
"status": "CREATED",
"idpData": {
"bindingMessage": "Snedig redning"
},
"paymentPrefillData": {
"reference": "composite-payment-1234",
"payments": [
{
"reference": "individual-payment-56",
"amount": "100",
"currency": "NOK",
"receiver": "ACME AS"
},
{
"reference": "individual-payment-78",
"amount": "200",
"currency": "NOK",
"receiver": "ACME AS"
}
]
},
"allowedProviders": [
"nbid"
],
"language": "en",
"flow": "headless",
"requestedAttributes": [
"dateOfBirth",
"firstName",
"lastName",
"name",
"nin",
"idpId",
"nbidAuthType",
"nbidOriginator",
"nbidUpdatedAt",
"nbidSubjectUuid",
"nbidAlternativeSubject",
"nbidSid",
"nbidMethod"
],
"sessionLifetime": 1200,
"expiresAt": "2026-04-20T12:27:54.4334025+00:00"
}
{
"id": "425cbb48--...",
"accountId": "a-sdge-...",
"status": "CREATED",
"idpData": {
"bindingMessage": "Snedig redning"
},
"allowedProviders": [
"nbid"
],
"flow": "headless",
"requestedAttributes": [
"dateOfBirth",
"firstName",
"lastName",
"name",
"nin",
"idpId"
],
"sessionLifetime": 1200,
"expiresAt": "2026-06-29T11:08:34.9495067+00:00"
}
The CREATED status means the end-user has not started to authenticate yet. The response also contains an idpData field, which contains necessary input data for your frontend, here to use the bindingMessage.
End-user authentication
To implement the headless flow, follow this sequence of events:
- Collect the national identity number (
nin): Ask the end-user for theirninand validate it. - Create a new session: Send the
ninin theprefilledInputobject of your request. This triggers a push notification to the end-user's BankID app. - Share the binding message: The API response includes a
bindingMessage.- Normal / Payment: Display this message on the screen in your app or website.
- Safe Conversation: Display the message in your agent interface for the support agent to read aloud (PHONE) or the end-user to see in the chat interface (CHAT).
- User confirmation: Ask the end-user to open their BankID app. What they see next depends on the flow:
- Normal / Safe Conversation: The app displays three different messages. The end-user must select the message that matches the one shown (or spoken) to them.
- Payment / Payment 3DS: The app first displays one binding message, which the end-user must confirm. After confirmation, the app shows the payment details, which the end-user must confirm.
- Authenticate: The end-user completes the final authentication step in their BankID app (e.g., using biometrics or a PIN).
See also the high-level feature descriptions of the different flows with screen examples on the About page.
2. Obtain user information (Get session status)
Make an HTTP GET request to the /sessions endpoint to poll for information regarding the session and ongoing authentication.
Upon successful authentication, a response is returned that contains the user information requested in the "Create a new session" call carried out earlier.
Request
No data specific for Norwegian BankID needs to be provided in this request.
To get the status of a session, send a GET request to https://api.signicat.com/auth/rest/sessions/{id}.
You can find the id value in the response that was returned when you created the session.
Response
The "Get session status" response contains a status field, which indicates the current status of the session. Below you can see example responses for a successfully completed headless authentication session for the different flows:
- Normal
- Payment
- Safe Conversation
{
"id": "91160261-...",
"accountId": "a-sdge-...",
"status": "SUCCESS",
"provider": "nbid",
"subject": {
"id": "fOthqpBQyuYxNPyuj...",
"idpId": "9578-6000-4-2595757",
"name": "Kari Nordmann",
"firstName": "Kari",
"lastName": "Nordmann",
"dateOfBirth": "1990-02-17",
"nin": {
"value": "17029012345",
"issuingCountry": "NO",
"type": "BIRTH"
}
},
"loa": "substantial",
"allowedProviders": [
"nbid"
],
"flow": "headless",
"requestedAttributes": [
"dateOfBirth",
"firstName",
"lastName",
"name",
"nin",
"idpId"
],
"sessionLifetime": 1200,
"expiresAt": "2026-06-29T14:54:14.9449404+00:00"
}
{
"id": "88fd4d...",
"accountId": "<ACCOUNT_ID>",
"status": "SUCCESS",
"provider": "nbid",
"subject": {
"id": "Zd-M6Bze8DPOGjzT5D0hxXkKhZn1kVRcbjQpRNuZYcU=",
"idpId": "9578-6000-4-1930136",
"name": "Kari Nordmann",
"firstName": "Kari",
"lastName": "Nordmann",
"dateOfBirth": "1990-02-17",
"nin": {
"value": "17029012345",
"issuingCountry": "NO",
"type": "BIRTH"
},
"nbidIdp": "BIS",
"nbidAuthType": "PAYMENT",
"nbidOriginator": "CN=BankID - TestBank1 - Bank CA 3,OU=123456789,O=TestBank1 AS,C=NO;OrginatorId=9980;OriginatorName=BINAS;OriginatorId=9980",
"nbidUpdatedAt": "1730117741",
"nbidSubjectUuid": "za7-4zkWYRUlMkZ6-dSHQj-tvgqmyr5NtBJdb-V1fBg",
"nbidAlternativeSubject": "9578-6000-4-1930136",
"nbidSid": "808ch4zl-Nx64_5iz349-upp8Kkr2anIiBj_djy-yFA",
"nbidMethod": "biometric"
},
"paymentPrefillData": {
"reference": "composite-payment-1234",
"payments": [
{
"reference": "individual-payment-56",
"amount": "100",
"currency": "NOK",
"receiver": "ACME AS"
},
{
"reference": "individual-payment-78",
"amount": "200",
"currency": "NOK",
"receiver": "ACME AS"
}
]
},
"loa": "substantial",
"allowedProviders": [
"nbid"
],
"language": "en",
"flow": "headless",
"requestedAttributes": [
"dateOfBirth",
"firstName",
"lastName",
"name",
"nin",
"idpId",
"nbidAuthType",
"nbidOriginator",
"nbidUpdatedAt",
"nbidSubjectUuid",
"nbidAlternativeSubject",
"nbidSid",
"nbidMethod"
],
"sessionLifetime": 1200,
"expiresAt": "2026-04-20T12:27:54.4334025+00:00"
}
{
"id": "91160261-...",
"accountId": "a-sdge-...",
"status": "SUCCESS",
"provider": "nbid",
"subject": {
"id": "fOthqpBQyuYxNPyuj...",
"idpId": "9578-6000-4-2595757",
"name": "Kari Nordmann",
"firstName": "Kari",
"lastName": "Nordmann",
"dateOfBirth": "1990-02-17",
"nin": {
"value": "17029012345",
"issuingCountry": "NO",
"type": "BIRTH"
}
},
"loa": "substantial",
"allowedProviders": [
"nbid"
],
"flow": "headless",
"requestedAttributes": [
"dateOfBirth",
"firstName",
"lastName",
"name",
"nin",
"idpId"
],
"sessionLifetime": 1200,
"expiresAt": "2026-06-29T14:54:14.9449404+00:00"
}
Status overview
In the session responses you will get a top level status in the status field.
What you need to do with the response
Depending on the top level status you receive in the response, you need to handle the response a bit differently:
- For
CREATEDstatus you want to read thebindingMessageand handle the response accordingly. - For
SUCCESSstatus you will find the authentication result in thesubjectfield. - For
ABORTstatus you can assume that the end-user intentionally cancelled the transaction. - For
ERRORstatus you can check theerror.codefield to see what kind of error occurred. See more details in the Error statuses section below. - For
CANCELLEDstatus you or the end-user has cancelled the transaction. For more details, see the Cancel a session section below.
We recommend that you poll for status every 3 seconds until the value for status is either SUCCESS, ABORT, ERROR, or CANCELLED, at which point the session is finalized.
Error codes
Create a session (error codes)
These are the error codes you might get from "Create a session":
idp:nbid:user-does-not-exist
The provided NIN could not be verified to belong to a user with a valid BankID app.
Recommended action: See the detail of the error message. If the end-user does not have the BankID app, we recommend that you direct the end-users to the redirect flow.
Example:
{
"status": 400,
"code": "idp:nbid:user-does-not-exist",
"title": "The user does not exist",
"detail": "The user is not registered with a BankID App or one that is sufficiently up to date",
"type": "https://developer.signicat.com/identity-methods/nbid/errors.html#idp:nbid:user-does-not-exist",
"traceId": "759141deb360964de14288365fbc2398"
}
idp:request-validation-failed
Something in the request to start the session was invalid.
Recommended action: See the detail of the error message for the specific field that could not be verified.
Example:
{
"status": 400,
"code": "idp:request-validation-failed",
"title": "Validation of request failed",
"detail": "Some detail specifying what in the request was invalid",
"type": "https://signicat.atlassian.net/wiki/spaces/HUB/pages/193592885339/Error+codes#idp:request-validation-failed",
"traceId": "7fc6f75104e124d3003d718672a1926f"
}
unexpected_error
Something unexpected went wrong. This can be any number of things.
Recommended action: Retry the session creation.
Example:
{
"status": 500,
"code": "unexpected_error",
"title": "An unexpected error has occurred.",
"type": "https://developer.signicat.com/docs/dashboard/error-codes/",
"traceId": "7c16b67eac18a90853b0a3263a5a4421"
}
Get session status (error codes)
You might get the following error code from "Get session status":
idp:nbid:unknown-error
Something unexpected went wrong. This can be any number of things.
Recommended action: Retry the session creation.
Example:
{
"id": "cfa3d4f3-fd38-41f5-a1fc-a59400271b4b",
"accountId": "a-sdge-oyNgetJTcOc5ba7Sj5ZR",
"status": "ERROR",
"error": {
"type": "https://signicat.atlassian.net/wiki/spaces/HUB/pages/193592885339/Error+codes#idp:nbid:unknown-error",
"title": "Unknown error",
"detail": "An unknown error occurred",
"code": "idp:nbid:unknown-error"
},
"allowedProviders": [
"nbid"
],
"flow": "headless",
"requestedAttributes": [
"dateOfBirth",
"firstName",
"lastName",
"idpId",
"nin"
],
"sessionLifetime": 1200,
"expiresAt": "2026-08-19T11:45:13.9869903+00:00"
}
Cancel a session (optional)
You can stop an ongoing authentication session by using the Cancel Authentication Session endpoint.
This is useful if you want to:
- Provide a way for your end-users to cancel the transaction, both at Signicat and Norwegian BankID (via a link/button). It is especially useful if you lock the transaction to a particular national identity number.
- Cancel an ongoing transaction for a particular national identity number before starting a new transaction for the same person.
A successful cancellation returns 200 OK of type CANCELLED.
Example response
{
"id": "3d07c219-0a88-45be-9cfc-91e9d095a1e9",
"accountId": "string",
"status": "CANCELLED",
"provider": "nbid",
...
}
Next steps
Dive deeper into Authentication REST API and improve your application with advanced security features: