What a Complete Berlin Group PSD2 Sandbox Should Implement

Under the Berlin Group PSD2 framework, Third-Party Providers (TPPs) are expected to integrate with banks using standardized APIs for Account Information (AIS) and Payment Initiation (PIS).

While the specification is detailed, real-world bank sandboxes are often incomplete, unstable, or misleading. As a result, development teams waste months debugging integration issues that only appear after going live.

A complete Berlin Group–compliant PSD2 sandbox is not just an API mock.
It is a regulatory-grade simulation of a real bank.

This article explains:

  • What a proper Berlin Group sandbox must implement
  • Where most bank sandboxes fail
  • How to design it correctly
  • Concrete sequence diagrams
  • Real Spring Boot examples used in production-grade sandboxes

Why Berlin Group Compliance Changes Everything

Berlin Group defines not just endpoints, but behavior:

  • Consent lifecycle rules
  • OAuth2 + SCA orchestration
  • PSU interaction models
  • Error semantics
  • State transitions

A sandbox that “returns JSON” but does not enforce these rules is dangerous, because it gives TPPs false confidence.


Architecture of a Complete Berlin Group PSD2 Sandbox

At a high level, a production-grade sandbox contains:

TPP Application
   ↓
OAuth2 / SCA Gateway
   ↓
Consent Management Engine
   ↓
AIS / PIS Domain Services
   ↓
Scenario-Driven Bank Core Simulator

Each layer must behave like a real bank—not like a demo.


1. OAuth2 & SCA – Berlin Group Style

Berlin Group mandates OAuth2 Authorization Code Flow, tightly coupled with consent and SCA.

Correct Berlin Group OAuth2 Sequence

TPP → Authorization Endpoint
TPP ← Redirect to PSU Login
PSU → Authenticate & SCA
PSU ← Consent Approval UI
TPP ← Authorization Code
TPP → Token Endpoint
TPP ← Access Token (Consent-Bound)

Key Sandbox Requirements

✔ Tokens must expire
✔ Tokens must be bound to consentId
✔ SCA must not always succeed
✔ Redirect-based PSU interaction must be enforced


2. Consent Management (AIS / PIS)

Why Consent Is the Core of Berlin Group

In Berlin Group, everything is consent-driven:

  • Accounts
  • Balances
  • Transactions
  • Payments

Most sandboxes create consents but never enforce them.
A real sandbox must block access if consent scope or status is invalid.

Consent Lifecycle

RECEIVED → VALID → REVOKED → EXPIRED

Spring Boot – Consent Validation Example

@Service
public class ConsentValidator {

    public void validate(String consentId, ConsentScope scope) {
        Consent consent = consentRepository.findById(consentId)
                .orElseThrow(() -> new ForbiddenException("Consent not found"));

        if (!consent.isValid()) {
            throw new ForbiddenException("Consent expired or revoked");
        }

        if (!consent.getScopes().contains(scope)) {
            throw new ForbiddenException("Consent scope missing");
        }
    }
}

3. AIS – Account Information Services

Mandatory Berlin Group AIS Endpoints

  • GET /accounts
  • GET /accounts/{accountId}
  • GET /accounts/{accountId}/balances
  • GET /accounts/{accountId}/transactions

What a Real Sandbox Must Simulate

✔ Multiple accounts per PSU
✔ Multiple currencies
✔ Booking date vs value date
✔ Pagination
✔ Realistic transaction histories

Example – Transactions Endpoint (Spring Boot)

@GetMapping("/accounts/{id}/transactions")
public ResponseEntity<TransactionsResponse> getTransactions(
        @PathVariable String id,
        @RequestHeader("Consent-ID") String consentId) {

    consentValidator.validate(consentId, ConsentScope.TRANSACTIONS);

    return ResponseEntity.ok(
        transactionService.getTransactionsForAccount(id)
    );
}

4. PIS – Payment Initiation Services

Supported Payment Types

A complete sandbox should support:

  • SEPA Credit Transfers
  • Instant Payments
  • Scheduled payments
  • Rejected & failed payments

Payment State Machine (Berlin Group)

RCVD → ACTC → ACSC
        ↓
       RJCT

Payment Flow – Sequence Diagram

TPP → Create Payment
TPP ← paymentId (RCVD)

TPP → Authorize Payment
PSU → SCA Challenge
PSU ← SCA Success / Failure

TPP → Get Payment Status
TPP ← ACTC / ACSC / RJCT

Payment Status Endpoint Example

@GetMapping("/payments/{paymentId}/status")
public PaymentStatusResponse getStatus(@PathVariable String paymentId) {
    return paymentService.getStatus(paymentId);
}

5. SCA Simulation (Critical for Realism)

Why Most Sandboxes Are Useless Here

Many sandboxes:
❌ Always pass SCA
❌ Never expire challenges
❌ Ignore PSU behavior

A real sandbox must simulate:

  • OTP success
  • OTP failure
  • Timeout
  • Cancelled authentication

Example SCA Challenge Response

{
  "scaStatus": "started",
  "scaMethod": "OTP",
  "expiresInSeconds": 120
}

6. Error Handling – Where Most Sandboxes Fail

Berlin Group Error Semantics Matter

TPPs rely on precise HTTP codes and error bodies.

ScenarioHTTP
Consent expired403
Invalid IBAN400
Unauthorized scope403
Rate limit exceeded429
Bank unavailable503

Example Error Response

{
  "tppMessages": [
    {
      "category": "ERROR",
      "code": "CONSENT_EXPIRED",
      "text": "The consent is no longer valid"
    }
  ]
}

7. Deterministic Test Scenarios (Essential for CI/CD)

A professional sandbox must offer predictable PSU profiles:

PSU_BASIC     → AIS only, no SCA exemptions
PSU_PREMIUM   → Multiple accounts, large balances
PSU_RISKY     → Frequent SCA, payment rejections

This enables:

  • Automated regression tests
  • Continuous integration
  • Safe pre-production validation

8. Observability for TPPs

A TPP-friendly sandbox exposes:

✔ Correlation IDs
✔ Deterministic logs
✔ Traceable consent/payment chains

X-Request-ID: 9a7c-psd2-sbx-001

This alone can cut integration time by 30–40%.


Why Teams Build Their Own Berlin Group Sandbox

Organizations that build internal PSD2 sandboxes report:

  • Faster bank onboarding
  • Fewer production incidents
  • Higher certification success rates
  • Stronger regulatory confidence

In a market where bank sandboxes are unreliable, a well-designed Berlin Group sandbox becomes a competitive advantage.


Final Thoughts

A Berlin Group PSD2 sandbox is not a mock API.
It is a bank behavior simulator, and it must fail, reject, expire, and challenge—just like a real bank.

If your sandbox:

  • Always succeeds
  • Never expires tokens
  • Ignores consent scopes

…it is actively hurting your Open Banking project.

This article is inspired by real-world challenges we tackle in our projects. If you're looking for expert solutions or need a team to bring your idea to life,

Let's talk!

    Please fill your details, and we will contact you back

      Please fill your details, and we will contact you back