Handelsbanken has launched a new version of the Sandbox

Handelsbanken has launched a new version of the Sandbox today the 16th of April. Kindly follow the instructions in the developer portals new Sandbox tab and change your test data accordingly to continue testing.

Testing the payments API

Now let's get started with some testing! But first you have to sign up and create your own Apps, if not already done.

You have to go through all steps, chronologically, in this guide to get successful results as each step is dependent on previous step.

Sandbox Gateway Host URL

When testing our APIs in our Sandbox environment, please ensure that the below base URL is used in the calls. 

 

Important 1:
When using our APIs in the Live environment, the base URL changes to https://api.handelsbanken.com/openbanking

Important 2:
The client id:s you get when creating your apps, have a format that differs from the live environment. The live environment creates client id:s that have a UUID format while the sandbox creates client id:s that have a UUID format without dashes.

Important 3:
The Transaction Status, received at execution of the payment, might not be fully correct as we haven't created test data for all scenarious that can happen in the Live environment. But in moste cases they are correct..

 

 

Step-by-step guide

 

Step 1: Request Client Credential Grant (CCG) token

The authorization process starts with requiring a Client Credentials Grant (CCG). The result of this call will be a CCG access token which is used to call the POST /payments/{paymentProduct} endpoint of the Payments API (which is used to acquire PIS consents for the PSU).

The Client Credential Grant request is identfied using the scope object (e.g. PIS). The CCG request is identical for all countries and is PSU independent.

Replace the “client_id” object with the client id you got when you created your App.

Further on in this guide you have to replace all objects in green color, with your client id, objects received from a previous step and objects that you have to choose yourself. Objects in red color are examples and cannot be used in requests.

Request example

curl -X POST https://sandbox.handelsbanken.com/openbanking/oauth2/token/1.0 \
-H 'Accept: application/json' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=client_credentials&scope=PIS&client_id=YOUR CLIENT ID'

See below for the type of information that needs to be in your request.

Parameter Description Example
grant_type Type of token request - CCG in this case. Allowed value: “client_credentials”.
Mandatory
client_credentials
scope A static scope with one or several values. For the Payment APIs, "PIS" must be the scope.
Mandatory
PIS

 
client_id The client_id (app-id) you got when you created your app".
Mandatory
f31b7318-8f21-4eaf-8817-6b5e4e02d6bc

Response example

This is what the response looks like when the CCG token has been successfully created. 

HTTP/1.1 200 OK
{
"access_token": "QVQ6YmNlZjI0M2QtZDBhZi00OGZiLWE0OTgtZGUwMTJhMDdjMjYz",
"expires_in": 86400,
"token_type": "Bearer"
}

Not that the access token is an example. The response you will receive is unique for your request. So be aware of that objects in red are examples and cannot be used by you.

Parameter Description Example
access_token The returned CCG token, associated with your registered application for the scope(s) you have requested. QVQ6YmNlZjI0M2QtZDBhZi00OGZiLWE0OTgtZGUwMTJhMDdjMjYz
expires_in

Number of seconds the access_token is valid.

86400
token_type Always the value ”Bearer”. Bearer
 


Step 2: Initiate payment (using CCG token)

The payment process starts with requesting a Payment ID and available SCA methods. These objects will later be used in Step 3.The CCG access token, received from previous step, is pasted into the Authorization header of the request.

Note that requests to the GB and the LU markets have the country defined in the URL while requests to the other markets defines the country with a header in the request.

For GB and LU the URL looks like this:
POST https://sandbox.handelsbanken.com/openbanking/psd2/gb/v1/payments
and
POST https://sandbox.handelsbanken.com/openbanking/psd2/lu/v1/payments
This applies to all /openbanking requests further down in this guide

Important 1: 

In the body of the request, you should include payment fields and accepted values as per our Implementation Guidelines. If you don't follow the Impementation Guidelines and don't add the information required, you will receive errors.  

Important 2: 

If the PSU is a Corporate customer, then the header parameters "PSU-Corporate-ID" and "PSU-Corporate-ID-Type" must be included in the request. The "PSU-Corpotate-ID-Type" header is alway equal to "BANK". The PSU-Corporate-ID" is found in the test data document.  



Request example

curl -X POST https://sandbox.handelsbanken.com/openbanking/psd2/v1/payments/swedish-domestic-giro-payment \
-H 'X-IBM-Client-Id: YOUR CLIENT ID' \
-H 'Authorization: Bearer CCG ACCESS TOKEN RECEIVED FROM PREVIOUS STEP' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Country: SE/NL/FI' \
-H 'TPP-Request-ID: YOUR REQUEST ID' \
-H 'TPP-Transaction-ID: YOUR TRANSACTION ID' \
-d '{"debtorAccount": {"value": "CHOOSE AN ACCOUNT FROM THE TEST DATA DOCUMENT","accountType": "IBAN"},"instructedAmount": {"currency": "SEK","amount": AMOUNT},"creditorAccount":{"value": "CREDITOR ACCOUNT","accountType": "BG OR PG"},"remittanceInformation":{"text": "REFERENCE TEXT"}}'

See below for the type of information that needs to be in your request.

Parameter Description Example
paymentproduct Payment product identifier.
Mandatory.
swedish-domestic-giro-payment
swedish-domestic-credit-transfer
british-domestic-credit-transfer
sepa-credit-transfer
cross-currency-credit-transfer
X-IBM-Client-Id The client_id (app-id) for your test app.
Mandatory.
f31b7318-8f21-4eaf-8817-6b5e4e02d6bc
Authorization

The CCG access token.

Use the CCG access token received in previous step.
Mandatory.

Bearer QVQ6YmNlZjI0M2QtZDBhZi00OGZiLWE0OTgtZGUwMTJhMDdjMjYx

Country ISO 3166-1 country code. 
Mandatory.
SE, FI, NL (one country per request)
TPP-Request-ID Unique identifier for the request. For Sandbox testing, you can make this up.
Mandatory.
c8271b81-4229-5a1f-bf9c-758f11c1f5b1
TPP-Transaction-ID Unique identifier for the transaction. For Sandbox testing, you can make this up.
Mandatory.
6b24ce42-237f-4303-a917-cf778e5013d6

Response example

This is what the response looks like when the payment initiation has been done. A successful response will include a Payment-id as well as links to endpoints for continuing the authorization process (next step) with the signing of the payment by the end user (PSU).

HTTP/1.1 200 OK {
 "paymentId": "d3f3dd9f-9d41-85b2-4866-789a23caccc6",
 "scaMethods": [{
  "_links": {
   "authorization": [{
    "href": "https://sandbox.handelsbanken.com/openbanking/oauth2/authorize/1.0",
    "name": "authorize_1.0",
    "type": "application/x-www-form-urlencoded"
   }
  ]
 },
 "scaMethodType": "REDIRECT"
 },
 {
  "_links": {
   "authorization": [{
    "href": "https://sandbox.handelsbanken.com/openbanking/decoupled/mbid/initAuthorization/2.0",
    "name": "decpld_mbid_2.0",
    "type": "application/json"
   }]
  },
 "scaMethodType": "DECOUPLED"
 }
]
"transactionStatus":"ACTC" }

 

Parameter Description Example
paymentId The payment-id that has been created to be used later on when the PSU signs the payment. 58cdfef9-7f6e-476e-a1af-c54c0a9a3135
scaMethods.[]._links.authorization.
[].href
Link to authorization endpoint for starting the PSU authorization process.

Redirect:
https://sandbox.handelsbanken.com/openbanking/redirect/oauth2/authorize/1.0

Decoupled:
https://sandbox.handelsbanken.com/openbanking/decoupled/mbid/initAuthorization/2.0

scaMethods.[].scaMethodType The type of PSU authorization method. REDIRECT
DECOUPLED
transactionStatus ACTC
 


Step 3: Payment Authorization Grant

We support two different authorization flows, Redirect and Decoupled. Redirect is available for all countries, while Decoupled is only available in Sweden.

Redirect Authorization flow

In this first phase of the authorization flow (Authorize Request) the PSU is signing the payment. However, the signing is not implemented in the sandbox, therefore the response comes immediately as if the PSU had signed the payment.

Authorize Request

Request example

curl -v -X GET 'https://sandbox.handelsbanken.com/openbanking/oauth2/authorize/1.0?response_type=code&scope=PIS:PAYMENT ID YOU GOT FROM PREVIOUS STEP&client_id=YOUR CLIENT ID&state=YOUR CHOICE&redirect_uri=CHOOSE AN ARBITRARY URI' \
-H 'Accept: application/json'

Parameter Description Example
response_type The type of response, should always be "code".
Mandatory.
code
scope "PIS" for Payment information plus payment-id
Mandatory.
PIS:5871c132-e2d1-0b18-4a14-5c86bc6130a5
client_id Your application's client-id.
Mandatory.
f31b7318-8f21-4eaf-8817-6b5e4e02d6bc
state An identifier chosen by you (the TPP), to be able to identify the current transaction. This will be provided in the call to your redirect URI.
Mandatory.
bc4b933c-bfc2-44c8-b858-eba90f559f91
redirect_uri This is the callback URI to your own service, that will be called after the PSU finishes authorizing themselves. In the sandbox it will be called immediately since we don't have to wait for a user.
Mandatory.
https://YourCallbackServer/redirect/result

Response example

In the sandbox the response is returned with a HTTP code 302 with Location header set to the redirect URI with query parameters of state (from the request) and an authorization code to be used in the next step: Request Authorization Code Grant token.

If there is an error, a Location header will be returned with the query parameters "error" and "error_description".

http://YourCallbackServer/redirect/result?state=bc4b933c-bfc2-44c8-b858-eba90f559f91&code=a445beb2-d1a1-b4e8-e05b-1803244c6722

Parameter Description Example
state The identifier that you provided in the authorize request, to identify the current transaction.
Mandatory.
bc4b933c-bfc2-44c8-b858-eba90f559f91
code An authorization code to be used in the next step.
Mandatory.
a445beb2-d1a1-b4e8-e05b-1803244c6722

Request Authorization Code Grant token

The final step in the redirect authorization flow is to retrieve an access token, by calling the Authorization Code Grant API

Request example

curl -X POST https://sandbox.handelsbanken.com/openbanking/oauth2/token/1.0 \
-H 'Accept: application/json' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=authorization_code&scope=PIS:PAYMENT ID YOU GOT FROM PREVIOUS STEP&client_id=YOUR CLIENT ID&code=AUTHORIZATION CODE FROM PREVIOUS STEP&redirect_uri=CHOOSE AN ARBITRARY URI'

See below for the type of information that needs to be in your request.

Parameter Description Example
grant_type The type of token call. Should be "authorization_code".
Mandatory.
authorization_code
scope "PIS" for Payment information plus payment-id.
Mandatory.
PIS:5871c132-e2d1-0b18-4a14-5c86bc6130a5
client_id Your application's client-id.
Mandatory.
f31b7318-8f21-4eaf-8817-6b5e4e02d6bc
code The authorization code from previous step.
Mandatory.
a445beb2-d1a1-b4e8-e05b-1803244c6722
redirect_uri This is the callback URI to your own service.
Mandatory.
http://YourCallbackServer/redirect/result

Response example

This is what the response looks like when an access token has been successfully retrieved from the authorization server.

HTTP/1.1 200 OK {
"access_token": "QVQ6YTU3ZWMxZTgtYzFkYS0zZTEwLTFmMmQtNDA5Zjk4ODhhNzg1",
"expires_in": 900,
"token_type": "Bearer"

}

Parameter Description Example
access_token The access token to be used in Authorization header in some of the coming requests against the endpoints of the payment API. QVQ6YTU3ZWMxZTgtYzFkYS0zZTEwLTFmMmQtNDA5Zjk4ODhhNzg1
expires_in Number of seconds the access_token is valid.
Note that the sandbox only has static data - the access_token will never expire.
900
token_type Always the value ”Bearer”. Bearer

 

Decoupled Authorization flow

The Decoupled Authorization flow is only available in Sweden. It uses the Mobile BankID for authentication. However the Sandbox is not connected to mobile bank id. Instead the authentication will always be successful.

Authorize Request

Request example

curl -X POST https://sandbox.handelsbanken.com/openbanking/decoupled/mbid/initAuthorization/2.0 \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{ "client_id": "YOUR CLIENT ID", "scope": "PIS:PAYMENT ID RECEIVED FROM PREVIOUS STEP", "psu_client_ip": "YOUR CHOICE", "bisa_same_device": true }'

See below for the type of information that needs to be in your request. Please make sure you replace the example values with the correct ones in your request.

Parameter Description Example
client_id Your application's client-id.
Mandatory.
f31b7318-8f21-4eaf-8817-6b5e4e02d6bc
scope "PIS" for Payment information plus payment-id
Mandatory.
PIS:d3f3dd9f-9d41-85b2-4866-789a23caccc6
psu_client_ip IP address of the PSU's device. Both IPV4 and IPV6 address formats are allowed.
Mandatory.
127.0.0.1
bisa_same_device Data type : boolean. Set value to true when the customer BankID app (BISA) run on the same device as the TPP client. An autoStartToken will be returned
in the response. Set value to false when the BISA app run on a different device then the TPP client. A complete QR code will be returned in the response.
Note that the parameter is not used by the sandbox, since the sandbox is not connected to Mobile BankID.
Mandatory.
true

Response example when bisa_same_device=true

HTTP/1.1 200 OK
{
"auto_start_token": "Not a valid auto_start_token",
"sleep_time": 2000,
"_links": {
 "token": {
  "href": "https://sandbox.handelsbanken.com/openbanking/decoupled/mbid/token/2.0?sessionId=d5471d98-decd-a249-82ad-5b477df28e89",
  "hints": {
   "allow": ["POST"]
   }
  },
 "cancel": {
  "href": "https://sandbox.handelsbanken.com/openbanking/decoupled/mbid/cancel/2.0?sessionId=d5471d98-decd-a249-82ad-5b477df28e89",
  "hints": {
   "allow": ["POST"]
   }
  }
 }
}

Response when bisa_same_device=false

HTTP/1.1 200 OK
{
"qr_code": "Not a valid qr_code",
"sleep_time": 2000,
"_links": {
 "token": {
  "href": "https://sandbox.handelsbanken.com/openbanking/decoupled/mbid/token/2.0?sessionId=d5471d98-decd-a249-82ad-5b477df28e89",
  "hints": {
   "allow": ["POST"]
   }
  },
 "cancel": {
  "href": "https://sandbox.handelsbanken.com/openbanking/decoupled/mbid/cancel/2.0?sessionId=d5471d98-decd-a249-82ad-5b477df28e89",
  "hints": {
   "allow": ["POST"]
   }
  }
 }
}

Description of response parameters.

Parameter Description Example
auto_start_token Optional, will only be returned when bisa_same_device=true. Token will be invalid since the sandbox is not connected to BankID. Not a valid auto_start_token
qr_code Optional, will only be returned when bisa_same_device=false. The QR-code will be invalid since the sandbox is not connected to BankID. Not a valid qr_code
sleep_time The minimum number of milliseconds to wait before invoking the token endpoint and between each call to that endpoint. 2000
links.token.href Link to the token endpoint, with your unique session-id, to use in the next step. https://sandbox.handelsbanken.com/openbanking/decoupled/mbid/token/2.0?sessionId=e42e8bcb-cbdc-40b5-97a7-ca47284b1b69
links.cancel.href Link to the cancel endpoint, to cancel the ongoing authorization process.
Note that the sandbox uses static data. It is therefore not possible to actually cancel the authorization process. Though it is possible to call the endpoint, but it will have no effect.
https://sandbox.handelsbanken.com/openbanking/decoupled/mbid/cancel/2.0?sessionId=e42e8bcb-cbdc-40b5-97a7-ca47284b1b69

Request Decoupled Grant token

In the Live environment it is necessary to start the BankID app, or display a QR-code to the user. However the sandbox is not connected to BankID. Therefor this skip is skipped.

The final step in the decoupled authorization process is to retrieve an access token, by calling the Decoupled Grant API

The URL to be used was received in previous step. In the Live environment it is necessary to poll this URL repeatedly, but in the sandbox it will always send a response with the "COMPLETE" status.

Request example

curl -X POST 'https://sandbox.handelsbanken.com/openbanking/decoupled/mbid/token/2.0?sessionId=SESSION ID RECEIVED FROM PREVIOUS STEP' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{}'

 

Response example

This is what the response looks like when the authorization has been successfully completed by the end user (PSU).

Note that the status will always be COMPLETE for the sandbox.

HTTP/1.1 200 OK
{
"result" : "COMPLETE”,
"access_token" : "QVQ6ZjdlODAyMTgtNGIwZi1kMDBkLThkMTctYjkwZjA4MjI2Njhi",
"token_type" : "Bearer",
"expires_in" : 900,
}

Parameter Description Example
result Information about which "status" the token request is in:
COMPLETE - the PSU has verified and the response includes token info.
COMPLETE
access_token The access token to be used in Authorization header in the coming requests against the endpoints of theaccounts and cards APIs.
Note! This token can only be used for the particular scope+PSU consent, that was given at initiation of the authorization.
QVQ6ZjdlODAyMTgtNGIwZi1kMDBkLThkMTctYjkwZjA4MjI2Njhi
token_type Always the value "Bearer". Bearer
expires_in Number of seconds the access_token is valid.
Note that the sandbox only has static data - the access_token will never expire.
900

 

Step 4: Request payment execution

The payment continues with payment execution, that is, approval of the payment. The ACG or DG access tokens, received from previous step, is pasted into the Authorization header of the request.

 

Request example

curl -X PUT https://sandbox.handelsbanken.com/openbanking/psd2/v1/payments/swedish-domestic-giro-payment/PAYMENT ID \
-H 'X-IBM-Client-Id: YOUR CLIENT ID' \
-H 'Authorization: Bearer ACG OR DG TOKEN RECEIVED IN PREVIOUS STEPS' \
-H 'Accept: application/json' \
-H 'TPP-Request-ID: YOUR OWN CHOICE' \
-H 'TPP-Transaction-ID: YOUR OWN CHOICE' \

See below for the type of information that needs to be in your request.

 

Parameter Description Example
paymentproduct Payment product identifier.
Mandatory.
swedish-domestic-giro-payment
swedish-domestic-credit-transfer
british-domestic-credit-transfer
sepa-credit-transfer
cross-currency-credit-transfer
paymentId The payment-id that was created in previous step..
Mandatory.
58cdfef9-7f6e-476e-a1af-c54c0a9a3135
X-IBM-Client-Id The client_id (app-id) for your test app which we said you should note down earlier.
Mandatory.
f31b7318-8f21-4eaf-8817-6b5e4e02d6bc
Authorization

The ACG/DG access token from previous step.


Mandatory.
Bearer QVQ6MGQ2YmYtMmZjOC00Yzg3LzYyOGU0NTg5YmM3
TPP-Request-ID Unique identifier for the request.
For Sandbox testing, you can make this up.
Mandatory.
fcbf8e7c-46ad-4a94-9853-0c3b5c1323ba
TPP-Transaction-ID Unique identifier for the request.
For Sandbox testing, you can make this up.
Mandatory.
c311a0b8-ed90-4af4-a5ca-1a8540644841

 

Response example

This is what the response looks like when the request to execute the payment is successfully done. The response contains the payment id and the current status of the payment.

HTTP/1.1 200 Created
{
"paymentId": "58cdfef9-7f6e-476e-a1af-c54c0a9a3135",
"transactionStatus": "ACCC",
}

Parameter Description Example
paymentId The payment-id that was created in Step 2. "58cdfef9-7f6e-476e-a1af-c54c0a9a3135"
transactionStatus The status of the payment. "ACCC"
"ACCP"
"ACSC"
"RJCT"

Note that execution of payments in the sandbox always will be successful. That is, you will never get a payment that will be rejected.

 


Step 5: Get payment status

To find out if a payment has been executed successfully, you can check its status.

Please note: The "Authorization" HTTP-header accepts either the CCG token from Step 1 or the ACG/DG token from Step 3. 

Request example

curl -X GET https://sandbox.handelsbanken.com/openbanking/psd2/v1/payments/swedish-domestic-giro-payment/PAYMENT ID/status \
-H 'X-IBM-Client-Id: YOUR CLIENT ID' \
-H 'Authorization: Bearer CCG, ACG OR DG TOKEN RECEIVED IN PREVIOUS STEP' \
-H 'Accept: application/json' \
-H 'Country: SE/FI/NL' \
-H 'TPP-Request-ID: YOUR OWN CHOICE' \
-H 'TPP-Transaction-ID: YOUR OWN CHOICE' \

See below for the type of information that needs to be in your request. 

Parameter Description Example
paymentproduct Payment product identifier.
Mandatory.
swedish-domestic-giro-payment
swedish-domestic-credit-transfer
british-domestic-credit-transfer
sepa-credit-transfer
cross-currency-credit-transfer
paymentId The payment-id that was created in previous step.
Mandatory.
58cdfef9-7f6e-476e-a1af-c54c0a9a3135
X-IBM-Client-Id The client_id (app-id) for your test app which we said you should note down earlier.
Mandatory.
f31b7318-8f21-4eaf-8817-6b5e4e02d6bc
Authorization The CCG token from Step 1 or the ACG/DG access token from Step 3.
Mandatory.
Bearer QVQ6MGQ2YmYtMmZjOC00Yzg3LzYyOGU0NTg5YmM3
Country ISO 3166-1 country code
Mandatory.
SE, FI, NL (one country per request)
TPP-Request-ID Unique identifier for the request.
For Sandbox testing, you can make this up.
Mandatory.
c8271b81-4229-5a1f-bf9c-758f11c1f5b1
TPP-Transaction-ID Unique identifier for the request.
For Sandbox testing, you can make this up.
Mandatory.
6b24ce42-237f-4303-a917-cf778e5013d6

Response example

This is what the response looks like when you retrieve a payment's status. The response contains the current status of the payment.

HTTP/1.1 200 Created
{
"paymentId": "58cdfef9-7f6e-476e-a1af-c54c0a9a3135",
"transactionStatus": "ACCC",
}
Parameter Description Example
paymentId The payment-id that was created in Step 2. 58cdfef9-7f6e-476e-a1af-c54c0a9a3135
transactionStatus The current status of the payment. "ACCP"
"RJCT"
"ACCC"