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

# Webhooks

> Konfiguriere Webhooks und erhalte Benachrichtigungen.

<Frame>
  <img src="https://mintcdn.com/fynnsubscriptionbilling/1WHsrw9xV98b8NDj/images/fynn-eu-settings-webhooks.png?fit=max&auto=format&n=1WHsrw9xV98b8NDj&q=85&s=c07445e877b05afd86b0391ef1765d20" alt="Fynn Webhooks Einstellungen" width="1678" height="1167" data-path="images/fynn-eu-settings-webhooks.png" />
</Frame>

Mit Webhooks kannst du externe Systeme in Echtzeit über Ereignisse in Fynn benachrichtigen lassen. Webhooks werden per `POST`-Request an deine hinterlegte URL gesendet und enthalten strukturierte JSON-Daten zum jeweiligen Ereignis.

Webhooks lassen sich unter [**Einstellungen → Webhooks**](https://app.fynn.eu/settings/webhooks) konfigurieren.

***

## Sicherheit: `X-Webhook-Signature`

Jede Webhook-Anfrage enthält einen Header `X-Webhook-Signature`, der wie folgt generiert wird:

```
hash_hmac('sha256', $body, $webhookSecret)
```

* `$body`: Der **ungeänderte JSON Body** der Webhook-Anfrage (als String)
* `$webhookSecret`: Dein geheimer Schlüssel für diesen Webhook

Den Secret findest du unter:
[**Einstellungen → Webhooks → Details**](https://app.fynn.eu/settings/webhooks)

<Warning>
  Wir empfehlen dringend, die Signatur zu validieren, um sicherzustellen, dass die Anfrage wirklich von Fynn stammt.
</Warning>

***

### Beispiele

<Tabs>
  <Tab title="PHP">
    ```php theme={null}
    $webhookSecret = 'dein_webhook_secret';
    $body = file_get_contents('php://input');
    $signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';

    $expectedSignature = hash_hmac('sha256', $body, $webhookSecret);

    if (!hash_equals($expectedSignature, $signature)) {
        http_response_code(401);
        exit('Invalid signature');
    }

    // Verarbeitung ...
    http_response_code(200);
    echo 'OK';
    ```
  </Tab>

  <Tab title=".NET (C#)">
    ```csharp theme={null}
    using System.Security.Cryptography;
    using System.Text;

    string body = await new StreamReader(Request.Body).ReadToEndAsync();
    string signature = Request.Headers["X-Webhook-Signature"];
    string secret = "dein_webhook_secret";

    using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret)))
    {
        var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(body));
        var expected = BitConverter.ToString(hash).Replace("-", "").ToLower();

        if (expected != signature)
        {
            return Results.Unauthorized();
        }
    }

    // Verarbeitung ...
    return Results.Ok();
    ```
  </Tab>

  <Tab title="Node.JS">
    ```js theme={null}
        const crypto = require('crypto');
        const express = require('express');
        const app = express();

        app.use(express.text({ type: 'application/json' }));

        app.post('/webhook', (req, res) => {
            const webhookSecret = 'dein_webhook_secret';
            const signature = req.headers['x-webhook-signature'];
            const expected = crypto
            .createHmac('sha256', webhookSecret)
            .update(req.body)
            .digest('hex');

            if (signature !== expected) {
                return res.status(401).send('Invalid signature');
            }

            // Verarbeitung ...
            res.send('OK');
        });
    ```
  </Tab>
</Tabs>

## Unterstützte Events

### Produkt

* `product.created`
* `product.updated`
* `product.deleted`
* `product.archived`

### Rabattcodes

* `coupon.created`
* `coupon.updated`
* `coupon.deleted`
* `coupon.toggled`

### Kunden

* `customer.created`
* `customer.updated`
* `customer.archived`
* `customer.unarchived`
* `customer.deleted`
* `customer.merged` — Wird ausgelöst, wenn mehrere Kunden zu einem zusammengeführt wurden.
* `customer.parent.assigned` — Wird ausgelöst, wenn ein Parent-Kunde in der [Organisationsstruktur](/guide/customers/organization-hierarchy) zugewiesen wurde.
* `customer.parent.removed` — Wird ausgelöst, wenn ein Parent-Kunde aus der [Organisationsstruktur](/guide/customers/organization-hierarchy) entfernt wurde.
* `payment_method.created`
* `payment_method.updated`

### Rechnungen

* `invoice.created`
* `invoice.finalized` — Wird ausgelöst, nachdem die Rechnung finalisiert und die Zahlungsabwicklung initialisiert wurde. Die Rechnung hat zu diesem Zeitpunkt den Status `STATUS_UNPAID`.
* `invoice.credited`
* `invoice.updated`
* `invoice.refunded`
* `invoice.canceled`
* `invoice.paid`
* `invoice.closed`
* `invoice.unpaid`
* `invoice.remindered`
* `invoice.requires_approval`
* `invoice.payment_method.updated`
* `invoice.pdf.generation_requested`
* `invoice.letter.dispatched` — Wird ausgelöst, sobald eine Rechnung als Brief an den Druckdienstleister übergeben wurde.
* `invoice.letter.delivered` — Wird ausgelöst, sobald die Zustellung des Briefs bestätigt ist.

### Preispläne

* `price_plan.archived`

### Abonnements

* `subscription.activated`
* `subscription.billed`
* `subscription.created`
* `subscription.changed`
* `subscription.invoice_address.updated`
* `subscription.delivery_address.updated`
* `subscription.payment_method.updated`
* `subscription.item.instant_metered`
* `subscription.item.metered`
* `subscription.item.quantity_changed`
* `subscription.products.ordered`
* `subscription.trial_expired`
* `subscription.trial_extended`
* `subscription.updated`
* `subscription.paused`
* `subscription.voided`
* `subscription.resumed`
* `subscription.canceled`
* `subscription.cancellation_revoked`
* `subscription.terminated`
* `subscription.phase.created`
* `subscription.phase.completed`
* `subscription.transferred`
* `subscription_item.terminated`

### Mahnwesen

* `dunning_document.created`
* `dunning_document.paid`
* `dunning_document.canceled`

### Warenkorb

* `cart.completed`
* `cart.paid`

### Bankkonten

* `bank_account.synced`

### Guthaben-Auszahlung

* `wallet.payout.executed`: Wird ausgelöst, wenn eine Guthaben-[Auszahlung](/guide/invoices/wallet-payout) von der Bank ausgeführt und über den Kontoumsatz bestätigt wurde.
* `wallet.payout.failed`: Wird ausgelöst, wenn die Einreichung einer Guthaben-Auszahlung fehlgeschlagen ist. Das Guthaben wurde automatisch zurückgebucht.

### Features & Entitlements

* `feature.created`
* `feature.activated`
* `feature.archived`
* `entitlement.state.updated`

***

## Hinweise

Die Events werden bei einem Fehler **bis zu 3x** wiederholt.
