Security
HubSpot-audit voor een CRM-agent retrofit: 4-blok checklist
Voor we een CRM-agent retrofit offreren, draaien we een audit van vier blokken op de HubSpot eronder. Dit scoren we, en de drie pipelines die het meestal overleven.

Het is 08:00 op een dinsdag bij een Rotterdams logistiek bedrijf. De operations lead zit op haar tweede koffie. Ze heeft een HubSpot Operations Hub Professional-seat, elf sales reps, een portal dat sinds 2019 draait, en een bestuursstuk waarop staat AI-agent op inbound vóór Q4. Ze heeft ons gevraagd de retrofit te offreren. Wij hebben haar eerst om een audit-window gevraagd.
Bijna elke CRM-agent retrofit die we hebben opgeleverd — veertien agents live op het moment van schrijven — begon met dezelfde audit van vier blokken. We draaien 'm voor we offreren. De agent is het makkelijke deel. De HubSpot eronder is meestal waar het project staat of valt.
Dit is de checklist. Gebouwd voor Nederlandse mkb'ers onder €18M op Operations Hub Professional, waar het portal oud genoeg is om gedrift te zijn en klein genoeg dat niemand er fulltime voor betaald wordt om het netjes te houden.
Waarom we auditen voor we offreren
Een AI-agent boven op HubSpot is in de praktijk een reeks reads en writes tegen dezelfde custom properties, pipelines en workflows die een menselijke rep met de muis aanraakt. Als die structuren gedrift zijn — en op een zes jaar oud portal zijn ze dat altijd — gaat de agent of fail closed (weigert updates, escaleert alles naar een mens) of fail open (schrijft rommel naar een property waar de rapportagelaag op vertrouwt).
De vier blokken hieronder scoren de vier meest voorkomende failure modes. Elk blok is een getal op 100. We offreren pas als we de vier scores kennen. We sturen de operations lead één pagina; geen deck van veertig pagina's.
Blok één: custom-property type-drift over de top 60 deal-stages
Met HubSpot maak je een custom property één keer aan, en vervolgens kan een portal-admin in de loop der jaren dezelfde internal name hergebruiken op een ander object met een ander type. De klassieke versie: lead_bron aangemaakt als single-line text op Contact in 2019, opnieuw gemaakt als enumeration op Deal in 2022, vervolgens teruggespiegeld naar Contact als calculated property in 2024. Drie verschillende vormen, één naam, drie verschillende rapportage-uitkomsten.
We trekken de top 60 deal-stages op dealvolume van de laatste twaalf maanden — ruwweg zes pipelines × de top tien stages per stuk — en voor elke custom property waarnaar die stages verwijzen stellen we drie vragen: welk type heeft hij op Deal, welk type op Contact, en welk type schrijft de workflow die een deal in de stage zet daadwerkelijk weg.
curl -s \
-H "Authorization: Bearer $HUBSPOT_PRIVATE_APP_TOKEN" \
"https://api.hubapi.com/crm/v3/properties/deals?archived=false" \
| jq '.results[] | select(.hubspotDefined != true)
| {name, type, fieldType, groupName}' \
> deals-properties.jsonDezelfde call draaien we tegen contacts, companies en tickets, joinen op name, en flaggen elke regel waar het type tussen objecten verschilt. Op een zes jaar oud portal zien we doorgaans 30 tot 60 gedrifte properties. De score is het aandeel van de top 60 deal-stages dat geen gedrifte property aanraakt. Onder de 70 betekent dat we de eerste sprint van de retrofit besteden aan property-opschoning voor we één regel agent-code schrijven.
De opschoning zelf is geen showwerk. We exporteren elke gedrifte property naar CSV, kiezen het canonieke type (bijna altijd dat wat de rapportagelaag al leest), schrijven een workflow die de oude waarde kopieert naar een nieuw aangemaakte property met het juiste type, draaien een dry-run op een sample van vijftig records, en draaien daarna de migratie op het hele portal in een rustig venster. Twee of drie gedrifte properties per dag is een realistisch tempo zodra je de dashboards en lijsten meerekent die ernaar verwijzen en met de hand omgehangen moeten worden. Zestig gedrifte properties is een project van drie weken, niet één, en de offerte moet dat op pagina één benoemen.
Eén property is een dubbele blik waard: hs_lead_status is een HubSpot-defined enumeration op Contact, en een portal-admin die ooit een custom lead_status op Deal aanmaakte, vergiftigt stilletjes elk rapport dat de twee objecten joint. Bijna de helft van de Nederlandse portals die we hebben geauditeerd heeft precies deze botsing.
Blok twee: workflow-replay coverage op de top 25 enrollments
Een agent enrolt contacts en deals in workflows op dezelfde manier als een mens — door een property te schrijven, door een form te triggeren, door de API aan te roepen. De vraag die telt: als de agent dezelfde enrolment tweemaal binnen een minuut triggert, wat gebeurt er?
HubSpot-workflows zijn niet idempotent by default. Re-enrolment is een per-workflow toggle, en zelfs als die aanstaat, resetten de delay until-stappen binnen de workflow niet altijd schoon. We hebben gezien hoe één dubbele enrolment dezelfde quote-PDF vier keer naar een Nederlandse groothandel verstuurde.
We pakken de top 25 workflows op enrolled-objects-per-week, replayen elke tegen een sandbox-contact, en scoren op drie criteria: re-enrolment-gedrag, delay-step-convergentie, en het verschil tussen de property-waarde die de workflow bij enrolment leest en de waarde die hij bij afronding schrijft. De score is het aandeel van de 25 dat een double-trigger overleeft zonder een side-effect te produceren dat een mens moet opruimen.
// Replay a workflow by writing the enrolment trigger property twice
import { Client } from '@hubspot/api-client'
const hs = new Client({ accessToken: process.env.HUBSPOT_PRIVATE_APP_TOKEN })
async function replay(contactId, triggerProperty, value) {
const at = new Date().toISOString()
await hs.crm.contacts.basicApi.update(contactId, {
properties: { [triggerProperty]: value, replay_marker: at },
})
await new Promise(r => setTimeout(r, 1500))
await hs.crm.contacts.basicApi.update(contactId, {
properties: { [triggerProperty]: value, replay_marker: at + '-dup' },
})
}Onder de 80 hier en we bouwen een idempotency-laag tussen de agent en HubSpot voor we de agent een workflow-trigger laten aanraken. Die laag is meestal een kleine queue met als key (object_id, intent, minute_bucket), TTL van vijf minuten. Twintig regels code, en de operations lead hoeft op maandagochtend geen "sorry hiervoor"-mailtjes te schrijven.
Blok drie: pipelines die een private-app scope-rotatie overleven
HubSpot private apps authentiseren met een long-lived access token dat een vast aantal scopes draagt. De realistische operationele aanname — en de security-aanname — is dat het token wordt geroteerd, en dat die rotatie plaatsvindt op een vrijdagmiddag terwijl degene die de scope-lijst oorspronkelijk opschreef op vakantie is. De eigen docs van HubSpot zijn expliciet dat het token niet auto-renewt; rotatie ligt bij jou.
We scoren dit met een kalere vraag: van de zes-of-zo pipelines in het portal, hoeveel zouden er nog werken als het private-app-token van de agent morgenochtend opnieuw werd uitgegeven met alléén de read/write-scopes voor de stages en properties van die pipeline, en verder niets?
Het antwoord, op elk portal onder €18M dat we hebben geauditeerd, is drie. Die drie zijn bijna altijd:
- de primaire sales pipeline,
- de renewal- of upsell-pipeline (als die als eigen pipeline bestaat in plaats van als stage op de primaire),
- en één back-office pipeline die geen objecten kruist — onboarding, retouren, of een billing-aanmaning-pipeline.
De pipelines die de rotatie niet overleven zijn die welke in de loop van de tijd associatie-eisen hebben gekregen: een deal-stage die stilletjes een custom associatie naar een Ticket verwacht, of een workflow die een Company-level property leest die de oorspronkelijke scope-lijst nooit verleende. De fix is niet meer scopes. De fix is om de agent te splitsen in twee private apps, elk met de kleinste scope-set die hij nodig heeft, en op te schrijven welke app eigenaar is van welke pipeline. We behandelen de score als het aantal pipelines dat overleeft gedeeld door het totaal. Onder de 50 en de retrofit wordt eerst een scope-architectuur-project en pas dan een agent-project.
Blok vier: de AVG-lead-bron-audit trail om 08:00
De Nederlandse implementatie van GDPR — de AVG — vereist dat je voor elk contact in je CRM kunt aantonen waar de lead vandaan kwam en op welke rechtsgrond je hem verwerkt. De Autoriteit Persoonsgegevens belt niet daadwerkelijk om 08:00, maar een Nederlandse B2B-salesvloer die om 08:30 begint betekent dat de audit-vraag op het bureau van de operations lead landt voordat het eerste telefoontje is gepleegd. Die trail moet in één adem queryable zijn.
De hs_analytics_source van HubSpot is noodzakelijk maar niet voldoende. Hij vertelt je de bucket (organic search, direct, paid, referral, offline) maar niet welk form, welke list-import, welke integratie, of welke mens het contact met de hand intypte op een vakbeurs. We scoren het portal op één vraag: voor een willekeurige sample van 200 contacts aangemaakt in de laatste zes maanden, kunnen we de lead-bron reconstrueren in minder dan drie property-reads?
Artikel 5(2) van de AVG noemt dit het verantwoordingsbeginsel: een verantwoordelijke moet naleving kunnen aantonen, niet enkel claimen. Een bucket-property plus een overal-weggeschreven detail-property is het minimumpatroon dat we hebben zien overleven in een interne audit bij een Nederlandse verzekeraar onder vendor risk review. Iets losser en het antwoord op "waar komt dit contact vandaan" wordt een archeologische opgraving van veertig minuten door workflow-historie, en die heeft een salesvloer om 08:35 niet.
Als ja — meestal omdat het portal een gedisciplineerde lead_bron_detail text-property heeft waarnaar elk form, elke import en elke integratie schrijft — is de score hoog en kan de agent de trail meedragen door dezelfde property te schrijven. Zo niet, dan voegen we de property en een kleine backfill toe voor de agent live gaat. De agent is het juiste moment om dit te fixen; een agent die contacts aanmaakt zonder een lead-bron weg te schrijven is een cadeau aan de toezichthouder.
De vier blokken scoren het portal, niet de agent. Scoort het portal onder de 70 op één blok, dan is de retrofit-offerte eerst voor opschoning en pas dan voor de agent.
De output van één pagina
We sturen de operations lead één pagina met de vier getallen en een eenregelige lezing per stuk. Vanaf die pagina schrijft het gesprek over scope, prijs en planning zichzelf. Zij kan de getallen verdedigen voor haar bestuur. Wij kunnen de offerte verdedigen voor onszelf.
Block 1 Property type-drift (top 60 stages) 82 / 100
Block 2 Workflow replay (top 25 enrollments) 64 / 100
Block 3 Scope rotation survivability (pipelines) 50 / 100 (3 of 6)
Block 4 AVG lead-bron trail (sample of 200) 91 / 100Blok 2 op 64 is de regel die in de offerte "twee weken idempotency-werk" wordt. Blok 3 op 50 is de regel die "splitsen in twee private apps" wordt. Geen van beide regels is verzonnen om de offerte op te plussen; ze rollen uit de audit.
De audit kost vijf dagen
Read-only toegang tot het portal is voldoende. We vragen om een private app met crm.objects.deals.read, crm.objects.contacts.read, crm.objects.companies.read, automation.read en settings.users.read, en we geven het token aan het einde terug. We vragen tijdens de audit niet om write-scopes. De deliverable is de pagina hierboven, plus een gesprek van dertig minuten om de vier getallen door te lopen.
Toen we eerder dit jaar de inbound-CRM-agent bouwden voor een Nederlandse industriële groothandel, kwam blok twee terug op 48 op 100 — een portal met een prachtig getekende pipeline en twaalf workflows die allemaal dubbel afvuurden bij re-enrolment. We hebben de eerste twee weken van het traject besteed aan de idempotency-queue, niet aan de agent. De agent ging vervolgens in week drie live en heeft sindsdien geen quote dubbel verstuurd. Dat is de vorm van het werk achter elk van onze AI-agents: eerst de audit, dan de agent.
Het kleinste wat je vandaag kunt doen: open je HubSpot, draai de curl uit blok één tegen je eigen portal, en tel hoeveel van je custom Deal-properties een naam delen met een Contact-property van een ander type. Het getal gaat je verbazen.
Kern
Voor je een CRM-agent retrofit op HubSpot offreert, scoor je vier blokken: property drift, workflow replay, scope-rotatie en de AVG-lead-bron-trail.
FAQ
Hoe lang duurt de audit van vier blokken?
Drie tot vijf werkdagen met read-only toegang tot het portal, plus een gesprek van dertig minuten met de operations lead om de vier scores door te lopen. Het access token leveren we aan het einde weer in.
Welke HubSpot-scopes heeft de audit nodig?
Read-only is genoeg: crm.objects.deals.read, crm.objects.contacts.read, crm.objects.companies.read, automation.read, settings.users.read. We vragen tijdens de audit nooit om write-scopes.
Wat als een blok onder de 50 scoort?
We offreren nog steeds, maar de eerste fase van het traject is opschoning. De agent gaat live nadat het portal op elk blok minstens 70 scoort. De offerte benoemt de opschoning-regels expliciet.
Geldt dit voor Sales Hub of alleen Operations Hub?
De vier blokken gelden voor elk HubSpot-portal met custom workflows en properties. Operations Hub Pro is waar we de meeste drift zien, vanwege de data-sync en custom-coded-action features.
Waarom de AVG-lead-bron-trail specifiek om 08:00 scoren?
Een Nederlandse B2B-salesvloer begint om 08:30. Elke compliance-vraag van een klant of partner landt voor het eerste telefoontje van de dag, dus de trail moet in één adem queryable zijn.