# KSeF API Integration

Java integration for the Polish **Krajowy System e-Faktur (KSeF)** - the national e-invoicing system for Poland.

## Overview

This integration provides secure communication with the KSeF API to upload electronic invoices. It handles the complex multi-step authentication flow and encryption requirements mandated by the Polish tax authorities.

- [Environment Endpoints](https://github.com/CIRFMF/ksef-docs/blob/main/srodowiska.md)
- [KSeF Official Documentation](https://www.gov.pl/web/kas/ksef)
- [KSeF API Specification](https://api-test.ksef.mf.gov.pl/docs/v2/index.html)
- [Upload Invoice](https://api-test.ksef.mf.gov.pl/docs/v2/index.html#tag/Wysylka-interaktywna/paths/~1api~1v2~1sessions~1online~1%7BreferenceNumber%7D~1invoices/post)
- [Facture Details](https://github.com/CIRFMF/ksef-docs/blob/main/sesja-interaktywna.md#2-wys%C5%82anie-faktury)
- [XML Invoice Example](https://github.com/CIRFMF/ksef-docs/blob/main/faktury/weryfikacja-faktury.md)
- [QR Code](https://github.com/CIRFMF/ksef-docs/blob/main/kody-qr.md)

- [Github Discussions](https://github.com/CIRFMF/ksef-docs/issues/351#issuecomment-3538013805)
- [Github Discussions](https://github.com/CIRFMF/ksef-docs/issues/399)

Test environment endpoint:

```
https://api-test.ksef.mf.gov.pl/api/v2
```

Production endpoint:

```
https://api.ksef.mf.gov.pl/api/v2
```

## Components

### 1. KSeFAuthManager

Manages authentication and session lifecycle for the KSeF API.

**Key Responsibilities:**

- Multi-step authentication flow
- RSA certificate management
- Session key generation and encryption
- Access token lifecycle management
- Session reuse and validation

### 2. KSeFAPIService

Provides business-level methods for invoice operations.

**Key Responsibilities:**

- Invoice encryption (AES-256-CBC)
- Invoice upload to KSeF
- Hash calculation and validation
- Error handling and reporting

## Authentication Flow

The KSeF API requires a sophisticated multi-step authentication process:

```
1. Load Public Keys
   └─> GET /security/public-key-certificates

2. Challenge Request
   └─> POST /auth/challenge
   └─> Returns: challenge + timestamp

3. Token Authentication
   └─> POST /auth/ksef-token
   └─> Encrypts: token|timestamp with RSA-OAEP SHA-256
   └─> Returns: authToken + referenceNumber

4. Token Redemption
   └─> POST /auth/token/redeem
   └─> Returns: accessToken

5. Open Interactive Session
   └─> POST /sessions/online
   └─> Generates AES-256 key + IV
   └─> Encrypts session key with RSA
   └─> Returns: sessionRefNumber + validUntil
```

## Invoice Upload Flow

Once authenticated, invoices can be uploaded:

```
1. Reuse or Create Session
   └─> Validates existing session or creates new one

2. Encrypt Invoice
   └─> AES-256-CBC encryption using session key

3. Calculate Hashes
   └─> SHA-256 of original XML
   └─> SHA-256 of encrypted XML

4. Upload Invoice
   └─> POST /sessions/online/{sessionRef}/invoices
   └─> Returns: referenceNumber
```

## Security Features

### Multi-Layer Encryption

- **RSA-OAEP SHA-256**: Token encryption with timestamp binding
- **RSA-OAEP SHA-1**: Session key encryption
- **AES-256-CBC**: Invoice content encryption

### Security Mechanisms

- **Replay Attack Protection**: Timestamp-bound tokens
- **Session Management**: Automatic session reuse and validation
- **Certificate Validation**: Dynamic X.509 certificate loading
- **UTC Timezone Handling**: Prevents timezone-related vulnerabilities

## Usage Example

```java
// Initialize Auth Manager
KSeFAuthManager authManager = new KSeFAuthManager();
authManager.setKsefToken("your-ksef-token");
authManager.setKsefNip("1234567890");
authManager.setKsefEndpoint("https://ksef-test.mf.gov.pl/api/v2");
authManager.init();

// Initialize API Service
KSeFAPIService apiService = new KSeFAPIService();
apiService.kseFAuthManager = authManager;

// Upload Invoice
ItemCollection workitem = new ItemCollection();
FileData fileData = new FileData("invoice.xml", xmlBytes, null, null);
workitem.addFileData(fileData);

String referenceNumber = apiService.uploadInvoice(workitem, "invoice.xml");
System.out.println("Invoice uploaded: " + referenceNumber);
```

## Configuration

Required environment variables:

```properties
ksef.api.token=your-ksef-authentication-token
ksef.api.nip=your-company-nip-number
ksef.api.endpoint=https://ksef-test.mf.gov.pl/api/v2
ksef.api.debug=false
```

## Session Management

The `KSeFAuthManager` automatically handles session lifecycle:

- **Session Reuse**: Validates `sessionValidUntil` timestamp (UTC)
- **Auto-Renewal**: Opens new session if current one expired
- **Thread-Safe**: Uses `@Lock(LockType.WRITE)` for concurrent access

## Testing

Test environment endpoint:

```
https://ksef-test.mf.gov.pl/api/v2
```

Production endpoint:

```
https://ksef.mf.gov.pl/api/v2
```

See `KSeFAPIServiceTest.java` for complete test examples.

## Error Handling

The implementation uses `PluginException` for error handling with two error types:

- `CONFIG_ERROR`: Configuration or setup issues
- `API_ERROR`: API communication or response errors

## Dependencies

- Jakarta EE (EJB, JSON-B)
- Java 11+ (HttpClient, Crypto APIs)
- Imixs Workflow (for document management)

# Validate XML

To validate XML results use xmllint. To install run:

```bash
$ sudo apt install libxml2-utils
```

With the bash script `src/test/resources/ksef/validate_xml.sh` you can test a xml file:

```bash
$ ./validate_xml.sh example-invoice-01.xml
```

or to manual test a xml run:

```bash
$ xmllint --noout --schema 'schemat-FA(3)-v1-0E.xsd' example-invoice-01.xml
example-invoice-01.xml validates
```

# KSeF FA(3) Invoice Types: VAT vs. KOR

This section explains the key differences between regular invoices (VAT) and correction invoices (KOR) in the Polish KSeF system using FA(3) structure.

## Invoice Types

### VAT - Regular Invoice

Standard invoice documenting a sale or service delivery.

### KOR - Correction Invoice

Invoice that corrects a previously issued invoice (VAT, ZAL, or ROZ).

---

## Key Differences

| Element                   | VAT Invoice                | KOR Invoice                                   |
| ------------------------- | -------------------------- | --------------------------------------------- |
| **RodzajFaktury**         | `VAT`                      | `KOR`                                         |
| **P_2 (Invoice Number)**  | `216525`                   | `216525-KOR` (with suffix)                    |
| **P_1 (Invoice Date)**    | Original date (2024-04-03) | Correction date (2024-04-15)                  |
| **Amount Fields**         | Absolute values            | **Difference values** (negative or positive)  |
| **DaneFaKorygowanej**     | ❌ Not present             | ✅ **Required** - references original invoice |
| **FaWiersz (Line Items)** | Original values            | **New/corrected values**                      |

---

## Critical: Amount Fields in KOR

**KOR invoices show DIFFERENCES, not absolute amounts!**

### Example: Correction from 4128.00 → 3500.00 EUR

```xml
<!-- VAT Invoice -->
<P_13_1>4128.00</P_13_1>  <!-- Total Net -->
<P_14_1>0.00</P_14_1>     <!-- Total VAT -->
<P_15>4128.00</P_15>      <!-- Total Gross -->
```

```xml
<!-- KOR Invoice -->
<P_13_6_1>-628.00</P_13_6_1>  <!-- Difference: 3500 - 4128 = -628 -->
<P_15>-628.00</P_15>          <!-- Difference in Total -->
```

## DaneFaKorygowanej Element

**Required in KOR invoices** - Must appear AFTER `<RodzajFaktury>KOR</RodzajFaktury>`

```xml
<DaneFaKorygowanej>
  <DataWystFaKorygowanej>2024-04-03</DataWystFaKorygowanej>
  <NrFaKorygowanej>216525</NrFaKorygowanej>
  <NrKSeF>1</NrKSeF>
  <NrKSeFFaKorygowanej>9552521552-20240403-ABCDEF-123456-AB</NrKSeFFaKorygowanej>
</DaneFaKorygowanej>
```

| Field                   | Description                                               |
| ----------------------- | --------------------------------------------------------- |
| `DataWystFaKorygowanej` | Date of **original** invoice                              |
| `NrFaKorygowanej`       | Number of **original** invoice                            |
| `NrKSeF`                | Flag: `1` = original was in KSeF                          |
| `NrKSeFFaKorygowanej`   | KSeF number of original invoice (mandatory if `NrKSeF=1`) |

⚠️ **Critical:** The KSeF number must be saved when uploading the original VAT invoice!

---

## FaWiersz in KOR

**Line items show the NEW/CORRECTED values**, not differences:

```xml
<!-- VAT Invoice -->
<FaWiersz>
  <P_9A>4128.00</P_9A>  <!-- Unit price -->
  <P_11>4128.00</P_11>  <!-- Net value -->
</FaWiersz>
```

```xml
<!-- KOR Invoice -->
<FaWiersz>
  <P_9A>3500.00</P_9A>  <!-- NEW unit price -->
  <P_11>3500.00</P_11>  <!-- NEW net value -->
  <P_12>0 KR</P_12>     <!-- Tax rate (0% for exempted) -->
</FaWiersz>
```

---

# Testdaten

Um Testdaten in die lokale Dev Umgebung zu importieren:

1. aus dem Produktiv Archiv System das XML eines Rechnungs-Snapshots unter /docker/transfer speichern
2. per api Call importieren:

   http://localhost:8080/api/cargosoft/import?file=/opt/jboss/wildfly/transfer/f28bf914-04de-4843-9809-54c724bdc9bf-1764111735524.xml
