0.0
The project is in a healthy, maintained state
Authenticates with your API key and decrypts open-banking.io's zero-knowledge data envelopes locally with your exported private key (ECDH P-256 -> HKDF-SHA256 -> AES-256-GCM). The service only ever returns ciphertext it cannot read.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

~> 13.0
~> 3.3, < 3.4
~> 3.0
~> 0.22
~> 1.0

Runtime

>= 0.1
 Project Readme

open-banking.io client SDKs

CI Semgrep Gitleaks OpenSSF Scorecard codecov License: MIT

Server-to-server clients for open-banking.io in .NET, Node, Python, Rust, Go, Java, Ruby, and PHP.

open-banking.io is zero-knowledge: the service stores and returns only ciphertext it cannot read. These SDKs do the two things an integrator needs — authenticate with your API key and decrypt the data locally with your exported private key — and hand you clean, typed models.

Language Package Path
.NET OpenBankingIO.Client (NuGet) dotnet/
Node / TypeScript @open-banking-io/client (npm) node/
Python open-banking-io (PyPI) python/
Rust open-banking-io (crates.io) rust/
Go github.com/open-banking-io/clients/go go/
Java io.open-banking:open-banking-io-client (Maven Central) java/
Ruby open-banking-io (RubyGems) ruby/
PHP open-banking-io/client (Packagist) php/

How it works

  1. In the app, export your credentials bundle (.json) — it contains your apiBaseUrl, an API key, and your encryption private key (PKCS#8).
  2. Point an SDK at the bundle. Every request sends X-Api-Key; every response is decrypted in-process.
// .NET
using var client = OpenBankingClient.FromCredentials("credentials.json");
foreach (var a in await client.GetAccountsAsync())
    Console.WriteLine($"{a.Iban}: {a.Balances.First(b => b.Type == "ITBD").Amount} {a.Currency}");
// Node
const client = OpenBankingClient.fromCredentials("credentials.json");
for (const a of await client.getAccounts())
  console.log(a.iban, a.balances.find(b => b.type === "ITBD")?.amount, a.currency);
# Python
client = OpenBankingClient.from_credentials("credentials.json")
for a in client.get_accounts():
    booked = next(b for b in a.balances if b.type == "ITBD")
    print(a.iban, booked.amount, a.currency)
// Rust
let client = OpenBankingClient::from_credentials("credentials.json")?;
for a in client.get_accounts()? {
    let booked = a.balances.iter().find(|b| b.type_ == "ITBD");
    println!("{:?} {:?} {}", a.iban, booked.map(|b| &b.amount), a.currency);
}
// Go
client, _ := openbanking.FromCredentials("credentials.json", nil)
accounts, _ := client.GetAccounts()
for _, a := range accounts {
    for _, b := range a.Balances {
        if b.Type == "ITBD" { fmt.Println(a.Iban, b.Amount, a.Currency) }
    }
}
// Java
var client = OpenBankingClient.fromCredentials("credentials.json");
for (Account a : client.getAccounts())
    a.balances().stream().filter(b -> b.type().equals("ITBD")).findFirst()
        .ifPresent(b -> System.out.println(a.iban() + " " + b.amount() + " " + a.currency()));
# Ruby
client = OpenBankingIO::Client.from_credentials("credentials.json")
client.get_accounts.each do |a|
  booked = a.balances.find { |b| b.type == "ITBD" }
  puts "#{a.iban} #{booked&.amount} #{a.currency}"
end
// PHP
$client = OpenBankingIO\Client::fromCredentials("credentials.json");
foreach ($client->getAccounts() as $a) {
    foreach ($a->balances as $b) {
        if ($b->type === "ITBD") echo "{$a->iban} {$b->amount} {$a->currency}\n";
    }
}

All eight expose the same surface: getAccounts, getTransactions(accountId, …), getConnections, sync(accountId), syncAll(). Sync decrypts the account's session uid locally and posts it, so the service can refresh from the bank without ever holding it in plaintext.

The encryption scheme

Each sensitive value is an envelope: version(1) | ephemeralPublicKey(65) | nonce(12) | tag(16) | ciphertext, produced with ephemeral ECDH on P-256 → HKDF-SHA256 (salt = 32 zero bytes, info = bank.core.ci/zk/v1) → AES-256-GCM. Only your private key can open it. All eight SDKs are verified against the same fixtures (fixtures/) so they decrypt identically and interoperate with the live service's wire format.

Development

# regenerate the shared test fixtures (keypair + encrypted sample responses)
node tools/generate-fixtures.mjs

# run each SDK's tests (crypto round-trip + a mock-server integration suite)
dotnet test dotnet/
cd node   && npm install && npm test
cd python && pip install -e .[dev] && pytest -q
cd rust   && cargo test
cd go     && go test ./...
cd java   && mvn -B verify
cd ruby   && bundle install && bundle exec rspec
cd php    && composer install && vendor/bin/phpunit

CI (.github/workflows/ci.yml) builds and tests all eight on every push. Releases are per-package: each package publishes from its own <dir>/vX.Y.Z tag (e.g. node/v0.2.0), so tagging one package never republishes the others. Cut a release from Actions → Release (pick a package + version) — see RELEASING.md. Targets: NuGet, npm, PyPI, crates.io, Maven Central, RubyGems, Packagist, and the Go module proxy.

Security & contributing

Zero-knowledge security model and trust boundaries: THREAT_MODEL.md. Report vulnerabilities privately per SECURITY.md. Contributions welcome — see CONTRIBUTING.md, CODE_OF_CONDUCT.md, and SUPPORT.md.

MIT licensed.