Zum Hauptinhalt springen
Webhooks für Angebote benachrichtigen dein System automatisch über Ereignisse im Lebenszyklus eines Angebots. Sobald ein Ereignis eintritt, sendet Fynn einen POST-Request mit strukturierten JSON-Daten an deine hinterlegte URL.
Die Einrichtung, die Zustellung und die Signaturprüfung sind für alle Webhooks gleich. Wie du Webhooks anlegst und absicherst, liest du unter Webhooks einrichten. Auf dieser Seite findest du nur, was für Angebote gilt: die verfügbaren Events und ihre Payloads.

Der Envelope

Jeder Angebots-Webhook hat denselben Aufbau. Das eigentliche Objekt steckt unter data, daneben liegen Metadaten zum Ereignis und der Vertriebskanal als Kontext.
event
object
erforderlich
Metadaten zum Ereignis.
salesChannel
object | null
Der Vertriebskanal, in dessen Kontext das Ereignis entstand. null, wenn sich kein Kanal auflösen ließ.
data
object
erforderlich
Die Nutzdaten des Ereignisses. Der Schlüssel darin benennt das betroffene Objekt, bei Angebots-Events also offer.

HTTP-Header

Jede Zustellung bringt diese Header mit:
HeaderInhalt
X-Webhook-EventDer Ereignistyp, zum Beispiel offer.expired.
X-Webhook-Event-VersionSchema-Version, aktuell v1.
X-Webhook-IdEindeutige Kennung der Zustellung, identisch mit event.id.
X-Webhook-SignatureSignatur des Bodys zur Echtheitsprüfung.
X-Sales-ChannelTechnischer Name des Vertriebskanals, oder default.
X-Tenant-IdKennung deiner Organisation.
Prüfe immer die Signatur aus X-Webhook-Signature, bevor du eine Zustellung verarbeitest. So stellst du sicher, dass die Anfrage wirklich von Fynn stammt. Den Ablauf und Beispielcode findest du unter Webhooks einrichten.

Verfügbare Events

EventWird ausgelöst, wenn
offer.expiredEin Angebot seinen Gültigkeitszeitraum überschreitet, bevor es angenommen wurde.
Aktuell ist offer.expired das einzige Angebots-Event mit Webhook. Diese Liste wächst, wenn weitere Ereignisse hinzukommen.

offer.expired

Das Ereignis feuert, sobald die Gültigkeit eines Angebots verstreicht, solange es noch offen ist. Ein bereits angenommenes oder archiviertes Angebot läuft nie ab. Fynn erkennt den Ablauf auf zwei Wegen: über eine regelmäßige Prüfung im Hintergrund und beim ersten Aufruf des abgelaufenen Links durch einen Empfänger. Egal welcher Weg zuerst greift, das Ereignis wird je Ablauf genau einmal gesendet. Verlängerst du ein abgelaufenes Angebot und es läuft erneut ab, gilt das als neues Ereignis.

Das offer-Objekt

Unter data.offer erhältst du das Angebot in seiner Lese-Darstellung. Die wichtigsten Felder:
id
string
Eindeutige Kennung des Angebots. Nutze sie, um über die Angebote-API den vollständigen Stand inklusive Kunde, Abonnement und Empfänger zu laden.
number
string
Fortlaufende Angebotsnummer, zum Beispiel AN-2026-000042.
name
string | null
Anzeigename des Angebots.
status
string
Der zuletzt gespeicherte Status: open, signing, awaiting_invoice_details, signed oder archived. Ein abgelaufenes Angebot behält seinen Status (meist open), der Ablauf selbst ergibt sich aus validUntil.
dealType
string
Art des Geschäfts: new_business, expansion, renewal oder one_off.
acceptanceMode
string
Wie der Empfänger zusagt: click, esignature oder print.
locale
string | null
Sprache des Angebots, zum Beispiel de.
validUntil
string | null
Datum, bis zu dem das Angebot angenommen werden konnte (ISO 8601). Bei offer.expired liegt dieser Zeitpunkt in der Vergangenheit.
issuedAt
string
Zeitpunkt der ersten Veröffentlichung (ISO 8601).
signed
boolean
Ob das Angebot vollständig unterschrieben ist.
signedAt
string | null
Zeitpunkt der vollständigen Unterschrift (ISO 8601), sonst null.
autoActivateSubscription
boolean
Ob aus dem angenommenen Angebot automatisch ein aktives Abonnement entsteht.
crmDealId
string | null
Verknüpfter Deal im CRM, sofern vorhanden.
customVariables
object | null
Eigene Variablen aus dem Editor als flaches Name-zu-Wert-Mapping.
capturedInvoiceDetails
object | null
Die vom Empfänger erfassten Rechnungsdaten, sofern bereits hinterlegt.
sections
array
Die Dokument-Blöcke des Angebots (Briefkopf, Parteien, Abonnement, Texte und mehr). Den Aufbau der Blöcke findest du unter Kernkonzepte.
publishedVersionHash
string | null
Prüfsumme der veröffentlichten Dokumentversion.
currentVersionHash
string | null
Prüfsumme der aktuellen Dokumentversion.
hasUnpublishedChanges
boolean
Ob seit der letzten Veröffentlichung Änderungen im Entwurf liegen.
Die Payload ist bewusst schlank. Verschachtelte Objekte wie customer, subscription, recipients und die Dokument-Referenzen sind im Webhook nicht ausgefüllt und kommen als leeres Objekt, leere Liste oder null. Brauchst du diese Details, lade das Angebot mit der id aus der Payload über GET /offers/{id} nach.

Beispiel-Payload

{
  "event": {
    "id": "01JZ8F3KQ9X7N2VYB4C6D8E0FG",
    "type": "offer.expired",
    "version": "v1",
    "createdAt": "2026-06-29T08:00:01+00:00"
  },
  "salesChannel": {
    "id": "01JH2K8M4P6R8T0V2X4Z6B8D0F",
    "name": "default",
    "brandName": "Deine Marke"
  },
  "data": {
    "offer": {
      "id": "01JZ7A2B3C4D5E6F7G8H9J0K1L",
      "number": "AN-2026-000042",
      "name": "Angebot Enterprise-Plan 2026",
      "status": "open",
      "dealType": "new_business",
      "acceptanceMode": "esignature",
      "locale": "de",
      "validUntil": "2026-06-28T23:59:59+00:00",
      "issuedAt": "2026-06-01T10:00:00+00:00",
      "signed": false,
      "signedAt": null,
      "autoActivateSubscription": true,
      "crmDealId": null,
      "customVariables": null,
      "capturedInvoiceDetails": null,
      "publishedVersionHash": "8f14e45fceea167a5a36dedd4bea2543",
      "currentVersionHash": "8f14e45fceea167a5a36dedd4bea2543",
      "hasUnpublishedChanges": false,
      "sections": [
        { "type": "letterhead", "...": "..." },
        { "type": "parties", "...": "..." },
        { "type": "subscription", "...": "..." }
      ],
      "customer": {},
      "subscription": null,
      "recipients": [
        {}
      ],
      "purchaseOrderDocument": null,
      "auditLogDocument": null,
      "signedDocument": null,
      "contactPerson": {}
    }
  }
}
Antworte mit einem 2xx-Statuscode, sobald du die Zustellung angenommen hast. Schlägt die Zustellung fehl, wiederholt Fynn sie bis zu dreimal.