Add bank account
This page details how the user can connect a payout account to their Safepay Nordic Account if not already done. This flow is the same for websites and iOS and Android apps. It assumes that you already have credentials to successfully call Safepay Nordic APIs and have subscribed to webhooks.
You obtain the user's {safepayAccountId} from the Connect flow.
How it works
- Your backend lists the available banks and lets the user choose one.
- Your backend starts the onboarding for that bank and redirects the user to the returned url.
- The user signs in with their bank and selects the accounts to share, then returns to your
returnUrl. - Your backend reads the selected accounts and adds the one(s) the user wants to use for payout.
A good time to start this flow is when you receive a user.bankaccount.missing webhook.
1. List available banks
Get the banks available for bank account onboarding. Use a returned bankId in the next step.
curl https://sandbox-api.safepaynordic.dk/v2/users/{safepayAccountId}/banks \
-H 'Authorization: Bearer {API_TOKEN}'
{
"banks": [
{
"bankId": "nordea",
"name": "Nordea",
"bankCentral": "Nordea"
}
]
}
2. Start bank account onboarding
curl https://sandbox-api.safepaynordic.dk/v2/users/{safepayAccountId}/bank-accounts/initialize \
-X POST \
-H 'Authorization: Bearer {API_TOKEN}' \
-H 'Content-Type: application/json' \
-d '{
"bankId": "nordea",
"returnUrl": "{returnUrl}"
}'
{
"url": "https://sandbox.mitsafepay.dk/l/b3a1f9c2"
}
Send your users to the returned url in a browser or an in-app browser on Android or iOS. After bank account validation the user is redirected back to your returnUrl.
Parameters
- bankId: Required. A
bankIdfrom step 1. - returnUrl: Required. Where the user is redirected after bank account validation.
- psd2Type: Optional.
PrivateorBusiness, to choose between the bank's private and business login. Defaults to the type of the user's Safepay Nordic Account.
Errors
404 Invalid Safepay account: thesafepayAccountIddoesn't exist or isn't connected to you.404 Invalid bank: thebankIdisn't one of the banks from step 1.400 Invalid bank url: the onboarding url for the bank couldn't be generated. Try again later.
3. Read the selected bank accounts
After the user returns, read the accounts they selected. The results are temporary and are only available for 30 minutes.
curl https://sandbox-api.safepaynordic.dk/v2/users/{safepayAccountId}/bank-accounts/initialize \
-H 'Authorization: Bearer {API_TOKEN}'
{
"bankId": "Nordea",
"bankName": "Nordea",
"bankCentral": "Nordea",
"bankAccounts": [
{
"bankAccountId": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"name": "Salary account",
"ownerName": "John Doe",
"bban": "20000123456789",
"iban": "DK5000400440116243",
"currency": "DKK"
}
]
}
If the user didn't select any accounts, cancelled, or the results have expired, the request fails with 400 Invalid results. Start again from step 2.
4. Add the chosen bank account
Add the selected account using its bankAccountId. The first bank account added to a Safepay Account is marked as default and used for payout.
curl https://sandbox-api.safepaynordic.dk/v2/users/{safepayAccountId}/bank-accounts/add \
-X POST \
-H 'Authorization: Bearer {API_TOKEN}' \
-H 'Content-Type: application/json' \
-d '{
"bankId": "nordea",
"bankAccountId": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
}'
If the user selected more than one account, call this endpoint once per account you want to add.
Adding an account the user already has (same IBAN or BBAN) replaces the existing one rather than creating a duplicate. If the replaced account was the default, the new one becomes the default.
The request fails with 404 Bank account not found if the bankAccountId isn't in the results from step 3, or with 404 No bank accounts if those results have expired.
Manage bank accounts
List bank accounts
curl https://sandbox-api.safepaynordic.dk/v2/users/{safepayAccountId}/bank-accounts \
-H 'Authorization: Bearer {API_TOKEN}'
{
"items": [
{
"bank": "Nordea",
"bankId": "nordea",
"bankAccountId": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"bban": "20000123456789",
"iban": "DK5000400440116243",
"accountName": "Salary account",
"isDefault": true
}
]
}
Set default bank account
The default bank account is used for payout. To change it:
curl https://sandbox-api.safepaynordic.dk/v2/users/{safepayAccountId}/bank-accounts/set-default \
-X POST \
-H 'Authorization: Bearer {API_TOKEN}' \
-H 'Content-Type: application/json' \
-d '{
"bankId": "nordea",
"bankAccountId": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
}'
Delete bank account
curl https://sandbox-api.safepaynordic.dk/v2/users/{safepayAccountId}/bank-accounts/delete \
-X POST \
-H 'Authorization: Bearer {API_TOKEN}' \
-H 'Content-Type: application/json' \
-d '{
"bankId": "nordea",
"bankAccountId": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
}'
A user must always have at least one bank account. Deleting the last one fails with 400 Bank account can't be deleted.
Webhooks
Bank account connected
A webhook is also sent when a new bank account is connected to the user's account.
{
"eventName": "user.bankaccount.connected",
"eventDate": "2026-01-01T12:00:00+01:00",
"webhookId": "ed3325d8-b379-444a-9cc1-7d119efefbea",
"safepayAccountId": "f6c4a43f-682e-4559-b8d1-11a63afd134a",
"connections": [
{
"referenceId": "your-user-id",
"connected": "2026-01-01T12:00:00+01:00"
}
]
}
Bank account missing
A user.bankaccount.missing webhook is sent when a payout to the user can't be made because they have no bank account. It is sent on every payout run until the user adds a bank account, so use it as the trigger to send the user through this flow.
{
"eventName": "user.bankaccount.missing",
"eventDate": "2026-01-01T12:00:00+01:00",
"webhookId": "ed3325d8-b379-444a-9cc1-7d119efefbea",
"safepayAccountId": "f6c4a43f-682e-4559-b8d1-11a63afd134a",
"connections": [
{
"referenceId": "your-user-id",
"connected": "2026-01-01T12:00:00+01:00"
}
]
}