Automating Customer Due Diligence Without Hard-Coding Compliance
Jurisdiction-aware CDD policies, provider abstraction, and risk-level-driven verification depth. Configuration over code.
Automating Customer Due Diligence: Architecture for Jurisdiction-Aware CDD
Somewhere in your codebase, there is an if-statement that decides how deeply to verify a customer. It checks the country. It checks the risk level. It calls a provider. When the regulator in Spain changes the rules for enhanced due diligence, an engineer modifies the if-statement, writes a test, deploys, and hopes no other branch was affected.
This is how most CDD implementations work. It is also why expanding to a new jurisdiction takes months instead of days: the compliance logic is embedded in code, not expressed as configuration. Every new country requires development work. Every rule change requires a release cycle. Every audit requires an engineer to explain what the code does, because the MLRO cannot read it directly.
The Hard-Coded CDD Problem
The pattern is recognizable:
if country == "DE" and risk_level == "high":
require_enhanced_document_verification()
elif country == "ES" and risk_level == "medium":
require_standard_address_verification()
elif country == "DE" and risk_level == "low":
require_basic_identity_check()
Scattered across the codebase. Each branch is a compliance rule encoded as application logic. The problems compound:
- Adding a jurisdiction means modifying code. Austria requires different address verification depth than Germany. Switzerland has different documentation requirements than either. Each addition is a code change, a test cycle, a deployment.
- Changing a rule means modifying code. The MLRO decides that high-risk customers in Spain now require enhanced document verification instead of standard. That decision travels through a ticket, waits in a sprint backlog, gets implemented by a developer who may not fully understand the regulatory context, and ships in the next release.
- Auditing the rules means reading code. When the regulator asks "what due diligence do you perform for high-risk customers in Germany?", the answer requires an engineer to trace code paths and explain branching logic. The compliance team cannot independently verify what the system does.
The Policy Model
A CDD policy is a record, not a code branch. It has four dimensions:
| Dimension | Values | Example |
|---|---|---|
| Jurisdiction | Country code or GLOBAL (fallback) | DE, ES, AT, GLOBAL |
| Risk Level | Low, Medium, High, Prohibited | High |
| Check Type | Address verification, document check, source of funds | address_verification |
| Depth | Standard, Enhanced | Enhanced |
A policy record says: "For jurisdiction X, at risk level Y, perform check type Z at depth W." The system stores these as data, queryable, versionable, auditable by non-engineers.
Example policy set:
| Jurisdiction | Risk Level | Check Type | Depth |
|---|---|---|---|
| DE | Low | Address verification | Standard |
| DE | High | Address verification | Enhanced |
| ES | Medium | Address verification | Standard |
| GLOBAL | Low | Address verification | Standard |
| GLOBAL | High | Address verification | Enhanced |
Resolution logic: when a CDD check is triggered, the system looks for a jurisdiction-specific policy first. If none exists, it falls back to GLOBAL. This means: launch in a new country with zero configuration, the GLOBAL policies apply automatically. Then add country-specific overrides when the compliance team is ready.
The fallback chain:
Address change, risk level upgrade, or periodic review triggers CDD check.
Use the jurisdiction-specific policy for check type and depth.
Use the GLOBAL fallback policy. Covers all jurisdictions by default.
Check record created with policy version, type, and depth. Routed to provider.
New country, day one: GLOBAL policies apply. No code change. No deployment. The MLRO adds jurisdiction-specific overrides through the admin interface when local regulations require different depth.
Policy Lifecycle
Policies are not static. They evolve as regulations change and as the compliance team refines its risk appetite. The lifecycle must be auditable:
Draft → Active → Archived.
Only one active policy can exist per jurisdiction × risk level × check type combination. Activating a new policy automatically archives the previous one. The archived policy remains in the database, immutable, queryable, timestamped. An auditor can reconstruct which policy was in effect for any given check at any point in time.
This matters during regulatory examination. The question is not "what are your current CDD policies?" It is "what policy was in effect when you onboarded Customer X on March 15?" If policies are code branches, the answer requires git archaeology. If policies are versioned records, the answer is a database query.
Provider Abstraction
The policy defines what to check. The provider interface defines how.
A CDD check for address verification can be fulfilled by Loqate (address validation API), Google Places (geocoding), a manual document review, or a combination. The policy says "verify the address at Enhanced depth." The provider implementation says "call Loqate, cross-reference with the postal registry, flag discrepancies for manual review."
The separation matters when providers change. Switching from Provider A to Provider B is a configuration change at the provider layer. No policy change. No code change in the CDD engine. The check type and depth remain the same, only the fulfillment mechanism changes.
This is the same pattern used for KYC verification: the system needs identity verification. Whether Identomat, Onfido, or Jumio fulfills it is a configuration choice. The onboarding flow does not know or care which provider is active.
Jurisdiction Profiles
Each jurisdiction carries more than CDD policy overrides. It carries the regulatory parameters that affect operations:
| Parameter | Purpose | Example |
|---|---|---|
| Retention years | How long to keep records (GoBD: 10 years, HGB §257) | DE: 10, ES: 10 |
| Holiday calendar | TARGET2 + national holidays for business day calculation | DE: TARGET2 + German federal, ES: TARGET2 + Spanish national |
| CDD configuration | Default risk thresholds, required check types | Configurable JSONB per jurisdiction |
| Chart of Accounts template | GL structure for jurisdiction-specific accounting | SKR04 (Germany), PGC (Spain) |
Business day calculation uses the jurisdiction's holiday calendar. "5 business days" in Germany is different from "5 business days" in Spain because of different public holidays. The holding period for SEPA R-transactions, the deadline for CDD check completion, the processing time for regulatory reports, all depend on the correct calendar.
Audit Trail
Every CDD check is recorded as an immutable record:
- Policy version that was in effect
- Check type and depth
- Provider used
- Result (pass, fail, manual review)
- Timestamp (created, completed)
- Reviewer (if manual escalation)
The check record is delete-protected at the database level (a trigger prevents DELETE operations on the audit table). Corrections are new records, not updates to existing ones. The complete history is preserved.
An auditor's path: Customer → CDD checks → for each check: which policy was active, what depth was applied, which provider fulfilled it, what was the result, who reviewed it (if manual). All from structured, queryable data. No code reading required.
Operational Impact
Market expansion without engineering. New jurisdiction? The GLOBAL fallback policies apply immediately. Country-specific overrides are added by the compliance team through the admin interface. No developer in the loop.
Rule changes without deployments. The MLRO updates a policy record. The new policy takes effect on the next check. The old policy is archived. The audit trail captures both versions and the transition timestamp.
Regulatory examination readiness. Every check is traceable to a specific policy version. Every policy change is timestamped and attributed. The compliance team can answer regulator questions directly, without engineering support.
Provider flexibility. KYC provider contract expires? Switch to a new provider through configuration. The CDD policies, the what, remain unchanged. Only the how changes.
Read more: Compliance Infrastructure | Security & Compliance
Sources:
- AMLD5, Directive 2018/843, Art. 13 (Customer due diligence measures)
- AMLD6, Directive 2024/1640, Art. 16-18 (Risk-based approach to CDD)
- GoBD (Grundsätze zur ordnungsmäßigen Führung und Aufbewahrung von Büchern), 10-year retention
- HGB §257, Retention periods for commercial records