TECHNICAL DOCUMENTATION

Picture

Notes

In this document the IBAN and BIC codes are intentionally replaced with technically invalid placeholders. The PSD2 implementation will return valid values.

If this document conflicts with the Berlin Group Implementation Guideline v1.3, the Berlin Group Implementation Guideline v1.3 should be followed, unless otherwise specified.

Consents

Create Consent

POST /v2/consents

The following JSON document creates a consent request for account and account balance information access. The accounts to which the PSU eventually grants access is negotiated between the PSU and the ASPSP. The status of the account access negotiation can be obtained with "Get Consent Status" and the full consent information with "Get Consent".

While the Berlin Group API knows access qualifiers "allPsd2" and "allAccounts", those can not be used in the Samlink PSD2 API implementation. The account access is always negotiated between the PSU and the ASPSP. If the "validUntil" date is further than 180 days in the future, the PSD2 implementation will adjust it to 180 days. Therefore it is ok to use date 9999-01-01 for consents of maximum duration. Likewise if the "frequencyPerDay" value is greater than 4 it will be adjusted to 4. If "recurringIndicator" is "false" the "frequencyPerDay" must be "1".

The following request creates a recurring consent with maximum validity period for account information and balance information for unspecified acounts. The accounts to which the consent is granted are filled in if the PSU confirms the consent.

{
"access": {
"accounts": [],
"balances": []
},
"combinedServiceIndicator": false,
"frequencyPerDay": 4,
"recurringIndicator": true,
"validUntil": "9999-01-01"
}

The response will contain the consent status, ID and links to the authentication service in which the account access negotiation between the PSU and the ASPSP will take place.

{
"consentStatus": "received",
"consentId": "a2753a17-b39d-4bfc-8ffd-44a04a735bf2",
"_links": {
"scaOAuth": "https://example.com/auth/",
"self": "/psd2/v2/consents/a2753a17-b39d-4bfc-8ffd-44a04a735bf2",
"status": "/psd2/v2/consents/a2753a17-b39d-4bfc-8ffd-44a04a735bf2/status"
}
}

Note: Calling Get Consent Status or Get Consent before the PSU has returned from the OAuth2 flow causes the consent to be cached, which adds a delay before changes to the consent become visible to the TPP.

Get Consent Status

GET /v2/consents/{consentId}/status

Get Consent Status does not contain a request body. The response will only contain the current status of the consent.

{
"consentStatus": "received"
}

Get Consent

GET /v2/consents/{consentId}

Get Consent does not contain a request body. The response will contain complete consent information.

{
"access": {
"accounts": [ {
"iban": "FI0000000000000000",
"resourceId": "e8f816f3-14d3-42a2-a440-f41613f16255"
}, {
"iban": "FI0000000000000001",
"resourceId": "addac7ad-6c5e-40c0-a7ae-2787ce3faf38"
} ],
"balances": [ {
"iban": "FI0000000000000000",
"resourceId": "e8f816f3-14d3-42a2-a440-f41613f16255"
}, {
"iban": "FI0000000000000001",
"resourceId": "addac7ad-6c5e-40c0-a7ae-2787ce3faf38"
} ]
},
"recurringIndicator": true,
"validUntil": "2019-03-19",
"frequencyPerDay": 4,
"lastActionDate": "2018-12-19",
"consentStatus": "valid"
}

Delete Consent

DELETE /v2/consents/{consentId}

Delete Consent does not contain a request or respose body. HTTP response status code 200 is returned if the consent is successfully deleted. It's status will be "terminatedByTpp" and it can no longer be used to access account information. The consent can be accessed via Get Consent and Get Consent Status until maintenance operations remove it from the database.

Accounts

Account operations are governed by the daily consent use restrictions. When the PSU is actively using the TPP service, the IP address from which the PSU accesses the TPP service shall be included in the PSU-IP-Address header. This information is used to determine whether the daily consent use restrictions are applied or not. When the PSU is not actively using the TPP service, the TPP is restricted to no more than 4 requests per day (unless a lower frequencyPerDay value was specified during the consent creation).

PSU-IP-Address: 172.217.21.163

List Accounts

GET /v2/accounts

List Accounts does not contain a request body. The response will contain basic account information for all accounts allowed by the consent specified in the Consent-ID header. The example shows accounts in a consent that grants access to basic account informations and account balance information. Had the consent also been granted to transaction information, the _links section would contain a link to the transactions-endpoint.

The "withBalance" URL parameter is supported and requires the consent to have balance permissions.

{
"accounts": [ {
"resourceId": "e8f816f3-14d3-42a2-a440-f41613f16255",
"iban": "FI0000000000000000",
"currency": "EUR",
"name": "CURRENT ACCOUNT",
"cashAccountType": "CASH",
"status": "enabled",
"bic": "ABCDEFGH",
"_links": {
"balances": "/v2/accounts/e8f816f3-14d3-42a2-a440-f41613f16255/balances",
}
}, {
"resourceId": "addac7ad-6c5e-40c0-a7ae-2787ce3faf38",
"iban": "FI0000000000000001",
"currency": "EUR",
"name": "MY SAVINGS ACCOUNT",
"cashAccountType": "CASH",
"status": "enabled",
"bic": "ABCDEFGH",
"_links": {
"balances": "/v2/accounts/addac7ad-6c5e-40c0-a7ae-2787ce3faf38/balances",
}
} ]
}

The fields returned from list accounts are:

  • resourceId: Identifier of the account in PSD2 AIS API

  • iban: Account number in IBAN format

  • currency: Account currency

  • name: Name given to account by PSU

  • cashAccountType: Account type

  • status: Account status

  • bic: BIC associated to the account

  • _links/balances: Link to account balance (if balance premission was granted in the consent)

  • _links/transactions: Link to account transactions (if transaction premission was granted in the consent)

Read Account Details

GET /v2/accounts/{resourceId}

Read Accounts Details does not contain a request body. The response will contain account information for the account specified in the URL path. The resource ID of the account must be of one of the accounts in the consent specified in the Consent-ID header.

{
"resourceId": "7bf3a0f4-db88-4d4d-9d23-8a59c2724b4f",
"iban": "FI0000000000000003",
"currency": "EUR",
"cashAccountType": "CASH",
"status": "enabled",
"bic": "ABCDEFGH",
"ownerName": "TEST USER3"
"_links": {
"balances": "/v2/accounts/7bf3a0f4-db88-4d4d-9d23-8a59c2724b4f/balances",
"transactions": "/v2/accounts/7bf3a0f4-db88-4d4d-9d23-8a59c2724b4f/transactions"
}
}

The fields returned from read accounts details are:

  • resourceId: Identifier of the account in PSD2 AIS API

  • iban: Account number in IBAN format

  • currency: Account currency

  • product: Product name of account

  • cashAccountType: Account type

  • status: Account status

  • bic: BIC associated to the account

  • ownerName: Account owners in a comma-delimited string

  • _links/balances: Link to account balance (if balance premission was granted in the consent)

  • _links/transactions: Link to account transactions (if transaction premission was granted in the consent)

Read Balance

GET /v2/accounts/{resourceId}/balances

Read Balance does not contain a request body. The response will contain balance information for the account specified in the URL path. The resource ID of the account must be of one of the accounts in the consent specified in the Consent-ID header and the consent must grant access to balances for the specified account.

{
"account": {
"iban": "FI0000000000000003"
},
"balances": [ {
"balanceAmount": {
"currency": "EUR",
"amount": "48115.40"
},
"balanceType": "forwardAvailable",
"lastChangeDateTime": "2018-12-05T00:00:00Z",
"referenceDate": "2018-12-05"
} ]
}

The fields returned from read balance are:

  • account/iban: Account number in IBAN format

  • balances/balanceAmount/currency: Account currency

  • balances/balanceAmount/amount: Account balance amount

  • balances/balanceType: Always "forardAvailable"

  • balances/referenceDate: Reference date of the balance

Read Transaction List

GET /v2/accounts/{resourceId}/transactions/?bookingStatus={bookingStatus}

Read Transaction List does not contain a request body. The response will contain transactions for the account specified in the URL path. The resource ID of the account must be of one of the accounts in the consent specified in the Consent-ID header and the consent must grant access to transactions for the specified account. Booked transactions are retrieved with bookingStatus parameter "booked". Pending transactions are retrieved with bookingStatus parameter "pending". The bookingStatus parameter "both" is not supported.

For booked transactions, if no other URL parameters are specified, the response contains 10 latest transactions. To get next 100 transactions the entryReference of the last transaction in the list shall be given in the entryReferenceFrom parameter. To get all transactions between a date interval, both dateFrom and dateTo must be given. The entryReferenceFrom parameter can not be used with the date interval parameters. The pending transaction listing does not support paging or date interval searching. All pending transactions are always returned in one response. Booked transactions will be returned in groups of 100 and subsequent searches must be made with the appropriate entryreference key. When the 'relevantEntryreference' value is null, no more transactions can be found.

If the entryReference query parameter is provided, the query will not count towards the consent usage limit.

Transaction list can be queried for transactions starting from the beginning of month 12 months ago in history. This is possible only for a limited time period (5 minutes) immediately after the consent has been confirmed. Afterwards, only up to 90 days old transactions are returned

A sample response for booked transaction query with no search parameters (the list is truncated to two transactions for brevity):

{
"account": {
"iban": "FI0000000000000003"
},
"relevantEntryreference": "000000000001016"
"transactions": {
"booked": [
{
"entryReference": "000000000001017",
"bookingDate": "2018-12-05",
"transactionAmount": {
"currency": "EUR",
"amount": "-50.00"
},
"creditorName": "JANE DOE"
}, {
"entryReference": "000000000001016",
"bookingDate": "2018-11-14",
"transactionAmount": {
"currency": "EUR",
"amount": "5.59"
},
"debtorName": "JOHN DOE"
"_links": {
"account": "/psd2/v2/accounts/7bf3a0f4-db88-4d4d-9d23-8a59c2724b4f"
}
}
}

A sample response for pending transaction query:

{
"account": {
"iban": "FI0000000000000003"
},
"transactions": {
"pending": [
{
"valueDate": "2018-09-10",
"transactionAmount": {
"currency": "EUR",
"amount": "50.00"
},
"creditorName": "JOHN DOE",
"debtorAccount": {
"iban": "FI0000000000000003"
}
}, {
"valueDate": "2038-12-22",
"transactionAmount": {
"currency": "EUR",
"amount": "1.00"
},
"creditorName": "JANE DOE",
"creditorAccount": {
"iban": "SE0000000000000001"
},
"debtorAccount": {
"iban": "FI0000000000000003"
}
}
]
}
}

Cards

Card operations are governed by the same daily consent use restrictions as Account operations.

List Cards

GET /v2/card-accounts

List Cards does not contain a request body. The response will contain all available card information for all cards allowed by the consent specified in the Consent-ID header. The example shows cards in a consent that grants access to basic card informations, card balance information and card transaction information.

The "withBalance" URL parameter is not supported as balances are always returned if the consent grants access to them.

{
"cardAccounts":": [ {
"resourceId": "6168d6ff-acf8-49c6-b38b-98aeff29d7df",
"maskedPan": "100000XXXXXX0000",
"currency": "EUR",
"product": "Visa Credit/Debit",
"status": "enabled",
"creditLimit": { "currency": "EUR", "amount": 1500.00 },
"balances": [
{
"balanceType": "interimAvailable",
"balanceAmount": { "currency": "EUR", "amount": "1435.78" }
},
{
"balanceType": "interimBooked",
"balanceAmount": { "currency": "EUR", "amount": "532.99" }
}
],
"_links": {
"transactions": "/v2/card-accounts/6168d6ff-acf8-49c6-b38b-98aeff29d7df/transactions"
}
} ]
}

Read Card Transaction List

GET /v2/card-accounts/{resourceId}/transactions/?bookingStatus={bookingStatus}&dateFrom={dateFrom}&dateTo={dateTo}

Read Card Transaction List does not contain a request body. The response will contain transactions for the card account specified in the URL path. The resource ID of the card account must be of one of the card accounts in the consent specified in the Consent-ID header and the consent must grant access to transactions for the specified card account. Booked transactions are retrieved with bookingStatus parameter "booked". Pending transactions are retrieved with bookingStatus parameter "pending". Both booked and pending transactions are retrieved with bookingStatus parameter "both".

To get transactions between a date interval, both dateFrom and dateTo must be given. DateFrom is mandatory. If no dateTo is specified, the response contains transactions until the current date. Regardless of the values provided in dateFrom and dateTo, the operation does not return transactions older than three months.

{
"cardAccount": {
"maskedPan": "100000XXXXXX0000",
},
"cardTransactions": {
"booked": [ {
"cardTransactionId": "0000453",
"transactionDate": "2019-12-03",
"bookingDate": "2019-12-03",
"transactionAmount": { "currency": "EUR", "amount": "15.00" },
"cardAcceptorAddress": {
"city" : "STOCKHOLM",
"country" : "SE"
},
"merchantCategoryCode": "5812",
"maskedPAN": "100000XXXXXX0000",
"transactionDetails": "Client Account Transfer VISA-TILISIIRTO",
"invoiced": false
} ],
"pending": [ {
"cardTransactionId": "201710020036959",
"transactionDate": "2019-12-03",
"transactionAmount": { "currency": "EUR", "amount": "14.24" },
"originalAmount": { "currency": "SEK", "amount": "150.00" },
"cardAcceptorAddress": {
"city" : "STOCKHOLM",
"country" : "SE"
},
"merchantCategoryCode": "2399",
"maskedPAN": "100000XXXXXX0000",
"transactionDetails": "WIFIMARKET.SE",
"invoiced": false
} ],
"_links": {
"cardAccount": "/v2/card-accounts/3d9a81b3-a47d-4130-8765-a9c0ff861b99"
}
}
}

Payments

Payment information and payment status request endpoints are shared by single and periodic payments. The payment-product URL path component defines whether the payment in question is a single payment (payments) or a periodic payment (periodic-payments).

Payment Initiation Request (Single SEPA payment)

POST /v1/payments/sepa-credit-transfers

The following JSON document contains the minimum set of fields for creating a SEPA payment initiation request for a payment that, once confirmed, will be paid without any additional delay. While the creditorAccount object allows both "iban" and "bban" fields and the creditorAgent allows both IBAN and clearing code formats, SEPA payments can only be made with an IBAN and a BIC.

Either the endToEndIdentification or remittanceInformationUnstructured must be provided. The endToEndIdentification will be used as the payment reference number and it can be either a domestic 20-digit reference number or a 25-character Creditor Reference. The remittanceInformationUnstructured will be used as the payment message.

The creditorAgent fields is optional.

{
"creditorAccount": {
"iban": "FI0000000000000004"
},
"creditorAgent": "ABCDEFGH",
"creditorName": "JANE DOE",
"debtorAccount": {
"iban": FI0000000000000003"
},
"instructedAmount": {
"amount": 50.0,
"currency": "EUR"
},
"remittanceInformationUnstructured": "PAYMENT TO JANE",
"endToEndIdentification": "12345 67890 12345 67904"
}

DebtorAccount field is now optional - in this alternative flow, PSU will choose an account during the payment authorization process. TPP may then retrieve the debtor account with Get Payment Information after payment authorization. Sample request without debtorAccount:

{
"creditorAccount": {
"iban": "FI0000000000000004"
},
"creditorAgent": "ABCDEFGH",
"creditorName": "JANE DOE",
"instructedAmount": {
"amount": 50.0,
"currency": "EUR"
},
"remittanceInformationUnstructured": "PAYMENT TO JANE",
"endToEndIdentification": "12345 67890 12345 67904"
}

A sample response for payment initiation.

{
"transactionStatus": "RCVD",
"paymentId": "b3763c20-6e99-4e3d-9af6-6443eccb6c79",
"transactionFeeIndicator": false,
"_links": {
"scaOAuth": "https://example.com/auth/",
"self": "/psd2/v1/payments/sepa-credit-transfers",
"status": "/psd2/v1/payments/b3763c20-6e99-4e3d-9af6-6443eccb6c79/status"
}
}

A future dated payment can be initiated by including the "requestedExecutionDate" field. The requested execution date must be at least one day and no more than five years in the future.

{
"requestedExecutionDate": "2025-01-09",
"creditorAccount": {
"iban": "FI0000000000000004"
},
"creditorAgent": "ABCDEFGH",
"creditorName": "JANE DOE",
"debtorAccount": {
"iban": FI0000000000000003"
},
"instructedAmount": {
"amount": 50.0,
"currency": "EUR"
},
"remittanceInformationUnstructured": "PAYMENT TO JANE",
"endToEndIdentification": "12345 67890 12345 67904"
}

Payment Initiation Request (Single foreign payment)

POST /v1/payments/cross-border-credit-transfers

The following JSON document contains the fields for creating a foreign payment initiation request. The "creditorAccount" can be specified with either an "iban" or "bban" field and the "creditorAgent" value can be either a BIC or a clearing code. Foreign payments can not be initiated as future dated payments.

The "creditorAddress" field must contain at least "country", "street" and "postalCode" values.

DebtorAccount field is now optional - in this alternative flow, PSU will choose an account during the payment authorization process. TPP may then retrieve the debtor account with Get Payment Information after payment authorization.

{
"creditorAccount": {
"bban": "1234567890123456"
},
"creditorAgent": "FW123456789",
"creditorName": "JANE DOE",
"creditorAddress": {
"street": "Street Name",
"buildingNumber": "10",
"city": "City Name",
"postalCode": "12345",
"country": "US"
},
"debtorAccount": {
"iban": "FI0000000000000003"
},
"instructedAmount": {
"amount": 50.00,
"currency": "USD"
},
"remittanceInformationUnstructured": "PAYMENT TO JANE"
}

The response is identical to that of single SEPA payment initiation, except for the _links-section, which points to the corresponding payment-service and payment-product.

Payment Initiation Request (Periodic)

POST /v1/periodic-payments/sepa-credit-transfers

The following JSON document contains the fields for creating a periodic payment initiation request on the fifth day of each month starting on 2019-03-05 and ending on 2019-12-31. While the creditorAccount object allows both "iban" and "bban" fields and the creditorAgent allows both IBAN and clearing code formats, periodic payments can only be made as SEPA payments, thus the fields can only contain an IBAN and a BIC and the same restrictions on endToEndIdentification and remittanceInformationUnstructured apply.

DebtorAccount field is now optional - in this alternative flow, PSU will choose an account during the payment authorization process. TPP may then retrieve the debtor account with Get Payment Information after payment authorization.

{
"creditorAccount": {
"iban": "FI0000000000000004"
},
"creditorAgent": "ABCDEFGH",
"creditorName": "JANE DOE",
"debtorAccount": {
"iban": "FI0000000000000003"
},
"remittanceInformationUnstructured": "MONTHLY PAYMENT TO JANE",
"startDate": "2019-03-05",
"endDate": "2019-12-31",
"frequency": "Monthly",
"instructedAmount": {
"amount": 50.0,
"currency": "EUR"
}
}

The executionRule and dayOfExecution fields can only be used when creating a periodic payment on last bank day of month. The fields must then have values "preceeding" and "31" and the frequency must be "Monthly" (i.e. on the last day of the month, but before any bank holidays):

{
"creditorAccount": {
"iban": "FI0000000000000004"
},
"creditorAgent": "ABCDEFGH",
"creditorName": "JANE DOE",
"debtorAccount": {
"iban": "FI0000000000000003"
},
"remittanceInformationUnstructured": "LAST BANK DAY OF MONTH PAYMENT",
"startDate": "2019-03-30",
"endDate": "2019-12-31",
"frequency": "Monthly",
"executionRule": "preceeding",
"dayOfExecution": "31",
"instructedAmount": {
"amount": 50.0,
"currency": "EUR"
}
}

The response is identical to that of single SEPA payment initiation, except for the _links-section, which points to the corresponding payment-service and payment-product.

Get Payment Information

GET /v1/{payment-service}/{payment-product}/{paymentId}

Get payment information request does not contain a request body. The response will contain information of a specific payment identified by the payment ID.

A sample response for payment information.

{
"endToEndIdentification": null,
"debtorAccount": {
"iban": "FI0000000000000003"
},
"debtorName": "JOHN DOE",
"instructedAmount": {
"currency": "USD",
"amount": "50.00"
},
"creditorAccount": {
"bban": "471900-15514"
},
"creditorAgent": "FW123456789",
"creditorName": "JANE DOE",
"creditorAddress": {
"street": "Street Name",
"buildingNumber": "10",
"city": "City Name",
"postalCode": "12345",
"country": "US"
},
"remittanceInformationUnstructured": "PAYMENT TO JANE",
"transactionStatus": "RCVD"
}

Payment Initiation Status Request

GET /v1/{payment-service}/{payment-product}/{paymentId}/status

Payment initiation status request does not contain a request body.

The response is simply the status of the payment:

{
"transactionStatus": "RCVD"
}

Supported payments statuses are

  • RCVD: Payment initiation request has been received and passed initial technical checks.

  • ACTC: Payment has been accepted by PSU and passed initial technical checks.

  • PDNG: Payment pending. Send Payment Initiation Status Request later again to see the final status of the payment.

  • ACFC: The availability of the funds on the PSU's account has been checked positively. Payment is in progress, but status is not final. Send Payment Initiation Status Request later again to see the final status of the payment. Status code is used only by Savings Banks and Oma Savings Banks for payments, that are tried to be processed to payee as SEPA Instant Payments, but the final status for the payment is not yet confirmed.

  • ACSC: Payment has been processed. This is the final status for all single payments

  • ACSP: Payment has been processed. The final state of periodic SEPA payments.

  • RJCT: Payment processing failed.

  • CANC: Payment has been cancelled (applies only to periodic SEPA payments).

Note! SEPA instant payments are used only for Oma Savings Bank and Savings Banks.

Payment Cancellation Request

DELETE /v1/periodic-payments/sepa-credit-transfers/{paymentId}

Payment cancellations can only be performed on periodic SEPA credit transfers. A successful cancellation will cancel all subsequent payments of the periodic payment instance that have not been sent to payment service for processing. Payment Cancellation Request does not contain a request body. The response will contain an HTTP status code 200 and the status of the payment (CANC). If a periodic payment can not be cancelled, HTTP status code 405 is returned.

A sample response for payment cancellation request:

{
"transactionStatus": "CANC"
}

Confirmation Of Funds

Confirmation Of Funds Request

POST /v2/funds-confirmations

The following request performs a confirmation of funds request for 40.00EUR to a specified account. While the account object allows "iban", "bban", "currency", "maskedPan", "msisdn" and "pan" fields , confirmation of funds requests can only be made with an IBAN. All other fields in the account object, as well as the "cardNumber" and "payee" fields, are ignored.

{
"account": {
"iban": "FI0000000000000003"
},
"instructedAmount": {
"amount": 40.00,
"currency": "EUR"
}
}

The response only tells whether or not the account has funds for the requested amount.

{
"fundsAvailable": true
}

TPP Registration API

TPP registration API is not a part of the Berlin Group PSD2 API specification.

Signing

All messages sent to TPP registration API must be signed using a valid QSEAL certificate. Message signing is performed in similar manner with the Samlink PSD2 API. Specification for the HTTP message signing can be found in Berlin Group Implementation Guideline v1.3 (chapter 12) with the following restrictions.

Mandatory headers are

  • Digest: SHA-256 or SHA-512 digest of the message content, as specified by Berlin Group Implementation Guideline.

  • X-Request-ID: UUID, as specified by Berlin Group Implementation Guideline.

  • TPP-Redirect-URI: only in TPP registration, as specified by Berlin Group Implementation Guideline.

  • TPP-Signature-Certificate: TPP's eIDAS QSEAL certificate, as specified by Berlin Group Implementation Guideline.

  • Signature: as specified by Berlin Group Implementation Guideline (chapter 12.2), constructed from headers Digest, X-Request-ID and TPP-Redirect-URI.

TPP-Redirect-URI is recorded during TPP registration. Subsequent calls to Samlink PSD2 API, where the TPP-Redirect-URI header is required, must match the recorded value (see Berlin Group Implementation Guideline).

Encryption

All communication between the client and the TPP registration API must be encrypted using TLS.

TPP Registration Request

PUT /tpp-registration/v1/tpp/{TPP-Global-URN}?ForceNewApiKey={boolean}

The following JSON document, along with the aforementioned HTTP headers, registers the short name and OAuth2 redirect URI of an AIS and/or PIS, identified by the TPP-Global-URN parameter, to Samlink PSD2 API. TPP-Global-URN parameter is the OrganizationIdentifier from your eIDAS certificate without PSD-prefix, e.g. "FI-ABC-12345". Short name is the name that is shown to the PSU during during payment and consent confirmation. It's maximum length is 35 characters and it is mandatory.

If you wish to register more than one OAuth2 redirect URI, you can use the optional additionalRedirectURIs field to provide them in your registration.

{
"shortName": "Royal Bank Of Scotland"
"additionalRedirectURIs": ["https://www.example.com", "https://developer.samlink.fi"]
}

A registration request can be sent multiple times. A new API key will be registered on the first request or if the ForceNewApiKey query parameter is true. The currently registered API key is returned in the success-response.

The response to the successful registration contains the API key that AIS and/or PIS uses to gain access to the Samlink PSD2 API.

{
"success": "true",
"message": "OK",
"apiKey": "c144bf8e-4c9a-4095-95db-efeef823f450",
"newApiKeyCreated": "true"
}

If the newApiKeyCreated parameter is "false" the value returned in apiKey is the key that was generated in the last successful registration request.

Errors are returned with the same data structure as the success response. HTTP status code is either 400 or 500, the "success" parameter is "false" and the "message" parameter contains a human readable error message.

{
"success": "false",
"message": "TPP certificate encoding error"
}

Example

PUT /tpp-registration/v1/tpp/FI-ABC-123456 HTTP/1.1
Host: psd2.example.com
Date: Thu, 6 Jun 2019 11:22:31 GMT
X-Request-ID: 6ad53b20-c4d8-4b5a-b2d8-fe29a3a24519
Digest: SHA-256=rCC59Xpw9DdFCB+VUT2yzGWgkZfJJoo1NJv4mQQxv0w
TPP-Signature-Certificate: [TPP's eIDAS certificate]
TPP-Redirect-URI: https://example.com/oauth/redirect
Signature: keyId="SN=00f3abe28bee1e8f10,CA=OID.1.2.840.113549.1.9.1=info@eidasca.org,CN=eIDAS Issuer CA,O=CA Org,C=FI",algorithm="rsa-sha256", \
headers="Digest X-Request-ID TPP-Redirect-URI", \
signature="Base64(RSA-SHA256(signing string))"
Content-Type: application/json

{
"shortName": "Royal Bank Of Scotland"
}

Certificate Registration Request

POST /tpp-registration/v1/certificate

Certificates are registered in a separate step after TPP registration. The certificate registration request does not contain a body. All information required in the request is contained in the HTTP request signature.

Example

POST /tpp-registration/v1/certificate HTTP/1.1
Host: psd2.example.com
Date: Thu, 6 Jun 2019 11:22:31 GMT
X-Request-ID: 6ad53b20-c4d8-4b5a-b2d8-fe29a3a24519
Digest: SHA-256=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=
TPP-Signature-Certificate: [TPP's eIDAS certificate]
Signature: keyId="SN=00f3abe28bee1e8f10,CA=OID.1.2.840.113549.1.9.1=info@eidasca.org,CN=eIDAS Issuer CA,O=CA Org,C=FI",algorithm="rsa-sha256", \
headers="Digest X-Request-ID", \
signature="Base64(RSA-SHA256(signing string))"
Content-Length: 0

List Certificates Request

GET /tpp-registration/v1/certificate

Returns list of all certificates registered by the TPP. The list certificate request does not contain a body. All information required in the request is contained in the HTTP request signature. The response contains the certificate identifier within the TPP registration service, certificate serial number and status.

{
"certificates": [
{
"certificateId": "7c990b13-e9ec-4a89-9543-c046a231618f",
"serialNumber": "1234567890",
"status": "revoked"
}
],
"message": "OK",
"success": true
}

Delete Certificate Request

DELETE /tpp-registration/v1/certificate/{CertificateId}

Deletes a certificate permanently. The deleted certificate can no longer be used in Samlink PSD2 API. The certificate is identified by the certificateId, which is returned in the list certificates response. The delete certificate request does not contain a body. All information required in the request is contained in the HTTP request signature. The response contains the result as in TPP registration.

{
"success": "true",
"message": "OK"
}

Example

DELETE /tpp-registration/v1/certificate/7c990b13-e9ec-4a89-9543-c046a231618f HTTP/1.1
Host: psd2.example.com
Date: Thu, 6 Jun 2019 11:22:31 GMT
X-Request-ID: 6ad53b20-c4d8-4b5a-b2d8-fe29a3a24519
Digest: SHA-256=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=
TPP-Signature-Certificate: [TPP's eIDAS certificate]
Signature: keyId="SN=00f3abe28bee1e8f10,CA=OID.1.2.840.113549.1.9.1=info@eidasca.org,CN=eIDAS Issuer CA,O=CA Org,C=FI",algorithm="rsa-sha256", \
headers="Digest X-Request-ID", \
signature="Base64(RSA-SHA256(signing string))"
Content-Length: 0

Certificate Renewal Instructions

Multiple registered certificates can be used simultaneously, which means that certificate renewal should be flexible. Outlined below are the suggested steps for renewing a certificate before it expires:

1. Register new QSEAL certificate:

POST /tpp-registration/v1/certificate

2. Switch your applications to use the new QSEAL certificate when convenient.

3. Optionally, if you want to block the old certificate before the expiration date, you can make a delete certificate request.

List certificates:

GET /tpp-registration/v1/certificate

Delete old certificate:

DELETE /tpp-registration/v1/certificate/{CertificateId}

Production Environment

Contradicting with Berlin Group Implementation Guideline v1.3, an eIDAS QWAC certificate is not required when opening TLS connections. A QSEAL certificate must be used to sign requests according to Berlin Group v1.3. Private key JWT Client authentication is required in token endpoint, this is done with QSEAL. The client_assertion (signed JWT) header-section may not contain duplicate key-values. Authorize/Token-endpoint also requires Authorization Code flow with PKCE (code_challenge/code_verifier).

All requests excluding authentication endpoints must contain the API key, received from TPP registration, as "apikey"-header instead of "Ocp-Apim-Subscription-Key"-header.

Production PSD2 API for each bank will be available at omasp-psdapi.samlink.fi, pop-psdapi.samlink.fi and sp-psdapi.samlink.fi respectively. Production TPP registration API for all banks will be available at reg.samlink.fi. Production authorization service for all banks will be available at authservice.samlink.fi.

Production OAuth2 authorization request

GET https://authservice.samlink.fi/<omasp,pop,sp>/oauthproxy/authorize?response_type=code &client_id=<organizationIdentifier from eIDAS QSEAL certificate subject> &redirect_uri=<tpp redirect-uri as registered previously> &scope=<AIS/PIS:id value> &state=<random string, e.g. UUID> &code_challenge=<base64url-encoded sha256 hash of the generated code_verifier secret> &code_challenge_method=S256 HTTP/1.1

Production OAuth2 token request

POST https://authservice.samlink.fi/<omasp,pop,sp>/oauthproxy/token?grant_type=authorization_code &client_id=<organizationIdentifier from eIDAS QSEAL certificate subject> &redirect_uri=<tpp redirect-uri as registered previously> &code=<code returned in the authorization redirect code-parameter> &code_verifier=<code_verifier secret (ASCII)> &client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer &client_assertion=<signed JWT - client_id as issuer and subject, token endpoint URL as audience, and signed by the eIDAS QSEAL certificate, jti and exp fields are mandatory> HTTP/1.1