Drie systemen, drie voorraadstanden, en niemand die kan zeggen welke klopt. De reflex is dan om er nog een koppeling bij te bouwen. Terwijl het probleem zelden in de koppeling zelf zit.
Het zit in een keuze die niemand hardop maakte: welk systeem is de baas over welk veld, en met welk ritme mag de rest dat te weten komen. Die keuze heet een synchronisatiepatroon. Er zijn er drie die er in de praktijk toe doen, en ze lopen alle drie op een andere manier stuk.
Het korte antwoord per situatie
Datasynchronisatie is het afspraakstelsel dat ervoor zorgt dat dezelfde gegevens in meerdere systemen hetzelfde betekenen: welk systeem eigenaar is van welk veld, met welk ritme wijzigingen worden doorgegeven, en wat er gebeurt als twee systemen tegelijk iets veranderen. Het is dus geen koppeling maar een besluit. De koppeling voert dat besluit alleen uit.
Lees je verder niets, lees dan dit:
- Orders, betalingen en voorraadmutaties: event-driven. Elke gebeurtenis duwt zichzelf door, binnen seconden, en je verwerkt hem precies één keer.
- Artikelen, prijzen, klant- en contactgegevens: delta-batch. Eens per uur of per nacht ophalen wat sinds de vorige keer is gewijzigd. Simpeler, goedkoper en betrouwbaarder dan events, en niemand merkt het verschil.
- Rapportage en dashboards over meerdere systemen: ETL of ELT naar één centrale laag. Je synchroniseert dan niet tussen systemen, je kopieert ze allemaal naar een plek waar je wél mag rekenen.
- Twee systemen die allebei hetzelfde veld mogen wijzigen: nog even niet koppelen. Wijs eerst per veld een eigenaar aan, anders bouw je een machine die netjes de verkeerde waarde verspreidt.
Bij alle drie geldt dezelfde regel: geen enkel patroon is af zonder een periodieke reconciliatie, een controleronde die de tellingen aan beide kanten vergelijkt en verschillen zichtbaar maakt. Shopify schrijft in zijn eigen documentatie dat webhook-aflevering niet gegarandeerd is en dat je daarom een reconciliatie-job hoort te draaien. Dat advies geldt voor elk koppelvlak dat je bouwt.
Wat je nodig hebt voordat je een patroon kiest
Een patroon kiezen kost een middag. De voorbereiding bepaalt of die keuze standhoudt. Wat je nodig hebt is geen tool maar zes dingen op papier, en het meeste ervan gaat over afspraken in plaats van techniek. Loop ze na voordat je een regel code of een enkele n8n-node aanraakt.
- Eén leidend systeem per entiteit. Klantgegevens uit je CRM, artikelen uit je voorraadsysteem, facturen uit je boekhouding. Uitzonderingen per veld mogen, maar zet ze op papier: het e-mailadres komt uit de webshop, de btw-status uit de boekhouding.
- Een stabiele sleutel per klant, artikel en order. Een e-mailadres is geen sleutel, want mensen veranderen die. Gebruik het klantnummer, de SKU, het ordernummer, en houd een koppeltabel bij die het id aan de ene kant aan het id aan de andere kant plakt.
- Een wijzigingsmarkering per record. Een veld als updated_at, Modified of een rijversie waarop je kunt filteren. Zonder dat veld kun je geen delta doen en zit je vast aan volledige exports. Staat je data nog in losse bestanden en mailtjes, breng die dan eerst terug naar machine-leesbare input voordat je gaat synchroniseren.
- Het cijfer van je API-limiet. Niet "die heeft wel een limiet", maar het getal, opgezocht in de documentatie. Dit is de vaakst onderschatte harde grens in het hele ontwerp.
- Een draaiplek met een logboek. Elke verwerkte gebeurtenis met tijdstip en uitkomst, plus een wachtrij waar mislukte berichten in landen in plaats van verdwijnen.
- Een testadministratie en een proefset. Twintig tot vijftig records waarop je de hele keten één keer kunt doorlopen zonder je echte cijfers te raken.
Dat laatste punt is geen formaliteit. Een synchronisatie zonder eigenaar wordt bij het eerste conflict een discussie in plaats van een beslissing.
De drie patronen naast elkaar
Actualiteit is hoe ver de ontvanger achterloopt. Belasting is wat het patroon kost aan API-calls op het bronsysteem, en dat is de kolom die in de praktijk het vaakst de keuze maakt.
| Patroon | Actualiteit | Belasting op de bron | Sterk bij | Loopt stuk op |
|---|---|---|---|---|
| Volledige batch | uren tot een dag | hoogst: elk record, elke run | kleine sets zonder wijzigingsmarkering | API-limieten en het tijdvenster |
| Delta-batch | minuten tot uren | laag: alleen wat veranderde | artikelen, prijzen, klantgegevens | records zonder betrouwbare wijzigingsdatum, en verwijderingen |
| Event-driven | seconden | laagst: één bericht per gebeurtenis | orders, betalingen, voorraadmutaties | dubbele en gemiste berichten |
| ETL, ELT of CDC | minuten tot een nacht | laag tot midden | rapportage en analyse over systemen heen | het is eenrichtingsverkeer, je schrijft niet terug |
Batch: op de klok, in bulk
Batch is de saaiste en veruit de meest onderschatte optie. Je draait op een vast moment een script dat gegevens ophaalt en wegschrijft. In de volledige variant haal je alles op. In de delta-variant alleen de records die zijn gewijzigd sinds je vorige run, het watermerk.
Delta-batch is voor de meeste stromen het juiste antwoord. Prijzen, artikelen en klantgegevens veranderen zelden zo hard dat een uur vertraging iemand raakt, en het patroon is ongevoelig voor het hele arsenaal aan event-problemen. Valt de run een keer om, dan draait de volgende hem gewoon in. Dat zelfherstel is de reden dat ik batch vaker adviseer dan mensen verwachten.
Volledige batch reserveer je voor bronnen die geen wijzigingsdatum kennen, en dan buiten kantooruren. De rekensom loopt sneller uit de hand dan je denkt. De Moneybird-API staat 150 verzoeken per 5 minuten toe, en dat plafond geldt platformbreed in plaats van per administratie. Exact Online kapt nieuwe koppelingen af op 5.000 API-calls per dag per administratie en per client id, met daarnaast een minuutlimiet van 60 calls. Bij 1.400 artikelen betekent een uursync 33.600 calls per dag. Je koppeling ligt om vier uur 's ochtends stil, en niet omdat de logica fout was. Deze limieten gelden juli 2026; controleer ze in de documentatie van je eigen pakket, want ze veranderen.
Event-driven: op het moment zelf
Bij event-driven wacht je niet, je krijgt geduwd. Het bronsysteem stuurt een bericht zodra er iets gebeurt: een betaalde order, een gewijzigde voorraad, een nieuwe klant. Dat bericht is meestal een webhook, en die kan dubbel binnenkomen omdat de verzender niet zeker weet of hij is aangekomen.
Precies daar zit het werk. Een event-driven koppeling is niet af als het bericht binnenkomt en er een factuur uitrolt. Hij is af als hetzelfde bericht drie keer binnen mag komen zonder dat er drie facturen ontstaan. Het gereedschap daarvoor is de idempotentiesleutel: een uniek kenmerk per gebeurtenis dat je opslaat vóórdat je iets doet. Stripe laat zien hoe streng dat mag zijn en bewaart het antwoord van de eerste aanroep per sleutel om bij een herhaling exact hetzelfde terug te geven, foutmeldingen inbegrepen, met opruiming van sleutels na 24 uur.
De andere kant is aflevering. Shopify wacht maximaal vijf seconden op je antwoord en probeert een mislukte aflevering acht keer opnieuw over de vier uur daarna; na acht opeenvolgende mislukkingen verwijdert het je abonnement gewoon. Ligt jouw kant er een halve dag uit door onderhoud, dan mis je die orders en krijg je ze nooit meer aangeboden. Zonder reconciliatie merk je dat pas bij de kwartaalafsluiting.
ETL, ELT en CDC: alles naar één centrale laag
Het derde patroon lost een ander probleem op. Je wilt niet dat systeem A iets naar systeem B stuurt, je wilt één plek waar de cijfers van alles bij elkaar staan, zodat een dashboard of een AI-assistent er in één keer doorheen kan kijken. Dan kopieer je periodiek alles naar een centrale laag: een datawarehouse of een eigen database.
De klassieke vorm heet ETL, waarbij je onderweg al bewerkt. De moderne vorm heet ELT: eerst ruw binnenhalen, daarna pas modelleren, zodat je een verkeerde bewerking kunt corrigeren zonder alles opnieuw op te halen. Voor de meeste bedrijven is ELT de verstandige keuze, simpelweg omdat je fouten er goedkoper in herstelt.
De snelste variant is change data capture. Je leest dan niet de tabellen uit maar het wijzigingslogboek van de database zelf. PostgreSQL beschrijft zijn logische replicatie als een publicatie- en abonnementsmodel waarbij de abonnee de wijzigingen in dezelfde volgorde toepast als de bron, zodat transactionele consistentie gegarandeerd is. Tools als Debezium bouwen daarop voort en zetten die stroom om in berichten waar de rest van je landschap op kan luisteren. Mooi patroon, maar je hebt er wel toegang tot de database nodig, en die krijg je bij een SaaS-pakket zelden.
Eén ding moet je hierbij scherp hebben: dit patroon is eenrichtingsverkeer. Een centrale laag maakt je rapportage waar, hij maakt je webshop niet actueel. Wil je terugschrijven naar de bronsystemen, dan heb je alsnog patroon één of twee nodig.
Waar het in de praktijk misgaat
Zes faalmodi, met de mitigatie erbij. Ze komen alle zes voor bij koppelingen die op de demo-dag prima werkten.
- Dubbele verwerking. Hetzelfde bericht komt twee keer binnen en je maakt twee facturen. Mitigatie: sla het unieke event-id op vóór je iets doet, en sla de verwerking over als je het al kent.
- Stilte die op succes lijkt. De koppeling meldt niets, dus je denkt dat het goed gaat, terwijl er al twee dagen niets binnenkomt. Mitigatie: bewaak niet de fouten maar het uitblijven van activiteit, en laat de reconciliatie een verschil melden in plaats van het stil op te lossen.
- Het watermerk dat records overslaat. Je filtert op "gewijzigd na 14:03" terwijl een record precies om 14:03 werd opgeslagen, of de klok van het bronsysteem loopt een paar seconden achter op de jouwe. Mitigatie: pak altijd een overlapvenster van een paar minuten terug en vertrouw op je idempotentie om de dubbelen op te vangen.
- Verwijderingen die nooit aankomen. Een delta-sync ziet toevoegingen en wijzigingen, maar een verwijderd record heeft geen wijzigingsdatum meer. Het blijft dus eeuwig aan de ontvangende kant staan. Mitigatie: werk met een archiveervlag in plaats van echt verwijderen, of laat de reconciliatie periodiek de volledige sleutelsets vergelijken.
- Twee schrijvers op één veld. Iemand past het adres aan in het CRM, iemand anders in de boekhouding, en de laatste sync wint. Er komt nooit een foutmelding en er is altijd dataverlies. Mitigatie: één eigenaar per veld, en de niet-eigenaar krijgt dat veld alleen-lezen of met een zichtbare waarschuwing te zien.
- De limiet die je op de drukste dag raakt. Je koppeling past prima in het API-budget, tot Black Friday of de maandafsluiting. Mitigatie: reken je piekdag door, bouw een oplopende wachttijd in bij een 429-antwoord, en verdeel zware runs over de nacht. Dat handmatig herstelwerk achteraf veel meer tijd kost dan de invoer zelf is precies waarom je hier vooraf een half uur in stopt.
Het beslis-kader: vijf assen en de drempels
Het kader draait om vijf assen. Leg ze per datastroom naast elkaar, niet per systeem, want dezelfde twee systemen kunnen prima drie stromen met drie verschillende patronen delen.
- Actualiteitseis. Hoeveel vertraging is acceptabel voordat iemand een verkeerd besluit neemt? Mag de ontvanger een nacht achterlopen, dan is batch bijna altijd het antwoord.
- Mutatievolume. Onder ongeveer vijftig wijzigingen per dag per stroom verdient event-driven de extra complexiteit zelden. Daarboven begint het te lonen.
- Richting. Eenrichting is een technische klus. Tweerichting is een organisatorische klus, en die los je op met veld-eigenaarschap voordat je iets bouwt.
- Foutkosten. Wat kost een verkeerde waarde die een dag blijft staan? Bij voorraad en betalingen is dat direct geld, bij een marketinglijst is het ruis.
- Beheerlast. Wie zet dit over een jaar weer aan als het omvalt? Dit is de as die het vaakst wordt overgeslagen en die de keuze het vaakst zou moeten kantelen.
Hoe vers moet de ontvangende kant zijn?
Kant-en-klaar of maatwerk
De vier routes verschillen minder in wat ze kunnen dan in wie het onderhoud draagt. Prijzen: juli 2026.
| Route | Wat je krijgt | Kosten | Kies dit als |
|---|---|---|---|
| Native koppeling in je pakket | de standaardvelden, geen controle over het ritme | meestal inbegrepen | je stromen standaard zijn en je geen uitzonderingen hebt |
| No-code platform | zelf flows bouwen, eigen logica, veel connectoren | n8n vanaf 20 euro per maand voor 2.500 uitvoeringen, self-hosted gratis | je patroon helder is en je volume voorspelbaar |
| Beheerd ELT-platform | honderden bronnen naar een datawarehouse, eenrichting | Fivetran gratis tot 500.000 maandelijks actieve rijen, Airbyte Cloud vanaf 10 dollar per maand | je doel rapportage is en niet terugschrijven |
| Maatwerk pipeline | idempotentie, reconciliatie en foutafhandeling naar jouw regels | hoger vooraf, geen plafond per uitvoering | je uitzonderingen de standaardtools breken of je data binnen eigen muren blijft |
Begin niet groter dan nodig. Zit je stroom in de native koppeling van je pakket en klopt het ritme, dan bouw ik er niets naast. n8n begint op 20 euro per maand voor 2.500 uitvoeringen en heeft een gratis self-hosted variant; welk no-code platform past hangt vooral af van je volume en of je alles in eigen beheer wilt draaien, waar n8n, Make en Zapier sterk in verschillen. Voor de rapportagelaag is Fivetran gratis tot 500.000 maandelijks actieve rijen, wat voor een MKB-landschap verrassend lang meegaat.
Maatwerk wordt de eerlijke keuze zodra je uitzonderingen de standaard breken: deelleveringen, retouren die drie systemen tegelijk raken, of een reconciliatie die meer moet doen dan tellen.
Zo pas je het kader toe
Zeven stappen, in deze volgorde. Elke stap levert iets op dat je kunt controleren voordat je door mag.
- Teken de stromen, niet de systemen. Schrijf per entiteit op waar hij ontstaat en wie hem daarna nodig heeft. Meestal kom je op vier tot acht stromen uit, en niet op de vier koppelingen die je in je hoofd had.
- Wijs per stroom de eigenaar aan. Eén systeem is leidend, de uitzonderingen per veld zet je eronder. Dit is de stap waar de discussie hoort te gebeuren, niet later in productie.
- Kies de sleutels en bouw de koppeltabel. Elk record aan de ene kant krijgt een vaste verwijzing naar zijn tegenhanger. Zonder die tabel gok je later op naam of e-mailadres, en daar ontstaan de dubbelen.
- Kies per stroom het patroon. Loop de vijf assen langs en noteer de keuze met de reden erbij. Over een jaar wil je terug kunnen lezen waarom je voor batch koos.
- Maak elke schrijfactie idempotent. Bepaal per stroom de sleutel die een gebeurtenis uniek maakt, sla hem op vóór de verwerking, en test met een bewust dubbel aangeboden bericht.
- Bouw de reconciliatie voordat je live gaat. Een nachtelijke run die aantallen en een paar totalen aan beide kanten vergelijkt, verschillen logt en jou mailt. Dit is de stap die het vaakst wordt uitgesteld en het meest oplevert.
- Ga gefaseerd live. Eerst een eenmalige backfill van de historie, dan een week schaduwdraaien waarin de sync alleen logt wat hij zou doen, dan pas echt schrijven. Welke stroom je als eerste aanpakt bepaal je op frequentie, foutgevoeligheid en databeschikbaarheid, niet op wie er het hardst over klaagt.
Uitgewerkt voorbeeld: een groothandel met drie systemen
Neem een handelsbedrijf met 1.400 artikelen en ongeveer 250 orders per werkdag, met de webshop op Shopify, de boekhouding in Exact Online en de voorraad in een eigen magazijnsysteem. De klacht: de webshop verkoopt artikelen die niet meer op voorraad liggen, en de omzet in de boekhouding loopt een dag achter.
De bestaande oplossing was een uursync die alle 1.400 artikelen langsliep. Reken mee: 1.400 calls per run maal 24 runs is 33.600 calls per dag, tegen een daglimiet van 5.000 per administratie. De koppeling stond dus elke ochtend na een uur of vier stil, en niemand wist dat, want er kwam geen foutmelding waar iemand naar keek.
Het herontwerp splitst dezelfde klus in drie stromen met drie patronen:
- Orders: event-driven. Een Shopify-webhook op een betaalde order boekt de voorraad af in het magazijnsysteem en legt de verkoopregel klaar in Exact Online. Ongeveer 250 gebeurtenissen per dag, elk met het event-id als idempotentiesleutel, en een wachtrij die opnieuw probeert als Exact even niet bereikbaar is.
- Artikelen en prijzen: delta-batch. Elke nacht ophalen wat sinds het vorige watermerk is gewijzigd. In de praktijk zijn dat er zo'n veertig, niet veertienhonderd.
- Voorraadstanden: reconciliatie. Elke nacht een gepagineerde vergelijking van de tellingen tussen het magazijnsysteem en de webshop. Verschillen worden gelogd en gemaild, niet stilletjes overschreven, want een onverklaard verschil is een signaal en geen ruis.
Het dagverbruik zakt van 33.600 naar ruim onder de duizend calls, met ruimte voor een piekdag erbij. Belangrijker is de actualiteit: de voorraad in de webshop loopt seconden achter in plaats van een uur, terwijl de artikelgegevens juist rustiger meebewegen. Loopt de factuurstroom uit dezelfde orders erachteraan, dan gelden daar dezelfde zes schakels van vastleggen tot archiveren met een sluitende audit-trail.
De winst zat niet in een betere koppeling. Hij zat in de erkenning dat drie soorten data drie verschillende ritmes verdienen.
Wat je hier echt mee koopt
Eén actuele waarheid is geen tool die je installeert. Het is de optelsom van een paar saaie beslissingen: wie is de baas over dit veld, hoe vers moet het zijn, en hoe merk je het als het misgaat. Neem je die beslissingen niet, dan neemt je koppeling ze impliciet voor je, meestal in het voordeel van wie het laatst opsloeg.
Begin daarom niet met bouwen maar met tekenen. Vier tot acht stromen op een vel papier, per stroom een eigenaar en een ritme, en dan pas de vraag welk gereedschap erbij past. Dat vel papier is goedkoper dan elke koppeling die je erna nog bouwt, en het blijft ook kloppen als je over twee jaar een systeem vervangt.
Veelgestelde vragen
Eén actuele waarheid, echt geregeld
Ik denk met je mee over welk systeem waar de baas is, ontwerp de datastromen en bouw daarna de pipelines die het afdwingen, van eerste schets tot draaiende sync met monitoring.
Dit artikel is geproduceerd samen met het Agent Team. Meer over de redactie.
