Docs en hulpKoppelen
Bestellingen doorsturen met een webhook
Bij elke nieuwe bestelling een ondertekend bericht naar een adres dat jij kiest: zo zet je bestellingen door naar Zapier, Make of n8n, en van daaruit naar Notion, Google Sheets of je eigen systeem.
Bij elke nieuwe bestelling stuurt Mark2Form een kort JSON-bericht naar een https-adres dat jij kiest. Dat heet een webhook. Daarmee koppel je Zapier, Make of n8n, en via die weg bijvoorbeeld Notion, Google Sheets of je ERP: elke bestelling komt er dan vanzelf in, zonder overtypen.
Instellen
In je portaal open je je software en ga je naar de tab Gebruiken. Klik op Koppelen, kies Op mijn website en open Meer uitleg. Via Stap voor stap koppelen kom je bij het scherm Koppelen; daar kies je bij Melding bij nieuwe bestelling voor Adres toevoegen. Tijdens je proef staat de knop Koppelen er nog niet.
- Alleen de eigenaar van het bedrijf kan een adres toevoegen.
- Na het opslaan zie je het geheim van dit adres (het begint met
whsec_). Je ziet het één keer: bewaar het meteen, bijvoorbeeld in de instellingen van je Zapier-, Make- of n8n-stap. - Met Stuur testbericht krijg je een bericht van het type
ping, zodat je je koppeling kunt proberen zonder een echte bestelling.
Het bericht
We sturen een POST met deze headers:
Content-Type: application/json
User-Agent: Mark2Form-Webhooks/1
Mark2Form-Signature: t=<unix-tijd>,v1=<hex>
Mark2Form-Event: bestelling.aangemaakt
Mark2Form-Delivery: <id van deze bezorging>
En deze body. De naam, het adres en de bestelling zijn verzonnen:
{
"id": "b66adce7-ec1d-8d38-89c3-f668edd73ca4",
"type": "bestelling.aangemaakt",
"versie": 1,
"aangemaakt_op": "2026-09-23T09:41:07.412Z",
"data": {
"bestelling_id": "3f2b8c1e-7a4d-4e21-9b6f-0c5d8e2a1b47",
"ordernummer": "3F2B8C1E",
"soort": "bestelling",
"aangemaakt_op": "2026-09-23T09:41:07.412Z",
"omschrijving": "Neonbord 'Open' — 80 cm, warmwit",
"klant": { "naam": "Jan Voorbeeld", "email": "jan@example.com" },
"bedrag": { "centen": 34950, "valuta": "EUR" },
"software": { "slug": "neon-studio", "naam": "Neon Studio" },
"portaal_url": "https://app.mark2form.com/portaal/bestellingen/3f2b8c1e-7a4d-4e21-9b6f-0c5d8e2a1b47"
}
}
Een testbericht is kleiner:
{ "id": "…", "type": "ping", "versie": 1, "aangemaakt_op": "…", "data": { "test": true } }
Er zit bewust niets anders in het bericht: geen ontwerpbestanden, geen
downloadlinks en geen interne gegevens. Die haal je op in je portaal, via het
adres in portaal_url. Zo belandt er nooit een productiebestand in een
spreadsheet of een mailbox waar het niet hoort.
Het bedrag staat in centen (34950 is 349,50 euro), zodat er geen
afrondingsverschil in je boekhouding sluipt.
Is het echt van ons? De handtekening controleren
Iedereen die je adres kent, kan er iets naartoe sturen. Daarom ondertekenen we elk bericht. Controleer die handtekening voordat je iets met het bericht doet.
De header Mark2Form-Signature bevat een tijd (t) en een handtekening
(v1). De handtekening is een HMAC-SHA256 over <t>.<ruwe body>, met je
geheim als sleutel. Drie dingen moeten kloppen:
- Gebruik de ruwe body, precies zoals hij binnenkwam, en niet de body na
JSON.parse. Een spatie verschil en de handtekening klopt niet meer. - De sleutel is het hele geheim, inclusief
whsec_, als UTF-8-tekst. - De tijd mag niet meer dan 300 seconden afwijken van nu. Zo kan niemand een oud bericht opnieuw afspelen.
Een voorbeeld in Node.js:
import { createHmac, timingSafeEqual } from "node:crypto";
export function isEchtVanMark2Form(ruweBody, header, geheim) {
if (!header) return false;
const delen = header.split(",").map((d) => d.trim().split("="));
const t = Number(delen.find(([k]) => k === "t")?.[1]);
if (!Number.isInteger(t) || Math.abs(Date.now() / 1000 - t) > 300) return false;
const verwacht = Buffer.from(createHmac("sha256", geheim).update(`${t}.${ruweBody}`).digest("hex"));
return delen
.filter(([k]) => k === "v1")
.some(([, v]) => {
const b = Buffer.from(v ?? "");
return b.length === verwacht.length && timingSafeEqual(b, verwacht);
});
}
Klopt de handtekening niet, antwoord dan met een 401 en doe verder niets met
het bericht.
Gebruik je Node? Dan doet @mark2form/contracts het voor je
Dezelfde controle zit in ons package @mark2form/contracts, dat openbaar op
npm staat (MIT-licentie). Wij ondertekenen de berichten met hetzelfde package.
npm install @mark2form/contracts
import { verifieerHandtekening, WEBHOOK_HEADERS } from "@mark2form/contracts/webhooks";
const ruweBody = await request.text(); // de ruwe body: niet eerst request.json()
const uitkomst = await verifieerHandtekening({
geheim: process.env.MARK2FORM_WEBHOOK_GEHEIM,
ruweBody,
header: request.headers.get(WEBHOOK_HEADERS.handtekening),
});
if (!uitkomst.geldig) return new Response(null, { status: 401 });
const bericht = JSON.parse(ruweBody); // pas nu
Dit hoort in een route die een standaard Request krijgt, zoals in Next.js,
Hono of een edge-functie. Goed om te weten:
- Het package is een ES-module: gebruik
import, nietrequire. Het heeft WebCrypto nodig, dus Node 20 of nieuwer. - Klopt de handtekening niet, dan staat in
uitkomst.redenwaarom, zoalsgeen-header,buiten-tolerantieofgeen-overeenkomst. Handig voor je eigen log.
Antwoorden, herkansingen en dubbele berichten
- Antwoord binnen een paar seconden met een 2xx (bijvoorbeeld
200). Doe het zware werk daarna, niet terwijl wij wachten. - Lukt dat niet, dan proberen we het opnieuw: na 1 minuut, 5 minuten, 30 minuten, 2 uur en 12 uur. Dat zijn zes pogingen in totaal.
- Komen vijf bestellingen op rij helemaal niet aan, dan zetten we het adres uit en mailen we de eigenaar.
- Hetzelfde bericht kan twee keer komen. We bezorgen “minstens één keer”,
en een herkansing draagt hetzelfde
id. Heb je datidal verwerkt, sla het bericht dan over.
Geheim kwijt of adres uitgezet?
In het portaal kun je bij een adres:
- Het geheim vernieuwen. Het oude geheim werkt dan meteen niet meer. Zet het nieuwe dus direct in je eigen systeem, of in je Zapier-, Make- of n8n-stap.
- Het adres weer aanzetten, als het is uitgezet omdat vijf bestellingen op rij niet aankwamen. De teller begint dan weer op nul.
Met Zapier, Make of n8n
Je hebt geen eigen server nodig: deze diensten geven je een adres dat je in je portaal plakt.
- Zapier. Begin een Zap met Webhooks by Zapier en kies Catch Hook. Zapier geeft je een adres; plak dat in je portaal en stuur een testbericht. Daarna kies je de volgende stap, bijvoorbeeld een regel in Google Sheets.
- Make. Begin een scenario met de module Webhooks en kies Custom webhook. Kopieer het adres naar je portaal en stuur een testbericht, zodat Make de velden van het bericht leert kennen.
- n8n. Begin een workflow met een Webhook-node, zet de methode op
POSTen gebruik het productie-adres van die node. Stuur een testbericht om de velden te zien.
Controleer ook daar de handtekening als de dienst dat kan, bijvoorbeeld in een code-stap. Kan dat niet, deel het adres dan met niemand, en werk bij twijfel met de gegevens uit je portaal in plaats van die uit het bericht.
Zie ook Neon Studio in je eigen site zetten.