> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fynn.eu/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom PDF Rendering

> Nutze deine eigene PDF-Rendering-Engine für Rechnungen, Gutschriften und Stornos.

<Note>
  Diese Funktion ist nur im **Enterprise**-Plan verfügbar. Kontaktiere unser Sales-Team unter [sales@fynn.eu](mailto:sales@fynn.eu) für weitere Informationen.
</Note>

## Übersicht

Mit Custom PDF Rendering kannst du deine eigene PDF-Rendering-Engine verwenden, um Rechnungen, Gutschriften und Stornos nach deinen individuellen Anforderungen zu generieren. Dies ermöglicht:

* **Vollständige Design-Kontrolle**: Gestalte Belege exakt nach deinen Corporate-Design-Vorgaben
* **Eigene Template-Engines**: Nutze deine bevorzugte Template-Engine (LaTeX, Typst, etc.)
* **Komplexe Layouts**: Erstelle mehrseitige Dokumente mit komplexen Tabellen und Grafiken
* **Integration mit bestehenden Systemen**: Binde deine vorhandene Dokumentengenerierung nahtlos ein

## Funktionsweise

```mermaid theme={null}
sequenceDiagram
    participant F as Fynn
    participant W as Dein Webhook-Server
    participant P as Deine PDF-Engine

    F->>F: Beleg finalisieren
    F->>W: Webhook: invoice.pdf.generation_requested
    W->>P: PDF generieren
    P->>W: PDF-Datei
    W->>F: POST /api/invoices/{id}/pdf
    F->>F: Finalisierung abschließen
```

1. **Beleg wird finalisiert**: Wenn ein Beleg finalisiert wird, wechselt er in den Status `STATUS_FINALIZING`
2. **Webhook wird ausgelöst**: Fynn sendet den `invoice.pdf.generation_requested` Webhook mit allen Belegdaten
3. **PDF generieren**: Dein System generiert das PDF mit deiner eigenen Rendering-Engine
4. **PDF hochladen**: Das fertige PDF wird über die API an Fynn zurückgesendet
5. **Finalisierung abschließen**: Fynn schließt den Finalisierungsprozess ab (ZUGFeRD-Einbettung, Versand, etc.)

## Konfiguration

### 1. Feature aktivieren

Kontaktiere den Fynn-Support, um das Feature für deine Organisation freizuschalten.

### 2. Webhook registrieren

Registriere einen Webhook für das Event `invoice.pdf.generation_requested`:

<Tabs>
  <Tab title="Web-App verwenden">
    <Steps>
      <Step title="Webhooks öffnen">
        Navigiere zu **Einstellungen** > **Webhooks**
      </Step>

      <Step title="Neuen Webhook erstellen">
        Klicke auf **Neuer Webhook** und konfiguriere:

        * **URL**: Die URL deines Webhook-Endpoints
        * **Events**: Wähle `invoice.pdf.generation_requested`
        * **Secret**: Ein sicheres Secret zur Signaturvalidierung
      </Step>
    </Steps>
  </Tab>

  <Tab title="API verwenden">
    ```bash theme={null}
    POST /webhooks
    {
        "url": "https://your-server.com/webhooks/fynn",
        "events": ["invoice.pdf.generation_requested"],
        "version": "v1",
        "enabled": true
    }
    ```

    Das Webhook-Secret wird automatisch generiert und kann nach Erstellung in den Webhook-Details abgerufen werden.
  </Tab>
</Tabs>

### 3. Einstellungen konfigurieren

Unter **Einstellungen** > **Abrechnung** > **Benutzerdefiniertes PDF-Rendering** kannst du folgende Optionen konfigurieren:

<Frame>
  <img src="https://mintcdn.com/fynnsubscriptionbilling/VXT1xu_IHT8wK2mb/images/integrations/custom-pdf-rendering-settings.png?fit=max&auto=format&n=VXT1xu_IHT8wK2mb&q=85&s=3143f18121763568393cf26c0801ae25" alt="Benutzerdefiniertes PDF-Rendering Einstellungen" width="2506" height="923" data-path="images/integrations/custom-pdf-rendering-settings.png" />
</Frame>

| Einstellung                                      | Beschreibung                                                                                                                              | Standard    |
| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| **Benutzerdefiniertes PDF-Rendering aktivieren** | Wenn aktiviert, wird die PDF-Generierung von Belegen über einen Webhook an ein externes System delegiert.                                 | Deaktiviert |
| **ZUGFeRD-XML einbetten**                        | ZUGFeRD-XML-Daten automatisch in das hochgeladene PDF einbetten. Deaktiviere dies, wenn dein externer Renderer bereits ZUGFeRD einbettet. | Aktiviert   |
| **Automatischer Fallback**                       | Automatisch auf den integrierten Renderer zurückfallen, wenn das externe System das PDF nicht innerhalb des Timeout-Zeitraums liefert.    | Deaktiviert |
| **Timeout**                                      | Timeout in Minuten (1-1440)                                                                                                               | 30          |

## Webhook-Payload

Der `invoice.pdf.generation_requested` Webhook enthält alle Belegdaten:

```json theme={null}
{
    "event": {
        "id": "01JKXYZ1234567890ABCDEFGH",
        "type": "invoice.pdf.generation_requested",
        "version": "v1",
        "createdAt": "2026-02-09T10:00:00+00:00"
    },
    "data": {
        "invoice": {
            "id": "550e8400-e29b-41d4-a716-446655440000",
            "number": "RE-2026-0001",
            "type": "TYPE_INVOICE",
            "status": "STATUS_FINALIZING",
            ...
        }
    }
}
```

## PDF hochladen

Nach der PDF-Generierung muss das Dokument über die API hochgeladen werden:

```bash theme={null}
curl -X POST "https://coreapi.io/api/invoices/{invoiceId}/pdf" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -F "file=@invoice.pdf"
```

### Endpoint-Details

| Methode | Pfad                     | Beschreibung            |
| ------- | ------------------------ | ----------------------- |
| `POST`  | `/api/invoices/{id}/pdf` | PDF für Beleg hochladen |

### Request

* **Content-Type**: `multipart/form-data`
* **Feld**: `file` - Die PDF-Datei (MIME-Type: `application/pdf`)

### Response

**200 OK**

```json theme={null}
{
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "STATUS_UNPAID",
    "message": "PDF uploaded and invoice finalization continued."
}
```

### Fehlercodes

| Code  | Beschreibung                                  |
| ----- | --------------------------------------------- |
| `404` | Beleg nicht gefunden                          |
| `409` | Beleg ist nicht im Status `STATUS_FINALIZING` |
| `422` | Ungültige Datei (kein PDF)                    |

## Timeout und Fallback

Wenn das Custom PDF Rendering aktiviert ist, wartet Fynn auf das Hochladen des PDFs. Falls das PDF nicht rechtzeitig hochgeladen wird:

* **Mit aktiviertem Fallback**: Nach Ablauf des Timeouts generiert Fynn das PDF automatisch mit der internen Rendering-Engine
* **Ohne Fallback**: Der Beleg bleibt im Status `STATUS_FINALIZING` bis das PDF manuell hochgeladen wird

<Warning>
  Stelle sicher, dass dein System das PDF innerhalb des konfigurierten Timeouts hochlädt, um Verzögerungen bei der Belegstellung zu vermeiden.
</Warning>

## ZUGFeRD-Einbettung

Wenn `embedZugferd` aktiviert ist, bettet Fynn automatisch die ZUGFeRD/Factur-X XML-Daten in das hochgeladene PDF ein. Dies gewährleistet die Compliance mit dem deutschen e-Rechnungsstandard.

<Tip>
  Du musst dich nicht um die ZUGFeRD-Generierung kümmern – Fynn übernimmt die Einbettung nach dem Upload automatisch.
</Tip>

## Best Practices

### Webhook-Verarbeitung

1. **Asynchrone Verarbeitung**: Bestätige den Webhook sofort (HTTP 200) und verarbeite die PDF-Generierung asynchron
2. **Idempotenz**: Implementiere Idempotenz, um doppelte Webhook-Aufrufe zu handhaben
3. **Retry-Logik**: Implementiere Retries für den PDF-Upload bei temporären Fehlern

### PDF-Anforderungen

* **Format**: PDF/A-3 wird empfohlen für beste ZUGFeRD-Kompatibilität
* **Größe**: Maximal 10 MB
* **Qualität**: Mindestens 150 DPI für eingebettete Bilder

### Sicherheit

* Validiere die Webhook-Signatur
* Nutze HTTPS für alle API-Aufrufe
* Speichere API-Tokens sicher

## Beispiel-Implementierung (Node.js)

```javascript theme={null}
const express = require('express');
const crypto = require('crypto');
const FormData = require('form-data');
const axios = require('axios');

const app = express();
app.use(express.json());

app.post('/webhooks/fynn', async (req, res) => {
    // 1. Webhook sofort bestätigen
    res.status(200).send('OK');

    // 2. Signatur validieren
    const signature = req.headers['x-fynn-signature'];
    const expectedSignature = crypto
        .createHmac('sha256', process.env.WEBHOOK_SECRET)
        .update(JSON.stringify(req.body))
        .digest('hex');

    if (signature !== expectedSignature) {
        console.error('Invalid webhook signature');
        return;
    }

    // 3. PDF generieren (deine eigene Logik)
    const { invoice } = req.body.data;
    const pdfBuffer = await generateInvoicePdf(invoice);

    // 4. PDF an Fynn hochladen
    const form = new FormData();
    form.append('file', pdfBuffer, {
        filename: `invoice-${invoice.number}.pdf`,
        contentType: 'application/pdf'
    });

    await axios.post(
        `https://coreapi.io/api/invoices/${invoice.id}/pdf`,
        form,
        {
            headers: {
                ...form.getHeaders(),
                'Authorization': `Bearer ${process.env.FYNN_API_TOKEN}`
            }
        }
    );
});

async function generateInvoicePdf(invoice) {
    // Implementiere hier deine PDF-Generierung
    // z.B. mit Puppeteer, PDFKit, LaTeX, etc.
}
```

## Troubleshooting

### PDF wird nicht akzeptiert

* Stelle sicher, dass die Datei ein gültiges PDF ist
* Überprüfe, dass der Beleg im Status `STATUS_FINALIZING` ist
* Validiere, dass du die richtige Invoice-ID verwendest

### Webhook wird nicht empfangen

* Überprüfe, dass der Webhook für `invoice.pdf.generation_requested` registriert ist
* Stelle sicher, dass dein Endpoint erreichbar ist
* Überprüfe die Webhook-Logs in den Fynn-Einstellungen

### Timeout-Fehler

* Erhöhe den `timeoutMinutes`-Wert
* Optimiere deine PDF-Generierung
* Aktiviere den Fallback für kritische Situationen

## API-Referenz

Weitere Details zur API findest du in der [API-Dokumentation](/api-reference/invoice/upload-invoice-pdf).
