# Aangepaste webhooks

POST inzendingsdata naar elk HTTPS-eindpunt — je backend, serverloze functie of proxy.

## Aangepaste webhooks

Stuur elke voltooide inzending als een ondertekend POST-verzoek naar elk HTTPS-eindpunt — je backend, automatiseringsplatform of serverloze functie.

<h2 id="how-it-works">Hoe het werkt</h2>

<p>
  Bij elke inzending stuurt Formstep een JSON-body via POST naar je webhook-URL. Het verzoek is ondertekend met HMAC-SHA256, wordt bij een
  fout opnieuw geprobeerd en wordt vastgelegd in het gebeurtenislogboek van de integratie. Deze pagina behandelt het instellen. De exacte
  payload, headers en het handtekeningalgoritme staan in de <a href="/nl/developers/webhooks-reference">webhookreferentie</a>.
</p>

<h2 id="add">Een webhook toevoegen</h2>

> ℹ️ **Meerdere webhooks**
> <p>Je kunt meerdere webhooks aan één formulier koppelen. Elke webhook wordt onafhankelijk geactiveerd voor elke gebeurtenis.</p>

<h2 id="url-rules">Welke URL's Formstep accepteert</h2>

<ul>
  <li>
    <code>https://</code> overal, of <code>http://</code> voor <code>localhost</code> en <code>*.localhost</code> tijdens ontwikkeling.
  </li>
  <li>Geen inloggegevens in de URL, en maximaal 2.048 tekens.</li>
  <li>
    Geen privé- of interne adressen. De hostnaam wordt opgelost en direct vóór <em>elke</em> levering opnieuw gecontroleerd, zodat een
    DNS-record dat na het instellen naar een intern adres wijst, alsnog wordt geweigerd.
  </li>
</ul>

<p>
  Een geweigerde URL is een configuratieprobleem, geen tijdelijk probleem: de levering mislukt permanent in plaats van opnieuw te worden
  geprobeerd.
</p>

<h2 id="payload">Wat je ontvangt</h2>

<p>
  Elk verzoek is dezelfde event-envelop — <code>id</code>, <code>type</code>, <code>createdAt</code>, <code>apiVersion</code>,{' '}
  <code>test</code> en <code>data</code>. In <code>data</code> staan het formulier, de inzending (id, e-mailadres van de respondent,
  tijdstip van indiening, PDF-link, taal), een <code>answers</code>-object met de <a href="/nl/requests/field-keys">veldsleutel</a> als key,
  en een <code>display</code>-object met dezelfde keys als leesbare tekst. Elk antwoord verschijnt één keer, in elke map.
</p>

<p>
  Zie de referentie voor de volledige <a href="/nl/developers/webhooks-reference#payload">payloadvorm</a>,{' '}
  <a href="/nl/developers/webhooks-reference#fields-vs-answers">answers en display</a>, en hoe een{' '}
  <a href="/nl/building-forms/repeating-groups">herhalende groep</a> wordt weergegeven.
</p>

<p>
  Om de exacte body voor je formulier te bekijken, open je de integratie en vouw je <strong>Voorbeeldpayload</strong> open onder het
  ondertekeningsgeheim. Deze toont je huidige koppeling met voorbeeldantwoorden.
</p>

<h2 id="signatures">Handtekeningen verifiëren</h2>

<p>
  Elk verzoek bevat een <code>X-Formstep-Signature</code>-header: <code>t=TIMESTAMP,sha256=HEX</code>, een HMAC-SHA256 van{' '}
  <code>TIMESTAMP.BODY</code> berekend met je ondertekeningsgeheim. Het geheim zelf wordt nooit verstuurd. De referentie bevat een{' '}
  <a href="/nl/developers/webhooks-reference#signing">kant-en-klaar verificatiefragment</a>.
</p>

> ⚠️ **Verifieer altijd in productie**
> <p>
>     Zonder verificatie kan iedereen die je URL ontdekt nepinzendingen posten. Wijs verzoeken af waarvan de handtekening ontbreekt of
>     ongeldig is.
>   </p>

<h2 id="abandoned-responses">Verlaten reactie-events</h2>

<p>
  Aangepaste webhooks worden alleen geactiveerd voor voltooide inzendingen en bewerkingen — nooit voor verlaten concepten. Een aangepaste
  webhook is de enige ontvanger die beide krijgt: een Zapier-, Make- of n8n-abonnement kiest eerste inzendingen of bewerkingen, nooit
  allebei. Gebruik voor verlaten concepten een provider met een stap <strong>Verlaten inzendingen</strong>: Google Sheets, Airtable, Notion,
  Slack, Discord, Linear of GitHub Issues. Elk daarvan heeft zijn eigen inactiviteitsvenster en, waar van toepassing, zijn eigen
  berichttemplate. Die stap vereist Pro of Business.
</p>

<h2 id="retries">Nieuwe pogingen en mislukkingen</h2>

<ul>
  <li>
    Een levering slaagt bij elke <code>2xx</code>.
  </li>
  <li>
    Tot 5 pogingen: de eerste wordt direct verstuurd, nieuwe pogingen wachten minstens 1, 2, 4 en 8 minuten. Formstep zoekt elke 30 minuten
    naar nieuwe pogingen die klaarstaan, dus de laatste poging komt zo'n twee uur na de eerste. Een <code>Retry-After</code>-header bij een{' '}
    <code>429</code> of <code>5xx</code> wordt gerespecteerd wanneer die om een langere wachttijd vraagt.
  </li>
  <li>
    <code>429</code>, <code>5xx</code>, timeouts en verbindingsfouten worden opnieuw geprobeerd. Elke andere <code>4xx</code> mislukt
    direct.
  </li>
  <li>
    Na 5 opeenvolgende mislukkingen pauzeert de integratie automatisch en ontvangt de persoon die haar heeft ingesteld een e-mail. Los het
    eindpunt op en klik daarna op <strong>Hervat</strong>.
  </li>
  <li>
    <code>401</code>, <code>403</code> en <code>404</code> stoppen de integratie meteen met een foutstatus en dezelfde e-mail — er wordt
    niet gewacht op vijf mislukkingen.
  </li>
  <li>
    Leveringen die alle 5 pogingen hebben verbruikt, verzamelen zich in een banner op de integratie. <strong>Alles opnieuw proberen</strong>{' '}
    zet ze opnieuw in de wachtrij en heractiveert een gepauzeerde integratie.
  </li>
</ul>

<h2 id="testing">Testen</h2>

<p>
  <strong>Stuur een test-event</strong> verschijnt bij de stap Afronden en opnieuw op de opgeslagen integratie. Het POST't een
  gesynthetiseerde voorbeeldinzending — <code>"John Doe"</code> voor tekst, <code>42</code> voor getallen, <code>john@example.com</code>{' '}
  voor e-mail — ondertekend en met je aangepaste headers, precies zoals een echte levering. Vanuit de opgeslagen integratie wordt ook een
  verbindingstest-vermelding aan het gebeurtenislogboek toegevoegd.
</p>

<p>Voor lokale ontwikkeling maak je je dev-server bereikbaar met een tunnel:</p>

```
# ngrok
ngrok http 3000

# cloudflare tunnel

cloudflared tunnel --url http://localhost:3000
```

<h2 id="faq">Veelgestelde vragen</h2>

  <p>
    Ja. Elke webhook heeft zijn eigen URL, ondertekeningsgeheim en aangepaste headers. Alle actieve webhooks worden onafhankelijk
    geactiveerd voor elke inzending.
  </p>

  <p>
    Ja — tot 5, toegevoegd tijdens het instellen of later vanuit de integratie. <code>Content-Type</code> wordt automatisch ingesteld en
    elke poging om dit te overschrijven wordt genegeerd.
  </p>

  <p>
    Nee. Het ondertekeningsgeheim wordt één keer gegenereerd wanneer de webhook wordt aangemaakt en kan niet worden gewijzigd. Als je een
    nieuw geheim nodig hebt, verwijder je de webhook en maak je een nieuwe aan.
  </p>

  <p>Ja. Open de integratie, bewerk de URL en sla op. Het ondertekeningsgeheim en de gebeurtenisgeschiedenis blijven behouden.</p>

  <p>
    Alleen voor <code>localhost</code> en <code>*.localhost</code> tijdens ontwikkeling. Alle andere URL's moeten HTTPS gebruiken.
  </p>

  <p>
    Verwijder hem via Formulierinstellingen → Integraties. Formstep stopt onmiddellijk met het versturen van verzoeken, en de
    gebeurtenisgeschiedenis van de integratie wordt er samen mee verwijderd.
  </p>

<h2 id="next-steps">Volgende stappen</h2>
<div class="not-prose grid gap-3 sm:grid-cols-2">
  - [Webhookreferentie](/nl/developers/webhooks-reference) — Payload, headers en handtekeningverificatie
  - [Airtable](/nl/integrations/airtable) — Stuur inzendingen naar een Airtable-base
  - [Linear](/nl/integrations/linear) — Verander inzendingen in Linear-issues
  - [Herhalende groepen](/nl/building-forms/repeating-groups) — Laat respondenten zoveel invoeren toevoegen als nodig
</div>
