Direct naar inhoud

Aan de slag

Webhooks via automatiseringen

Laat Factora je systeem aanroepen zodra er iets gebeurt, zoals een betaalde factuur of een geaccepteerde offerte.

Hoe het werkt

Webhooks stel je in als actie Stuur webhook in een automatisering in Factora. Je kiest een trigger (bijvoorbeeld *Factuur betaald*), eventuele voorwaarden en de URL die Factora moet aanroepen. Er is geen apart API-endpoint om webhooks te registreren.

  1. 1Open Automatiseringen in Factora en maak een nieuwe automatisering.
  2. 2Kies een trigger, bijvoorbeeld invoice.paid.
  3. 3Voeg de actie Stuur webhook toe met je HTTPS-URL, de methode (POST, PUT of PATCH) en een geheim (secret).
  4. 4Voeg eventueel eigen headers en eigen velden toe; je kunt daarin variabelen uit de trigger gebruiken.
  5. 5Test de automatisering met een simulatie en zet hem aan.

Beschikbare triggers

GroepTriggers
Factureninvoice.created, invoice.updated, invoice.sent, invoice.viewed, invoice.paid, invoice.partially_paid, invoice.overdue, invoice.due_soon, invoice.cancelled, invoice.payment_failed, invoice.status_changed
Offertesquote.created, quote.updated, quote.sent, quote.viewed, quote.accepted, quote.rejected, quote.expired, quote.due_soon
Klantencustomer.created, customer.updated, customer.deleted, customer.label_added, customer.label_removed, customer.status_changed, customer.balance_threshold, customer.inactive
Betalingenpayment.received, payment.failed, payment.refunded, payment.partial, payment.provider_succeeded, payment.provider_failed
Boekhoudingaccounting.document_added, accounting.purchase_invoice_added, accounting.receipt_added, accounting.document_scanned, accounting.document_processed, accounting.transaction_added, accounting.entry_created, accounting.period_closed
Abonnementsubscription.started, subscription.changed, subscription.cancelled, subscription.limit_reached, subscription.payment_failed, subscription.expiring
Organisatieuser.added, user.removed, user.role_changed, organization.created, organization.settings_changed
CRM-modulecrm.lead.created, crm.lead.status_changed, crm.lead.converted, crm.lead.unattended, crm.deal.created, crm.deal.stage_changed, crm.deal.won, crm.deal.lost, crm.deal.stale, crm.task.overdue, crm.contact.created
Planningschedule.once, schedule.daily, schedule.weekly, schedule.monthly, schedule.weekday, schedule.month_start, schedule.month_end, schedule.cron
Handmatigmanual

Het verzoek dat je ontvangt

POST /webhooks/factora HTTP/1.1
Content-Type: application/json
X-Factora-Event: invoice.paid
X-Factora-Delivery: 9d4a1f3e-2c5b-4e8a-b7d1-0f6e9c3a2b18
X-Factora-Signature: 5b2c0e4f…(64 hex-tekens)
{
    "event": "invoice.paid",
    "automation_id": "9d4a1f3e-1111-4c2d-9e8f-7a6b5c4d3e2f",
    "run_id": "9d4a1f3e-2c5b-4e8a-b7d1-0f6e9c3a2b18",
    "data": {
        "organization": {
            "id": "9d3c…10",
            "name": "Demo BV",
            "email": "info@demo.nl"
        },
        "customer": {
            "id": "9d3c…02",
            "name": "Jansen Bouw",
            "email": "info@jansenbouw.nl",
            "status": "active",
            "outstanding_balance": 0
        },
        "invoice": {
            "id": "9d3c…aa",
            "number": "2026-0142",
            "status": "paid",
            "total": "€ 181,50",
            "total_cents": 18150,
            "amount_due": "€ 0,00",
            "amount_due_cents": 0,
            "days_overdue": 0
        },
        "quote": null,
        "trigger": []
    },
    "custom": {
        "bron": "factora"
    }
}
Veld of headerBetekenis
event / X-Factora-EventDe trigger die de automatisering startte
run_id / X-Factora-DeliveryUniek per uitvoering; gebruik het om dubbele leveringen te herkennen
automation_idDe automatisering die de webhook stuurde
dataDe variabelen van de trigger: organization, customer, invoice, quote, trigger, date en bij CRM-triggers ook deal-, lead- en contactgegevens. Niet van toepassing = null. Bedragen staan zowel opgemaakt (total) als in centen (total_cents)
customDe eigen velden die je in de actie hebt ingesteld
X-Factora-SignatureHMAC-SHA256 (hex) van de ruwe body met je geheim; alleen als je een geheim instelde

Handtekening controleren

Bereken HMAC-SHA256 over de ruwe body zoals je hem ontvangt, met het geheim uit de automatisering, en vergelijk die in constante tijd met X-Factora-Signature. Parse de JSON pas daarna.

// Laravel-route die een Factora-webhook ontvangt.
Route::post('/webhooks/factora', function (Request $request) {
    $expected = hash_hmac('sha256', $request->getContent(), config('services.factora.webhook_secret'));

    abort_unless(hash_equals($expected, (string) $request->header('X-Factora-Signature')), 401);

    $event = $request->input('event');        // bijv. "invoice.paid"
    $delivery = $request->header('X-Factora-Delivery'); // uniek per uitvoering

    // Verwerk idempotent: sla $delivery op en sla dubbele leveringen over.
    ProcessFactoraEvent::dispatch($event, $request->input('data'), $delivery);

    return response()->noContent();
});

Levering en betrouwbaarheid

  • Alleen openbare https://-adressen zijn toegestaan; lokale en privé-adressen worden geweigerd en redirects niet gevolgd.
  • Factora wacht maximaal 10 seconden op antwoord en probeert het bij een fout na 300 ms nog één keer.
  • Een 4xx- of 5xx-antwoord of een time-out geldt als mislukt en is zichtbaar in de uitvoeringen van de automatisering.
  • Antwoord snel met 204 en verwerk het werk daarna in een wachtrij.
  • Verwerk idempotent op basis van X-Factora-Delivery: dezelfde levering kan vaker binnenkomen.
  • Wil je zeker zijn van de actuele stand? Haal het object na de webhook op via de API.