← All insights
Compliance Architecture 9 min read

Making Compliance Declarative

Why "just add Sweden" became a three-month project — and how we rebuilt the compliance layer so jurisdiction rules are configuration, not code.

W
WebPrefer Engineering
November 2025
Compliance Architecture
Rules Are Data, Not Code
Before: Code Per Jurisdiction
if (jurisdiction == "SE") { kycDays = 30; }
if (jurisdiction == "ON") { kycDays = 14; }
if (jurisdiction == "CW") { kycDays = 90; }
Every new market = deployment · Regression risk · Weeks to add
Now: Declarative Configuration
🇸🇪 Sweden
KYC: 30d · SOW: 5,000 SEK
🇨🇦 Ontario
KYC: 14d · SOW: 3,000 CAD
🇨🇼 Curacao
KYC: 90d · SOW: 10,000 USD
+ New Market
Config only · No deploy
Config update · Zero risk · Hours, not weeks

Regulated gaming markets are not interchangeable. Each one has its own KYC timeline, its own self-exclusion rules, its own requirements for what triggers a source-of-wealth check, and its own expectations for how deposit limits work. What's acceptable in Curacao is not acceptable in Sweden. What Sweden requires may not match Ontario. Ontario's rules are different again from Malta.

Early in PAM's life, we handled this the way most platforms handle it: bespoke code per market.

How it started

The first jurisdiction was straightforward enough. We had a single operator, a single market, and a set of compliance requirements we understood well. The logic was hardcoded — KYC was required within a certain number of days of registration, withdrawals above a threshold triggered a source-of-wealth check, self-exclusion propagated to all brands under the same operator.

Then a second market came online.

The KYC timelines were different. The SOW thresholds were different. Self-exclusion had a different cross-brand propagation model. We added conditionals. Market A does this; market B does that. The existing compliance logic grew branches.

The pattern that emerged

Each new jurisdiction added code. Not configuration — code. New conditional branches in the compliance service, new test cases, a new deployment. The release cycle for adding a market was measured in weeks, sometimes months. And every change to an existing jurisdiction's rules meant touching code that also served other jurisdictions — with real regression risk.

The compliance layer had become a ball of market-specific logic, all entangled. Adding Ontario required understanding — and not breaking — Sweden. A rule change from a Swedish regulator required a deployment that also touched Curacao and Ontario. The testing surface was the entire compliance module every time.

The structural problem

The underlying issue is that compliance rules are data — they describe what the rules are, not how to enforce them. The enforcement logic is stable: check KYC status, evaluate SOW thresholds, trigger communications, enforce deposit limits. The enforcement mechanism doesn't change when a regulator updates a timeline. The value changes.

Mixing the two — treating compliance rules as code rather than configuration — creates a system that has to be redeployed every time a regulator changes a number.

That's the wrong architecture. And regulators change numbers more often than you'd like.

The declarative model

We rebuilt the compliance layer around a declarative configuration model. Each jurisdiction has its own configuration block that defines:

The compliance enforcement code reads these configuration values. It doesn't know it's enforcing "Swedish rules" or "Ontario rules" — it knows it's evaluating the rule set for the jurisdiction the player is registered in. The logic is the same. The parameters are different.

The key shift

When Sweden introduced new deposit limit rules, it was a configuration update. No deployment. No regression risk to Ontario or Curacao. No code review cycle. The change was reviewed by the compliance team, applied to the configuration, and the system enforced it immediately. The deployment cycle for a regulatory change dropped from weeks to hours.

Where this gets complex: cross-jurisdiction players

The harder edge case is players who are registered in one jurisdiction but playing on a brand in another. PAM's multi-brand, multi-jurisdiction architecture means a player registered under Swedish rules might be eligible to play on a brand operating under Ontario rules, depending on the operator's licensing model.

The compliance layer handles this through a jurisdiction resolution order: the player's registration jurisdiction takes precedence for KYC and SOW requirements; the brand's jurisdiction applies for deposit limits and responsible gaming interventions. The resolution is deterministic and auditable — every compliance decision logs which jurisdiction rule set it applied and why.

This matters in regulatory audits. "We applied Swedish KYC rules to this player because their registration jurisdiction is Sweden" is a defensible, documented answer. "We applied whichever rules the code happened to evaluate" is not.

Self-exclusion: a case study in complexity

Self-exclusion is where the compliance model is most visibly tested. When a player self-excludes, several things must happen:

Each of these steps has jurisdiction-specific variants. The propagation scope is different. The required confirmation communication is different. The reactivation conditions (how a player can end a self-exclusion and after what cooling-off period) differ per market.

In the old model, this logic was a branching mess. In the declarative model, the behavior engine (BeAware) reads the self-exclusion configuration for the player's jurisdiction and executes the appropriate sequence of actions — no conditional branches in the core enforcement code, just configuration-driven execution.

The compliance team as the primary user

One effect of this shift that we didn't fully anticipate: the compliance team can now own their configuration. They don't need to raise a development ticket to update a KYC timeline. They don't need to wait for a deployment to change a SOW threshold. They review the configuration, make the change in the back office, and it's live.

This is the right division of labor. Compliance rules are a compliance domain problem. They should be owned by the people who understand the regulatory requirements — not filtered through a development team who have to translate regulatory text into conditional logic.

Today

PAM is live in five regulated markets. Each operates with its own jurisdiction configuration. When a market's rules change, the update is a configuration edit — reviewed by the compliance team, applied without a deployment, effective immediately. The last time a regulatory update required a code change, it was because the regulator introduced an entirely new data requirement that didn't exist in our data model — which is the correct trigger for a code change.

The principle

If compliance changes keep triggering deployments, the architecture has confused data with logic. The enforcement mechanism is code. The rules it enforces are data. Separating the two isn't just an architectural preference — in a regulated industry, it's the only model that scales without accumulating risk with every new market.

Share this insight
Share on LinkedIn
Preview post text
More insights
Get in Touch

Ready to see it?

We offer live demos scoped to your specific operation type — whether you're launching a new brand, migrating from an existing platform, or evaluating options for a white-label deployment.

Address
Wahlbecksgatan 8, 582 13 Linköping, Sweden
Mikael Lindberg Castell
mikael@webprefer.com
CEO & Founder, WebPrefer AB