You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 4 Current »

Outgoing Payment Field Mapping

ISO20022 pain.001.001.03 - Customer Credit Transfer Initiation

This document defines the mapping between ProBill database fields and ISO20022 XML structure for outgoing payments (utbetalningar).


1. GROUP HEADER (GrpHdr) - File Level


ProBill SourceISO20022 XML PathRequiredData TypeNotes
@FileID parameterGrpHdr/MsgId REQUIREDString(35)Unique message identifier for the file
SYSDATETIME()GrpHdr/CreDtTm REQUIREDDateTimeISO8601 format: YYYY-MM-DDTHH:MM:SS
COUNT all transactionsGrpHdr/NbOfTxs REQUIREDIntegerTotal number of payment transactions in file
SUM(Amount) all transactionsGrpHdr/CtrlSum REQUIREDDecimalTotal of all transaction amounts (control sum)
Swedbank: \
PaymentAccount.SwedbankAgreementID \
\
Nordea: \
PaymentAccount.NordeaSignerID
GrpHdr/InitgPty/Id/OrgId/Othr/Id REQUIREDString(35)Bank-specific initiating party identifier
Swedbank: 'BANK' \
Nordea: 'CUST'
GrpHdr/InitgPty/Id/OrgId/Othr/SchmeNm/Cd REQUIREDString(4)Identification scheme code

2. PAYMENT INFORMATION (PmtInf) - Batch Level


ProBill SourceISO20022 XML PathRequiredData TypeNotes
@FileID parameterPmtInf/PmtInfId REQUIREDString(35)Payment information identifier
Based on PayoutTypeID: \
• 'TRF' = Transfers (1,3,4) \
• 'CHK' = Money orders (2)
PmtInf/PmtMtd REQUIREDString(3)Payment method code
COUNT in batchPmtInf/NbOfTxs REQUIREDIntegerNumber of transactions in this payment batch
SUM(Amount) in batchPmtInf/CtrlSum REQUIREDDecimalControl sum for this payment batch
Literal: 'NORM'PmtInf/PmtTpInf/InstrPrty REQUIREDString(4)Instruction priority (Normal)
Literal: 'MPNS'PmtInf/PmtTpInf/SvcLvl/Prtry REQUIREDString(35)Proprietary service level (mandatory for BG/PG)
Literal: 'SUPP'PmtInf/PmtTpInf/CtgyPurp/Cd REQUIREDString(4)Category purpose code (Supplier payment)
CONVERT(VARCHAR(12), SYSDATETIME(), 23)PmtInf/ReqdExctnDt REQUIREDDateRequested execution date: YYYY-MM-DD
PaymentAccount.CustomerNumberPmtInf/Dbtr/Nm REQUIREDString(140)Debtor name (company/organization name)
Literal: 'SE'PmtInf/Dbtr/PstlAdr/Ctry REQUIREDString(2)Debtor country code (ISO 3166-1 alpha-2)
Nordea: \
PaymentAccount.NordeaOrgID \
Fallback: \
PaymentAccount.PayoutOrgID
PmtInf/Dbtr/Id/OrgId/Othr/Id REQUIREDString(35)Debtor organization number
Literal: 'BANK'PmtInf/Dbtr/Id/OrgId/Othr/SchmeNm/Cd REQUIREDString(4)Organization ID scheme code
REPLACE(PaymentAccount.IBAN, ' ', '')PmtInf/DbtrAcct/Id/IBAN CONDITIONALString(34)REQUIRED if using IBAN \
Mutually exclusive with Othr/Id
Swedbank: \
REPLACE(PaymentAccount.OutBankgiroNumber, '-', '') \
Nordea/Others: \
REPLACE(PaymentAccount.OutPlusgiroNumber, '-', '')
PmtInf/DbtrAcct/Id/Othr/Id CONDITIONALString(34)REQUIRED if not using IBAN \
Account number (cleaned)
'BBAN' (if not BG)PmtInf/DbtrAcct/Id/Othr/SchmeNm/Cd CONDITIONALString(4)When using Othr/Id with BBAN format
'BGNR' (if Bankgiro)PmtInf/DbtrAcct/Id/Othr/SchmeNm/Prtry CONDITIONALString(35)When using Bankgiro as debtor account
Currency.ExternalID \
Default: 'SEK'
PmtInf/DbtrAcct/Ccy REQUIREDString(3)Debtor account currency (ISO 4217)
PaymentAccount.BICPmtInf/DbtrAgt/FinInstnId/BIC REQUIREDString(11)Bank Identifier Code (SWIFT)
Literal: 'SE'PmtInf/DbtrAgt/FinInstnId/PstlAdr/Ctry REQUIREDString(2)Bank country code

3. CREDIT TRANSFER TRANSACTION (CdtTrfTxInf) - Per Payment

3.1 Payment Identification & Amount


ProBill SourceISO20022 XML PathRequiredData TypeNotes
LedgerPayout.IDCdtTrfTxInf/PmtId/EndToEndId REQUIREDString(35)Unique transaction identifier for tracking
Currency.ExternalIDCdtTrfTxInf/Amt/InstdAmt/@Ccy REQUIREDString(3)Currency attribute (e.g., "SEK", "EUR")
ISNULL(LedgerPayout.CurrencyAmount, LedgerPayout.Amount)CdtTrfTxInf/Amt/InstdAmt REQUIREDDecimal(18,2)Instructed amount (use CurrencyAmount if foreign currency)

3.2 Creditor Agent (Recipient Bank)


ProBill SourceISO20022 XML PathRequiredData TypeNotes
Based on PayoutTypeID: \
• 'SESBA' if PG/BG/Bank with clearing
CdtTrfTxInf/CdtrAgt/FinInstnId/ClrSysMmbId/ClrSysId/Cd CONDITIONALString(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 CONDITIONALString(35)Clearing member ID \
Extracted via FnPrGetClearingsNrFromAccountNr()

3.3 Creditor (Recipient)


ProBill SourceISO20022 XML PathRequiredData TypeNotes
{{COALESCE( \
CustomerContactInformation.Name, \
Customer.DispName1 \
)}}
CdtTrfTxInf/Cdtr/Nm REQUIREDString(140)Creditor/recipient name
{{ISNULL( \
CustomerContactInformation.Address, \
Customer.DispAddress \
)}}
CdtTrfTxInf/Cdtr/PstlAdr/StrtNm CONDITIONALString(70)REQUIRED for money orders (TypeID=2 only)
{{REPLACE( \
ISNULL( \
CustomerContactInformation.Zipcode, \
Customer.Zipcode \
), ' ', '' \
)}}
CdtTrfTxInf/Cdtr/PstlAdr/PstCd CONDITIONALString(16)REQUIRED for money orders (TypeID=2 only) \
Spaces removed
{{ISNULL( \
CustomerContactInformation.City, \
Customer.City \
)}}
CdtTrfTxInf/Cdtr/PstlAdr/TwnNm CONDITIONALString(35)REQUIRED for money orders (TypeID=2 only)
{{COALESCE( \
Country.IsoCode, \
'SE' \
)}}
CdtTrfTxInf/Cdtr/PstlAdr/Ctry REQUIREDString(2)Creditor country code

3.4 Creditor Account (Recipient Account)


ProBill SourceISO20022 XML PathRequiredData TypeNotes
Money order (TypeID=2): \
Literal: 'NOTPROVIDED' \
\
Others: \
{{FnPrCleanPayoutAccountNumber( \
COALESCE( \
BillLocation.PayoutAccount, \
Customer.PayoutAccount, \
LedgerPayout.AccountNumber \
) \
)}}
CdtTrfTxInf/CdtrAcct/Id/Othr/Id REQUIREDString(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 CONDITIONALString(4)Account scheme code for BBAN format
'BGNR' if Bankgiro (4)CdtTrfTxInf/CdtrAcct/Id/Othr/SchmeNm/Prtry CONDITIONALString(35)Proprietary scheme for Bankgiro

3.5 Remittance Information (Payment Reference)

Structured Remittance (for Plusgiro/Bankgiro)


ProBill SourceISO20022 XML PathRequiredData TypeNotes
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
OPTIONALString(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
OPTIONALString(25/35)Invoice/reference number \
Swedbank: max 25 chars \
Nordea: max 35 chars
Currency.ExternalIDCdtTrfTxInf/RmtInf/Strd/RfrdDocAmt/RmtdAmt/@Ccy OPTIONALString(3)Currency attribute for remitted amount
{{ISNULL( \
LedgerPayout.CurrencyAmount, \
LedgerPayout.Amount \
)}}
CdtTrfTxInf/RmtInf/Strd/RfrdDocAmt/RmtdAmt OPTIONALDecimal(18,2)Remitted document amount

Unstructured Remittance (for Bank accounts)


ProBill SourceISO20022 XML PathRequiredData TypeNotes
{{COALESCE( \
CAST(Invoice.InvoiceNumber AS VARCHAR(100)), \
CAST(Invoice2.InvoiceNumber AS VARCHAR(100)), \
CAST(Payment.ReferenceID AS VARCHAR(100)) \
)}}
CdtTrfTxInf/RmtInf/Ustrd OPTIONALString(140)Unstructured remittance information \
Shown only for bank account transfers

4. PayoutTypeID Logic & Account Format Rules

Payment Type Mapping


TypeIDSwedish NameDescriptionAccount FormatSpecial Rules
1KontoinsättningBank Account TransferClearing (4 digits) + Account number• Requires valid clearing number \
• CdtrAgt/ClrSysMmbId required \
• SchmeNm: 'BBAN'
2KontantutbetalningMoney Order / CheckLiteral: 'NOTPROVIDED'REQUIRES full postal address \
• PmtMtd: 'CHK' \
• No account number needed \
Swedbank: Separate PmtInf segment
3PlusgiroinsättningPlusgiro TransferPlusgiro number (no dashes)• ClrSysMmbId: '9960' \
• SchmeNm: 'BBAN' \
• Structured remittance supported
4BankgiroinsättningBankgiro TransferBankgiro number (no dashes)• ClrSysMmbId: '9900' \
• SchmeNm/Prtry: 'BGNR' \
• Structured remittance supported
5AutogiroDirect Debit (AG)N/AHandled separately \
• Uses spPrExpDirectDebitPayout \
• Not included in pain.001 file

Account Number Cleaning Function

-- FnPrCleanPayoutAccountNumber removes:
• Dashes (-)
• Spaces ( )
• Slashes (/, \)
• Dots (.)
• Special characters

Result: Pure numeric string for Swedish accounts

Clearing Number Extraction

-- 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)

5. Bank-Specific Variations

Swedbank Implementation

Key Differences:

  • Uses SwedbankAgreementID for InitgPty identification
  • Requires OutBankgiroNumber field in PaymentAccount
  • Creates separate <PmtInf> segments for TRF and CHK methods:
    • PmtInfId = @FileID for TRF transactions
    • PmtInfId = @FileID + 1 for CHK transactions (money orders)
  • Uses 'CINV' code in structured remittance (RfrdDocInf/Tp/CdOrPrtry/Cd)
  • Reference number in RfrdDocInf/Nb (max 25 characters)

Required Configuration:

PaymentAccount.SwedbankAgreementID  -- NOT NULL
PaymentAccount.OutBankgiroNumber    -- NOT NULL
PaymentAccount.BIC                  -- NOT NULL
PaymentAccount.PayoutOrgID          -- NOT NULL

Nordea Implementation

Key Differences:

  • Uses NordeaSignerID for InitgPty identification
  • Prefers IBAN format for DbtrAcct/Id/IBAN
  • Falls back to OutPlusgiroNumber/OutBankgiroNumber if no IBAN
  • Uses 'SCOR' code in structured remittance (CdtrRefInf/Tp/CdOrPrtry/Cd)
  • Reference number in CdtrRefInf/Ref (max 35 characters)
  • Single <PmtInf> segment for all payment methods
  • Optional secure envelope wrapping via spPrSecureEnvelope

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

6. Validation Rules & Business Logic

Amount Validation

✓ 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

Date Handling

• 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')

Account Number Rules

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)

Currency Handling

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')

Address Requirements for Money Orders

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

Reference Number Rules

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)

7. Error Handling & Status Tracking

LedgerPayout Status Flow

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)

Validation Failures

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"

File Generation Tracking

LedgerPayout.FileID = @FileID  →  Links payment to export file
LedgerPayout.Handled = GETDATE()  →  Timestamp of export
LedgerEvent.StatusID updated based on PayoutAwaitResponse setting

8. Database Tables & Relationships

Primary Tables

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

Key Relationships

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)

9. Sample SQL Query for Data Extraction

-- 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

10. Configuration Checklist

Before First Export

PaymentAccount Setup (per company/bank)

  • CustomerNumber populated
  • BIC code configured
  • Organization number (PayoutOrgID) set
  • Bank-specific IDs configured (SwedbankAgreementID or NordeaSignerID)
  • At least one account number set (IBAN, OutPlusgiroNumber, or OutBankgiroNumber)

System Settings (PrSys.AppSetting)

  • PayoutPlacementDateDays = Days ahead for placement (default: 0)
  • PayoutAwaitResponse = Wait for bank confirmation? (0/1)
  • EventForDeleteAndPayout = Create offsetting ledger events? (0/1)

Customer/BillLocation Data Quality

  • PayoutTypeID set correctly (1-5)
  • PayoutAccount populated when PayoutTypeID requires it
  • Both fields set together (PayoutTypeID + PayoutAccount)
  • Address complete for money order recipients (TypeID=2)

Currency Configuration

  • Currency.ExternalID uses ISO 4217 codes (SEK, EUR, USD, etc.)
  • CurrencyAmount populated when using foreign currency
  • Default currency ID = 4 (SEK) in your installation

11. Reference Information

ISO20022 Message Standards

  • pain.001.001.03 - Customer Credit Transfer Initiation
  • Namespace: urn:iso:std:iso:20022:tech:xsd:pain.001.001.03
  • Schema validation recommended before bank submission

Swedish Payment System Codes

  • SESBA - Swedish Bankers' Association clearing system
  • 9900 - Standard clearing code for all Bankgiro numbers
  • 9960 - Standard clearing code for all Plusgiro numbers
  • BBAN - Basic Bank Account Number (domestic format)
  • BGNR - Bankgiro Number (proprietary Swedish format)

Contact & Support

For questions about implementation or field mapping, reference:

  • ProBill stored procedure: dbo.spPrPayoutCreate
  • Swedbank variant: dbo.spPrPayoutCreate_Swedbank
  • Helper functions: dbo.FnPrCleanPayoutAccountNumber, dbo.FnPrGetClearingsNrFromAccountNr

Document Version: 1.0
Last Updated: 2026-01-30
Based on: ProBillDB version 2.0.4751.0+


------------------------------------------------------------------------------------------------------------------------

Incoming Payments Mapping

ProBill handles AutoGiro, TotalIN, BgMax, and Camt.054 files for incoming payments.

Autogiro (if BIS will have an AG flow):

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

Camt.054:

# Requirements Specification – CAMT.054 Payments in ProBill
**Date:** 2026-03-04  
**Scope:** Incoming payments and CAMT.054 outgoing payments. Pain.002 handling is covered by this specification above in this page.

---

## 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)

---

## 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. Swish payments carry the code `WEBI`, `SUPP` or `REFU`. |
| `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 (`IsSwish = 1`) if **both** of the following conditions are met:

**Condition 1 – Prerequisite (must be satisfied):**
- `TxDtls/Refs/EndToEndId` is NOT NULL

**Condition 2 – At least one of the following:**

| Check | XML source | Condition |
|---|---|---|
| Free text contains order ID | `RmtInf/Strd/AddtlRmtInf` | Contains the string `'OrderID:'` |
| Purpose code is a Swish code | `TxDtls/Purp/Cd` | Is one of: `WEBI`, `SUPP`, `REFU` |

If `EndToEndId` is NULL, `IsSwish = 0` is always returned regardless of other fields.

### 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.*

---


  • No labels