erwinkramer/bank-api: a design reference for compliant ASP.NET Core banking APIs
The Bank API is a design reference project suitable to bootstrap development for a compliant and modern API.
At a glance
- What is it?
- This repository is a reference implementation rather than a library: an ASP.NET Core Minimal API wired to Spectral linting, OpenAPI 3.2.0, CloudEvents, an MCP server and Aspire orchestration. Its value is the compliance scaffolding around the endpoints, and its cost is the tooling you inherit with it.
- Who is it for?
- Adopt it as a starting skeleton if your team already runs ASP.NET Core and you need the compliance wiring (Spectral rulesets, JWS response signing, JWKS endpoint, CloudEvents outbox) in place before the first endpoint is written. Do not adopt it as a runtime dependency, and do not treat it as a drop-in for an existing service.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What the Bank API reference is actually for
The README describes the project as "a design reference project suitable to bootstrap development for a compliant and modern API". That wording matters. This is not a NuGet package you add to an existing service, and it is not a bank. It is a working skeleton whose endpoints exist mainly to demonstrate how the surrounding compliance, eventing and documentation layers fit together. The audience is a team starting a new API in a regulated or audited context, or a team that wants a concrete example of what OWASP API Security Top 10 alignment looks like in ASP.NET Core Minimal API code rather than in a slide deck. The Dutch public sector design rules (NLGov REST API Design Rules 2.2.1) and the GDPR and CCPA references in the README suggest the primary context is European, and the homepage domain points the same way. If you are building an internal CRUD service with no external consumers and no audit surface, the compliance apparatus here is overhead you will spend time removing.
The layered project structure and what each layer owns
The Mermaid flowchart in the README is the clearest documentation of the architecture. BankApi.Core holds three groups: Defaults, DownstreamClients and Implementation. DownstreamClients depends on both Defaults and Implementation; Defaults and Implementation feed into the API hosts. There are two hosts, BankApi.Service.Beta and BankApi.Service.Stable, which is a versioning split expressed at the project level rather than through URL segments alone. BankApi.Orchestration sits above the hosts and depends on Infra.Generated. BankApi.Tests depends on Implementation. Specs.Generated is produced from the API hosts and consumed by BankApi.Mcp, which is the Model Context Protocol server. The consequence of that layout is that the MCP server is generated from the same specification as the HTTP API, so the two surfaces cannot drift apart without the build noticing. Infra.Generated likewise comes out of the orchestration layer. Two of the five projects in the diagram are generated artifacts, which is worth knowing before you start editing files by hand.
Spectral rulesets are the compliance mechanism, not a checklist
The README lists compliance items with check marks, but the mechanism behind them is Spectral. Four rulesets are named: the Spectral OWASP API Security ruleset for the 2023 Top 10, the Spectral "oas" ruleset for OpenAPI Specification v3.2.0, the Logius API Design Rules ruleset for NLGov 2.2.1, and a project-local ruleset at Specs.Ruleset/ruleset.bank.yml for naming conventions, structure and clarity. That last one is the part most reference projects omit. It means the house style of this API is machine-checked rather than described in a wiki. The practical implication is that linting runs against a generated OpenAPI document, so the OpenAPI generation step has to succeed before the compliance check means anything. If your team already treats OpenAPI output as a build artifact, this fits. If your team writes the specification by hand and generates code from it, the direction of flow here is reversed and you will be fighting the pipeline.
Response signing, JWKS and the outbox pattern for events
Two compliance areas go beyond linting. Response signing uses RFC 7515 JSON Web Signature, delivered through an X-JWS-Signature header, with the corresponding public keys exposed at a /.well-known/jwks.json endpoint per RFC 7517. A client that wants to verify a response fetches the key set and validates the signature, which means key rotation is a client-visible concern, not an internal one. Event delivery is built on the outbox pattern and conforms to CloudEvents 1.0.2, using the HTTP protocol binding, with the OpenAPI webhooks field describing delivery. The README cites the CloudEvents HTTP 1.1 webhook specification for the delivery mechanism. The outbox pattern implies a store that holds events until they are dispatched, so a database is part of the picture even though the README excerpt does not name one. That is a gap worth checking in the source before you assume the persistence choice is made for you.
Running it: prerequisites, Aspire and the Dev Container path
The README gives two routes. The first is the Dev Container defined at .devcontainer/devcontainer.json, which is the path of least resistance because it pins the toolchain. The second is manual, and the excerpt lists one prerequisite explicitly: the .NET 11 SDK. The technology stack section names ASP.NET Core 11.0 Minimal API, so the SDK version and the framework version line up. Beyond the SDK, the stack lists Aspire for development bootstrapping, Scalar for interactive documentation, Kiota for downstream client generation, Gridify for filtering, ordering and paging, TUnit for unit tests, and the REST Client extension for Visual Studio Code to drive .http files. Two hosted instances are referenced in the README: a live API with sidecars at an Azure Container Apps URL under /v1/docs, and an MCP server at the same host under /mcp/.well-known/oauth-protected-resource. The MCP endpoint path is a protected-resource metadata document rather than the MCP transport itself, which is consistent with the OAuth discovery flow the specification describes. Local testing is done through .http files rather than a test harness, which keeps the feedback loop short but leaves request scripting outside the test project.
Where the reference model stops being useful
The project is a reference, and the README says so. The first limitation follows from that: there are no published packages, so every consumer forks or copies. A fork does not receive upstream fixes automatically, and the release cadence here is edition-based rather than semantic. The three listed releases are dotnet10 GA in November 2025, then dotnet10-3 in March 2026 and dotnet10-4 in June 2026, each labelled by season. That is a roughly quarterly rhythm tied to the .NET release train, which is fine for a reference and awkward for a dependency. The second limitation is the .NET 11 SDK prerequisite. A team on .NET 8 LTS cannot use this without a framework upgrade first, and the release names show the project moved with .NET 10 and then .NET 11 rather than holding a long-term-support line. The third is the licence. The repository metadata reports NOASSERTION while the README displays a CC BY-NC-SA 4.0 badge. Those two signals do not agree, and the NonCommercial clause in that Creative Commons licence is a real constraint for a commercial bank or vendor. Resolve that discrepancy with your own legal review before copying code; nothing here constitutes legal advice.
How this differs from NSwag, Swashbuckle or a plain Minimal API template
The obvious comparison is the tooling most ASP.NET Core teams already use for specification and documentation. Swashbuckle and NSwag generate an OpenAPI document from your endpoints and serve a UI. This project does that too, via the built-in OpenAPI support and Scalar, but it adds a linting gate with four rulesets and a project-local ruleset file. That is the substantive difference: the specification is validated against external rule sets rather than merely produced. A second comparison is the MCP server. Most API projects expose HTTP only. Here, BankApi.Mcp is generated from Specs.Generated, so the same contract drives both the REST surface and the Model Context Protocol surface. If you have no intention of exposing tools to an MCP client, that entire branch of the build is dead weight. A third difference is Aspire. A plain dotnet new webapi template gives you one project and a launch profile. This gives you an orchestration project plus generated infrastructure, which buys local multi-service composition and costs you familiarity with Aspire's model.
Editorial conclusion
Adopt it as a starting skeleton if your team already runs ASP.NET Core and you need the compliance wiring (Spectral rulesets, JWS response signing, JWKS endpoint, CloudEvents outbox) in place before the first endpoint is written. Do not adopt it as a runtime dependency, and do not treat it as a drop-in for an existing service. Before you commit, verify three things in the repository itself: the actual licence file behind the NOASSERTION label, whether the .NET 11 SDK and Aspire tooling are available on your build agents, and how much of Specs.Generated and Infra.Generated you would have to regenerate for your own domain.
Community notes