Summary
Record::getAccount() returns an account DTO with only the account identification (for IBAN-backed accounts, an IbanAccount containing the IBAN and optional account name). The CAMT.052, CAMT.053, and CAMT.054 schemas also carry the servicing institution (the bank running the account) via <Acct><Svcr><FinInstnId>..., but this element is not surfaced through any public API on the record / statement / report / notification DTOs.
Would you accept a PR that exposes the account servicer on the public DTOs?
Why it matters
Reconciliation-layer tools built on top of genkgo/camt often want to persist a bank_statements row alongside every imported file so operators can answer questions like "show me all statements from my Deutsche Bank account". The IBAN is enough to identify the account, but the BIC is what disambiguates it for users who operate across multiple banks. More practically, IBAN+BIC is still a common pair for downstream payment and reconciliation workflows.
Concrete downstream use case: My app has a bank_statements table with iban and bic columns. The IBAN is populated today via $record->getAccount()->getIdentification(). The bic column stays NULL because there is no equivalent getter, even when the source XML contains the servicing institution.
What the library does today
The omission appears to be current behavior, not just missing docs:
src/Camt052/Decoder/Message.php
src/Camt053/Decoder/Message.php
src/Camt054/Decoder/Message.php
All three currently decode <Acct><Id>... into an Account DTO, but do not read <Acct><Svcr><FinInstnId>.
The DTO surface also has no place for the servicer today:
Record::getAccount() returns an Account
IbanAccount currently stores only the IBAN and optional account name
Where the servicer lives in CAMT
Depending on message version, the financial institution identifier may be represented as either BIC or BICFI under <FinInstnId>.
Example using BIC
<Acct>
<Id>
<IBAN>DE89370400440532013000</IBAN>
</Id>
<Svcr>
<FinInstnId>
<BIC>COBADEFFXXX</BIC>
<Nm>Commerzbank AG</Nm>
</FinInstnId>
</Svcr>
</Acct>
Example using BICFI
<Acct>
<Id>
<IBAN>CH2801234000123456789</IBAN>
</Id>
<Svcr>
<FinInstnId>
<BICFI>UBSWCHZH80A</BICFI>
<Nm>UBS SWITZERLAND AG</Nm>
</FinInstnId>
</Svcr>
</Acct>
The repo’s own fixtures already contain this structure for supported versions, so this is not hypothetical.
Proposed API
Three options, in order of non-invasiveness:
Option A — new getters on Record
public function getAccountServicerBic(): ?string
public function getAccountServicerName(): ?string
Backward compatible. Existing getAccount() callers keep working. This is the smallest public change.
Option B — extend IbanAccount / Account with optional servicer info
public function getServicingBic(): ?string
public function getServicingName(): ?string
This is conceptually closer to the XML shape, since the servicer belongs to the account. But it widens the DTO contract more than Option A.
Option C — add a dedicated account-servicer DTO
Something like:
final class FinancialInstitution
{
public function getBic(): ?string
public function getName(): ?string
}
and then either Record::getAccountServicer(): ?FinancialInstitution or Account::getServicer(): ?FinancialInstitution.
Probably the cleanest model long-term, but likely too large a delta for the immediate need.
I’d propose Option A as the smallest compatible change.
Decoder path
This looks like a sibling-of-account-identification change, not a new schema branch:
- extract
<Acct><Svcr><FinInstnId><BIC> or <BICFI>
- optionally also expose
<Nm>
- wire the result onto the chosen DTO/API for all supported CAMT.052 / .053 / .054 record decoders
Happy to send a PR for whichever API shape you prefer.
Summary
Record::getAccount()returns an account DTO with only the account identification (for IBAN-backed accounts, anIbanAccountcontaining the IBAN and optional account name). The CAMT.052, CAMT.053, and CAMT.054 schemas also carry the servicing institution (the bank running the account) via<Acct><Svcr><FinInstnId>..., but this element is not surfaced through any public API on the record / statement / report / notification DTOs.Would you accept a PR that exposes the account servicer on the public DTOs?
Why it matters
Reconciliation-layer tools built on top of
genkgo/camtoften want to persist abank_statementsrow alongside every imported file so operators can answer questions like "show me all statements from my Deutsche Bank account". The IBAN is enough to identify the account, but the BIC is what disambiguates it for users who operate across multiple banks. More practically, IBAN+BIC is still a common pair for downstream payment and reconciliation workflows.Concrete downstream use case: My app has a
bank_statementstable withibanandbiccolumns. The IBAN is populated today via$record->getAccount()->getIdentification(). Thebiccolumn staysNULLbecause there is no equivalent getter, even when the source XML contains the servicing institution.What the library does today
The omission appears to be current behavior, not just missing docs:
src/Camt052/Decoder/Message.phpsrc/Camt053/Decoder/Message.phpsrc/Camt054/Decoder/Message.phpAll three currently decode
<Acct><Id>...into anAccountDTO, but do not read<Acct><Svcr><FinInstnId>.The DTO surface also has no place for the servicer today:
Record::getAccount()returns anAccountIbanAccountcurrently stores only the IBAN and optional account nameWhere the servicer lives in CAMT
Depending on message version, the financial institution identifier may be represented as either
BICorBICFIunder<FinInstnId>.Example using
BICExample using
BICFIThe repo’s own fixtures already contain this structure for supported versions, so this is not hypothetical.
Proposed API
Three options, in order of non-invasiveness:
Option A — new getters on
RecordBackward compatible. Existing
getAccount()callers keep working. This is the smallest public change.Option B — extend
IbanAccount/Accountwith optional servicer infoThis is conceptually closer to the XML shape, since the servicer belongs to the account. But it widens the DTO contract more than Option A.
Option C — add a dedicated account-servicer DTO
Something like:
and then either
Record::getAccountServicer(): ?FinancialInstitutionorAccount::getServicer(): ?FinancialInstitution.Probably the cleanest model long-term, but likely too large a delta for the immediate need.
I’d propose Option A as the smallest compatible change.
Decoder path
This looks like a sibling-of-account-identification change, not a new schema branch:
<Acct><Svcr><FinInstnId><BIC>or<BICFI><Nm>Happy to send a PR for whichever API shape you prefer.