← Blog

Process automation

Animana en InfoMedics afstemmen: agent voor dierenartsen

Hoe een Tilburgse keten met 36 dierenartsen stopte met het wekelijks handmatig matchen van 2.840 Animana-regels tegen InfoMedics, en wat we misten bij de €400-sign-off.

Jacob Molkenboer· Oprichter · A Brand New Company· 15 jun 2026· 9 min
Koperen weegschaal op ivoorpapier, papieren strookjes met touw op een schaal, kaart met groen lint op andere, rode lakzegel.

Het is maandag, 07:40, op de hoofdvestiging van een Tilburgse dierenartsketen met vier praktijken. De praktijkmanager opent haar browser en begint aan het wekelijkse ritueel dat ze al vier jaar draait: de afgelopen week exporteren uit Animana, de bijbehorende declaratiebatch downloaden bij InfoMedics, en regel voor regel matchen. Vorige vrijdag schreef een senior maat €1.840 af omdat niemand de originele verrichting in een van beide systemen kon terugvinden. Daarover werden we gebeld.

De vorm van het probleem

De keten telt 36 mensen verdeeld over vier praktijken in de regio Tilburg. Elke week genereren ze ongeveer 2.840 verrichtingen in Animana: consulten, vaccinaties, gebitsbehandelingen, chipimplantaties, af en toe een orthopedische ingreep. Die regels moeten worden afgestemd met de declaratiepijplijn bij InfoMedics, de derde partij die de eigenaren factureert en de betaling incasseert.

Elke regel heeft een NHV-code, een prijs, een datum, een animal_id, een owner_id en een vrije notitie. Matchen zou triviaal moeten zijn. Dat is het niet. Dierenartsen typen vrije codes in voor nieuwe ingrepen. Een senior maat past achteraf een prijs aan in Animana terwijl InfoMedics de batch van die dag al verstuurd heeft. Een eigenaar wisselt tussen praktijken en het dossier volgt op papier, maar de IDs voegen niet schoon samen.

Het resultaat, voordat wij in beeld kwamen: ongeveer vier tot zes procent van de regels viel elke week buiten de automatische match. Dat zijn ruwweg 140 regels per week die iemand handmatig moest natrekken. Bij twintig minuten per slechte regel is dat een volle werkdag per week, plus een vrijdagmiddag kruiscontrole, plus de incidentele afschrijving als niemand een regel op tijd kon oplossen.

Waar een join-key script tekortschiet

Dit probleem ziet eruit als iets dat je oplost met een Python-script en een join key. Dat hebben we eerst geprobeerd. Het vangt de makkelijke 94 procent, en dat is precies het deel dat niemand opbrandde. De resterende regels zitten waar het rommelige menselijke signaal zit, en die vragen om oordeel, niet om een fuzzy-match drempel.

Drie randvoorwaarden maakten die regels resistent tegen een naïef script.

Eén, de €400-regel. De Nederlandse aansprakelijkheidsregels voor dierenartsen, plus het huisbeleid van deze keten, betekenen dat elke verrichting boven €400 bevestigd moet worden door de verantwoordelijke dierenarts voordat de declaratie de deur uit gaat. Je kunt geen regel met label orthopedische ingreep stilletjes opnieuw matchen en opnieuw indienen, ook al kloppen de prijzen.

Twee, de chip-registratie sync. Chipimplantaties moeten binnen twee weken na plaatsing worden aangemeld in een landelijke database. Het chip-ID staat in Animana, de implantatiedatum in het patiëntendossier en de eigenaarsgegevens in InfoMedics. Een reconciler die die drie niet koppelt, laat chips ongeregistreerd en huisdieren onvindbaar.

Drie, de audit trail. Dierenartspraktijken worden gecontroleerd door hun accountant en periodiek door de NVWA. Elke wijziging in een financieel record vraagt om een wie, een wanneer en een waarom. Een black-box reconciler is niet auditbaar, en in de praktijk betekent dat: de eerste keer dat een maat een regel niet kan uitleggen, gaat het systeem uit.

De architectuur waar we op uitkwamen

De agent draait op een kleine VPS. Elke maandag om 06:00 Amsterdamse tijd haalt hij de verrichtingen van de afgelopen week op uit Animana en de bijbehorende InfoMedics-declaratiebatch. Beide komen binnen als CSV. Ze worden geladen in één Postgres-tabel met een status-kolom en een rules_version-kolom.

Het matchen gebeurt in drie passes.

Pass één is een exacte join op (animal_id, code, date, price). Ongeveer 92 procent van de regels sluit hier. Pass twee is een fuzzy join op (animal_id, date ±2 dagen, price ±5%). Nog eens vier tot vijf procent sluit hier, elk met een confidence score en een reden. Pass drie stuurt alles wat overblijft naar een queue.

De queue is het deel dat dit van een script in een agent veranderde. Elke ongematchte regel krijgt een context bundle: de oorspronkelijke Animana-regel, de dichtstbijzijnde InfoMedics-kandidaat, de dossiernotitie van die dag, en de drie voorgaande bezoeken voor dat dier. De agent schrijft een neutrale samenvatting van één zin over wat er volgens hem gebeurd is, en stelt vervolgens een actie voor: opnieuw matchen aan kandidaat X, de declaratie crediteren, of vasthouden voor dierenartsbeoordeling.

def classify_row(row, candidates, patient_file):
    if row.price >= 400:
        return Action.HOLD_FOR_VET, "Over \u20ac400, requires veearts sign-off"
    if not candidates:
        return Action.VOID, f"No matching declaratie for {row.code} on {row.date}"
    best = candidates[0]
    if best.confidence >= 0.85:
        return Action.RE_MATCH, f"High-confidence match to {best.id}"
    return Action.HOLD_FOR_REVIEW, summarize(row, candidates, patient_file)

De queue staat in een kleine interne web-app, niet ingebouwd in Animana (dat hebben we geprobeerd; zie verderop). De praktijkmanager ziet op een maandagochtend 15 tot 25 regels. Elke regel heeft een één-klik goedkeuren, bewerken of escaleren. Goedkeuringen worden teruggepusht naar InfoMedics via hun REST-endpoint. Escalaties leveren een melding op in de Animana-inbox van de verantwoordelijke dierenarts en op zijn telefoon.

De €400-goedkeuringsqueue in detail

Dit is het deel dat we de eerste keer fout deden. We gingen ervan uit dat de €400-regel een softe check was. Dat is hij niet. Het is een aansprakelijkheidsvraag. Het oorspronkelijke prototype liet de praktijkmanager elke regel goedkeuren, ook de dure. De senior maat stopte in week twee met het systeem omdat ze tijdens een audit niet kon aantonen dat zij persoonlijk de orthopedische verrichtingen had goedgekeurd. De audit trail toonde de naam van de praktijkmanager waar haar naam had moeten staan.

We bouwden de goedkeuringsflow opnieuw rond met name genoemde tekenbevoegden. Elke dierenarts heeft een rij in een vets-tabel met zijn BIG-registratienummer en een aangewezen vervanger. Regels boven €400 routeren via de responsible_vet_id van de verrichting naar die dierenarts, niet naar een algemene queue. De dierenarts keurt vanaf zijn telefoon goed, de handtekening krijgt zijn BIG-nummer en een tijdstempel mee, en de regel-status gaat naar vet_approved voordat hij naar InfoMedics kan. Regels die meer dan 48 uur ongetekend blijven liggen, vallen door naar de vervanger en beide handtekeningen worden op de audit-regel bewaard.

Let op

Aansprakelijkheidsgebonden goedkeuringen kunnen geen queue delen met operationele. Zodra de tekenende dierenarts niet meer kan wijzen naar één scherm en zeggen "dat zijn de regels die ik heb goedgekeurd", verliest hij vertrouwen in het systeem. Bouw het goedkeuringsoppervlak rond de met name genoemde mens, niet rond de data.

De chip-registratie cron

De chip-registratie sync draait als een aparte wekelijkse job op vrijdag om 18:00. Waarom apart? Twee redenen.

Andere faalmodus. Een gemiste reconciliatie kost de praktijk geld dat ze volgende week kunnen terughalen. Een gemiste chip-registratie kost vertrouwen en uiteindelijk een boete. Andere urgentie, andere alerting, andere on-call. Door ze te mengen, lopen luidruchtige meldingen over de stille maar belangrijke heen.

Idempotent by design. Chip-registraties zijn write-once. De cron haalt elke chip op die de afgelopen zeven dagen is geplaatst, controleert via hun lookup-endpoint of de registratie er al staat, en post alleen de nieuwe. Draai hem twee keer op dezelfde week en er dupliceert niets.

Het registry-endpoint is XML-over-SOAP, een leuke herinnering dat Nederlandse overheidssystemen rond 2009 zijn gebouwd en geen haast hebben om dat te veranderen. De cron gebruikt een dunne wrapper rond python-zeep om de envelope af te handelen. De volledige payload, inclusief eigenaarsgegevens, beslaat ongeveer 4 KB XML per chip. We loggen elke post en elke response naar een platte file die de praktijk zeven jaar bewaart, op instructie van hun accountant.

Drie dingen die we fout deden

Eén, we bouwden de queue-UI bovenop Animana via een iframe-embed. Het idee was dat de praktijkmanager daar toch al de hele dag werkte, dus waarom haar verhuizen. Het frame-contract van Animana veranderde in de eerste maand twee keer stilletjes en onze embed brak beide keren. We trokken de queue eruit naar een standalone tab en de onderhoudslast viel naar nul.

Twee, we onderschatten hoeveel de dierenartsen hechtten aan de bewoording van de samenvattingsregel van de agent. Zinnen als "waarschijnlijk een duplicaat" of "vermoedelijk mismatch" lazen als beschuldigingen. We herschreven het samenvattingstemplate neutraal en feitelijk: "Twee regels delen animal_id en datum; prijzen verschillen €12." Acceptatie steeg in dezelfde week.

Drie, we hadden de matching rules niet versioneerd. Toen een dierenarts vroeg "waarom sloot deze regel vorige week en deze week niet", konden we het niet beantwoorden. We slaan de regels nu op als JSON-document met versienummer, en elke matchbeslissing verwijst naar de versie die hem produceerde. Elke rapportage kan opnieuw gedraaid worden tegen de regels die op dat moment actief waren. Audit-klaar.

Elf weken verder

De cijfers, stand vorige vrijdag.

  • 2.840 regels per week gemiddeld. Ongeveer hetzelfde weekvolume als ervoor.
  • 132 regels per week gerouteerd naar de queue. Lager dan de vier tot zes procent baseline, omdat pass twee een stuk vangt dat eerst doorzakte.
  • 4,5 uur per week tijd van de praktijkmanager aan de queue, terug van een volle dag. Het meeste is gewoon goedkeuren klikken.
  • 14 chip-registratie posts per week naar de landelijke database. Nul missers in elf weken.
  • Eén audit-notitie van de accountant van de keten: positief. De audit log van de reconciler werd genoemd als best practice.

De senior maat tekent inmiddels €400+ verrichtingen vanaf haar telefoon onderweg naar het werk. De praktijkmanager draait de queue voor het eerste consult op maandag en is klaar voor de koffie.

Kerngedachte

De juiste plek om de menselijke grens te trekken is waar de aansprakelijkheid ligt. Automatiseer het matchen, route het oordeel naar de met name genoemde tekenbevoegde, en hou de audit log saai.

Wat dit is, en wat het niet is

Dit is geen AI-wonder. Het is een reconciler met een queue, een goedkeuringsflow en een wekelijkse SOAP-cron. Het agent-deel, het stukje dat een ongematchte regel in één zin samenvat en een actie voorstelt, is misschien acht procent van de codebase. De andere 92 procent is leidingwerk: het Postgres-schema, de Animana-export client, de InfoMedics REST-integratie, de SOAP envelope voor het chip register, de audit log, de e-mailmelding, de versie-beheerde regels, en de kleine standalone web-app waar de praktijkmanager daadwerkelijk in klikt.

Die verhouding is de eerlijke voor het meeste procesautomatiseringswerk in zorggerelateerde sectoren. De krantenkop gaat naar het model. De uren gaan naar de integraties en de grenzen.

Toen we dit voor de Tilburgse keten bouwden, liepen we tegen de aansprakelijkheidsgrens aan. We losten het op door elke dierenarts een eigen goedkeuringsoppervlak te geven gekoppeld aan zijn BIG-nummer, zodat de agent nooit een tekenbevoegdheid in handen heeft die niet bij een met name genoemd mens hoort. Hetzelfde patroon zien we in het meeste reconciliatiewerk dat we opleveren, en het is meestal het stuk dat bepaalt of het systeem in maand drie nog gebruikt wordt of stilletjes wordt uitgezet.

Het kleinste dat je vandaag kunt doen: open het spreadsheet dat je team elke maandagochtend afstemt, en omcirkel de regels waar de aansprakelijkheid ligt. Die cirkel is waar je queue thuishoort.

Kern

Trek de menselijke grens daar waar de aansprakelijkheid ligt: automatiseer het matchen, route het oordeel naar de met name genoemde tekenbevoegde, en hou de audit log saai.

FAQ

Waarom niet gewoon een Python-script met een fuzzy join draaien?

Een naïeve join vangt ongeveer 94 procent van de regels. De resterende zes procent vraagt om oordeel, dierenarts-sign-off op dure regels, en een audit trail. Dat zijn geen problemen die een join key in zijn eentje oplost.

Hoe gaat de €400-sign-off om met vakanties van dierenartsen?

Elke dierenarts heeft een aangewezen vervanger in de vets-tabel. Regels die meer dan 48 uur ongetekend blijven, routeren naar die vervanger, en beide handtekeningen worden op de audit-regel bewaard zodat de goedkeuringsketen intact blijft.

Werkt dezelfde opzet ook voor andere praktijksoftware?

De match- en queue-lagen zijn systeem-agnostisch. We hebben vergelijkbare reconcilers omgezet naar exports van andere PMS-en. De integratielaag, dus het export-endpoint en de regulator sync, is het deel dat per klant herschreven moet worden.

Wat gebeurt er als InfoMedics zijn API wijzigt?

De client is versie-vast en pinned op een specifiek contract. We monitoren hun changelog en alerten op elke onverwachte response code. Een version bump is een code change met testsuite, nooit een stille upgrade in productie.

process automationai agentsautomationintegrationscase studyworkflow

Iets bouwen?

Start een project