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

# Server-Ereignisse senden

> Kauf-, Registrierungs- und Lead-Konversionen aus Ihrem Backend an die Scanova-Tracking-API senden — mit Codebeispielen in cURL, Node.js, Python und PHP.

Mit der API für Server-Ereignisse melden Sie Konversionen, die auf Ihrem Server stattfinden — Käufe, bestätigte Registrierungen, Leads oder jede andere Backend-Aktion, die Sie einem QR-Code-Scan zuordnen wollen.

## Endpunkt

```
POST https://track.scanova.io/server-events
```

**Erforderliche Header:**

```http theme={null}
Content-Type: application/json
X-API-Key: YOUR_SITE_API_KEY
```

## Pflichtfelder

| Feld              | Beschreibung                                                                                         |
| ----------------- | ---------------------------------------------------------------------------------------------------- |
| `site_id`         | Die ID Ihrer Tracking-Website aus dem Dashboard                                                      |
| `event_name`      | Der Name des Konversionsereignisses (z. B. `purchase`, `signup`, `lead`)                             |
| `scan_session_id` | Die Scan-Sitzungs-ID aus dem Browser des Nutzers. Sie verknüpft die Konversion mit dem QR-Code-Scan. |

## Beispiele

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://track.scanova.io/server-events" \
      -H "Content-Type: application/json" \
      -H "X-API-Key: YOUR_API_KEY" \
      -d '{
        "site_id": "YOUR_SITE_ID",
        "event_name": "purchase",
        "event_id": "550e8400-e29b-41d4-a716-446655440000",
        "scan_session_id": "7ad26d4f-3181-4ef8-b6ca-b8f59499dd43",
        "conversion_value": { "amount": 49.99, "currency": "USD" },
        "properties": { "order_id": "ord_9876", "plan": "pro" }
      }'
    ```
  </Tab>

  <Tab title="Node.js">
    ```javascript theme={null}
    import crypto from 'node:crypto';

    async function trackConversion({ scanSessionId, orderId, amount }) {
      const response = await fetch('https://track.scanova.io/server-events', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-API-Key': process.env.SCANOVA_API_KEY,
        },
        body: JSON.stringify({
          site_id: process.env.SCANOVA_SITE_ID,
          event_name: 'purchase',
          event_id: crypto.randomUUID(),   // generate once and persist for retries
          scan_session_id: scanSessionId,
          conversion_value: { amount, currency: 'USD' },
          properties: { order_id: orderId },
        }),
      });

      if (!response.ok) {
        const error = await response.json();
        throw new Error(`Tracking failed: ${response.status} — ${JSON.stringify(error)}`);
      }
    }
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import os
    import uuid
    import requests

    def track_conversion(scan_session_id: str, order_id: str, amount: float):
        response = requests.post(
            "https://track.scanova.io/server-events",
            headers={
                "Content-Type": "application/json",
                "X-API-Key": os.environ["SCANOVA_API_KEY"],
            },
            json={
                "site_id": os.environ["SCANOVA_SITE_ID"],
                "event_name": "purchase",
                "event_id": str(uuid.uuid4()),  # generate once, persist for retries
                "scan_session_id": scan_session_id,
                "conversion_value": {"amount": amount, "currency": "USD"},
                "properties": {"order_id": order_id},
            },
            timeout=10,
        )
        response.raise_for_status()
    ```
  </Tab>

  <Tab title="PHP">
    ```php theme={null}
    <?php
    function trackConversion(string $scanSessionId, string $orderId, float $amount): void {
        $payload = json_encode([
            'site_id'          => getenv('SCANOVA_SITE_ID'),
            'event_name'       => 'purchase',
            'event_id'         => sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
                                    mt_rand(0, 0xffff), mt_rand(0, 0xffff),
                                    mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000,
                                    mt_rand(0, 0x3fff) | 0x8000,
                                    mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)),
            'scan_session_id'  => $scanSessionId,
            'conversion_value' => ['amount' => $amount, 'currency' => 'USD'],
            'properties'       => ['order_id' => $orderId],
        ]);

        $ch = curl_init('https://track.scanova.io/server-events');
        curl_setopt_array($ch, [
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => $payload,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 10,
            CURLOPT_HTTPHEADER     => [
                'Content-Type: application/json',
                'X-API-Key: ' . getenv('SCANOVA_API_KEY'),
            ],
        ]);

        $response = curl_exec($ch);
        $status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($status !== 200) {
            throw new RuntimeException("Tracking failed: {$status} — {$response}");
        }
    }
    ```
  </Tab>
</Tabs>

## Optionale Felder

| Feld               | Beschreibung                                                                                                                                |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `event_id`         | UUID für gefahrlose Wiederholungen. Einmal erzeugen und bei jeder Wiederholung erneut verwenden. Ohne Angabe wird automatisch eine erzeugt. |
| `event_time`       | Zeitstempel nach ISO 8601, wann das Ereignis stattfand. Standard ist der Eingangszeitpunkt. Nützlich, wenn Sie Ereignisse asynchron senden. |
| `conversion_value` | `{ "amount": 49.99, "currency": "USD" }`. Die Währung muss ein dreistelliger ISO-4217-Code sein.                                            |
| `user_identifiers` | Gehashte Nutzerkennungen: `email_hash`, `phone_hash`, `external_id`. Senden Sie niemals E-Mail-Adressen oder Telefonnummern im Klartext.    |
| `properties`       | Eigenes Schlüssel-Wert-Objekt. Höchstens 10 KB. Keine personenbezogenen Daten im Klartext.                                                  |
| `consent`          | `granted`, `denied` oder `pending`. Steuert den Umgang mit personenbezogenen Daten.                                                         |

## scan\_session\_id vom Browser an den Server übergeben

Die `scan_session_id` entsteht im Browser. Sie müssen sie von Ihrem Frontend an Ihr Backend weitergeben.

**Variante 1: Verstecktes Formularfeld**

```html theme={null}
<form action="/checkout" method="POST">
  <input type="hidden" name="scan_session_id" id="scan_session_id_field">
  <!-- other form fields -->
</form>

<script>
  // _scnv is the SDK's internal localStorage key (structure may change in future SDK versions)
  const stored = localStorage.getItem('_scnv');
  const sessionId = stored ? JSON.parse(stored).sid : null;
  if (sessionId) {
    document.getElementById('scan_session_id_field').value = sessionId;
  }
</script>
```

**Variante 2: Im API-Anfragetext aus dem Frontend mitschicken**

```javascript theme={null}
// _scnv is the SDK's internal localStorage key (structure may change in future SDK versions)
const stored = localStorage.getItem('_scnv');
const scanSessionId = stored ? JSON.parse(stored).sid : null;

await fetch('/api/checkout', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    cart: cartData,
    scan_session_id: scanSessionId,  // pass to your server
  }),
});
```

## Mehrere Ereignisse im Stapel senden

Mit dem Batch-Endpunkt senden Sie bis zu 100 Ereignisse in einer einzigen Anfrage:

```
POST https://track.scanova.io/server-events/batch
```

```json theme={null}
{
  "events": [
    {
      "site_id": "YOUR_SITE_ID",
      "event_name": "purchase",
      "scan_session_id": "7ad26d4f-...",
      "conversion_value": { "amount": 49.99, "currency": "USD" }
    },
    {
      "site_id": "YOUR_SITE_ID",
      "event_name": "signup",
      "scan_session_id": "3b5e1234-..."
    }
  ]
}
```

Die Antwort weist je Ereignis aus, ob es angenommen oder abgelehnt wurde:

```json theme={null}
{
  "accepted": 2,
  "rejected": 0,
  "results": [
    { "index": 0, "event_id": "...", "status": "accepted" },
    { "index": 1, "event_id": "...", "status": "accepted" }
  ]
}
```

## Nächste Schritte

* [Idempotenz & Wiederholungen](/de/conversion-tracking/server/idempotency-retries) — fehlgeschlagene Anfragen gefahrlos wiederholen
* [Zustellung prüfen](/de/conversion-tracking/server/verify) — prüfen, ob Ereignisse ankommen
* [API-Referenz: einzelnes Ereignis](/de/conversion-tracking/api/events-collect) — vollständige Spezifikation des Endpunkts
* [API-Referenz: Stapelverarbeitung](/de/conversion-tracking/api/events-batch) — Spezifikation des Batch-Endpunkts
