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

# Nutzungsereignisse senden

> Sende Nutzungsereignisse über CSV oder die API für nutzungsbasierte Abrechnung

Nutzungsereignisse sind die Grundlage für nutzungsbasierte Abrechnung. Es gibt zwei Möglichkeiten, Ereignisse zu senden: über CSV-Dateien oder direkt über die REST API.

## Übersicht

| Methode        | Verwendung                     | Limit                          |
| -------------- | ------------------------------ | ------------------------------ |
| **CSV Import** | Bulk-Import historischer Daten | Bis zu 10 MB pro Datei         |
| **API Import** | Echtzeit-Event-Erfassung       | Bis zu 1000 Events pro Request |

<Tip>
  Für einmalige Imports historischer Daten oder Backfill-Szenarien verwende CSV Import. Für kontinuierliche, Echtzeit-Event-Erfassung aus Anwendungen verwende die API.
</Tip>

## CSV Import

### CSV Format

Die CSV-Datei muss folgende Spalten enthalten:

| Spalte           | Typ      | Erforderlich | Beschreibung                                        |
| ---------------- | -------- | ------------ | --------------------------------------------------- |
| `transaction_id` | string   | Ja           | Eindeutige Transaktions-ID für Idempotenz           |
| `event_name`     | string   | Ja           | Name des Events (z.B. "api\_call", "storage\_used") |
| `timestamp`      | ISO 8601 | Ja           | Event-Zeitstempel (z.B. "2026-01-13T10:30:00Z")     |
| `customer_id`    | string   | Ja           | Kunden-Identifier (Fynn-UUID oder `externalId`)     |
| `properties`     | JSON     | Ja           | Event-Eigenschaften als JSON-Objekt                 |

<Warning>
  Die Datei muss im UTF-8 Format vorliegen. Die `properties`-Spalte muss ein gültiges JSON-Objekt enthalten. Maximale Dateigröße: 10 MB.
</Warning>

### Import über die Benutzeroberfläche

1. Navigiere zur Seite **Verbrauchsdaten**
2. Klicke auf das **Aktionen**-Dropdown im Header
3. Wähle **CSV Import**
4. Im Dialog:
   * Klicke auf den Upload-Bereich oder ziehe eine CSV-Datei hinein
   * Wähle die CSV-Datei aus
   * Klicke auf **Importieren**

<Frame>
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/fynnsubscriptionbilling/images/usage-events-import-dialog.png" alt="CSV Import Dialog" />
</Frame>

**Nach dem Import:**

* Die Events werden asynchron verarbeitet
* Die Tabelle wird automatisch aktualisiert
* Bei Fehlern wird eine Fehlermeldung angezeigt

### Beispiel CSV

```csv theme={null}
transaction_id,event_name,timestamp,customer_id,properties
tx-12345,api_call,2026-01-13T10:30:00Z,550e8400-e29b-41d4-a716-446655440000,"{""endpoint"":""/api/v1/users"",""method"":""GET"",""response_time_ms"":145,""status_code"":200}"
tx-12346,storage_used,2026-01-13T10:31:00Z,550e8400-e29b-41d4-a716-446655440000,"{""bytes"":1048576,""storage_type"":""database""}"
tx-12347,api_call,2026-01-13T10:32:00Z,550e8400-e29b-41d4-a716-446655440000,"{""endpoint"":""/api/v1/products"",""method"":""POST"",""response_time_ms"":234,""status_code"":201}"
```

<Info>
  JSON-Objekte in der `properties`-Spalte müssen mit doppelten Anführungszeichen escaped werden (`""`).
</Info>

## API Import

Nutzungsereignisse können programmatisch über die REST API gesendet werden. Unterstützt einzelne Events oder Batch-Import (bis zu 1000 Events pro Anfrage).

### Authentifizierung

Der API-Schlüssel muss im Request-Header übergeben werden:

```http theme={null}
Authorization: Bearer YOUR_API_KEY
```

### Einzelnes Event senden

**Endpoint:** `POST /api/usage-events`

```bash theme={null}
curl -X POST https://coreapi.io/api/usage-events \
  --header "Content-Type: application/json" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --data '{
    "events": [
      {
        "transactionId": "tx-12345",
        "eventName": "api_call",
        "timestamp": "2026-01-13T10:30:00Z",
        "customerId": "550e8400-e29b-41d4-a716-446655440000",
        "properties": {
          "endpoint": "/api/v1/users",
          "method": "GET",
          "response_time_ms": 145,
          "status_code": 200
        }
      }
    ]
  }'
```

### Batch Import

Bis zu 1000 Events können in einem Request gesendet werden:

```bash theme={null}
curl -X POST https://coreapi.io/api/usage-events \
  --header "Content-Type: application/json" \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --data '{
    "events": [
      {
        "transactionId": "tx-12345",
        "eventName": "api_call",
        "timestamp": "2026-01-13T10:30:00Z",
        "customerId": "550e8400-e29b-41d4-a716-446655440000",
        "properties": {
          "endpoint": "/api/v1/users",
          "method": "GET",
          "response_time_ms": 145,
          "status_code": 200
        }
      },
      {
        "transactionId": "tx-12346",
        "eventName": "storage_used",
        "timestamp": "2026-01-13T10:31:00Z",
        "customerId": "550e8400-e29b-41d4-a716-446655440000",
        "properties": {
          "bytes": 1048576,
          "storage_type": "database"
        }
      }
    ]
  }'
```

### Antwortformat

**Erfolgreiche Antwort (202 Accepted):**

```json theme={null}
{
  "ingested": 2,
  "failed": 0,
  "errors": []
}
```

**Antwort mit Fehlern:**

```json theme={null}
{
  "ingested": 1,
  "failed": 1,
  "errors": [
    {
      "index": 1,
      "transactionId": "tx-12346",
      "error": "Invalid customer ID"
    }
  ]
}
```

**HTTP Status Codes:**

| Code  | Bedeutung                                                  |
| ----- | ---------------------------------------------------------- |
| `202` | Events wurden akzeptiert (kann teilweise Fehler enthalten) |
| `400` | Ungültige Anfrage - Validierungsfehler                     |
| `401` | Nicht autorisiert - Ungültiger API-Schlüssel               |

## Event-Struktur

### Erforderliche Felder

Jedes Nutzungsereignis muss folgende Felder enthalten:

```typescript theme={null}
{
  transactionId: string;    // Eindeutige ID für Idempotenz
  eventName: string;         // Name des Events
  timestamp: string;         // ISO 8601 Zeitstempel
  customerId: string;        // Fynn-UUID oder externalId des Kunden
  properties: object;        // Beliebige Event-Eigenschaften
}
```

### Idempotenz

Events mit derselben `transactionId` werden nur einmal verarbeitet. Bei wiederholtem Senden wird das bereits existierende Event zurückgegeben (HTTP 200 statt 201).

<Tip>
  Verwende eindeutige, deterministische Transaction IDs. Beispiel: UUID oder `${customerId}-${timestamp}-${eventName}`
</Tip>

### Properties

Die `properties` können beliebige JSON-Objekte enthalten. Typische Beispiele:

**API Call Event:**

```json theme={null}
{
  "endpoint": "/api/v1/users",
  "method": "GET",
  "response_time_ms": 145,
  "status_code": 200
}
```

**Storage Event:**

```json theme={null}
{
  "bytes": 1048576,
  "storage_type": "database",
  "region": "eu-central-1"
}
```

**Transaction Event:**

```json theme={null}
{
  "amount": 99.99,
  "currency": "EUR",
  "transaction_type": "purchase"
}
```

## Best Practices

### Timestamps

Verwende immer UTC-Zeitstempel im ISO 8601 Format.

### Batch-Größe

Für optimale Performance:

* **Kleine Batches**: 10-100 Events für Echtzeit-Erfassung
* **Große Batches**: 500-1000 Events für Bulk-Import
* **Vermeide**: Sehr kleine Batches (\< 10) bei hohem Volumen

### Rate Limiting

Respektiere Rate Limits:

* **Empfohlen**: Maximal 10 Requests pro Sekunde
* **Burst**: Kurzzeitig bis zu 50 Requests pro Sekunde
* **Vermeide**: Längerfristige Überschreitung der Limits

## Fehlerbehebung

### CSV Import schlägt fehl

**Problem:** "Ungültiges CSV-Format"

**Lösung:**

1. Prüfe, ob alle erforderlichen Spalten vorhanden sind
2. Stelle sicher, dass die Datei UTF-8 kodiert ist
3. Validiere JSON in der `properties`-Spalte
4. Prüfe, ob Anführungszeichen korrekt escaped sind

**Problem:** "Datei zu groß"

**Lösung:**

* Teile die CSV-Datei in kleinere Dateien auf (max. 10 MB)
* Importiere die Dateien nacheinander

### API Import Fehler

**Problem:** `401 Unauthorized`

**Lösung:**

* Prüfe, ob der API-Schlüssel korrekt im Header übergeben wird
* Stelle sicher, dass der API-Schlüssel aktiv ist
* Prüfe die Berechtigungen des API-Schlüssels

**Problem:** `400 Bad Request`

**Lösung:**

* Validiere die Event-Struktur
* Prüfe, ob alle erforderlichen Felder vorhanden sind
* Stelle sicher, dass `customerId` eine gültige UUID oder `externalId` ist
* Prüfe das `timestamp`-Format (ISO 8601)

**Problem:** Events werden nicht angezeigt

**Lösung:**

1. Prüfe die Antwort auf Fehler (`errors` Array)
2. Validiere `transactionId` (möglicherweise Duplikat)
3. Prüfe Filter in der Events-Tabelle
4. Warte kurz, da Events asynchron verarbeitet werden

## Verwandte Dokumentation

* [Abrechenbare Einheiten verwalten](/guide/catalogue/measurements/introduction)
* [Nutzungsbasierte Abrechnung](/guide/subscriptions/introduction)
* [API Referenz - Nutzungsereignisse](/api-reference/usage-events)
