Skip to content

78 providers

ArticleDeep-dive

UK RTS 12 Gross Deposit Limits: Database Migration Before September 30, 2026

Since September 30, 2026, only a gross limit counts as a deposit limit under UKGC RTS 12B. A withdrawal no longer frees up headroom, which breaks the running counter of legacy systems. The fix is a deposit events table, a PSP webhook contract and a 5-year retention envelope.
Editorial TeamUpdated iGaming Payment Solutions
Updated 14 min read
Contents5 sections
  1. What "gross" means in your data model
  2. Why the running-counter pattern breaks under RTS 12B
  3. Deposit events table schema for gross deposit limits
  4. The PSP webhook contract you need before cutover
  5. Retention, audit, and the RTS 12B cutover

A legacy deposit-limit subsystem on a UKGC-licensed platform checks the player's headroom by reading what the wallet holds against the limit. Deposit £500, withdraw £300, and the system credits £300 back to the daily allowance because the wallet went down. That logic is correct for a net deposit limit. Under RTS 12B, which has required gross deposit limits since September 30, 2026, the same logic is wrong, because a withdrawal no longer gives back any of the allowance.

The amended standard defines a deposit limit as gross and makes it the required minimum. The cap applies to the money a customer puts into the account, and withdrawals and game returns do not reduce it. A player who deposits £500 and withdraws £300 has used £500 of a gross daily allowance, where a net limit would count £200.

The fix sits in the data model. The deposit-limit check has to move from a balance-derived running counter to an events table it can query, and the PSP webhooks feeding that table have to carry what the counter needs, because the platform cannot count what the PSP does not report. Two other workstreams touch the same deposit path: the financial vulnerability check under LCCP 3.4.4, in force since August 2024, and Financial Risk Assessments, which the Commission confirmed on July 7, 2026 for a staged rollout, largest operators first. Stage one triggers at net deposits above £5,000 in a rolling 24 hours for customers aged 25 and over (£2,500 for customers under 25), and the Commission will set its start date in the formal consultation response.

What "gross" means in your data model

The regulation reads as one sentence. The data model has to read three things off that sentence.

First, the unit of accumulation is a deposit event. A deposit is committed once the funds have cleared the operator's PSP and been credited to the player's gambling account, and from that point its contribution to the gross counter is fixed for the period. RTS 12B defines gross as the amount a customer deposits over the period and leaves the treatment of reversals to the operator. Keep a settled deposit in the counter when a refund, chargeback, void or partial refund later zeroes the wallet, since the wording ties the limit to what the customer deposited, and a deposit that settled was deposited whatever happens to it afterwards.

Second, a gross limit runs on fixed periods of 24 hours, 7 days and 1 month, so the counter resets at a period boundary and does not roll. Each period starts at the boundary the operator shows the player when the limit is set, in the player's local time. A player on CET at an operator whose servers run on UTC is a quiet source of bugs, because the two clocks put the daily boundary an hour apart.

Third, when a player sets more than one limit, the most restrictive one applies. Under RTS 12, a player who set both a £10 daily and a £100 weekly cap may deposit £10 per day and £70 per week.

Net deposit limits, stake limits and loss limits all remain permitted products under RTS 12. What changed is the label. Anything called a "deposit limit" in the customer journey now has to compute as gross. A net product can keep computing the way it always did, but it has to be labeled "net deposit limit", and the gross limit must appear with at least equal prominence on the same screen.

Why the running-counter pattern breaks under RTS 12B

The pattern that breaks comes in two shapes. The deposit-limit check either reads a "remaining" value computed at request time as limit - (sum of period deposits) + (sum of period withdrawals), or it reads the player's wallet balance against a high-water mark and infers what the player has spent. Both net withdrawals against deposits, which is how a net limit computes.

Three bugs surface when the counter moves to gross.

The first is the withdrawal-redeposit cycle. A player with a £500 daily gross cap deposits £500 at noon, plays through £200, withdraws the remaining £300 at 2pm and tries to deposit again at 3pm. The legacy net counter computes 500 - 500 + 300 = 300 of headroom and accepts a £300 deposit, so the player has deposited £800 that day against a £500 gross cap. The audit log shows two clean deposits with a clean withdrawal between them, and the regulator can compute the breach from the same log the operator handed over.

The second bug is the refund flow. A player deposits £200, the deposit settles, a fraud rule reverses it 10 minutes later, and the player tries another £200 with a new card. The legacy pattern subtracts the reversal, sees nothing used and lets the retry through. A counter that keeps settled deposits still holds the first £200, so the retry would take the player to £400, and a £300 daily cap blocks it.

The third bug is silent precedence. An operator that wrote a "first matching limit applies" rule instead of "every active limit must pass" lets weekly caps slip past daily checks on some deposit patterns, because the daily check returns first and the weekly limit is never queried. The breach shows up only at the audit layer and only after the period closes.

Wallet-balance enforcement on play-through does not change. The gross counter governs what the player can put in and does not limit what the player stakes from an existing balance, so the deposit-limit subsystem and the wagering-limit subsystem stay separate in the migration.

Deposit events table schema for gross deposit limits

The architectural answer is to make the deposit event the canonical record and compute the gross counter as a query against it. A platform that already runs a separate deposit_events log can usually wire the new check in days. A platform whose only deposit record is a wallet ledger entry, with credits and debits intermixed and no event-type discrimination, has the bigger lift.

The minimum schema:

sql
CREATE TABLE deposit_events (
  id              BIGSERIAL PRIMARY KEY,
  player_id       BIGINT NOT NULL,
  amount_minor    BIGINT NOT NULL,         -- pence, never null
  currency        CHAR(3) NOT NULL,
  occurred_at     TIMESTAMPTZ NOT NULL,    -- PSP settlement time, not request time
  psp_reference   TEXT NOT NULL,           -- idempotency key from PSP
  source_psp      TEXT NOT NULL,           -- e.g. 'worldpay', 'trustly'
  status          TEXT NOT NULL,           -- 'settled' | 'reversed' | 'pending'
  reversed_at     TIMESTAMPTZ NULL,        -- nullable, reversal does NOT delete the row
  reversal_reason TEXT NULL,
  CONSTRAINT psp_ref_unique UNIQUE (source_psp, psp_reference)
);
 
CREATE INDEX idx_dep_player_time ON deposit_events (player_id, occurred_at DESC);

Three properties of this schema map onto the gross counter. Reversals do not delete rows. They set status and stamp reversed_at, so a settled deposit stays in the count. The gross-counter query reads WHERE status IN ('settled', 'reversed') AND occurred_at >= :period_start. The unique constraint on (source_psp, psp_reference) prevents double-counting when a PSP retries the same webhook, which after a PSP outage can happen many times for one deposit.

The gross check at deposit-attempt time:

sql
SELECT COALESCE(SUM(amount_minor), 0) AS used
FROM deposit_events
WHERE player_id = :pid
  AND occurred_at >= :period_start
  AND occurred_at <  :period_end
  AND status IN ('settled', 'reversed');

Run this query for every active limit period (daily, weekly, monthly) and reject the attempt if the amount used plus the new deposit would exceed any cap. The order of the checks does not matter, because all of them have to pass, and that is the most-restrictive rule written as code.

The operational details that often go missing on first migration:

  • Store the player's timezone on the limit record and compute every period start from it, never from the server clock or from request headers.
  • Pending deposits should count toward an in-flight sub-counter so a player cannot fire ten parallel deposit attempts in the same second and have all of them pass the check before any of them settle. Treat the in-flight count as a soft reservation that is reconciled when the PSP webhook confirms or rejects.
  • Under RTS 12, a limit decrease takes effect immediately, while an increase takes effect only after a 24-hour cooling-off. Store requested_at, effective_from, previous_value, and new_value on the limit-change record, and have the deposit check read whichever value is currently in force.
  • Multi-currency operators normalize to a stored player currency at deposit time. RTS 12 does not provide for a limit that spans currencies, so set one currency per active limit and document the conversion path.

The migration from a net-style running counter runs as a dual-write window. Every deposit and reversal is written to both the legacy ledger and the new deposit_events table, and the gross query runs against the new table in shadow mode, logging mismatches against the legacy net check. The mismatches are the deposits the legacy check counted differently, and the log is the operator's proof that the migration is correct on real production deposits.

The PSP webhook contract you need before cutover

The deposit-limit subsystem sits downstream of the PSP, and every deposit it counts arrives as a PSP webhook. The general webhook reliability and idempotency design sets the base contract, and gross counting under RTS 12B needs the fields and delivery rules below on top of it. A UK cashier can run several PSPs side by side, with Worldpay or Nuvei acquiring debit cards, Trustly or Brite carrying Pay by Bank, Paysafe bringing Skrill, Neteller and paysafecard, and Adyen as the second card acquirer or fallback. Each PSP emits deposit events in a slightly different shape, and the migration is the moment to lock one contract for all of them.

Gross counting needs five fields from every PSP:

  1. Settlement timestamp. The time the PSP committed the deposit to the operator's account, not the time the player tapped pay. The gross counter buckets against this timestamp into the player's period.
  2. Final amount in minor units after FX and after any PSP-side fee deduction. The gross counter reads what actually credited the player's wallet.
  3. PSP transaction reference plus PSP identifier. The unique pair forms the idempotency key that prevents double-counting when the webhook retries.
  4. Final settlement status. The outcome is binary, settled or rejected. Pending events are not gross-counted, while a deposit reversed after settlement stays gross-counted because it settled.
  5. Reversal events as separate webhooks. A subsequent reversal arrives as its own event referencing the original PSP transaction reference. The platform marks the original row reversed and does not subtract from the counter.

Two fields that operators frequently want but should not depend on:

  • The PSP's own deposit-attempt counter for the player. Different PSPs increment differently, and routing across multiple PSPs makes the per-PSP counter useless for a player-level gross.
  • A category classification of the deposit (top-up, recurring, bonus reversal). Categories are operator-side concepts and the PSP cannot reliably inform them. Track category in the operator's own deposit ledger if needed.

The webhook delivery semantics matter as much as the field set. Specify at-least-once delivery with idempotency on the (source_psp, psp_reference) pair. Do not specify exactly-once delivery, because the major PSPs do not offer it, and a design that assumes it double-counts silently when retries pile up after a PSP outage. The UNIQUE constraint in the schema above is the platform's defense against this, whatever the PSP promises at the integration call.

Where an integration agreement signed before the gross rule does not define a deposit as settled regardless of a later reversal, the clean fix at the next renewal is a one-paragraph rider that defines the deposit event the PSP will emit, the fields it must carry and at-least-once delivery. A PSP that serves several UKGC-licensed operators has little reason to push back, because every one of them needs the same event shape to count gross deposits.

Retention, audit, and the RTS 12B cutover

retention sits at the LCCP and gambling-AML layer rather than at RTS 12 itself. The applicable floor for transaction records, including deposit events and limit-change history, is 5 years from the end of the customer relationship under the operator's AML obligations. Some operators keep records longer for litigation holds or contract terms.

What the deposit-limit migration adds to the retention question is the reproducibility obligation. The events table is the regulator's audit surface. The operator must be able to reproduce, for any given deposit, the period the deposit fell into, the gross used at deposit time, the active limits at deposit time, and the cooling-off status of any limit changes during the period. That requires an event log of limit changes, because an in-place update on the player record overwrites the history the regulator asks about.

The minimum retention contract:

  • Deposit events: 5 years post-relationship, immutable, append-only, with reversal as a distinct status update on the same row.
  • Limit changes: 5 years post-relationship, with requested_at, effective_from, previous_value, new_value, and the cooling-off audit trail.
  • Deposit-rejection events (limit hit, cooling-off active, currency mismatch, etc.): 5 years, with a machine-readable rejection reason for regulator queries.
  • Decline copy shown to the player at the cashier: log the exact text so a regulator complaint can be reconciled against what the player saw at the time.

On May 26, 2026, the moved the phase-two date from June 30 to September 30, 2026, and the migration work did not change with it. Phase one, in force since October 2025, brought the customer-facing tools: the limit prompt at registration, the limit-setting link on the home page and the reminder to review limits every 6 months. An operator that missed phase one now carries both builds at once, and the customer-journey work competes with the database migration for the same engineers.

Sep 30, 2026

RTS 12B gross deposit limits in force

Operators meet it with the gross-counter check, the PSP webhook contract and the dual-write data path. On packaged platforms (SoftSwiss, EveryMatrix, Bragg), the vendor runs the migration.

The cutover question is when to switch the gross check from shadow mode to enforcement. The cleaner path is a feature flag per player, rolled out first to a high-volume cohort whose deposit shapes surface the remaining edge cases and then to the full population. A shadow window of 4 to 8 weeks suited an operator that migrated before the rule took effect. An operator still on the legacy counter breaches RTS 12B whenever a withdrawal-redeposit cycle takes gross deposits past the cap, so its shadow window runs while the breach is live and should last only until the two checks below pass. Switching to enforcement with no shadow window carries its own risk, because in the first hours deposits blocked by a bug in the new logic look like legitimate cap hits, and customer support has no playbook for telling them apart.

The two things to verify before declaring the migration complete:

  • The shadow-mode mismatch log shows zero divergence between the new gross query and the legacy net query for players whose deposit pattern in the period is purely additive, with no withdrawals or reversals. If that case diverges, the new query has a bug, and it has to be fixed before cutover.
  • The shadow-mode mismatch log shows the expected divergence for players who withdrew during a period and then redeposited. That divergence is the bug class the rule closes, and seeing it in the log proves the new logic does what the regulation requires.

When both hold, the gross logic is correct and the remaining cutover risk sits in the implementation. The audits deposit limits against the gross rule, and the events table is the record that proves compliance.

Sources (6)

  1. 01UKGC: Definition of deposit limits in the RTS, consultation response, Proposal 1
  2. 02UKGC: RTS 12 wording in full from 30 September 2026 (Annex 2)
  3. 03UKGC: RTS 12 Financial limits
  4. 04UKGC: Implementation extension for new deposit limit requirements
  5. 05UKGC blog: Changes to customer-led tools, financial limits
  6. 06UKGC: Commission to introduce Financial Risk Assessments in staged approach