Webhooks

Push-notificaties wanneer Corlega events plaatsvinden in je organisatie.

Webhooks sturen een HTTP POST naar jouw endpoint zodra een specifiek event plaatsvindt. bijvoorbeeld een nieuwe goedgekeurde offerte of een betaalde factuur.

Wanneer gebruik je webhooks

  • Bestaand CRM bijwerken bij goedgekeurde offerte
  • Notificatie naar Slack/Teams bij betaalde factuur
  • Boekhouding-systeem syncen
  • Custom-dashboards realtime updaten

Opzetten

  1. Dashboard → Organisatie → Instellingen → Webhooks → Nieuwe endpoint
  2. Vul de URL in (HTTPS verplicht)
  3. Kies de events waar je notificaties voor wilt ontvangen
  4. Kopieer de signing secret. wordt maar één keer getoond
  5. Test met de "Stuur test-event"-knop

Event types

EventTrigger
quote.createdConcept-offerte aangemaakt
quote.sentOfferte verstuurd naar klant
quote.approvedKlant heeft offerte goedgekeurd
quote.rejectedKlant heeft offerte afgewezen
invoice.createdConcept-factuur aangemaakt
invoice.sentFactuur verstuurd naar klant
invoice.paidFactuur volledig betaald
contact.createdNieuw contact aangemaakt (via UI, API of agent)
contact.updatedContact-gegevens gewijzigd
customer_booking.confirmedKlant heeft afspraak via Planning-agent bevestigd

Payload-formaat

Elke webhook POST heeft dezelfde wrapper:

{
  "event": "quote.approved",
  "id": "evt_01HE8K2X4Q9...",
  "timestamp": "2026-05-25T14:32:01.234Z",
  "organizationId": "org_01HD...",
  "data": {
    "quoteId": "qte_01HE8K1Z0...",
    "number": "Q-2026-0042",
    "total": "1287.50",
    "currency": "EUR",
    "contact": {
      "id": "con_01HC...",
      "name": "Bouwbedrijf De Vries B.V."
    },
    "approvedAt": "2026-05-25T14:31:55.000Z"
  }
}

De data-payload verschilt per event-type. Zie de REST API reference voor de resource-shapes.

Signature verificatie

Elke request bevat de header X-Corlega-Signature: sha256=<hex>. een hex-encoded HMAC-SHA256 over de raw body met je signing-secret als sleutel.

Verifieer deze om man-in-the-middle of replay-attacks te voorkomen.

Node.js voorbeeld

import crypto from "node:crypto";
import express from "express";

const app = express();

function verifyCorlegaSignature(rawBody, signatureHeader, secret) {
  if (!signatureHeader) return false;
  const received = signatureHeader.replace(/^sha256=/, "");
  const expected = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  if (expected.length !== received.length) return false;
  return crypto.timingSafeEqual(
    Buffer.from(expected, "hex"),
    Buffer.from(received, "hex"),
  );
}

// Belangrijk: raw body capture nodig voor signature-verificatie
app.post(
  "/corlega-webhook",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const sig = req.headers["x-corlega-signature"];
    const ok = verifyCorlegaSignature(
      req.body,
      sig,
      process.env.CORLEGA_WEBHOOK_SECRET,
    );
    if (!ok) return res.status(401).send("Invalid signature");

    const event = JSON.parse(req.body.toString());
    // verwerk event…
    res.status(200).send("OK");
  },
);

Next.js Route-handler voorbeeld

import crypto from "node:crypto";
import { NextResponse } from "next/server";

export const runtime = "nodejs";

export async function POST(req: Request) {
  const rawBody = await req.text();
  const sig = req.headers.get("x-corlega-signature");
  const secret = process.env.CORLEGA_WEBHOOK_SECRET!;

  const received = sig?.replace(/^sha256=/, "") ?? "";
  const expected = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");

  if (
    received.length !== expected.length ||
    !crypto.timingSafeEqual(
      Buffer.from(expected, "hex"),
      Buffer.from(received, "hex"),
    )
  ) {
    return new NextResponse("Invalid signature", { status: 401 });
  }

  const event = JSON.parse(rawBody);
  // verwerk event…
  return NextResponse.json({ ok: true });
}

Retries

Webhook-delivery retries bij niet-2xx-responses:

PogingVertraging
1 (initial)direct
21 minuut
35 minuten
430 minuten
52 uur
612 uur
7 (laatste)24 uur

Bij 3 opeenvolgende mislukte delivery-pogingen voor dezelfde endpoint krijg je een notificatie in het dashboard, en de endpoint wordt automatisch op inactive gezet na 7 dagen.

Idempotentie

Stuur dezelfde event-id meerdere keren? Behandel idempotent. Corlega kan dezelfde event meerdere keren leveren bij network-issues. Gebruik event.id als deduplicatie-sleutel.

if (await db.hasProcessed(event.id)) {
  return res.status(200).send("Already processed");
}
await db.markProcessed(event.id);
await processEvent(event);
res.status(200).send("OK");

Test events

In het dashboard kun je elk event-type handmatig triggeren met een test-payload. Handig voor development zonder een echte klant-actie te triggeren.

Volgende stap

On this page