Pétrusse Bank – PSD2 Exercise
Finance & Technology – University of Luxembourg
Deadline for submission: Friday, 11 December 2026
In-class review: Monday, 14 December 2026
Questions: georges@berscheid.lu
1. Your mission
You run a small fintech that helps people manage their money. Under PSD2 your company is a Third Party Provider (TPP):
- As an AISP (Account Information Service Provider), you may read a client's bank accounts once the client has given consent.
- As a PISP (Payment Initiation Service Provider), you may initiate payments from the client's account once the client has approved them.
Your client banks at Pétrusse Bank, a fictional bank that offers a PSD2 interface based on the Berlin Group NextGenPSD2 standard. Many European banks use this standard, including most Luxembourg banks.
Your client is between jobs. They ask you to make sure their current account will not go into the red next month. You will:
- read their accounts and transactions,
- work out exactly how much money must be moved from their savings account to their current account, and
- initiate that transfer for them.
Everything happens in a sandbox. No real money moves. The bank's data is frozen at Thursday, 5 November 2026: treat that date as "today" for the bank's accounts.
2. What you received
You received a personal sheet, on paper in class or as a PDF by email. It contains:
- A. Your fintech (TPP): your
client_idand a one-time activation code for the developer portal. - B. Your client at Pétrusse Bank (PSU): your client's PSU ID, PIN and TAN card. In this exercise you play both roles, the fintech and its client.
- C. Pétrusse Bank app: a QR code that turns your phone into your client's banking app.
- D. Phone call from your client: a short note with information your client gave you by phone. It matters for your calculation.
Your sheet is personal and every action is logged against it. Do not share it, and never type your PIN, TAN codes, activation code or client secret into an AI tool, a chat or a shared document. Under PSD2 (Article 69), a payment service user must keep their personalised security credentials safe. Giving them to a third party, including an AI tool, is exactly what PSD2 is designed to prevent.
3. Rules of the game
- You may use AI assistants (Claude, ChatGPT, Gemini, Le Chat, the Gemini assistant in Colab and so on). Free versions are enough. You remain responsible for your code and your results.
- You will be asked about your own work. At the in-class review you get three personal questions about what you did, based on the bank's log of your requests. For example: why a specific request of yours failed, or why you included or excluded a specific payment. You cannot prepare by memorising. You prepare by understanding each step.
- You have 3 attempts at the final payment amount. Check your calculation before you pay.
- If you get stuck (account locked, lost sheet, lost phone), write to georges@berscheid.lu. Don't create workarounds with other students' credentials: the bank refuses them, and the log shows the attempt.
4. Set up Google Colab
- Go to colab.research.google.com, sign in with a Google account and create a new notebook. Name it
psd2-<your-matriculation-number>. - Open the Secrets panel: the key icon in the left sidebar. This is where you store passwords instead of writing them in your code. Your notebook, and any AI assistant reading it, then never contains them.
- You will add two secrets there:
CLIENT_IDnow (from your sheet) andCLIENT_SECRETin step 5.1. Enable "Notebook access" for both.
Useful documentation, keep it open:
- Instructions (this text): https://petrussebank.berscheid.lu/instructions
- Interactive API documentation: https://petrussebank.berscheid.lu/docs
- API specification (OpenAPI file): https://petrussebank.berscheid.lu/openapi.json
5. The steps
Each step ends with a checkpoint, so you know when you are done. Keep each step in its own notebook cell, with a short comment in your own words explaining what it does.
5.1 Activate your developer access
Real banks have a developer portal where fintechs get their credentials. Open https://petrussebank.berscheid.lu/portal in your browser. Enter your client_id and the activation code from your sheet, and choose a portal password.
The portal shows your client secret once. Copy it straight into Colab Secrets as CLIENT_SECRET. If you lose it, you can generate a new one in the portal, and the old one stops working.
In the portal you can also see My activity: the bank's log of your requests. It is very useful when something goes wrong.
Checkpoint: the portal says your access is active, and CLIENT_SECRET is stored in Colab Secrets.
5.2 Install your client's banking app
Scan the QR code (section C of your sheet) with your phone. Log in with the PSU ID and PIN from section B. Your phone is now your client's Pétrusse Bank app. You will need it to approve the payment in step 5.7.
Only one phone can be activated. Use the phone you will have with you while working on the exercise.
Checkpoint: the app on your phone shows "Device activated".
5.3 Authenticate your fintech
Every request your fintech sends must carry an access token. Your fintech gets one by presenting its credentials to the bank. This starter cell does it for you:
import requests, uuid
from google.colab import userdata
BASE_URL = "https://petrussebank.berscheid.lu"
CLIENT_ID = userdata.get("CLIENT_ID")
CLIENT_SECRET = userdata.get("CLIENT_SECRET")
r = requests.post(f"{BASE_URL}/oauth/token",
data={"grant_type": "client_credentials"},
auth=(CLIENT_ID, CLIENT_SECRET))
print(r.status_code)
print(r.json())
Tokens expire after 15 minutes. When you get an error about an expired token, run this cell again. In real PSD2 a fintech proves its identity with a qualified eIDAS certificate. The token is the sandbox's simplified stand-in.
Checkpoint: you get status 200 and an access_token.
5.4 Ask for your client's consent (AIS)
Your fintech may only read the accounts after your client has given consent. Find the right endpoint in the API documentation and create a consent that lets you read the accounts, balances and transactions your calculation needs.
Things to find out from the documentation:
- which headers the bank requires (every request needs a unique
X-Request-ID; Python'suuid.uuid4()creates one); - how to say which accounts the consent covers, when you don't know your client's account numbers yet;
- how long the consent should be valid and how often per day you want to access the data.
The bank's answer contains a link for Strong Customer Authentication (SCA). Open it in your browser. You now act as the client: log in with the PSU ID and PIN, check what you are agreeing to, and enter the code from your TAN card at the position the bank asks for.
After that, check the consent status from your notebook.
Checkpoint: your consent has status valid.
5.5 Read the data
Use your consent to read:
- the list of your client's accounts,
- the balances of the current account, and
- all transactions of the current account for the last three full calendar months and the current month, both booked and pending.
Watch out:
- Banks do not send everything at once. Look for a link to the next page in each answer, and keep going until there is none.
- PSD2 limits how often a fintech may access account data when the client is not actively present. The documentation explains which header tells the bank that the client is actively involved. If you hit the limit, read the error message carefully.
- If the bank refuses a request, the
tppMessagespart of the answer explains why. Read it before changing anything.
Keep the data in Python variables or in a pandas DataFrame. pd.DataFrame(list_of_dicts) is a good start.
Checkpoint: you have every booked and pending transaction of the current account, and you can print how many there are per month.
5.6 Analyse: how much must be transferred?
Compute the amount using exactly these rules:
- A recurring debit is a SEPA direct debit (same mandate) or a standing order (same creditor account) that was debited in each of the last three full calendar months. A direct debit that was returned or refunded does not count as debited for that month. Card payments are never recurring.
- Each recurring debit will be taken next month at the amount of its most recent occurrence.
- Start from the current account's closing booked balance. Assume all pending transactions will be booked at their amount in EUR. The overdraft must not be used.
- No salary or other incoming payment will arrive next month.
- Apply what your client told you on the phone (section D of your sheet).
- Transfer = (total of recurring debits + anything from the phone call) − (closing booked balance + total of pending transactions), rounded up to the next whole euro. If the result is negative, nothing needs to be transferred.
Tips:
- Each transaction has a
bankTransactionCode, an international ISO 20022 code that tells you what kind of transaction it is. Look up what the codes mean. - Show your working in the notebook: a table of the recurring debits you counted, the ones you excluded, and why.
- An AI assistant can help you write the code, but it does not know your client's phone call or your data. Check its reasoning against the rules, line by line.
Checkpoint: you have one amount in EUR and a table that justifies it.
5.7 Initiate the payment (PIS)
Initiate a SEPA credit transfer from your client's savings account to their current account for the amount you computed.
Things to find out from the documentation:
- how to write the amount (banks are strict about format);
- which accounts and names belong in which fields;
- which header the bank needs so it knows which client must approve the payment.
This time there is no link to open. Pétrusse Bank uses decoupled SCA for payments: the approval request appears in the app on your phone. Check the amount, the payee and the "name check" result shown in the app, then approve with your PIN.
Back in your notebook, follow the payment's authorisation status and then its payment status. The payment does not settle instantly. Poll the status until it is final, waiting a few seconds between requests (time.sleep(5)).
Checkpoint: the payment status is final. ACSC means your amount was right. RJCT means it was rejected; the answer tells you why. If it was the amount, you have 3 attempts in total.
5.8 Submit
Before the deadline, log in to the developer portal and open Submit:
- Upload your notebook (in Colab: File → Download → Download .ipynb).
- Answer the three reflection questions:
- Describe in your own words the journey from your client's consent to your fintech reading the data.
- Which pitfalls did you run into, and how did you notice them?
- How did you use AI? Where was it helpful, and where was it wrong or missing information?
You may resubmit until the deadline; the latest version counts.
6. In-class review
On Monday, 14 December 2026 you answer three personal questions in writing (about 10 minutes). The questions are generated from your log: your requests, your errors, your consents, your payment attempts. If you understood what you did at each step, you will be fine. If you can't attend, contact georges@berscheid.lu to arrange a short video call.
7. When something goes wrong
| What you see | What it usually means |
|---|---|
400 | Your request is malformed: a missing header, wrong format, wrong parameter. Read tppMessages. |
401 | Your token is missing or expired, or your consent doesn't allow this request. |
403 / 404 | You asked for something that doesn't exist or isn't yours. Check IDs and paths. |
429 | Too many requests. Slow down, or read about the PSD2 access limit (step 5.5). |
| SCA page refuses your PIN | After 5 wrong PINs the client is locked for 15 minutes. |
| TAN rejected 3 times | That authorisation failed. Start again with a new consent or payment. |
| App shows nothing to approve | Check that the payment request succeeded and that you told the bank who the client is. |
Your My activity page in the portal shows every request the bank received from you, which makes it the fastest way to find a mistake.
8. Glossary
| Term | Meaning |
|---|---|
| ASPSP | The bank that holds the account (here: Pétrusse Bank) |
| TPP | Third Party Provider: your fintech |
| AISP / PISP | A TPP that reads account information / initiates payments |
| PSU | Payment Service User: the bank's client |
| Consent | The client's permission for a TPP to access specific data, for a limited time |
| SCA | Strong Customer Authentication: at least two of knowledge (PIN), possession (TAN card, phone) and inherence (fingerprint) |
| Redirect / decoupled SCA | The client authenticates on the bank's web page / in the bank's app |
| Booked / pending | Final transactions / transactions not yet final |
| IBAN | International Bank Account Number |
| VoP | Verification of Payee: the bank checks that the payee's name matches the account |
| ACSC / RJCT | ISO 20022 payment statuses: settled / rejected |