This document defines the mapping between ProBill database fields and ISO20022 XML structure for outgoing payments (utbetalningar).
| ProBill Source | ISO20022 XML Path | Required | Data Type | Notes |
|---|---|---|---|---|
| @FileID parameter | GrpHdr/MsgId | String(35) | Unique message identifier for the file | |
| SYSDATETIME() | GrpHdr/CreDtTm | DateTime | ISO8601 format: YYYY-MM-DDTHH:MM:SS | |
| COUNT | GrpHdr/NbOfTxs | Integer | Total number of payment transactions in file | |
| SUM(Amount) all transactions | GrpHdr/CtrlSum | Decimal | Total of all transaction amounts (control sum) | |
| Swedbank: \ PaymentAccount.SwedbankAgreementID \ \ Nordea: \ PaymentAccount.NordeaSignerID | GrpHdr/InitgPty/Id/OrgId/Othr/Id | String(35) | Bank-specific initiating party identifier | |
| Swedbank: 'BANK' \ Nordea: 'CUST' | GrpHdr/InitgPty/Id/OrgId/Othr/SchmeNm/Cd | String(4) | Identification scheme code |
| ProBill Source | ISO20022 XML Path | Required | Data Type | Notes |
|---|---|---|---|---|
| @FileID parameter | PmtInf/PmtInfId | String(35) | Payment information identifier | |
| Based on PayoutTypeID: \ • 'TRF' = Transfers (1,3,4) \ • 'CHK' = Money orders (2) | PmtInf/PmtMtd | String(3) | Payment method code | |
| COUNT | PmtInf/NbOfTxs | Integer | Number of transactions in this payment batch | |
| SUM(Amount) in batch | PmtInf/CtrlSum | Decimal | Control sum for this payment batch | |
| Literal: 'NORM' | PmtInf/PmtTpInf/InstrPrty | String(4) | Instruction priority (Normal) | |
| Literal: 'MPNS' | PmtInf/PmtTpInf/SvcLvl/Prtry | String(35) | Proprietary service level (mandatory for BG/PG) | |
| Literal: 'SUPP' | PmtInf/PmtTpInf/CtgyPurp/Cd | String(4) | Category purpose code (Supplier payment) | |
| CONVERT(VARCHAR(12), SYSDATETIME(), 23) | PmtInf/ReqdExctnDt | Date | Requested execution date: YYYY-MM-DD | |
| PaymentAccount.CustomerNumber | PmtInf/Dbtr/Nm | String(140) | Debtor name (company/organization name) | |
| Literal: 'SE' | PmtInf/Dbtr/PstlAdr/Ctry | String(2) | Debtor country code (ISO 3166-1 alpha-2) | |
| Nordea: \ PaymentAccount.NordeaOrgID \ Fallback: \ PaymentAccount.PayoutOrgID | PmtInf/Dbtr/Id/OrgId/Othr/Id | String(35) | Debtor organization number | |
| Literal: 'BANK' | PmtInf/Dbtr/Id/OrgId/Othr/SchmeNm/Cd | String(4) | Organization ID scheme code | |
| REPLACE(PaymentAccount.IBAN, ' ', '') | PmtInf/DbtrAcct/Id/IBAN | String(34) | REQUIRED if using IBAN \ Mutually exclusive with Othr/Id | |
| Swedbank: \ REPLACE(PaymentAccount.OutBankgiroNumber, '-', '') \ Nordea/Others: \ REPLACE(PaymentAccount.OutPlusgiroNumber, '-', '') | PmtInf/DbtrAcct/Id/Othr/Id | String(34) | REQUIRED if not using IBAN \ Account number (cleaned) | |
| 'BBAN' (if not BG) | PmtInf/DbtrAcct/Id/Othr/SchmeNm/Cd | String(4) | When using Othr/Id with BBAN format | |
| 'BGNR' (if Bankgiro) | PmtInf/DbtrAcct/Id/Othr/SchmeNm/Prtry | String(35) | When using Bankgiro as debtor account | |
| Currency.ExternalID \ Default: 'SEK' | PmtInf/DbtrAcct/Ccy | String(3) | Debtor account currency (ISO 4217) | |
| PaymentAccount.BIC | PmtInf/DbtrAgt/FinInstnId/BIC | String(11) | Bank Identifier Code (SWIFT) | |
| Literal: 'SE' | PmtInf/DbtrAgt/FinInstnId/PstlAdr/Ctry | String(2) | Bank country code |
| ProBill Source | ISO20022 XML Path | Required | Data Type | Notes |
|---|---|---|---|---|
| LedgerPayout.ID | CdtTrfTxInf/PmtId/EndToEndId | String(35) | Unique transaction identifier for tracking | |
| Currency.ExternalID | CdtTrfTxInf/Amt/InstdAmt/@Ccy | String(3) | Currency attribute (e.g., "SEK", "EUR") | |
| ISNULL(LedgerPayout.CurrencyAmount, LedgerPayout.Amount) | CdtTrfTxInf/Amt/InstdAmt | Decimal(18,2) | Instructed amount (use CurrencyAmount if foreign currency) |
| ProBill Source | ISO20022 XML Path | Required | Data Type | Notes |
|---|---|---|---|---|
| Based on PayoutTypeID: \ • 'SESBA' if PG/BG/Bank with clearing | CdtTrfTxInf/CdtrAgt/FinInstnId/ClrSysMmbId/ClrSysId/Cd | String(5) | Swedish Banking Association clearing system | |
| Based on PayoutTypeID: \ • '9900' = Bankgiro (4) \ • '9960' = Plusgiro (3) \ • 4-digit = Bank clearing (1) \ • NULL = Money order (2) | CdtTrfTxInf/CdtrAgt/FinInstnId/ClrSysMmbId/MmbId | String(35) | Clearing member ID \ Extracted via FnPrGetClearingsNrFromAccountNr() |
| ProBill Source | ISO20022 XML Path | Required | Data Type | Notes |
|---|---|---|---|---|
| {{COALESCE( \ CustomerContactInformation.Name, \ Customer.DispName1 \ )}} | CdtTrfTxInf/Cdtr/Nm | String(140) | Creditor/recipient name | |
| {{ISNULL( \ CustomerContactInformation.Address, \ Customer.DispAddress \ )}} | CdtTrfTxInf/Cdtr/PstlAdr/StrtNm | String(70) | REQUIRED for money orders (TypeID=2 only) | |
| {{REPLACE( \ ISNULL( \ CustomerContactInformation.Zipcode, \ Customer.Zipcode \ ), ' ', '' \ )}} | CdtTrfTxInf/Cdtr/PstlAdr/PstCd | String(16) | REQUIRED for money orders (TypeID=2 only) \ Spaces removed | |
| {{ISNULL( \ CustomerContactInformation.City, \ Customer.City \ )}} | CdtTrfTxInf/Cdtr/PstlAdr/TwnNm | String(35) | REQUIRED for money orders (TypeID=2 only) | |
| {{COALESCE( \ Country.IsoCode, \ 'SE' \ )}} | CdtTrfTxInf/Cdtr/PstlAdr/Ctry | String(2) | Creditor country code |
| ProBill Source | ISO20022 XML Path | Required | Data Type | Notes |
|---|---|---|---|---|
| Money order (TypeID=2): \ Literal: 'NOTPROVIDED' \ \ Others: \ {{FnPrCleanPayoutAccountNumber( \ COALESCE( \ BillLocation.PayoutAccount, \ Customer.PayoutAccount, \ LedgerPayout.AccountNumber \ ) \ )}} | CdtTrfTxInf/CdtrAcct/Id/Othr/Id | String(34) | Recipient account number \ Cleaned of dashes, spaces, special chars \ Money orders use literal 'NOTPROVIDED' | |
| 'BBAN' if Bank (1) or PG (3) | CdtTrfTxInf/CdtrAcct/Id/Othr/SchmeNm/Cd | String(4) | Account scheme code for BBAN format | |
| 'BGNR' if Bankgiro (4) | CdtTrfTxInf/CdtrAcct/Id/Othr/SchmeNm/Prtry | String(35) | Proprietary scheme for Bankgiro |
| ProBill Source | ISO20022 XML Path | Required | Data Type | Notes |
|---|---|---|---|---|
| Swedbank: \ 'CINV' (if invoice exists) \ \ Nordea: \ 'SCOR' (if invoice exists) | Swedbank: \ CdtTrfTxInf/RmtInf/Strd/RfrdDocInf/Tp/CdOrPrtry/Cd \ \ Nordea: \ CdtTrfTxInf/RmtInf/Strd/CdtrRefInf/Tp/CdOrPrtry/Cd | String(4) | Document type code (if invoice reference provided) | |
| {{COALESCE( \ CAST(Invoice.InvoiceNumber AS VARCHAR(100)), \ CAST(Invoice2.InvoiceNumber AS VARCHAR(100)), \ CAST(Payment.ReferenceID AS VARCHAR(100)) \ )}} | Swedbank: \ CdtTrfTxInf/RmtInf/Strd/RfrdDocInf/Nb \ \ Nordea: \ CdtTrfTxInf/RmtInf/Strd/CdtrRefInf/Ref | String(25/35) | Invoice/reference number \ Swedbank: max 25 chars \ Nordea: max 35 chars | |
| Currency.ExternalID | CdtTrfTxInf/RmtInf/Strd/RfrdDocAmt/RmtdAmt/@Ccy | String(3) | Currency attribute for remitted amount | |
| {{ISNULL( \ LedgerPayout.CurrencyAmount, \ LedgerPayout.Amount \ )}} | CdtTrfTxInf/RmtInf/Strd/RfrdDocAmt/RmtdAmt | Decimal(18,2) | Remitted document amount |
| ProBill Source | ISO20022 XML Path | Required | Data Type | Notes |
|---|---|---|---|---|
| {{COALESCE( \ CAST(Invoice.InvoiceNumber AS VARCHAR(100)), \ CAST(Invoice2.InvoiceNumber AS VARCHAR(100)), \ CAST(Payment.ReferenceID AS VARCHAR(100)) \ )}} | CdtTrfTxInf/RmtInf/Ustrd | String(140) | Unstructured remittance information \ Shown only for bank account transfers |
| TypeID | Swedish Name | Description | Account Format | Special Rules |
|---|---|---|---|---|
| 1 | Kontoinsättning | Bank Account Transfer | Clearing (4 digits) + Account number | • Requires valid clearing number \ • CdtrAgt/ClrSysMmbId required \ • SchmeNm: 'BBAN' |
| 2 | Kontantutbetalning | Money Order / Check | Literal: 'NOTPROVIDED' | • REQUIRES full postal address \ • PmtMtd: 'CHK' \ • No account number needed \ • Swedbank: Separate PmtInf segment |
| 3 | Plusgiroinsättning | Plusgiro Transfer | Plusgiro number (no dashes) | • ClrSysMmbId: '9960' \ • SchmeNm: 'BBAN' \ • Structured remittance supported |
| 4 | Bankgiroinsättning | Bankgiro Transfer | Bankgiro number (no dashes) | • ClrSysMmbId: '9900' \ • SchmeNm/Prtry: 'BGNR' \ • Structured remittance supported |
| 5 | Autogiro | Direct Debit (AG) | N/A | • Handled separately \ • Uses spPrExpDirectDebitPayout \ • Not included in pain.001 file |
-- FnPrCleanPayoutAccountNumber removes: • Dashes (-) • Spaces ( ) • Slashes (/, \) • Dots (.) • Special characters Result: Pure numeric string for Swedish accounts
-- FnPrGetClearingsNrFromAccountNr extracts: For Bank Accounts (TypeID=1): • First 4 digits of account number • Used in CdtrAgt/FinInstnId/ClrSysMmbId/MmbId For Plusgiro (TypeID=3): • Returns fixed value: '9960' For Bankgiro (TypeID=4): • Returns fixed value: '9900' For Money Orders (TypeID=2): • Returns NULL (not applicable)
Key Differences:
Required Configuration:
PaymentAccount.SwedbankAgreementID -- NOT NULL PaymentAccount.OutBankgiroNumber -- NOT NULL PaymentAccount.BIC -- NOT NULL PaymentAccount.PayoutOrgID -- NOT NULL
Key Differences:
Required Configuration:
PaymentAccount.NordeaSignerID -- NOT NULL PaymentAccount.NordeaSenderID -- NOT NULL (if using secure envelope) PaymentAccount.BIC -- NOT NULL PaymentAccount.IBAN -- Preferred, or fallback to PG/BG PaymentAccount.NordeaOrgID -- Preferred, or fallback to PayoutOrgID
✓ Amount must be > 0 ✓ Use CurrencyAmount if LedgerPayout.CurrencyID is set ✓ CtrlSum must match SUM of all transaction amounts ✓ NbOfTxs must match COUNT of all transactions
• ReqdExctnDt calculated with weekend adjustment: - Friday → Monday (+3 days) - Saturday → Monday (+2 days) - Sunday → Monday (+1 day) - Weekday → Next day (+N days based on AppSetting 'PayoutPlacementDateDays')
Swedish Format Requirements: • Bank: 4-digit clearing + 7-12 digit account • Plusgiro: 1-8 digits (may include control digit) • Bankgiro: 7-8 digits (format: XXXX-XXXX) • All cleaned before export (no formatting chars)
Domestic (SEK): • CurrencyID = 4 (or NULL defaults to SEK) • Amount field used directly • Currency/@Ccy = 'SEK' Foreign Currency: • CurrencyID set to non-SEK currency • CurrencyAmount must be populated • Use CurrencyAmount for Amt/InstdAmt • Currency/@Ccy = Currency.ExternalID (e.g., 'EUR', 'USD')
All three fields REQUIRED when PayoutTypeID = 2: ✓ Cdtr/PstlAdr/StrtNm (Street address) ✓ Cdtr/PstlAdr/PstCd (Postal code, no spaces) ✓ Cdtr/PstlAdr/TwnNm (Town/city name) Missing any field → Payment rejected/error logged
Structured Remittance (PG/BG): • Swedbank: Max 25 characters in RfrdDocInf/Nb • Nordea: Max 35 characters in CdtrRefInf/Ref • Used for invoice numbers or payment references Unstructured Remittance (Bank accounts): • Max 140 characters in Ustrd • Typically shows first 12 chars in practice • Used when PayoutTypeID NOT IN (3, 4)
StatusID = 0 → Ej behandlad (Not processed)
↓
StatusID = 1 → Utbetalning skickad (Payment sent to bank)
↓
StatusID = 2 → Utbetalning utförd (Payment completed)
OR
StatusID = 3 → Utbetalning nekad (Payment rejected)
When validation fails, payment is removed from batch and logged:
• ErrorData field populated with error description • StatusID remains 0 (not processed) • PrSys.ExtUpdate notified for client refresh • Examples: - "Utbetalningstyp och Konto, utbetalning ej komplett uppsatt" - "Ingen BIC i PaymentAccount" - "Inget PlusGiro, BankGiro eller IBAN i PaymentAccount"
LedgerPayout.FileID = @FileID → Links payment to export file LedgerPayout.Handled = GETDATE() → Timestamp of export LedgerEvent.StatusID updated based on PayoutAwaitResponse setting
LedgerPayout (Main payout record)
ID INT -- Used as EndToEndId in XML LedgerEventID INT -- Link to accounting event BillLocationID INT -- Link to billing location CustomerID INT -- Link to customer Amount NUMERIC(18,2) -- Base amount (SEK) CurrencyAmount NUMERIC(18,2) -- Foreign currency amount CurrencyID SMALLINT -- Foreign currency ID TypeID INT -- PayoutTypeID (1-5) StatusID INT -- Processing status AccountNumber NVARCHAR(40) -- Recipient account Name/CareOf/Address/Zipcode/City -- Recipient address info FileID INT -- Export file reference TransactionDate DATE -- Transaction/placement date
PaymentAccount (Sender configuration)
ID INT CustomerNumber NVARCHAR(80) -- Company name (Dbtr/Nm) BIC VARCHAR(11) -- Bank BIC IBAN VARCHAR(34) -- Debtor IBAN OutPlusgiroNumber VARCHAR(20) -- Outgoing Plusgiro OutBankgiroNumber VARCHAR(50) -- Outgoing Bankgiro (NEW) PayoutOrgID VARCHAR(20) -- Organization number NordeaOrgID VARCHAR(36) -- Nordea org ID NordeaSignerID VARCHAR(50) -- Nordea signer NordeaSenderID VARCHAR(50) -- Nordea sender SwedbankAgreementID VARCHAR(35) -- Swedbank agreement CompanyGroupID INT -- Links to Company.GroupID
Customer / BillLocation (Recipient info)
-- Recipient details hierarchy: 1. CustomerContactInformation (ContactInformationTypeID=3) - Name, Address, Zipcode, City 2. Customer (fallback) - DispName1, DispAddress, Zipcode, City 3. BillLocation (account override) - PayoutAccount, PayoutTypeID
LedgerPayout ├─> LedgerEvent (accounting) ├─> BillLocation (PayoutAccount override, PayoutTypeID) ├─> Customer (recipient info, PayoutAccount, PayoutTypeID) ├─> Currency (foreign currency) └─> Invoice (via LedgerEvent, for remittance info) PaymentAccount └─> Company.GroupID (multi-company support)
-- Example: Extract data for payment batch export SELECT -- Transaction ID lp.ID AS EndToEndId, -- Amount ISNULL(lp.CurrencyAmount, lp.Amount) AS Amount, ISNULL(cu.ExternalID, 'SEK') AS Currency, -- Recipient Info COALESCE(cci.Name, c.DispName1) AS CreditorName, COALESCE(bl.PayoutAccount, c.PayoutAccount, lp.AccountNumber) AS CreditorAccount, ISNULL(bl.PayoutTypeID, c.PayoutTypeID) AS PayoutTypeID, -- Recipient Address (for money orders) ISNULL(cci.Address, c.DispAddress) AS StreetName, REPLACE(ISNULL(cci.Zipcode, c.Zipcode), ' ', '') AS PostalCode, ISNULL(cci.City, c.City) AS TownName, COALESCE(co.IsoCode, 'SE') AS Country, -- Remittance Info COALESCE(i.InvoiceNumber, i2.InvoiceNumber, p.ReferenceID) AS Reference, -- Payment Account Info pa.CustomerNumber AS DebtorName, pa.BIC, pa.IBAN, pa.OutBankgiroNumber, pa.OutPlusgiroNumber, pa.PayoutOrgID FROM dbo.LedgerPayout lp INNER JOIN dbo.LedgerEvent le ON le.ID = lp.LedgerEventID INNER JOIN dbo.BillLocation bl ON bl.ID = lp.BillLocationID INNER JOIN dbo.V_RepCustomer c ON c.ID = lp.CustomerID INNER JOIN dbo.PaymentAccount pa ON pa.ID = @PaymentAccountID LEFT JOIN dbo.Currency cu ON cu.ID = lp.CurrencyID LEFT JOIN dbo.CustomerContactInformation cci ON cci.CustomerID = c.ID AND cci.ContactInformationTypeID = 3 AND cci.IsDeleted = 0 LEFT JOIN dbo.Country co ON co.ID = ISNULL(cci.CountryID, c.CountryID) LEFT JOIN dbo.Payment p ON p.ID = le.PaymentID LEFT JOIN dbo.Invoice i ON i.ID = le.ReferencedInvoiceID LEFT JOIN dbo.Invoice i2 ON i2.ID = p.InvoiceID WHERE lp.StatusID = 0 -- Not processed AND le.StatusID = 4 -- Approved for payout AND lp.TypeID != 5 -- Exclude Autogiro AND ISNULL(lp.CurrencyID, 4) = @CurrencyID ORDER BY lp.ID
PaymentAccount Setup (per company/bank)
System Settings (PrSys.AppSetting)
Customer/BillLocation Data Quality
Currency Configuration
For questions about implementation or field mapping, reference:
Document Version: 1.0
Last Updated: 2026-01-30
Based on: ProBillDB version 2.0.4751.0+
------------------------------------------------------------------------------------------------------------------------
ProBill handles AutoGiro, TotalIN, BgMax, and Camt.054 files for incoming payments.
Flow description: Flöde autogiro i ProBill.xlsx
Old file layout according to: https://www.bankgirot.se/globalassets/dokument/tekniska-manualer/autogiro_tekniskmanual_sv.pdf
# Requirements Specification – CAMT.054 Payments in ProBill
**Date:** 2026-03-04
**Scope:** Incoming payments and CAMT.054 outgoing payments. Pain.002 handling is **not** covered by this specification.
---
## 1. Purpose and Scope
This requirements specification describes how ProBill interprets and stores payments from CAMT.054 files (ISO 20022 standard, message type `BkToCstmrDbtCdtNtfctn`, version `camt.054.001.02`).
**Included:**
- Identification of incoming and outgoing payment files
- Which XML tags are read
- Logic for calculating key variables (incoming payments)
- Mapping to `dbo.Payment` (incoming payments)
- Mapping to `dbo.LedgerPayoutResult` (outgoing payments)
- Error handling and status assignment (incoming payments)
**Excluded:**
- Pain.002 (payment status / rejected outgoing payments)
---
## 2. Identification of File Type
A file is identified as CAMT.054 if the XML content contains the element name `BkToCstmrDbtCdtNtfctn`.
**XML namespace:** `urn:iso:std:iso:20022:tech:xsd:camt.054.001.02`
The file type is then determined by `GrpHdr/AddtlInf`:
| Condition | File type | Target table |
|---|---|---|
| `GrpHdr/AddtlInf` does not contain `DEBT` | Incoming payment | `dbo.Payment` |
| `GrpHdr/AddtlInf` contains `DEBT` | Outgoing payment | `dbo.LedgerPayoutResult` |
---
## 3. XML Structure and Tags Read
The CAMT.054 file has a hierarchical structure with three levels that are read:
```
Document/BkToCstmrDbtCdtNtfctn
├── GrpHdr ← Message header (one per file)
└── Ntfctn ← Notification / account (one or more per file)
├── Id
├── CreDtTm
├── Acct ← Receiver account
└── Ntry ← Transaction / entry (one or more per Ntfctn)
├── BookgDt/Dt
├── ValDt/Dt
└── NtryDtls/TxDtls ← Transaction details
├── Refs
├── AmtDtls
├── RltdPties ← Involved parties
├── Purp
├── RltdDts
└── RmtInf ← Remittance information
├── Ustrd
└── Strd ← Structured remittance (one or more)
```
### 3.1 Message Header – GrpHdr
Read once per file from `/Document/BkToCstmrDbtCdtNtfctn`.
| XML tag | Description |
|---|---|
| `GrpHdr/MsgId` | Unique message ID |
| `GrpHdr/CreDtTm` | Message creation date and time |
| `GrpHdr/AddtlInf` | Additional information. Used to distinguish incoming payments (no `DEBT`) from outgoing payments (`DEBT` present). |
### 3.2 Account Information – Ntfctn
Read per `Ntfctn` node. Represents the receiving account (seller's account).
| XML tag | Description |
|---|---|
| `Ntfctn/Id` | Unique notification ID. Mandatory per standard. Used to link the account to the correct transactions. |
| `Ntfctn/CreDtTm` | Notification creation date and time |
| `Ntfctn/Acct/Id/IBAN` | Receiver account IBAN number |
| `Ntfctn/Acct/Id/Othr/Id` | Receiver account BBAN (e.g. bankgiro number) |
| `Ntfctn/Acct/Id/Othr/SchmeNm/Cd` | Account scheme code (e.g. `BBAN`) |
| `Ntfctn/Acct/Ownr/Id/OrgId/Othr/Id` | Account owner organisation ID (e.g. organisation number) |
> **Note:** A CAMT.054 file may contain multiple `Ntfctn` nodes. Each `Ntfctn` has a unique `Id` used to ensure each transaction is linked to the correct account.
### 3.3 Transaction Details – Ntry / TxDtls / Strd
Read per transaction. An `Ntfctn` can have multiple `Ntry` nodes, and each `Ntry` can have multiple `TxDtls` and/or `Strd` nodes.
> Transactions without a `Strd` element are still included (e.g. Swish payments).
| XML tag | Description |
|---|---|
| `Ntfctn/Ntry/BookgDt/Dt` | Booking date |
| `Ntfctn/Ntry/ValDt/Dt` | Value date |
| `TxDtls/Refs/AcctSvcrRef` | Bank's internal transaction ID |
| `TxDtls/Refs/EndToEndId` | End-to-end reference. Used for Swish to identify the mobile number. |
| `TxDtls/AmtDtls/TxAmt/Amt` | Transaction amount |
| `TxDtls/AmtDtls/TxAmt/Amt/@Ccy` | Currency code for the transaction amount (XML attribute) |
| `TxDtls/RltdPties/Dbtr/Nm` | Payer name |
| `TxDtls/RltdPties/Dbtr/PstlAdr/StrtNm` | Payer street address |
| `TxDtls/RltdPties/Dbtr/PstlAdr/PstCd` | Payer postal code |
| `TxDtls/RltdPties/Dbtr/PstlAdr/TwnNm` | Payer city |
| `TxDtls/RltdPties/Dbtr/Id/OrgId/Othr/Id` | Payer organisation number |
| `TxDtls/RltdPties/DbtrAcct/Id/IBAN` | Payer account number (IBAN) |
| `TxDtls/RltdPties/DbtrAcct/Id/Othr/Id` | Payer account number (BBAN or other). Also used as Swish mobile number. |
| `TxDtls/RltdPties/DbtrAcct/Id/Othr/SchmeNm/Prtry` | Account scheme name for payer's account |
| `TxDtls/RltdPties/UltmtDbtr/Nm` | Ultimate debtor name (if different from Dbtr) |
| `TxDtls/RltdPties/UltmtDbtr/PstlAdr/StrtNm` | Ultimate debtor street address |
| `TxDtls/RltdPties/UltmtDbtr/PstlAdr/PstCd` | Ultimate debtor postal code |
| `TxDtls/RltdPties/UltmtDbtr/PstlAdr/TwnNm` | Ultimate debtor city |
| `TxDtls/RltdPties/UltmtDbtr/Id/OrgId/Othr/Id` | Ultimate debtor organisation number |
| `TxDtls/RltdPties/Cdtr/Nm` | Payee (creditor) name |
| `TxDtls/RltdPties/CdtrAcct/Id/IBAN` | Payee IBAN |
| `TxDtls/RltdPties/CdtrAcct/Id/Othr/Id` | Payee BBAN (bankgiro) |
| `TxDtls/Purp/Cd` | Payment purpose code. Used for Swish identification. |
| `TxDtls/RltdDts/AccptncDtTm` | Acceptance date/time |
| `TxDtls/RmtInf/Ustrd` | Unstructured remittance message (free text) |
| `RmtInf/Strd/RfrdDocInf/Nb` | Invoice number |
| `RmtInf/Strd/RfrdDocAmt/CdtNoteAmt` | Credit note amount |
| `RmtInf/Strd/RfrdDocAmt/CdtNoteAmt/@Ccy` | Currency for credit note amount (XML attribute) |
| `RmtInf/Strd/RfrdDocAmt/RmtdAmt` | Remitted amount (actual amount paid) |
| `RmtInf/Strd/RfrdDocAmt/RmtdAmt/@Ccy` | Currency for remitted amount (XML attribute) |
| `RmtInf/Strd/CdtrRefInf/Ref` | OCR reference (payer's reference to the creditor) |
| `RmtInf/Strd/AddtlRmtInf` | Additional remittance information. May appear **multiple times** in the same `Strd` element – all repetitions are concatenated into a single text value. Used among other things for Swish payments (contains `OrderID:`). |
---
## 4. Logic for Key Variables
The following variables are calculated before mapping to the target table.
### 4.1 Swish Identification (IsSwish)
A payment is classified as Swish based on a combination of three signals:
| Signal | XML source |
|---|---|
| Mobile number / reference | `ISNULL(TxDtls/Refs/EndToEndId, TxDtls/RltdPties/DbtrAcct/Id/Othr/Id)` |
| Free text | `RmtInf/Strd/AddtlRmtInf` |
| Purpose code | `TxDtls/Purp/Cd` |
Results in `IsSwish = 1` (Swish) or `IsSwish = 0` (not Swish).
### 4.2 ReferenceID
Calculated using the following priority order (first non-empty value is used):
| Priority | Source | Comment |
|---|---|---|
| 1 | `RmtInf/Strd/CdtrRefInf/Ref` | OCR reference |
| 2 | `RmtInf/Strd/RfrdDocInf/Nb` | Invoice number |
| 3 | Extracted from `RmtInf/Strd/AddtlRmtInf` | **Only if IsSwish = 1:** the text between `'OrderID: '` and `'-'` is extracted. Swish messages contain an order ID formatted as `'OrderID: XXXXX-...'`. |
| 4 | `RmtInf/Strd/AddtlRmtInf` (if not Swish) | Used as reference if none of the above are present |
| 5 | `RmtInf/Ustrd` | Unstructured message as last resort |
### 4.3 Amount
Calculated using the following priority order:
| Priority | Source | Comment |
|---|---|---|
| 1 | `RmtInf/Strd/RfrdDocAmt/RmtdAmt` | Remitted amount – actual payment |
| 2 | `-` + `RmtInf/Strd/RfrdDocAmt/CdtNoteAmt` | Credit note amount stored with **negative sign** (credit note = refund) |
| 3 | `TxDtls/AmtDtls/TxAmt/Amt` | Transaction amount |
| 4 | `0` | Fallback if no amount is found (field is NOT NULL in target table) |
### 4.4 EntryDate (Booking Date)
```
EntryDate = Ntfctn/Ntry/BookgDt/Dt (NULL if empty)
```
### 4.5 PaymentDate
Calculated using the following priority order:
| Priority | Source |
|---|---|
| 1 | `TxDtls/RltdDts/AccptncDtTm` |
| 2 | `Ntfctn/Ntry/ValDt/Dt` |
| 3 | `Ntfctn/Ntry/BookgDt/Dt` |
---
## 5. Incoming Payments – Mapping to dbo.Payment
The table below shows exactly how each column in `dbo.Payment` is populated.
| Column | XML source / Logic |
|---|---|
| `FileID` | File ID (link to source file) |
| `Created` | `Ntfctn/CreDtTm` – converted to DATETIME2. Four conversion formats are tried in order. Fallback: `1900-01-01`. |
| `SellerReference` | `Ntfctn/Acct/Ownr/Id/OrgId/Othr/Id` – seller's organisation identification |
| `SellerAccount` | Receiver account formatted in priority order: IBAN prefixed with `[IBAN]`, otherwise BBAN prefixed with the scheme code e.g. `[BBAN] 12345678` |
| `EntryDate` | See §4.4. Fallback: `1900-01-01` (NOT NULL). |
| `PaymentDate` | See §4.5. Fallback: `1900-01-01` (NOT NULL). |
| `ArchiveID` | `TxDtls/Refs/AcctSvcrRef` – bank's internal transaction ID |
| `ReferenceID` | See §4.2. **Only if the value is numeric** – otherwise NULL (placed in Comment instead). |
| `Comment` | Populated according to three cases in priority order: (1) if ReferenceID is non-numeric: the non-numeric reference value, (2) if IsSwish = 1: `'Swish från mobilnummer 0'` + mobile number, (3) otherwise: NULL |
| `OCRMessage` | `RmtInf/Strd/AddtlRmtInf` – raw additional information. NULL if empty. |
| `PayeeName` | `UltmtDbtr/Nm` if present, otherwise `Dbtr/Nm` |
| `PayeeAddress` | `UltmtDbtr/PstlAdr/StrtNm` if present, otherwise `Dbtr/PstlAdr/StrtNm` |
| `PayeeZipCode` | `UltmtDbtr/PstlAdr/PstCd` if present, otherwise `Dbtr/PstlAdr/PstCd`. **Spaces are removed.** |
| `PayeeCity` | `UltmtDbtr/PstlAdr/TwnNm` if present, otherwise `Dbtr/PstlAdr/TwnNm` |
| `PayeeOrgNumber` | `UltmtDbtr/Id/OrgId/Othr/Id` if present, otherwise `Dbtr/Id/OrgId/Othr/Id` |
| `PaymentAccount` | Receiver account in priority order: (1) `CdtrAcct/Id/IBAN`, (2) `CdtrAcct/Id/Othr/Id` (bankgiro), (3) fallback to SellerAccount (if CdtrAcct is missing) |
| `PayeeAccount` | Payer account in priority order: (1) `[IBAN]` + `DbtrAcct/Id/IBAN`, (2) scheme code + `DbtrAcct/Id/Othr/Id`, (3) `DbtrAcct/Id/Othr/Id` |
| `Amount` | See §4.3. NOT NULL. |
| `Currency` | Currency code: `RmtdAmt/@Ccy` → `CdtNoteAmt/@Ccy` → `TxAmt/@Ccy` |
| `CurrencyID` | Currency ID via lookup on currency code |
| `ReturnMaterialCode` | NULL (not mapped) |
| `RecordCode` | `6` if IsSwish = 1 (Swish), otherwise `3` (BG/PG) |
| `CorrectionCode` | `0` (fixed value) |
| `SourceID` | `1` if SellerAccount matches a debt collection or post-watch account, otherwise `0` (bank) |
| `ErrorID` | See §6.1 |
| `StatusID` | See §6.2 |
| `Handled` | See §6.3 |
---
## 6. Incoming Payments – Error Handling and Status Assignment
### 6.1 ErrorID – Error Code
Checked in priority order – **first matching error** is used:
| Priority | Condition | ErrorID | Description |
|---|---|---|---|
| 1 | ReferenceID missing/non-numeric **and** Amount = 0 | `1` | Invoice not found |
| 2 | ReferenceID missing or non-numeric | `6` | Incorrect reference number |
| 3 | Amount = 0 | `38` | Unreasonable amount |
| 4 | SellerAccount is a post-watch account | `8` | Post-watch |
| 5 | EntryDate missing | `43` | Booking date missing |
| 6 | PaymentDate missing | `44` | Payment date missing |
| 7 | No errors | `NULL` | – |
### 6.2 StatusID – Status
| Condition | StatusID | Status |
|---|---|---|
| ReferenceID missing/non-numeric, **or** Amount = 0, **or** EntryDate missing, **or** PaymentDate missing | `2` | Error |
| None of the above | `0` | New |
### 6.3 Handled – Direct Flagging
Records with an identified error are marked as handled immediately upon import (Handled = current timestamp). This prevents a subsequent process from overwriting the specific error code with a more generic value.
**Records are flagged immediately if:** ReferenceID is missing/non-numeric, Amount = 0, EntryDate is missing, or PaymentDate is missing.
All other records are left unflagged (Handled = NULL) for further processing.
---
## 7. Outgoing Payments – Mapping to dbo.LedgerPayoutResult
### 7.1 Identification
A record is treated as an outgoing payment if `GrpHdr/AddtlInf` contains the string `DEBT`.
### 7.2 Link to LedgerPayout
The outgoing payment is linked to an existing payout order via:
- `TxDtls/Refs/EndToEndId` cast as integer → matched against `LedgerPayout.ID`
- `CustomerID` is retrieved from the matching `LedgerPayout` record
### 7.3 Mapping
The same XML tags described in section 3 are used. The table below shows how each column in `dbo.LedgerPayoutResult` is populated.
| Column | XML source / Logic |
|---|---|
| `FileID` | File ID (link to source file) |
| `Inserted` | Current timestamp at import |
| `Handled` | NULL on INSERT (processed further by a subsequent job) |
| `StatusID` | `2` (= Payout executed) |
| `FileDate` | `Ntfctn/CreDtTm` – converted to DATETIME. If direct conversion fails, conversion via DATETIMEOFFSET is attempted. |
| `PayerAccount` | `Ntfctn/Acct/Id/IBAN` if present, otherwise `Ntfctn/Acct/Id/Othr/Id` |
| `Reason` | NULL (not mapped) |
| `Amount` | Priority order: (1) `RmtInf/Strd/RfrdDocAmt/RmtdAmt`, (2) `-` + `RmtInf/Strd/RfrdDocAmt/CdtNoteAmt` (credit note stored with negative sign), (3) `TxDtls/AmtDtls/TxAmt/Amt` |
| `PayoutDate` | `Ntfctn/Ntry/ValDt/Dt` if present, otherwise `Ntfctn/Ntry/BookgDt/Dt` |
| `Name` | `TxDtls/RltdPties/Cdtr/Nm` |
| `PayeeAccount` | `TxDtls/RltdPties/CdtrAcct/Id/IBAN` if present, otherwise `TxDtls/RltdPties/CdtrAcct/Id/Othr/Id` |
| `PayoutID` | `TxDtls/Refs/EndToEndId` cast as integer → ID in `LedgerPayout` |
| `CustomerID` | Retrieved from the matching `LedgerPayout` record via `PayoutID` |
### 7.4 Post-processing
After INSERT, each outgoing payment record is marked as handled (Handled = current timestamp). If outgoing payment records were inserted, a subsequent process for result handling is triggered.
---
*Based on existing implementation in ProBill version: 2.0.4833.0. XML standard: ISO 20022 camt.054.001.02.*
---