Camt.Net
1.1.0
dotnet add package Camt.Net --version 1.1.0
NuGet\Install-Package Camt.Net -Version 1.1.0
<PackageReference Include="Camt.Net" Version="1.1.0" />
<PackageVersion Include="Camt.Net" Version="1.1.0" />
<PackageReference Include="Camt.Net" />
paket add Camt.Net --version 1.1.0
#r "nuget: Camt.Net, 1.1.0"
#:package Camt.Net@1.1.0
#addin nuget:?package=Camt.Net&version=1.1.0
#tool nuget:?package=Camt.Net&version=1.1.0
Camt.Net
Zero-dependency ISO 20022 bank statement parser for .NET. Turn camt.053, camt.052 and camt.054 XML into a typed, ergonomic object model, with decimal money and DateOnly dates, across schema versions.
MIT Zero dependencies Native AOT clean
Why
ISO 20022 camt is the modern successor to the SWIFT MT940 statement (if you still consume those, see the sibling Mt940.Net). Banks increasingly hand you camt.053 end-of-day statements, camt.052 intraday reports and camt.054 debit/credit notifications, and the XML is verbose, deeply nested, and versioned by namespace.
The existing options are heavy. The generic Iso20022 code-generated packages ship thousands of DTO classes for the entire standard and pin you to one schema version, so a camt.053.001.02 file and a camt.053.001.08 file need different types. Camt.Net is the small, focused primitive instead: it reads exactly the statement, balance and entry data you actually use, and it does so namespace-agnostically so multiple schema versions parse through the same code path. In-box System.Xml.Linq only, no runtime dependencies.
Install
dotnet add package Camt.Net
Use
using Camt;
CamtDocument doc = CamtStatement.Parse(xml); // string or Stream
foreach (Statement statement in doc.Statements)
{
Console.WriteLine($"{statement.AccountId} ({statement.Currency})");
foreach (Balance balance in statement.Balances)
{
Console.WriteLine($" {balance.Type}: {balance.SignedAmount} {balance.Currency}");
}
foreach (Entry entry in statement.Entries)
{
Console.WriteLine($" {entry.BookingDate}: {entry.SignedAmount} {entry.Currency} {entry.Reference}");
}
}
Non-throwing variant:
if (CamtStatement.TryParse(xml, out CamtDocument? doc))
{
// use doc
}
The balance-conservation guarantee
Every entry and balance exposes a SignedAmount: positive for a credit, negative for a debit. That makes the fundamental statement invariant a one-liner you can assert against your own data:
Balance opening = statement.Balances.Single(b => b.Type == BalanceType.Opening);
Balance closing = statement.Balances.Single(b => b.Type == BalanceType.Closing);
decimal movement = statement.Entries.Sum(e => e.SignedAmount);
// opening + net movement == closing
Debug.Assert(opening.SignedAmount + movement == closing.SignedAmount);
Money is decimal throughout and parsed with InvariantCulture, so there is no binary floating-point drift and no locale surprise in your reconciliation.
Model
CamtDocument { CamtMessageType MessageType, IReadOnlyList<Statement> Statements }Statement { string? Id, string? AccountId, string? Currency, IReadOnlyList<Balance> Balances, IReadOnlyList<Entry> Entries }Balance { BalanceType Type, decimal Amount, string Currency, CreditDebit CreditDebit, DateOnly? Date, string? ProprietaryCode, decimal SignedAmount }Entry { decimal Amount, string Currency, CreditDebit CreditDebit, DateOnly? BookingDate, DateOnly? ValueDate, string? Reference, string? AdditionalInfo, string? Status, string? ProprietaryCode, string? BankTransactionCode, decimal SignedAmount }
AccountId prefers the IBAN and falls back to the proprietary other identifier. BalanceType maps the ISO codes: OPBD/OPAV/PRCD to Opening, CLBD/CLAV to Closing, ITBD/ITAV to Interim, everything else to Other.
Proprietary codes and bank transaction codes
Banks often carry their own codes alongside (or instead of) the standard ISO ones. Camt.Net surfaces these raw values instead of discarding them:
Balance.ProprietaryCodeholds the raw code from a<Prtry>balance type, for exampleLEDGER. When it is populated,Balance.TypeisBalanceType.Other, so a consumer can still read the exact bank code.Entry.ProprietaryCodeholds the raw proprietary status code from the entry<Sts>when it is not a standard ISO status.Entry.BankTransactionCodecategorizes the entry: the ISO domain, family and sub-family joined by/(for examplePMNT/RCDT/ESCT), or the proprietary<BkTxCd><Prtry><Cd>value (for exampleNTRF+00100) when no ISO structure is present.
All three are additive and default to null when the source XML does not carry them.
Namespace handling
camt messages carry a URN namespace that encodes the schema version, for example urn:iso:std:iso:20022:tech:xsd:camt.053.001.02 and ...camt.053.001.08. Camt.Net matches elements by local name and ignores the namespace, so files written against different schema versions parse through the same code with no configuration.
Notes and limitations
- Parse-only. This library reads XML; it does not generate it.
camt.05xstatement family only (camt.053,camt.052,camt.054). Other ISO 20022 message groups are out of scope.- The model surfaces the core statement, balance and entry fields, plus proprietary balance/status codes and the entry bank transaction code. Deeper sub-structures such as full structured remittance and related parties are not mapped.
decimaloutput andDateOnlyinput/output. Time-of-day onDtTmdates is intentionally dropped.
License
MIT. Copyright Israel Iyonsi.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.