ediverse Explore the platform

Spotlight PEPPOL BIS Billing 3.0 The EU e-invoicing mandate is here — France Sept 2026, Belgium Jan 2026, Germany 2025.

E-faktura — Bankgirot / Nets, consumer invoicing

E-faktura is Sweden's historical electronic invoicing system for consumers, launched in 1995 by Bankgirot. With ~12 million users and ~250 million invoices per year, it is Europe's most mature B2C network. Not to be confused with PEPPOL (B2B/B2G): the two coexist without functional overlap.

History — 30 years of Bankgirot

The E-faktura system is the result of 30 years of payment innovation in Sweden:

  • 1959: creation of Bankgirocentralen (BgC) by the Swedish banks to manage domestic interbank transfers.
  • 1971: introduction of the Bankgiro system (7-8-digit numbers) for invoice payments, alternative to Plusgiro (postal).
  • 1995: launch of E-faktura BgC — world's first "invoice presented inside the online bank" offering, pioneer of EBPP (Electronic Bill Presentment and Payment).
  • 2005: mobile integration via banking apps (BankID required for signature).
  • 2014: renamed to simply "E-faktura", opening to foreign players (Klarna, PayEx) for B2C presentation.
  • 2022: acquisition of Bankgirot by Nets Group (Mastercard subsidiary since 2021) for ~SEK 9.5 billion. See next section.

Acquisition by Nets in 2022

The acquisition of Bankgirot by Nets in 2022 marked a structural turning point for the Nordic payment landscape:

  • Seller: consortium of 7 Swedish banks (SEB, Swedbank, Handelsbanken, Nordea, Danske Bank, Länsförsäkringar Bank, Skandiabanken) — historical shareholders.
  • Buyer: Nets Group, acquired by Mastercard in 2021 (deal ~USD 7.3B). Creation of a pan-European Nets player covering DK, NO, SE, FI.
  • Scope: 100% of Bankgirot assets — BG payment infrastructure, E-faktura, OCR processing, Autogiro reconciliation.
  • Operational continuity: no end-user change, "Bankgirot" brand maintained. Headquarters remain in Stockholm.
  • Regulatory consequences: authorisation by Konkurrensverket (competition authority) in April 2022, conditional on a non-discrimination commitment between banks.
  • Nets vision: consolidate SE E-faktura with eBoks (DK), Vipps (NO), MobilePay (DK/FI) to create a unified Nordic platform — "Nordic Hub" project 2025-2027.

How E-faktura works

The E-faktura flow follows a 3-corner model:

  1. Issuer: B2C company (Telia, Vattenfall, Ellevio, Apotek, ICA, SJ AB) issues the invoice in its ERP, sends it in ITSME format (Internet Transaction Security Multipart Encoding) to Bankgirot via a secure SFTP/HTTPS connection.
  2. Bankgirot Hub: routes the invoice to the recipient's bank (lookup by E-faktura contract number = customer identifier + bank number).
  3. Receiving bank: presents the invoice in the recipient's app/online banking, who can approve in one click (BankID signature), modify the amount or refuse.
  4. Payment: on due date, the bank automatically debits the recipient's account and credits the issuer via Bankgiro (T+1 settlement).
  5. Confirmation: Bankgirot returns a payment acknowledgement to the issuer, who can close the receivable in its ERP.

Integration with SE banks

E-faktura is present in 100% of Swedish retail banks connected to Bankgirot:

BankB2C market shareApp
Swedbank ~28% Swedbank Mobilbanken
Handelsbanken ~17% Handelsbanken Mobilbanken
SEB ~20% SEB Privat-App
Nordea ~15% Nordea Mobile
Länsförsäkringar Bank ~5% LF Mobilbank
Skandiabanken ~3% Skandia App
ICA Banken ~5% ICA Bank App
Resurs Bank, Klarna Bank, others ~7% Respective apps

Coexistence with PEPPOL B2B

E-faktura and PEPPOL coexist without functional overlap — each targets a different segment:

  • E-faktura: B2C only, presentation inside the online banking of natural persons, BankID signature for approval. No B2B validation cycle.
  • PEPPOL: B2B / B2G via AS4 eDelivery network, addressed to ERPs / management systems. No presentation to natural persons.
  • No migration: unlike the Norwegian scenario (eFaktura B2C on EHF being unified), Sweden does not plan a merger. Both systems will remain independent in the medium term.
  • Possible bridges: some ERP vendors (Visma, Fortnox) offer a dual mode that issues the invoice in PEPPOL for B2B and in E-faktura for B2C depending on the recipient. No standardisation.

Bankgirot OCR — structured reference

At the heart of the Bankgirot/E-faktura system: the OCR reference (Optical Character Recognition reference, actually closer to a Modulo 10 identifier), the Swedish equivalent of the Belgian structured communication or the SEPA creditor reference.

  • Length: 2 to 25 digits (typically 8-12), last digit = checksum.
  • Algorithm: "Modulo 10 vikt 1212" (Luhn variant with alternating 1-2-1-2 weighting from the right).
  • Long variant: some issuers use the "OCR with length" format (one digit indicates the total length, allowing stricter control).
  • Usage: printed on the paper invoice (OCR line at the bottom), automatically reproduced by banking apps during payment, allows the issuer to do automatic reconciliation payment → receivable.
python ocr-bankgirot-checksum.py
# Computing a Swedish Bankgirot OCR reference (Modulo 10 vikt 1212 algorithm)
# Reference: length 1-25 digits + 1 checksum + (optional) length digit
# Example: invoice 123456 at Telia
#   Company internal reference: 123456
#   We add a Luhn-like checksum ("Modulo 10 vikt 1212")

def calculate_ocr_checksum(ref):
    """Bankgirot's OCR checksum — modulo 10 with alternating 1-2-1-2 weighting"""
    digits = [int(d) for d in str(ref)]
    weighted_sum = 0
    for i, d in enumerate(reversed(digits)):
        # Position 1 (rightmost) = weight 2, position 2 = weight 1, etc.
        weight = 2 if i % 2 == 0 else 1
        weighted = d * weight
        # If > 9, sum the two digits (equivalent to -9)
        weighted_sum += weighted if weighted < 10 else weighted - 9
    return (10 - weighted_sum % 10) % 10

# Examples
ref = "123456"
checksum = calculate_ocr_checksum(ref)
print(f"OCR reference: {ref}{checksum}")
# Output: OCR reference: 1234562

# Variant with encoded length ("long" Bankgirot reference)
ref = "98765432"  # 8 digits
checksum = calculate_ocr_checksum(ref + str(len(ref) + 1))  # +1 for checksum
length = (len(ref) + 1 + 1) % 10  # total length (final digit)
print(f"Long OCR: {ref}{length}{checksum}")