Upcoming changes in Swedish payment infrastructure

Sweden is facing one of the biggest changes in the history of its payment infrastructure, regarding the updated payment type Credit Transfer. Please refer to the information in the below link.

PLEASE NOTE - UPDATED NEWS REGARDING THE TIMELINE FOR MIGRATION!

Update regarding the migration from the legacy Payments API to the NEW Swedish-market Payments APIs

The date previously communicated for completing this migration, 18 June, is being revised.

This is due to dependencies on the underlying Swedish clearing infrastructure operated by Bankgirot, the timeline of which lies outside Handelsbanken's control.

Until that dependency is resolved, we are not in a position to confirm a new fixed date.

We will share confirmed dates with you as soon as they are available, with sufficient notice for you to plan accordingly.

Information regarding SEK Credit transfer

For frequently asked questions and answers about SEK Credit transfer please follow below link

FAQ: FAQ about SEK Credit Transfer

Frequently Asked Questions

General FAQs

Why can't I log into the Developer Portal?

Please Contact us and let us know the issue. If you've forgotten your password you can Reset your password

When I try to open a page, why do I see "Access denied. You are not authorized to access this page"?

If you click on a link and on the following page you see the error message "Access denied. You are not authorized to access this page", please log into our Developer Portal and then try to access the page again.

Does Handelsbanken support browsers with disabled cookies?

At the moment it's not a requirement to use cookies in the browser, so it will work. However, in general we recommend to use cookies.

General API FAQs

Who can use Handelsbanken's PSD2 APIs?

When you add an application you are provided with an API Key and Secret for the application. You must supply these credentials when you call an API that requires you to authenticate your application.

To register an application click on Apps in the main menu and then click on the 'Create new app' link. Once you have provided an application name, description, etc you will be shown your application API Key and Secret.

Make a note of your API Secret because it is only displayed once.

How do I reset my application API Secret?

Your API Secret is stored encrypted so we cannot retrieve the unencrypted version to tell you the value if you forget it.

You can reset it, which will update the stored value and return the new value to you.

To do that click 'Apps' in the main menu, click on the application in question and then you can click the 'Reset' link in the 'API Secret' section.

Your new Secret will be displayed at the top of the page.

Can Short Term Consent be used to access card information?

Yes. In Sweden, short term consent is supported not only for accounts and balances but also for retrieving card-related data such as card list and balances.

This applies exclusively to individual users and is typically used for one-time data access.

Account & Card Account API FAQs

Do your APIs support transaction pagination?

No, we do not support pagination. If there are too many account / card transactions in the response, please limit the search using the date interval.

Why can I see a customer's account displayed multiple times?

If you are seeing a customer's account displayed more than once with the same Account number / IBAN, but different accountIds, it can be caused by the PSU giving multiple consents. This is due to a new accountId being generated each time they give you consent to their account(s).

Several consents can be active at the same time, so there can be multiple accountId's "pointing" to the same account.

Payment API FAQs

What happens when an end user cancels on the payment confirmation window?

Please read our technical guidelines below (depending on which SCA method has been used), as we mention this situation:

SCA Decoupled - Step 3

SCA Redirect - Step 2

Is the transactionStatus in the Payment Initiation flow, updated after the user has signed the SCA flow?

No, the transactionStatus is not updated after the end user has signed the payment. It is updated after the executePayment (PUT) operation.

When can we (the TPP) request the status of a payment?

                                                                                                                                                                                    

DescriptionRequest withinDeletion of PaymentId
If the PSU has signed the payment but it has not been executed, the TPP can ask for the status of the payment within 20 minutes. 20 minsMonthly
If the payment is completed, the status of the payment can be asked for up to 24 months. 24 monthsMonthly

Note: When the PaymentId has been deleted, an HTTP 404 will be returned (GET).

Can I use a short term consent?

You can use a short term consent in the PIS flow.

What is the maximum execution date I can set on a Payment?

                                                                                                                                                                                    

Description
For Private individuals, execution date can be set up to 12 months in the future. This means that Handelsbanken will monitor and execute the payment on set date. Payments with execution date "today" will be sent for processing directly after final approval. Payments that are monitored are sent for processing to the bank on the execution date's morning, at 07:15 CET.  
For Corporates, execution date can be set up to 12 months in the future. This means that Handelsbanken will monitor and execute the payment on set date. Payments with execution date "today" will be sent for processing directly after final approval. Payments that are monitored are sent for processing to the bank on the execution date's morning. 

Note: Please note that this is subject to change.

Technical FAQs

How long are the access / refresh tokens and consents valid for?

Intent (validity) - how long the PSU has to confirm the intent after a POST/ Consent or POST/ Payment is made by a TPP.
Access token (validity) - how long the ACG / DG token, which is needed to call the APIs, is valid for.
Refresh token (validity) - how long the refresh token, which is required to get a new access token, is valid for.
Consent (validity) - how long the consent given to the TPP from the PSU, is valid for.

Intent typeIntent (validity)Access token (validity)Refresh token (validity)Consent (validity)
Accounts15 mins24 hours90 days90 days for GB, 180 days for the other supported countries
Card Accounts15 mins24 hours90 days90 days for GB, 180 days for the other supported countries
Payments15 mins15 minsN/A15 mins
Confirmation of Funds15 mins15 minsN/AUntil consent is removed

Important: The above times are what the value times are currently set at. However, please always use the expires_in parameter value rather than hard-coding the set time values (e.g. 24 hours, 15 mins), as these could change in the future.

How do I integrate with your authorization flow?

Please refer to our Technical Guidelines, specifically the ones dedicated to SCA Decoupled and SCA Redirect

 

 

How can I update the Redirect URL for my App?

At the moment, we don't support functionality for updating Apps (other than adding subscriptions). So to update the Redirect URL for your App, you'll need to register a new App with the new Redirect URL. The functionality to update the Redirect URL for an existing App is in our road map for future improvements.

How does the SCA Decoupled authentication flow work in case we don't support QR codes?

The BankID app always needs to be started with an autoStartToken. The autoStartToken is used in two ways:

1) If the Mobile BankID app is on a different device, you have to build a QR code based on the autoStartToken.
2) If the Mobile BankID is on the same device, you can use the autoStartToken as a query-parameter.

Sandbox FAQs

Where can I find the PSD2 API test data?

The test data for our PSD2 APIs (Account Information API, Card-Account Information API, Payment Initiation API and Confirmation of Funds API) is located in our Technical Guidelines, at the bottom of the page in a section called Sandbox test data

When I created a new test application, I received the ClientID but why did I not get the Client Secret?

You only need the ClientId for testing in our Sandbox environment, the Client Secret is not needed. When you go Live, you also need a valid eIDAS certificate (QWAC) from a Qualified Trust Service Provider (QTSP). To read more about this, check out our page for Live Data Enrollment

Live environment FAQs

Which certificates does Handelsbanken accept?

Before using our Live Data APIs, a TPP (Third Party Provider) must have one of the below from a Qualified Trust Service Provider (QTSP):

- A valid PSD2 eIDAS certificate (QWAC)

- A valid UK Open Banking certificate (OBWAC)

To read more about accessing our Live Data APIs and enrolling with us as a TPP, please see Live Data Enrollment

I am a new TPP that is trying to enroll but I am experiencing issues. What could be the problem?

Please see below for helpful tips if you are a TPP who is trying to enroll with us for the first time so you can use our Live Data APIs.

- You must follow Step 1. Request third party access on our Live Data Enrollment page and use the POST endpoint.

- If you encounter issues when enrolling, it could be that your QTSP is not on our trusted list and we need to add them. Please contact us and include the name of the QTSP and the link to the CRL distribution points (i.e. the URL where the revocation list can be located). You can send us a message here Contact us

- If you have already enrolled as a TPP and are having issues adding a new certificate, please see the below FAQ.

I have enrolled as a TPP and would like to add a new certificate but I am experiencing issues. What could be causing this?

Please see below for helpful tips if you are a TPP who has already enrolled with us to use Live Data APIs but would like to add another certificate.

- You must follow Step 1.1 Add an additional certificate on our Live Data Enrollment page and use the PUT endpoint, not the POST endpoint.

- If you encounter issues when enrolling, it could be that your QTSP is not on our trusted list and we need to add them. Please contact us and include the name of the QTSP and the link to the CRL distribution points (i.e. the URL where the revocation list can be located). You can send us a message here Contact us

- When adding a new certificate (and in order to successfully do Step 1.1), you must have the same organizationIdentifier (OID 2.5.4.97) as the previous certificate. If you have a new organizationIdentifier, you'll need to enroll as a new TPP, so follow Step 1. Request third party access 

- It is very important that the new client certificate is used in both the TLS (Transport Layer Security) and in the payload of the request. There should be no line breaks or white spaces either.

- If you're an existing TPP, but used an integration platform and have some issues, please see the below FAQ.

I am a TPP that used an integration platform from a provider and I will migrate to another. Do I need to change anything?

Please see below for some tips if you are a TPP who has moved from one integration platform to another. (Note: we won't be able to provide support for issues you have with your integration platform!)

- If you intend to use the same client certificate as previously, you can continue using the same client IDs / subscriptions / applications.

- However, if you want to use a new client certificate and keep the same client IDs / subscriptions / applications, you must add a new client certificate to your current TPP registration. This can be done by following the instructions for Step 1.1 Add an additional certificate

How can I see my applications for the Live environment in the Developer Portal?

Our Developer Portal is only for the Sandbox (test) environment. Live and Sandbox are totally separate environments, which means you won't see any applications / subscriptions you have in the Live enironment when you log into our Developer Portal.

How can I query what apps are registered / see the app's subscriptions / delete an app in the Live environment?

At the moment, this functionality is not supported, but it is in our road map for future improvements.

Do you support multiple redirect_uris?

There is no support for multiple redirect_uris on a single app.

If you would like to add another redirect_uri, you will need to register a separate app. To do this, please follow Step 3. Register your app and subscribe to our APIs

If you would like that app to consume several APIs, please then follow 3.1 Add an additional API subscription (one per request)

Error message FAQs

Why do I receive a 401 HTTP error message stating "Invalid token grant type"?

If you receive an error message like this:

{"httpCode": "401","httpMessage": "Unauthorized","moreInformation": "Invalid token grant type."}

This means that you (the TPP) are using a token incorrectly. For example, using a CCG token where an ACG or DG token should be used instead. Please refer to the SCA Redirect - Authorization flow chart or the SCA Decoupled - Authorisation flow chart

Why do I receive an error stating "unsupported_grant_type"?

There are a number of reasons why you can receive this error, such as having incorrect values for the grant_type. However, one of the most common reasons is because an incorrect URL has been used. Below we've listed the different URLs for the Authorization APIs, depending on which environment you're working with.

Authorization Code Grant API - Sandbox environment
(initate authorization) https://sandbox.handelsbanken.com/openbanking/redirect/oauth2/authorize…
(request token) https://sandbox.handelsbanken.com/openbanking/redirect/oauth2/token/1.0
(refresh token*) https://sandbox.handelsbanken.com/openbanking/refresh/oauth2/token/1.0

Authorization Code Grant API - Live environment
(initate authorization) https://secure.handelsbanken.com/bb/gls5/oauth2/authorize/1.0
(request token) https://api.handelsbanken.com/bb/gls5/oauth2/token/1.0
(refresh token*) https://api.handelsbanken.com/bb/gls5/oauth2/token/1.0

Decoupled Grant Mobile BankID API - Sandbox environment
(initate authorization) https://sandbox.handelsbanken.com/openbanking/decoupled/mbid/initAuthori...
(request token) https://sandbox.handelsbanken.com/openbanking/decoupled/mbid/token/1.0
(refresh token*) https://sandbox.handelsbanken.com/openbanking/refresh/oauth2/token/1.0

Decoupled Grant Mobile BankID API - Live environment
(initate authorization) https://api.handelsbanken.com/bb/gls5/decoupled/mbid/initAuthorization/…
(request token) https://api.handelsbanken.com/bb/gls5/decoupled/mbid/token/1.0
(refresh token*) https://api.handelsbanken.com/bb/gls5/oauth2/token/1.0

*the refresh token is only applicable to the Accounts API and Card Accounts API.

Why do I receive a 401 HTTP error message stating "Not registered to plan"?

If you get this error message it means that you have not subscribed to the API(s).

In the Sandbox environment, you do this by pressing the "Subscribe" button on the API product pages e.g. Consents API

In Live, you register your apps and subscribe to our APIs by calling the Subscriptions API, see Step 3 Register your app and subscribe to our APIs on our Live Data Enrollment page.

You can find a list of the ENUM values of our available products under "ApiSubscription" > "product" on the Subscriptions API

Please note that if you have subscribed to the Accounts API or the Card Accounts API, you must also subscribe to the Consents API, otherwise you will receive the error "Not registered to plan".

Why do I receive "not_shb_approved" for Swedish customers?

This response means that the end user / PSU (Payment Service User) does not have the correct permissions, or (in rare cases), they don't have a Handelsbanken Online Banking service agreement.

For the end user / agent (PSU) to be able to access the Corporate customer's account information or make payments, they need to have the appropriate permissions as per the Corporate mandate, as well as the "Additional service API Corporate". An end user's permissions can be updated by the Corporate customer's administrator in the Handelsbanken online services by going to “Administration” and then “Mandates”, or by contacting their local branch.
For an end user / agent (PSU) to be able to access a Sub-account (underkonto), a mandate from the owner of the Main-account (huvudkonto) is needed.

Why do I receive "not_shb_approved" for British customers?

This response means that the end user / PSU (Payment Service User) does not have the correct permissions, or (in rare cases), they don't have a Handelsbanken Online Banking service agreement.
For the end user / agent (PSU) to be able to access the Corporate customer's account information or make payments, they need to have the appropriate permissions as per the Corporate mandate. An end user's permissions can be updated by the Corporate customer's administrator in the Handelsbanken Online Banking services (e.g. under "Profile", then "Permission administration"). They then need to select "Permission by person" and select the name of the user.
For our Account Information API, the user needs to have the "View account information" permission.
For our Payment Initiation API, the user needs to have the "Input" permission and if they need to execute payments, then they will need to be an authorised signatory.
Providing the user has the correct permission(s), they will be able to view the account and make payments in the Handelsbanken Online Banking services, as well as the Third Party Provider's services. If a PSU is unsure about their permissions, they need to contact their local branch.

Why do I receive "not_shb_approved" for Dutch customers?

This response means that the end user / PSU (Payment Service User) does not have the correct permissions, or (in rare cases), they don't have a Handelsbanken Online Banking service agreement.
For the end user / agent (PSU) to be able to access the Corporate customer's account information or make payments, they need to have the appropriate permissions as per the Corporate mandate. An end user's permissions can be updated by the Corporate customer's administrator in the Handelsbanken online services or by contacting their local branch.

Why do I receive "mbid_not_shb_activated" for Swedish customers?

This is an error message specific to Swedish customers and is received when the customer tries to use Mobile BankID that wasn't issued by Handelsbanken (i.e. another bank issued it) and it needs to be activated before it can be used. This is achieved by the end user (PSU) logging into the Handelsbanken online services (for the first time).

Why do I receive an "mbid_error" response for Swedish customers?

This is an error between you (the TPP) and Mobile BankID, which means we cannot provide technical support regarding this. There are a number of reasons why you can get this error, but below we've listed some characteristics / rules that we think you should be aware of. For further help, please refer to BankID's technical support page

1 - BankID has a 30-second timeout if the client has not scanned the QR code.
2 - The polling request against the authorization server must not be made more often than the sleep_time specifies, as of today - every 2 seconds.
3 - The maximum number of calls is 30, then the transaction is cancelled against BankID and an error is sent.
4 - Only 1 session/connection per PSU, against the authorization server is allowed. If several sessions are started, you'll get an error.

Why do I receive "mbid_max_polling" for Swedish customers?

This is an error message specific to Swedish customers and is received when the max number of token requests has been reached and the order has been cancelled in BankID. After you receive this error message, you can try the initiation again, but avoid automatically initiating it.

Why do I receive a 400 HTTP error message stating "Invalid account", with an accountId that has worked before?

If the accountId has worked before and you receive an error message like this:

{"httpCode":"400","httpMessage":"Bad Request","moreInformation":"Invalid account"}

This means that the GUID for the accountId has changed due to a new Consent being issued. The same error can also occur if the account is closed, because the accountId has been terminated.

Why do I receive an error message stating "access_denied"?

A TPP will receive an "access_denied" error message when the PSU (customer) has cancelled the operation / approval.

Why do I receive a 401 HTTP error message stating "Bearer error=invalid_token"?

If you receive an error message like this:

{"httpCode": "401","httpMessage": "Unauthorized","moreInformation": "Bearer error='invalid_token"}
This is a general error message meaning that the authorization token or client Id used is wrong.

Why do I receive a 401 HTTP error message stating "Invalid client id or secret"?

If you receive an error message like this:

{"httpCode": "401","httpMessage": "Unauthorized","moreInformation": "Invalid client id or secret."}.
The clientId used in the request is wrong.

Why do I receive a 401 HTTP error message stating "Cannot find valid subscription for the incoming API request."?

If you receive an error message like this:

{"httpCode": "401","httpMessage": "Unauthorized","moreInformation": "Cannot find valid subscription for the incoming API request."}.
The clientId is exists but there is no subscirption on the API that you are using, i.e you need to subscribe to the API wou want to use.

SEK Credit Transfer FAQs

Which APIs are affected by this migration?

  • Legacy: Payments API v1.3.2 (multi-country)
  • New:
    • Payments SE Private API v2.0.0
    • Payments SE Corporate API v2.0.0

The Accounts API (v2.1.30) and Subscriptions API (v1.0.22) are not part of this migration.

Payments SE Corporate API v2.0.0

Where do I start?

  1. Review the new OpenAPI specifications on the Developer Portal.
  2. Subscribe your app to the relevant product (payments-se-private and/or payments-se-corporate) via the Subscriptions API.
  3. Develop and test in the Sandbox environment.
  4. Use the Go Live process on the Developer Portal when ready for production.

What's the recommended migration path?

  1. Subscribe your existing app to the new products via the Subscriptions API:
    • payments-se-private (PIS scope)
    • payments-se-corporate (PIS scope)
  2. Update base URL from /openbanking/psd2/v1 to /openbanking/psd2/se/v2.
  3. Split your code paths by customer segment (private vs corporate).
  4. Map your product calls to the new endpoint structure (/single/{product} vs /signing-basket).
  5. Adapt payloads to the product-specific schemas — particularly creditorAccount.accountType, chargeBearer, paymentTypeInformation and remittance text patterns.
  6. Move SEK Credit Transfer flows into baskets — single sek-credit-transfer is not supported in v2.
  7. Re-test SCA flows — both DECOUPLED and REDIRECT are still supported, but URLs and link structures are versioned.
  8. Regression-test cancellation flows for future-dated payments.
  9. Verify in Sandbox, then complete Go Live on the Developer Portal.

Which payment products are supported in the new Swedish APIs?

ProductCode (URL identifier)PrivateCorporate
Handelsbanken Domestic Credit Transfer (SHBCT)handelsbanken-domestic-credit-transfer
SEK Credit Transfer (SEKCT) — former bank transfers and giro paymentssek-credit-transfer✓ (basket only)✓ (basket only)
SEPA Credit Transfer (SEPACT)sepa-credit-transfer
Cross Currency Credit Transfer (CCCT)cross-currency-credit-transfer

Handelsbanken Domestic Credit Transfer is for Handelsbanken accounts only

The payment product handelsbanken-domestic-credit-transfer (SHBCT) can only be used to credit accounts held at Handelsbanken. It cannot be used to pay an account at another Swedish bank.

This restriction is enforced by the schema. A request that targets an account at another bank will be rejected with an HTTP 400, typically referencing creditorAgent.identification.code and creditorAccount.value.

If the destination clearing number falls outside 6000–6999, the account is not a Handelsbanken account and this product is not the correct one to use.

Paying an account at another Swedish bank

To send a domestic SEK payment to an account held at another Swedish bank, use the SEK Credit Transfer product (sek-credit-transfer, SEKCT) instead. SEKCT accepts accountType values IBAN, BBAN, PG and BG, so you can pass a Swedish IBAN directly without splitting out the clearing number.

Note that SEKCT is available only through a signing basket. There is no single-payment endpoint for this product.

What are the new base URLs?

EnvironmentURL
Sandboxhttps://sandbox.handelsbanken.com/openbanking/psd2/se/v2
Livehttps://api.handelsbanken.com/openbanking/psd2/se/v2

Note the new /se/v2 path segment. The legacy API used /openbanking/psd2/v1.

What is the URL structure for the new endpoints?

The new APIs split clearly between customer segment and payment type:

  • /payments/private/single/{paymentProduct} — single private payments
  • /payments/private/signing-basket — private basket payments
  • /payments/corporate/single/{paymentProduct} — single corporate payments
  • /payments/corporate/signing-basket — corporate basket payments
  • /payments/private/accounts/shorttermconsents — short-term consent (Private only)

In v1.3.2, all payments used a single /payments/{paymentProduct} endpoint regardless of customer type.

What is the mapping from legacy product names to the new ones?

Legacy v1.3.2 productNew SE v2.0.0 product
swedish-domestic-giro-paymentsek-credit-transfer (SEKCT, basket only)
swedish-domestic-credit-transfersek-credit-transfer (SEKCT, basket only)
sepa-credit-transfersepa-credit-transfer (Corporate only)
cross-currency-credit-transfercross-currency-credit-transfer
(new in v2)handelsbanken-domestic-credit-transfer (SHBCT)

Important: In v2, SEKCT can only be executed inside a signing basket — single SEKCT payments are no longer supported. SHBCT, SEPACT and CCCT can only be executed as single payments.

How have signing baskets changed?

AspectLegacy v1.3.2New v2.0.0
EligibilitySweden, individuals, swedish-domestic-giro-payment onlyBoth Private and Corporate, sek-credit-transfer
Max payments per basket3030 (Private) / 100 (Corporate)
Min payments per basket11

What are the main structural changes in the payment payload?

  • Dedicated product-specific schemas: each product (SHBCT, SEKCT, SEPACT, CCCT) now has its own validated request schema with the right field set, account types and patterns. The legacy API used one generic PaymentPayload for all products.
  • creditorAccount.accountType is now strictly enumerated per product:
    • SHBCTBBAN only (8–9 digit Swedish SHB account number)
    • SEKCTBBAN, IBAN (Swedish IBANs only), PG, BG
    • SEPACT, CCCT Nordic, CCCT EU-paymentIBAN only
    • CCCT Normal / ExpressIBAN or BBAN
  • chargeBearer values are now tied to product:
    • SHAR — SEPACT, CCCT Nordic, CCCT EU-payment
    • CHAR, CRED, DEBT — CCCT Normal and Express
  • PaymentTypeInformation uses ISO 20022 codes (SEPA, URGP, NURG) and category-purpose codes (SUPP, NOPA, EUSE).
  • Stricter character patterns apply to creditor.name, remittanceInformation.text and similar fields — particularly for SHBCT, where remittance text is limited to 14 characters.

Can I use the V2 to Cancel or ask for Status on payments created in V1?

No, You must use the old endpoint (V1) to cancel and ask for status on payments.

Where do I get support?

Is SEK Credit Transfer available only as a basket payment?

Yes. There is no /payments/corporate/single/sek-credit-transfer endpoint. SEK credit transfers can be initiated only via POST /payments/corporate/signing-basket.

A basket containing a single payment is the correct and supported approach: the request requires the sekCreditTransfers array with minItems 1 (maxItems 100), so an array of length 1 is the intended way to initiate an individual cross-bank SEK transfer.

How do we check status after executing a basket?

There is no basket-level status endpoint. Use the existing per-payment endpoint GET /payments/corporate/{paymentProduct}/{paymentId}/status with paymentProduct = sek-credit-transfer and the paymentId returned per payment in the initiation response.

The initiation response returns a payments array, each element carrying its own paymentId plus your tppPaymentReference; use that mapping to poll each payment.

On PARTIAL_FAILURE, how do we identify which payments failed?

The basket execute response returns only a basket-leveltransactionStatus (SUCCEEDED / FAILED / PARTIAL_FAILURE); it does not break results down per payment.

To identify individual outcomes, call the per-payment status endpoint for each paymentId. At payment level, transactionStatus uses ISO 20022 codes (ACTC, ACCP, ACSC, ACCC, PATC, CANC, RJCT). A failed payment shows RJCT, with reasonCode and reason giving the specific cause.

Recommended PARTIAL_FAILURE pattern

  1. Execute basket. If transactionStatus = PARTIAL_FAILURE,
  2. Iterate the payments array from the initiation response,
  3. Call GET .../sek-credit-transfer/{paymentId}/status for each, treating RJCT + reasonCode/reason as the failure detail.