Je klant belt omdat het portaal zegt dat een factuur betaald is, terwijl Moneybird hem nog open toont. Of een klant ziet het dossier van een andere organisatie omdat de URL een ander klantnummer accepteert. Een klantportaal is pas een verbetering als de schermlaag nooit belangrijker wordt dan de brondata erachter.
Deze gids is voor een operations- of customer-serviceteam dat klanten zelf status, documenten en aanvragen wil laten beheren zonder CRM en boekhouding te kopiëren naar een tweede administratie. Je bouwt één controleerbare flow: de klant wordt aan precies één account gekoppeld, het portaal leest actuele gegevens uit HubSpot en Moneybird, een aanvraag komt als begrensde write in een eigen wachtrij, een bevoegde medewerker geeft risicovolle acties vrij en het portaal toont daarna alleen wat werkelijk is opgeslagen.
Een klantportaal is een afgeschermde online omgeving waarin een klant zijn eigen dossier, documenten en actuele status ziet en een beperkte aanvraag kan indienen. De portal-database is daarbij geen nieuwe bron van waarheid. Zij bewaart identiteit, leesrechten, aanvraagstatus en bewijs van de verwerking, terwijl CRM en boekhouding eigenaar blijven van hun eigen gegevens.
De juiste eerste keuze is dus niet Softr, Noloco, HubSpot of maatwerk. Het is de datastroom. De vraag per veld luidt: welk systeem mag dit gegeven bewijzen, wie mag het wijzigen, hoe vers is de lezing en hoe toon ik na een actie aan dat de write echt geland is? De routekeuze tussen kant-en-klaar, no-code en maatwerk komt daarna. De eerdere keuze voor een portaalroute op basis van koppelingen, eigendom en overdraagbaarheid blijft nuttig, maar deze gids gaat één laag dieper: de live uitvoering.
Wat je nodig hebt voordat je bouwt
Je hebt zes bouwstenen nodig. Ontbreekt er één, dan kun je wel een scherm laten zien, maar nog geen betrouwbare portaalflow draaien.
| Bouwsteen | Wat je klaarzet | Controle vóór de bouw |
|---|---|---|
| Portaallaag | Een kant-en-klaar portaal, Softr of Noloco voor de voorkant, of een eigen webapp met bijvoorbeeld Next.js | De voorkant kan geen geheime CRM- of boekhoudsleutel bevatten |
| Identiteit | Magic link, eenmalige code, wachtwoord of SSO; bij eigen bouw bijvoorbeeld Supabase Auth | Eén ingelogde gebruiker is gekoppeld aan één organisatie en één intern klant-ID |
| Bronnen | HubSpot voor klant- en dossierstatus, Moneybird of Exact Online voor facturen en betalingen | Je hebt leestoegang, de juiste API-scopes en een testadministratie |
| Verwerkingslaag | Een server-side API-laag, n8n, Make of een eigen worker | Inkomende events worden snel bevestigd en daarna duurzaam verwerkt |
| Eigen bewijslaag | PostgreSQL of Supabase voor relaties, snapshots, aanvragen, idempotentiesleutels en auditregels | Een timeout en een dubbele aanvraag kunnen worden teruggevonden zonder workflowgeschiedenis |
| Menselijk proces | Eén eigenaar voor de herstelqueue en één bevoegde vrijgever voor financiële of privacygevoelige acties | Er staat een naam, deadline en toegestane beslissing op elk queue-item |
Budgeteer naast abonnementen ook de bouw en het beheer. Als concrete begrotingsorde voor deze gids kun je voor een kleine read-only pilot met één CRM, één boekhoudpakket, login en documenten rekenen op €8.000–€15.000 bouw. Met twee bronnen, een eigen aanvraagledger, menselijke vrijgave, audit en read-back ligt €20.000–€45.000 bouw meer voor de hand; een multi-administratie- of compliance-zware variant begint eerder bij €45.000–€80.000. Reserveer na livegang €500–€2.000 per maand voor monitoring, updates, incidenten, kleine wijzigingen en herstel; externe SaaS, hosting en verbruik komen daar nog bovenop. Dit is een FLOH-begrotingsorde, exclusief btw, gecontroleerd op 22 oktober 2026, geen vaste offerte.
De actuele details van je systemen doen ertoe. HubSpot beschrijft scopes als toegang tot specifieke API-eindpunten en bijbehorende accountdata. Kies dus per route de kleinst mogelijke lees- en schrijfrechten; een brede token maakt je portaal niet robuuster. De HubSpot-documentatie over scopes verwijst per endpoint naar de vereiste machtiging, geraadpleegd op 22 oktober 2026.
Moneybird ondersteunt OAuth2 en persoonlijke API-tokens. Die laatste zijn eenvoudiger, maar de documentatie waarschuwt dat een persoonlijk token toegang kan geven tot de hele bedrijfsadministratie. Voor productie kies ik daarom OAuth met alleen de benodigde scopes. Voor contacten is minstens één van de scopes voor sales invoices, documents, estimates, bank of settings nodig. De actuele Moneybird-authenticatiedocumentatie beschrijft deze keuze en scopes, geraadpleegd op 22 oktober 2026.
Voor een eigen portaal zijn Auth en databasebeveiliging één ontwerpbesluit. Supabase Auth ondersteunt onder meer wachtwoord, magic link, OTP, sociale login en SSO. RLS, Row Level Security, hoort vervolgens op elke tabel die via een exposed schema bereikbaar is. De huidige Supabase-instructie zegt expliciet dat je RLS moet inschakelen, grants moet beperken en allow- en deny-tests moet uitvoeren. Supabase beschrijft de combinatie van Auth en RLS voor autorisatie, gecontroleerd op 22 oktober 2026, en de RLS-handleiding werkt het testen per bewerking uit, eveneens gecontroleerd op 22 oktober 2026.
Verwerk ook niet meer persoonsgegevens dan de aanvraag nodig heeft. De Europese Commissie noemt dataminimalisatie, juistheid, integriteit en vertrouwelijkheid en aantoonbare verantwoordelijkheid als beginselen van de AVG. Die beginselen staan in de actuele uitleg van de Europese Commissie, geraadpleegd op 22 oktober 2026.
Zet voor de eerste proef 20 tot 50 echte maar gecontroleerd geselecteerde records klaar. Neem minstens één klant met meerdere contactpersonen, één factuur met een document, één openstaande factuur, één betaalde factuur, één dubbele relatiekandidaat en één aanvraag die menselijke vrijgave nodig heeft. Masker gegevens waar dat kan en gebruik een aparte testadministratie voor writes.
Concrete stappen: van login naar geverifieerde aanvraag
De flow hieronder is het patroon dat je voor iedere functie opnieuw kunt testen. Begin met lezen. Voeg pas een write toe nadat de lezing, autorisatie en betekenis vaststaan.
1. Maak per veld een bron- en toegangsmatrix
Begin niet met een scherm. Begin met een tabel waarin ieder veld één eigenaar heeft. Een klantdossier kan meerdere systemen bevatten: HubSpot bezit de relatie en commerciële status, Moneybird bezit de factuur en betalingsstatus, een documentopslag bezit bestanden en het portaal bezit de aanvraagstatus. Dat is geen rommel zolang je de grenzen expliciet maakt.
| Gegeven | Bronhouder | Stabiele sleutel | Portalactie | Mag de klant dit direct wijzigen? |
|---|---|---|---|---|
| Organisatie en contact | HubSpot | company_id en contact_id | Lezen | Nee, alleen een wijzigingsaanvraag |
| Dossier- of ticketstatus | HubSpot | ticket_id of deal_id | Lezen | Nee |
| Factuurbedrag en vervaldatum | Moneybird | sales_invoice_id | Lezen | Nee |
| Betaalstatus | Moneybird | payment_id of factuur-ID | Lezen | Nee |
| Factuurdocument | Moneybird of documentopslag | document-ID plus factuur-ID | Tijdelijk downloaden | Nee |
| Verzoek om adreswijziging | Eigen aanvraaglaag | request_id plus organisatie-ID | Aanmaken | Alleen via een begrensd formulier |
| Verwerkingsstatus van het verzoek | Eigen aanvraaglaag | request_id | Lezen | Nee |
De aanvraaglaag is bewust een uitzondering. Zij is de bron van de workflowstatus, niet van de klant- of factuurwaarde. Leg ook vast welke waarden je nooit terugschrijft. Een portalgebruiker mag een factuur als betaald zien, maar mag geen paid naar Moneybird sturen. Een klant mag een adrescorrectie aanvragen, maar de aanvraag mag niet direct de bestaande factuurhistorie overschrijven.
Controlepunt: een collega kan voor ieder schermveld aanwijzen waar de waarde vandaan komt, welke sleutel erbij hoort en welk systeem de beslissing bezit.
2. Koppel de klant aan een interne organisatie, niet aan een URL-parameter
Na login haal je de identiteit uit de sessie en zoek je in je eigen relatiekaart. Die kaart bevat bijvoorbeeld portal_user_id, organization_id, hubspot_company_id, moneybird_contact_id, toegestane documentgroepen en de rol van de gebruiker. De browser mag een organisatie-ID meesturen voor navigatie, maar de server beslist of de ingelogde gebruiker die organisatie mag zien.
Dit voorkomt Broken Object Level Authorization. OWASP beschrijft dit risico als het manipuleren van een object-ID in pad, query of payload om records van iemand anders te lezen of te wijzigen. De impact is datalek, dataverlies of manipulatie. OWASP noemt objectniveau-autorisatie in API1:2023 een veelvoorkomende en eenvoudig uit te buiten zwakte, geraadpleegd op 22 oktober 2026.
In Supabase modelleer je dit als een membership- of organization-tabel en test je minstens deze gevallen: gebruiker ziet zijn eigen organisatie, gebruiker ziet geen andere organisatie, een medewerker met meerdere organisaties ziet alleen de toegewezen organisaties en een uitgeschakelde gebruiker leest niets. RLS is een vangnet, geen vervanging voor een duidelijke relatiekaart.
Bij documenten moet je een tweede controle uitvoeren. Controleer de organisatie opnieuw op het moment dat je een download-URL maakt. Een object-ID uit de browser is nooit voldoende bewijs. Laat een server-side endpoint na autorisatie een kort geldige signed URL maken, of stream het document via de server.
Controlepunt: verander in een testrequest alleen het organisatie-ID en controleer dat je een lege uitkomst of een autorisatiefout krijgt, nooit data van een andere klant.
3. Lees status en documenten live, met een zichtbare versheidsgrens
Lees voor een portaalpagina de brondata opnieuw uit, of lees uit een korte cache met een duidelijk tijdstip. Zet bij iedere externe lezing een read_at, bron-ID en bronstatus. Toon bij een vertraging bijvoorbeeld Laatst bijgewerkt om 10:42, niet een scherm dat stilletjes een oude waarde als actueel presenteert.
HubSpot heeft een CRM Search API waarmee je over CRM-objecten kunt filteren, sorteren en zoeken. Gebruik hem om een bedrijf, ticket of deal op de interne sleutel te vinden, en gebruik daarna de associations-API om relaties naar contactpersonen, deals of tickets op te halen. HubSpot beschrijft de Search API als route voor zoeken over CRM-objecttypen, gecontroleerd op 22 oktober 2026. De associations-API beheert de relaties tussen CRM-records, eveneens gecontroleerd op 22 oktober 2026.
Moneybird is de bron voor de financiële status. Lees factuurkop, regels, vervaldatum, betaling en documentverwijzing met de administratie-ID en de opgeslagen contact-ID. Gebruik niet de HubSpot-dealstage als betaalbewijs. Een gewonnen deal is dus geen betaalbewijs; een CRM-deal die eerst als gecontroleerde conceptfactuur naar Moneybird gaat houdt die grens expliciet. Moneybird beschrijft voor het maken van verkoopfacturen zelf de volgorde: eerst een contact vinden of maken, daarna met de juiste ledger account en tax rate werken. De officiële Moneybird-flow voor verkoopfacturen bewaart ook een externe klant-ID op het contact, geraadpleegd op 22 oktober 2026.
Een stale status is soms beter dan een verzonnen actuele status. Stel een versheidsbeleid op: factuur- en betalingsstatus maximaal vijf minuten oud voor een interactief scherm, projectstatus maximaal vijftien minuten en documenten direct uit de bron of uit een opslag met versie-ID. Dit zijn beleidswaarden die je per proces test, geen technische waarheden.
Controlepunt: je kunt in een schermopname zien welke bron, bron-ID en leestijd de klantstatus hebben bepaald.
4. Leg een aanvraag vast als een begrensde write
Maak van ieder klantformulier een eigen aanvraagtype met een klein schema. Geen vrij tekstvak dat later door een medewerker moet worden geïnterpreteerd als een financiële mutatie. Een aanvraagrecord bevat minimaal:
- request_id en organization_id;
- het vaste type, zoals address_change, missing_document of payment_question;
- alleen de toegestane velden voor dat type;
- de bronversies en bronwaarden die de klant zag;
- payload_hash en idempotency_key;
- actor, tijdstip, kanaal en bijlagen;
- status: submitted, needs_review, approved, rejected, processing, verified of exception;
- eigenaar, deadline, laatste poging en foutcode.
Gebruik een stabiele sleutel per zakelijke handeling. Voor een adresaanvraag kan dat address_change:{organization_id}:{payload_hash} zijn. Komt dezelfde browseractie twee keer binnen, dan levert de server het bestaande request terug. Maak alleen een nieuwe sleutel wanneer de klant bewust een nieuwe versie indient.
Valideer in deze volgorde: sessie, organisatie, aanvraagtype, toegestane velden, formaat, bijlagegrootte, bronversheid, rate limit en idempotentie. Geef de browser nooit een token waarmee hij zelf HubSpot of Moneybird kan schrijven. De write begint bij jouw server nadat de aanvraag een besluit heeft gekregen.
Een aanvraag om een factuur opnieuw te sturen kan laag risico zijn. Een aanvraag om het factuuradres te veranderen, een document te vervangen of een creditnota te starten raakt bewijs of geld. Zet die standaard op needs_review.
Controlepunt: dezelfde POST twee keer uitvoeren maakt één aanvraagrecord en iedere niet-toegestane veldnaam wordt geweigerd.
5. Laat een mens vrijgeven waar de gevolgen niet omkeerbaar zijn
Een menselijke vrijgave is geen e-mail met een akkoord. Zet een reviewscherm neer waarop de medewerker bronwaarde, aangevraagde waarde, bronversie, klantorganisatie, reden, risico en voorgestelde write naast elkaar ziet. De medewerker kiest één van vier besluiten: goedkeuren, afwijzen, extra informatie vragen of terugzetten naar de herstelqueue.
Laat de medewerker eerst de bron opnieuw lezen. Een aanvraag die gisteren op versie hubspot-184 gebaseerd was, mag vandaag niet blind op versie hubspot-184 schrijven. Is de bron veranderd, maak je een nieuwe preview en vraag je opnieuw om vrijgave. Dit is optimistic concurrency: schrijven mag alleen wanneer de voorwaarde nog klopt. RFC 9110 beschrijft If-Match als een voorwaarde die state-changing requests kan stoppen wanneer de huidige ETag niet overeenkomt, meestal met HTTP 412. De IETF-specificatie koppelt dit rechtstreeks aan het voorkomen van lost updates, geraadpleegd op 22 oktober 2026.
De bevoegdheid hoort bij de actie. Een customer-serviceagent mag een ontbrekend document opnieuw laten versturen. Finance mag een factuurcontact of creditnota vrijgeven. De portalgebruiker mag zijn eigen aanvraag indienen, nooit zichzelf als vrijgever registreren. Bewaar decision_id, vrijgever, tijdstip, reden, bronversie en payloadhash als onveranderlijk auditrecord.
Controlepunt: je kunt een goedgekeurde aanvraag tonen als combinatie van wie, wat, op basis van welke bronversie en met welk doel.
6. Voer de write server-side uit en registreer ieder resultaat
Maak writes zo klein als mogelijk. Voor HubSpot schrijf je bijvoorbeeld een toegestaan contactveld of een ticketstatus. Voor Moneybird schrijf je alleen wanneer het gekozen aanvraagtype en het mandaat dat toestaan. Een klantportaal hoeft niet zelf verkoopfacturen te maken om een factuurstatus te tonen. Vaak is een CRM-ticket de juiste gecontroleerde write en blijft de boekhouding alleen leesbron.
Gebruik een aparte verwerkingspoging met attempt_id, request-ID, doelendpoint, doelrecord-ID, payloadhash, starttijd, eindtijd, HTTP-status, response-body of veilige verwijzing ernaar en een foutklasse. Deel geen volledige persoonsgegevens in algemene logs.
Voor Moneybird-webhooks is de retourstroom net zo belangrijk als de write. Moneybird vraagt een HTTPS-endpoint, verwacht HTTP 200, probeert bij een andere status maximaal tien keer opnieuw en levert een Idempotency-Key mee. De webhook bevat ook een Moneybird-Signature waarmee je de ongewijzigde request body met HMAC-SHA256 verifieert. De actuele Moneybird-webhookdocumentatie beschrijft retries, idempotentie en ondertekende payloads, gecontroleerd op 22 oktober 2026, en de signature-handleiding schrijft voor dat je de ruwe body en een timestamp van maximaal vijf minuten oud controleert, eveneens gecontroleerd op 22 oktober 2026.
Bewaar een ontvangen webhook vóór je hem verwerkt. Geef snel 200 terug nadat je hem duurzaam hebt opgeslagen. Laat de worker daarna bepalen of dit een nieuwe gebeurtenis, een duplicaat of een late versie is.
Controlepunt: je kunt na iedere externe call zeggen of de write geslaagd, afgewezen, mislukt of onbekend is.
7. Lees de werkelijk opgeslagen status terug
Een HTTP 200 is een transportresultaat, geen bewijs dat de juiste bedrijfswaarde in het doel staat. Lees na de write het doelrecord opnieuw uit met de stabiele doel-ID. Vergelijk minimaal de velden die je wilde wijzigen, de doelstatus, het externe ID en de relevante bron- of recordversie. Sla de read-back op als apart resultaat, niet als overschreven response-log.
Bij een Moneybird-contactcontrole lees je bijvoorbeeld contact-ID, customer_id, naam, adres en land opnieuw uit. Bij HubSpot lees je het contact of ticket terug met de properties die je wijzigde. Zet pas daarna de aanvraag op verified. Het portal leest de uitkomst vervolgens uit de bron of uit een verified-projection met bron-ID en leestijd.
Als de write na verzending een timeout geeft, is de uitkomst onbekend. Stuur niet meteen nogmaals. Zoek eerst op de stabiele externe sleutel, payloadhash of eigen request-ID. Vind je de verwachte waarde, markeer je de poging als verified_after_timeout. Vind je niets of een tegenstrijdige waarde, zet je hem op write_unconfirmed in de herstelqueue.
Als de bronversie na de write is veranderd, markeer je de oude poging als superseded, lees je opnieuw en maak je een nieuwe aanvraagversie. De klant ziet dan In behandeling of Nieuwe controle nodig, niet een optimistische succesmelding. Bij een API-upgrade geldt dezelfde grens: shadow reads en reconciliatie vóór de nieuwe route laten je vergelijken voordat je writes omzet.
Controlepunt: de succespagina wordt pas getoond nadat een tweede GET de bedoelde doelwaarde en identiteit bevestigt.
8. Bouw een herstelqueue en periodieke reconciliatie
De queue is een werkvoorraad, geen lijst met foutmeldingen. Elk item krijgt een reden, eigenaar, deadline, laatste geldige toestand, nieuwe toestand, toegestane acties, aantal pogingen en een link naar de auditregels. Gebruik foutklassen die iemand kan begrijpen:
- authorization_mismatch: gebruiker en organisatie passen niet bij elkaar;
- source_stale: bronversie veranderde vóór vrijgave;
- duplicate_request: bestaande aanvraag gevonden;
- target_rejected: doel valideerde de write niet;
- write_unconfirmed: timeout na de externe call;
- readback_mismatch: doelwaarde wijkt af;
- webhook_invalid: handtekening of timestamp klopt niet;
- rate_limited: wacht op het opgegeven herstelmoment.
Plan ook een reconciliatie. Controleer bijvoorbeeld elk uur alle openstaande aanvragen, dagelijks de set van actieve relaties en na iedere Moneybird-webhook de factuurstatus voor de betrokken klant. Vergelijk telling, sleutelset en relevante veldwaarden. Een webhook maakt de flow snel. Reconciliatie ontdekt dat een webhook ontbrak, dubbel kwam of nooit tot een doelwaarde leidde.
Neem bij herstel een overlapvenster mee. Een exacte updated_at-grens kan een record missen door klokverschil of een late verwerking. Idempotentie maakt die overlap veilig.
Controlepunt: een medewerker kan een mislukte aanvraag hervatten zonder een tweede write te veroorzaken, en een nachtelijke controle kan ontbrekende gebeurtenissen aanwijzen.
Valkuilen die je vóór livegang test
Een portaal breekt zelden op het ideale pad. Test deze situaties als aparte acceptatiegevallen.
-
De klant-ID komt uit de browser.
Een aanvaller verandert organization_id=10421 in organization_id=10422 en krijgt een ander dossier. Controleer organisatie en rol altijd vanuit de sessie en de server-side relatiekaart. Test lezen, downloaden en schrijven afzonderlijk.
-
De portal-database wordt een kopie van de waarheid.
Een nachtelijke kopie van facturen lijkt snel, maar toont na een betaling de oude toestand. Bewaar alleen wat je nodig hebt voor autorisatie, aanvraag en bewijs. Haal financiële status live of geef de cacheleeftijd zichtbaar mee.
-
Een brede token staat in de frontend.
Een API-sleutel in JavaScript is geen veilige koppeling. Houd HubSpot- en Moneybird-credentials server-side, geef per connector minimale scopes en roteer secrets zonder de portalcode te wijzigen.
-
Een succesresponse wordt als business-succes gelezen.
Een API kan een aanvraag accepteren, asynchroon verwerken of na een timeout al hebben uitgevoerd. Classificeer accepted, completed, rejected en unknown apart. Read-back beslist of je verified mag tonen.
-
Een retry maakt een tweede aanvraag.
Browser-refresh, webhook-herhaling en worker-retry zijn normale gebeurtenissen. Maak de eigen aanvraag idempotent en zoek na een onbekende write eerst naar het bestaande doelrecord. Een derde poging is geen herstelstrategie.
-
Een klant kan een boekhoudkundige waarde direct wijzigen.
Laat een klant een adrescorrectie of betaalvraag indienen, maar stuur die naar een expliciet proces. De factuurstatus, btw, factuurdatum en boekingsstatus blijven bronvelden met een zwaarder mandaat.
-
De herstelqueue heeft geen eigenaar.
Een status failed zonder reden, deadline en persoon blijft liggen. Maak owner, next_action, due_at en toegestane uitkomsten verplichte velden.
-
Je vertrouwt alleen op webhooks.
Een webhook levert snelheid, geen volledigheid. Moneybird kan opnieuw afleveren, HubSpot-events kunnen later komen en een netwerkstoring kan een ontvangst missen. Plan een reconciliatie op sleutelset en bedrijfstotalen.
-
Een documentlink is breder dan het dossier.
Een signed URL die niet aan de organisatie wordt gebonden lekt alsnog een factuur. Autoriseer vlak voor uitgifte, laat links verlopen en log wie welk document opvroeg.
-
De prijs van de orkestratielaag wordt niet getest.
n8n rekent per volledige workflowuitvoering; de bedragen hieronder zijn gecontroleerd op 22 oktober 2026. Starter kost €20 per maand bij jaarlijkse facturatie voor 2.500 uitvoeringen, Pro €50 voor 10.000 en Business €667 voor 40.000, waarbij Business self-hosted is. Make rekent sinds 27 augustus met credits per moduleactie. De actuele Make-prijspagina legt uit dat lezen, zoeken, aanmaken en bijwerken credits verbruiken en dat inkomende webhooks bij lege credits worden gequeue’d, geraadpleegd op 22 oktober 2026. Meet het aantal aanvragen én de CRM- en boekhoudacties per aanvraag.
Beslis-kader: kant-en-klaar, no-code of maatwerk
Kies een kant-en-klaar portaal als je vooral standaarddocumenten en status wilt tonen en aanvragen naar een menselijke inbox mogen. Kies no-code als je een snelle voorkant wilt bovenop gestructureerde data, maar bereid een server-side API-proxy en een exportpad voor. Kies maatwerk zodra klantgrenzen, meerdere bronnen, gevoelige documenten of gecontroleerde writes de kern van het product zijn.
Mijn harde grens: laat een no-code-scherm geen directe schrijfrechten naar Moneybird of HubSpot krijgen. Gebruik Softr of Noloco eventueel voor de leeslaag, en laat writes via een eigen endpoint lopen dat autorisatie, snapshot, vrijgave, idempotentie en read-back beheert. Een workflowplatform versnelt de orkestratie, maar het is geen vervanging voor een eigen bewijslaag.
Leg je situatie langs vijf vragen:
- Is de functie standaard? Alleen login, documenten en status past bij kant-en-klaar. Een eigen aanvraagproces met uitzonderingen duwt naar no-code of maatwerk.
- Hoe diep zijn de koppelingen? Eén CRM met een beperkte leesflow kan via een workflowlaag. CRM, boekhouding, documentopslag en meerdere administraties vragen een eigen integratielaag.
- Wat kost een fout? Een gemiste afspraak is anders dan een verkeerde factuur, betaalstatus of document voor de verkeerde klant. Hoe hoger de foutkosten, hoe zwaarder menselijke vrijgave en read-back wegen.
- Wie beheert de uitzonderingen? Zonder vaste queue-eigenaar is een kant-en-klaar formulier eerlijker dan schijnautomatisering.
- Hoe belangrijk zijn eigendom en exit? Bij een tijdelijk experiment volstaat huren. Bij een kernproces wil je eigen accounts, export, code, logs en een tweede partij die de flow kan overnemen.
Wat moet de klant vooral kunnen?
Vergelijkingstabel: routes, tools en kosten
De prijzen hieronder zijn gecontroleerd op 22 oktober 2026. Abonnementen, wisselkoersen en gebruiksgrenzen veranderen. Gebruik ze als actuele orde van grootte en controleer de leverancier opnieuw vóór je een contract tekent.
| Route | Voorbeeldtool | Actueel detail | Writes en herstel | Kies deze route als |
|---|---|---|---|---|
| Kant-en-klaar | Gespecialiseerd klantportaal of portaalmodule in je CRM | Leveranciersprijs per plan of gebruiker; vraag prijs en exportvoorwaarden op voor de gekozen leverancier | Beperkte formulieren; vaak geen eigen bronversie- of read-backmodel | Je vooral standaarddocumenten en status toont |
| No-code voorkant | Een no-code portal builder met CRM/API-bron | Leveranciersprijs is plan- en gebruikersafhankelijk; vergelijk externe gebruikers, records, workflowruns en export voordat je 24 maanden rekent | Gebruik een eigen proxy voor writes, queue en credentials | Je snel een eigen scherm wilt bovenop bestaande data |
| Workflowlaag | n8n of Make | n8n Starter €20 per maand bij jaarfacturatie voor 2.500 uitvoeringen, Pro €50 voor 10.000; Make rekent per moduleactie met credits | Goed voor orkestratie en retries; eigen ledger blijft nodig | De regels overzichtelijk zijn en je technisch beheer hebt |
| Eigen portalstack | Next.js, Supabase Auth en PostgreSQL | Supabase Pro vanaf $25 per maand, met 100.000 maandelijkse actieve gebruikers, 8 GB schijf en 250 GB egress; extra hosting en beheer komen erbij | Volledige controle over RLS, aanvraagstatus, audit en read-back | Autorisatie, meerdere bronnen en foutkosten de kern vormen |
De Supabase-prijs is een infrastructuurprijs, geen bouwprijs. De actuele pagina noemt ook extra projecten vanaf $10 per maand en verbruikstarieven boven de inbegrepen grenzen. De prijsdetails zijn gecontroleerd op de officiële Supabase-prijspagina, geraadpleegd op 22 oktober 2026.
Uitgewerkt voorbeeld: adrescorrectie vanuit het portaal
Neem een fictieve onderhoudsdienst met HubSpot voor klantdossiers en Moneybird voor facturen. De gegevens hieronder zijn een illustratief testscenario, geen klantcase. De organisatie heeft 42 zakelijke klanten en wil drie vragen uit de mailbox halen: waar staat mijn dossier, welke facturen zijn nog open en kun je het factuuradres aanpassen?
De afgesproken bronverdeling
- HubSpot bezit de organisatie, contactpersonen, tickets en dossierstatus.
- Moneybird bezit factuurnummer, factuurbedrag, vervaldatum, document en betaalstatus.
- De eigen portal-laag bezit de relatiekaart, aanvraagstatus, auditregels en technische pogingen.
- Niemand mag een factuur als betaald markeren vanuit het portaal.
Stap 1: login en autorisatie
Een contactpersoon logt in met een magic link. De sessie bevat portal_user_id = usr_8f2, maar nog geen vrij klantnummer. De server haalt uit de relatiekaart organization_id = org_10421, hubspot_company_id = 10421 en moneybird_contact_id = mbc_771. De gebruiker ziet alleen records die via org_10421 zijn verbonden. Een handmatige wijziging naar org_10422 levert geen record op.
Stap 2: live lezen
Het portaal vraagt bij het openen van het dashboard de HubSpot-dossierstatus en de Moneybird-facturen op. Het toont illustratief factuur 2026-00481, €1.210,00, vervaldatum 31 oktober 2026, status open, met een read_at van 22 oktober 2026 om 09:02. De portal bewaart de factuur niet als eigen waarheid. Het bewaart de relatie tussen gebruiker, bron-ID en laatst bekende leestijd.
Stap 3: aanvraag indienen
De contactpersoon kiest Factuuradres aanpassen. Het formulier accepteert alleen bedrijfsnaam, straat, postcode, plaats en land. Het request krijgt:
request_id = req-2026-10-22-0042
organization_id = org_10421
type = address_change
source_snapshot = hubspot:10421:2026-10-22T09:02:00+02:00
payload_hash = sha256:adres-v2
idempotency_key = address_change:org_10421:sha256-adres-v2
status = needs_review
De aanvraag wijzigt nog niets in HubSpot of Moneybird. De klant ziet Aanvraag ontvangen.
Stap 4: vrijgave
Een medewerker ziet de oude en nieuwe adresgegevens, de organisatie-ID, de contact-ID’s en de tijd van de snapshot. Hij leest HubSpot opnieuw. De contactpersoon hoort nog bij company_id 10421, de bronversie is niet veranderd en er is geen tweede organisatie met hetzelfde externe klant-ID. De medewerker keurt goed. De beslissing krijgt een eigen decision_id en reden.
Stap 5: gecontroleerde write
De worker schrijft eerst het goedgekeurde contactveld naar HubSpot. Als het beleid voorschrijft dat Moneybird-contactgegevens gelijk moeten lopen, schrijft dezelfde case daarna het Moneybird-contact bij via de opgeslagen mbc_771. De bestaande factuur 2026-00481 blijft historisch ongewijzigd. Dat onderscheid voorkomt dat een adrescorrectie met terugwerkende kracht een boekhoudkundig document herschrijft.
Elke poging bewaart doel-ID, payloadhash, HTTP-status en responseverwijzing. Bij een timeout zoekt de worker eerst op mbc_771 en de eigen case. Hij maakt geen tweede contact aan.
Stap 6: read-back
De worker leest het HubSpot-contact en, als dat is bijgewerkt, het Moneybird-contact opnieuw uit. Naam, adres, land en externe klantcode moeten overeenkomen met de goedgekeurde payload. Pas dan wordt het request verified en toont het portaal Adres verwerkt. Als HubSpot de nieuwe waarde toont maar Moneybird nog de oude, wordt de status exception en ziet de klant Nog in controle.
Stap 7: herstel
Stel dat Moneybird na de write een timeout gaf. De queue toont write_unconfirmed, eigenaar Finance, deadline 22 oktober 2026 om 12:00 en de toegestane acties Opnieuw lezen, handmatig vergelijken of afwijzen. Een medewerker ziet dat de waarde al goed staat en sluit het item als verified_after_timeout. De klant krijgt geen dubbele contactpersoon en het auditrecord legt uit waarom de tweede write niet is verstuurd.
Dit voorbeeld laat de kern zien: de portalactie is klein, de write is begrensd, de mens beslist op actuele brondata en de klant ziet de eindstatus pas na read-back.
Een portaal is volwassen wanneer je bij iedere zichtbare status drie vragen kunt beantwoorden: waar komt hij vandaan, voor welke klant is hij geldig en wanneer heb je gecontroleerd dat hij nog klopt? En bij iedere aanvraag nog drie: wat mocht er gebeuren, wie gaf het vrij en wat staat er nu werkelijk opgeslagen? Wie die vragen niet kan beantwoorden, heeft geen self-service gebouwd maar een tweede administratie met een mooiere voorkant.
Veelgestelde vragen
Een portaal dat klopt
Ik ontwerp en realiseer de koppeling tussen je klantportaal, CRM en boekhouding, inclusief autorisatie, menselijke vrijgave, herstelqueue en read-back.
Dit artikel is geproduceerd samen met het Agent Team. Meer over de redactie.
