Tutorial
How the Payment Initiation (PSD2) API works
Single payments:
- Register a payment.
- Request single payment consent from the BUUT account holder through the consent application.
- Execute the payment.
The consent application
The consent application is used to obtain consent from an BUUT account holder, and grant you with third-party access to execute a registered payment, or to access account information on behalf of the account holder. This is a so-called redirect. In the consent application, the BUUT client can review the payment details that were registered by you and authorize the payment.
The account holder consent process consists of three steps:
- Authenticate.
- Check the requested access to an account.
- Confirm and redirect back to 3rd party.
All payment initiation consents provide one time access to execute a payment and perform one available balance check. Consent is given using the consent application BUUT Mobile Banking app.
The BUUT client can either authorize or cancel the requested authorization.
Notes:
- For details on how to access the consent application through the OAuth server
- If an account owner is not authorized on the account number in the registered payment, they can select a different account number for which they are authorized.
- The consent application uses Strong Customer Authentication (SCA).This completes the consent. The process now continues with the technical redirect.
- When the debit account is prefilled in the pre-registered payment the user cannot change this later.
Authorization Code
The consent application is visible to the account owner only. It provides you with an access code for the requested authorization using an OAUTH 2.0 authorization code process.
Authorization is a grant on an account for one or multiple scopes. For more information, see Authorization Code.
Scopes in the authorization code process
A scope defines the type of access. For payments there are write, read, and delete scopes. Here are some rules on how scopes can be combined in the authorization code:
- Write scopes can be combined with read scopes.
- Scopes for different products cannot be combined.
- Write scopes cannot be combined with write scopes.
- Delete scopes cannot be combined with other scopes.
Scopes are as follows
- "buut:payment:sepa:read",
- "buut:payment:sepa:write",
Error messages
The following table describes consent application error scenarios. The error message is returned as parameter in the URL.
| Error message | Explanation |
|---|---|
| error=access_denied# | No current accounts are available to authorize or user declined authorization. |
An account holder may report an incident where they see the following error message in their browser, or application: "The page you are trying to access is no longer available". In this scenario, no redirect is occurring, this error message is visible to the user only, and occurs when consent flow is restarted manually. For example, by using the refresh button.
Generic information
- There is no duplicate check on any of the payment methods.
- A response is always sent. Ensure that your application does not time-out.
- If a 5xx or time-out occurs, it cannot be assumed the payment failed:
- If a POST operation fails, the payment can be safely posted again.
- If reposting, avoid using short retry periods to keep out of rate limiting scenarios.
Character set
The following character set can be used for SEPA single.
| Character set |
|---|
| space |
| ! & ' ( ) + - . / 0 1 2 3 4 5 6 7 8 9 : ? _ ` , |
| aAbBcCdDeEfFgGhHiljJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ |
| àÀáÁâÂãÃäÄåÅæÆçÇèÈéÉêÊëËìÌíÍîÎïÏðÐñÑòÒóÓôÔõÕöÖ×øØùÙúÚûÛüÜýÝþÞßÞÿ |
Requirements
To use this API in a production environment, you must have the following:
PSD2 access:
- A PSD2 license for payment initiation.
- An EIDAS certificate.
Open Banking UK access:
- A FCA license for payment initiation.
- An OBWAC certificate with the appropriate license details.
License
To use this API in a production environment, or if you require TPP access to ABN AMRO accounts, you must have a PSD2 license from a local competent authority. In the Netherlands, this is De Nederlandsche Bank (DNB).
Licensing requirements
| API | AISP License | PISP License | Banking License | Payment Instrument Issuing License |
|---|---|---|---|---|
| Payment Initiation (PSD2) | N | Y | Y | N |
EIDAS certificate
BUUT only accepts Qualified Website Authentication Certificates (QWAC) from Qualified Trusted Service Providers (QSTPs) that are on the trusted list with CEF Digital. This certificate is used for identification, and is also required for OAUTH authorization when accessing APIs.
Sandbox access
The sandbox and production API are in function the same with the distinction that the Sandbox contains static data. This static data means that you can perform all operations without making any transactions on an account. Transactions posted in the sandbox are cleaned every day.
To use this API in the sandbox environment, complete the following steps:
- Register and create an account:
- Click Sign up.
- Enter your details, and click Create new account.
- Developer Support will send you an activation link by email.
- Click the activation link.
- Create an register application:
- Log in to your account.
- In the left-side navigation bar, click Apps.
- Click Add app.
- In the App name field, enter a name for your application.
- In the APIs field, select BUUT - Payment Initiation (PSD2), and click Add app.
Sandbox access details
Sandbox URL: https://api-sandbox.abnamro.com/
Sandbox token URL: https://auth-sandbox.abnamro.com/as/token.oauth2/
Use the following credentials for the sandbox:
| Attribute | Value for Sandbox |
|---|---|
| client_id | TPP_test |
| API-Key | The API Key for your app from the Developer Portal |
| redirect_uri | https://localhost/auth |
Note: Redirect URL's in sandbox cannot be modified. For production environment desired URL's can be specified in the setup process.
| Certificate files: |
|---|
| Download public certificate: Download |
| Download private key: Download |
Notes: The sandbox handles functional error scenarios only.
Production access
Important:: To use this API in a production environment, you must have a license. For more information, see Requirements.
To get access to production:
- Log in to your account.
- In the left-side navigation, click Apps.
- Click Request Production Access.
- Select the API category that you want to request production access on. >Note: It is not possible to request production access for multiple API categories in one request.
- Fill in the form, and click Submit.
- You receive a confirmation email and ticket-ID.
- ABN AMRO Developer Support validates the form, and if necessary contacts you.
- When the setup is complete, ABN AMRO Developer Support contacts you and supplies you with a client_id.
- A new App is added in Apps. This new app contains your API key.
Note:: It is not possible for account holders to get API access on their own accounts.
Production access details
Production URL: https://api.abnamro.com/buut/payment-initiation/v1/
Production Token URL: https://security-ifs.nl.eu.abnamro.com/as/token.oauth2/
Use the following credentials for production:
| Attribute | Value for Production |
|---|---|
| client_id | The Client Id for your production app from the Developer Portal |
| API-Key | The API Key for your production app from the Developer Portal |
| redirect_uri | The URLs that you specified in your request access form |
Certificates
| Certificate files: |
|---|
| Certificate file : Your QWAC EIDAS certificate |
| Private key : Your private key |
Payments tutorial
This instruction describes how to connect an application to the Payment Initiation API (PSD2) in the sandbox environment, and execute a single payment.
Note: Before you start this process, you must complete the steps described in Sandbox access.
Note: In the production environment, the PSD2 compliant EIDAS QWAC certificate, production redirect-uri, and production API-Key are used.
Step 1 - Request an access token for payment
This step uses OAUTH2.0 client credentials as an authorization method. When requesting a client credentials access token, you must authenticate yourself as a client using an SSL certificate. In the response, an access token is returned. This token is used to register a payment. For security reasons, the validity of this token is temporary.
Request attributes
You must specify the scope for the operation that is to be authorized. The possible scopes are described in the table below.
Scope is the following:
| Operation | Request for scope |
|---|---|
| POST SEPA payment | "buut:payment:sepa:write" |
Certificates
| Certificate files |
|---|
| Download public certificate: Download |
| Download private key: Download |
Request examples
Request a client credentials access token to register a payment, using one of the following sample requests:
SEPA payment request
curl -X POST https://auth-sandbox.abnamro.com/as/token.oauth2/
-u ‘pablo_tpp_client:password’ \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=client_credentials&client_id=TPP_test&scope=buut:payment:sepa:write'
Sample response
{
"token_type": "Bearer",
"access_token": "X1PTWZre0fnW72l263yrhAWB2FDwx3tg",
"expires_in": 7199
}
Step 2 - Register a payment
Use the access token that you created in Step 1 of this process to register a payment. This payment must be authorized by the account holder using the consent process described in Step 3 of this process.
Sample requests
Register a payment using one of the following sample POST requests:
SEPA payment request
curl -X POST https://api-sandbox.abnamro.com/buut/payment-initiation/v1\
-H 'Accept: application/json' \
-H 'Authorization: Bearer X1PTWZre0fnW72l263yrhAWB2FDwx3tg' \
-H 'tpp-id:pablo_tpp_client’ \
-H 'api-key: X1QTWZre0fnW72l263yrhAWB2FDwx3tg' \
-d '{
"amountInCents": 130,
"creditorIban": "NL75INGB0081123456",
"creditorName": "Bob Marley",
"currency": "EUR",
"debtorIban": "NL77BUUT0016036938",
"debtorName": "Joep Mol",
"description": "Psd2 test",
"initiationMethod": "PSD2",
"paymentRecurrence": "ONCE",
"requestedExecutionDate": "2025-07-19T14:56:05Z",
"transactionType": "SEPA_CT"
}'
For more information, see the POST payments operation.
Note: You must store the transactionId. It is used to check the account holder authorization and to execute the authorized payment.
Step 3 – Confirm the payment
For production and sandbox both we only have the possibility to initiate the payment. The confirmation of payment can be done via the BUUT-app, only by the account-holder. This is also where the user authorizes the payment.
Note: A redirectURL & transactionId is needed to execute a payment. This is obtained in the previous step.
The user needs to use the redirectUrl, along with the following query-params, to be redirected to the BUUT app, and authorise the payment.
- resumePath : the resume path where the user should be redirected to
- scope: buut:payments:sepa:write
- transactionId: from the previous call
- clientId: the clientId configured while onboarding
Example of redirect url looks like this:
https://api-sandbox.abnamro.com/psd/pis/qr?resumePath={resumePath}&scope={scope}&transaction_id={transaction_id}&client_id={client_id}
Third-parties cannot execute the payment, only the BUUT users can.
Additional operations
Check payment status
The status of the transaction initiated can be viewed using the Account Information API.
Account Information (see other API) scopes for BUUT are as follows:
| Action | Request for scope |
|---|---|
| Read details of account (such as address) | "buut:account:details:read" |
| Read the transactions and/or activities on an account | "buut:account:transaction:read" |
| Read the balance of account | "buut:account:balance:read" |
| Check availability of funds on an account | "buut:account:funds:read" |
Sample request
{
"iban": "NL12BUUT9999876523",
"transactionId": 8932710937381,
"scopes": "buut:account:transaction:read",
"valid": "1525691979"
}
Sample response
{
"accountNumber": "NL62ABNA9999841479",
"transactionId": "8338L5812304793S0PD",
"status": "COMPLETED"
}
Response statuses:
- StatusProcessing = "Processing"
- StatusPending = "Pending" //recurring/scheduled
- StatusCompleted = "Completed"
- StatusConfirmed = "CONFIRMED"
- StatusError = "Error"
- StatusRejected = "Rejected"
The status of a successful payment is "COMPLETED". For a rejected payment, the status is "REJECTED". In exceptional cases, it may take several seconds for the initial intermediate status "PROCESSING" to be updated. If due to other issues, transaction cannot be executed, the status of such a transaction is ÉRROR”.
Cancel payments
To cancel a released payment that has a future execution date, use one of the following samples.
Sample SEPA payment request
A future-dated SEPA payment can be cancelled using the transactionId and access_token. Using the following sample request, execute the registered request using the DELETE operation:
curl -X DELETE https://api-sandbox.abnamro.com/v1/payments/8338L5812304793S0PD \
-v \
-H 'API-Key: X1QTWZre0fnW72l263yrhAWB2FDwx3tg' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer {your_access_token}'
For more information, see the DELETE SEPA payment operation.
Sample request to cancel a SEPA standing order payment
A scheduled SEPA standing order payment can be cancelled using the transactionId and access_token.
curl -X DELETE https://api-sandbox.abnamro.com/v1/payments/standingorder/8338L5812304793S0PD \
-v \
-H 'API-Key: X1QTWZre0fnW72l263yrhAWB2FDwx3tg' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer GPgYglX4sO1WhzfChx4tmjr4y7Qg'
-H 'Content-Length= 0'
For more information, see the DELETE standing order operation.
Payments can be also cancelled by the account holder using Mobile App
Refresh an access token
When the short-lived access_token, received in Step 4, expires, the long-lived refresh_token can be used to get a new access_token and a new refresh_token. This renders the used refresh token as invalid.
Sample request
curl -X POST https://auth-mtls-sandbox.abnamro.com/as/token.oauth2 \
-v \
--cert TPPCertificate.crt \
--key TPPprivateKey.key \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=refresh_token&client_id=TPP_test&refresh_token=UHjIAzBZfLGh4dLm8cvEcH6d8BrOmCZXumOpznQBP1&scope=psd2:payment:sepa:write+psd2:payment:sepa:read'
Sample response
{
"access_token": "{mkwAngBIJtlL9TxxNhECHV4LaBBt}",
"refresh_token": "{nLlBcohGqcAvs2iyQ4SAdenC5moqRh9y3NifBR3j04}",
"token_type": "Bearer",
"expires_in": 7193
}
Store the access_token to access the payment API, and the refresh_token to request a new access_token when it expires.
Need help?