Skip to content

Matching & Auto-crediting

About This Page

What: How the system identifies "whose money is this" after a user transfers via FPS/online banking, and under what conditions fully automatic crediting occurs Audience: Product managers who need to understand the core deposit mechanism Prerequisites: Deposit Methods OverviewReading time: 7 minutes Owner: Deposit Product Manager

Key Takeaways: The matching engine pairs bank statements with user applications through five-dimension comparison (amount + currency + name + date + card number), executing automatically every 3 minutes. A two-tier tolerance mechanism ensures both automation and matching accuracy, with approximately 95% of deposits completing automatically.


Quick Navigation — What you might want to do:

Why the Matching Engine is Needed

Imagine this scenario: a HKD 50,000 FPS transfer arrives at the company's SCB account. At this moment, the system only knows "someone transferred 50,000," but doesn't know which user. Meanwhile, dozens of users' deposit applications may be waiting — someone applied for 50,000, someone else applied for 49,980 (bank deducted fees), and there might even be two people who simultaneously applied for 50,000.

The matching engine's job is to find the correct one from these candidate applications, pairing bank statements (Flow) with deposit applications (Apply).

When is matching not needed?

eDDA and BST don't need the matching engine because these methods are system-initiated debits — the system includes "which user, which application" info when sending the debit instruction. When money arrives, ownership is inherently known. The matching engine explicitly skips eDDA and BST applications in the code.


How the Matching Engine Operates

Each bank has an independent matching task that executes every 3 minutes. Each run:

Why 3 minutes instead of real-time?

The matching engine uses a database polling model: each run performs a full table scan of all status=0 records in the flows and applys tables, comparing each pair across five dimensions. This batch processing mode is the most efficient choice at current daily statement volumes — one scan processes all pending records, reducing significantly more database connections and transaction overhead compared to real-time per-record triggers. 3 minutes is the empirical balance point between "user-perceived speed" and "database load." If business volume grows significantly, frequency increase or event-driven architecture can be considered, but DB load assessment is needed. To adjust frequency -> Deposit Change Guide - Adjusting Matching Frequency

  1. Fetches all pending bank statements from the Flow table
  2. Fetches all pending match deposit applications from the Apply table
  3. Compares each statement against candidate applications across five dimensions
  4. Outputs three types of results based on match quality

Five Matching Dimensions

1. Currency: Must Be Exactly the Same

HKD statements can only match HKD applications; no cross-currency matching is performed. This is the most basic filter condition.

2. Amount: Reasonable Differences Allowed

Bank transfers may incur fees, causing actual arrival to be less than the applied amount. The matching engine allows certain tolerances:

  • Local transfers: HKD allows up to 20 difference, USD allows up to 3 difference
  • Interbank/cross-border: Wider tolerance (HKD up to 420), because intermediary bank fees are uncontrollable
  • Different banks have different standards: HSBC's auto-credit tolerance (HKD 65) is more lenient than BOCHK (HKD 20), because HSBC statements have a different fee deduction model

Complete tolerance rules by bank -> Deposit Quick Reference - Matching Tolerance

Why these specific numbers?

Each tolerance tier has a specific business reason:

  • HKD +/-20: Local bank intra-bank transfer fee cap is approximately HKD 15~20. This tolerance covers the vast majority of FPS and local transfer scenarios — user applies 50,000 but 49,982 arrives, the difference being the bank's local fee.
  • HKD +/-420: Cross-border/interbank transfers (e.g., CHATS, wire transfer) pass through intermediary banks with uncontrollable and unpredictable fee amounts. HKD 420 is an empirical value based on historical data, covering the vast majority of cross-border intermediary fee scenarios.
  • HSBC auto-credit -65: HSBC statements are special — fees are deducted directly from the credited amount (rather than listed separately like other banks). Meaning a user transfers 50,000 but the HSBC statement shows arrival of 49,935. The HKD 65 threshold covers most of HSBC's standard fee scenarios.
  • USD +/-3 / +/-60: Proportionally converted from HKD tolerances by exchange rate. USD 3 ≈ HKD 20, USD 60 ≈ HKD 420.
Tolerance Configuration Code Location

Amount tolerance rules are defined in:

  • deposit/src/app/Business/Match/MatchRule.php — common matching rule base class
  • deposit/src/app/Business/Match/NewMatchRule.php — new version matching rules
  • Each bank's Match class (e.g., BocMatch.php, HsbcMatch.php) may override or refine common tolerances

3. Name: Exact or Fuzzy

The system compares the remitter's name in the statement with the applicant's registered name. Two levels supported:

Exact match:

  • Chinese name: character-level exact match
  • English name: converted to uppercase then exact match ("Chan Tai Man" -> "CHAN TAI MAN")

Fuzzy match:

  • Name order reversal handling: Bank statements may have surname first (CHAN TAI MAN), while user registration may be given name first (TAI MAN CHAN). System tokenizes by spaces, sorts, then compares: {CHAN, MAN, TAI} === {CHAN, MAN, TAI}, considered a match.
  • Special character normalization: Remove commas (CHAN, TAI MAN -> CHAN TAI MAN), hyphens (CHAN TAI-MAN -> CHAN TAI MAN), excess spaces, then compare.
  • Bank code prefix removal: Some banks add 3-digit bank code prefix to remitter names (e.g., "004CHAN TAI MAN"); system auto-identifies and removes such prefixes.

Why not more aggressive fuzzy matching? For example, only comparing surname initials, or pinyin matching. The reason is: it's better to let a deposit downgrade to assisted matching for manual operations confirmation than to risk auto-crediting to the wrong account. Crediting A's money to B's securities account — that's far more serious than "being slow." The current fuzzy strategy already covers 90%+ of format difference scenarios, with the remaining edge cases being safest with manual handling.

Name Matching Code Location
  • deposit/src/app/Business/Match/MatchRule.php:252-323 — name comparison core logic (exact + fuzzy)
  • deposit/src/app/Business/Match/NewMatchRule.php:124-139 — new version name normalization rules

4. Date: Within a Reasonable Time Window

The application date and statement date must be within a reasonable range. Window size depends on statement type:

  • Real-time statements (FPS, MT910, etc.): narrow window near statement arrival time
  • Batch statements (BOCHK B2E, etc.): statement date +/-3 days approximately, wider window

Design rationale for each time window:

  • Standard window -3 days / +2 days: Application might be earlier than statement by 3 days (user submits application in App, then goes to bank 2-3 days later to transfer), or later by 2 days (bank statement arrives first, user submits application afterward). This window covers the vast majority of normal operation sequences.
  • BOCHK B2E uses +4 days (not +2 days): BOCHK B2E statements are only pulled 3 times daily, plus ~2 hours format conversion time, so statements may enter the system 1~2 days after the actual bank transaction. Therefore the window is extended backward by 2 extra days.
  • FPS uses -1 hour: FPS settles in seconds. But in practice, users might complete the FPS transfer in banking app first, then submit the deposit application seconds to tens of seconds later in moomoo App — meaning statement arrival time may be slightly earlier than application time. The -1 hour window covers this common "transfer first, apply later" operation sequence.
  • Real-time statements use arrival time (not transaction date): MT910 and BST are precise to the second, allowing the system to use more precise time windows for matching rather than day-level comparison like batch statements. This significantly reduces false match risk for same-amount same-user multiple deposits.

Complete time window configuration -> Deposit Quick Reference - Matching Time Window

Time Window Configuration Code Location
  • deposit/src/app/Business/Match/MatchRule.php:112-223 — time window definitions for each bank and statement type

5. Card Number: Exact Match

The remitter's account number in the statement is compared exactly with the bank card number in the application (after cleaning: removing currency identifier digits, excluding credit card numbers, etc.).


Real Matching Cases

The following 5 cases demonstrate matching engine behavior in different scenarios, helping understand how matching logic works in practice.

Case 1: Standard FPS Exact Match

DimensionApplication (Apply)Statement (Flow)Comparison Result
CurrencyHKDHKDMatched
Amount50,00050,000Matched, difference=0, within tolerance
NameCHAN TAI MANCHAN TAI MANExact match
Date04-28 10:0004-28 10:02Within window (2 min difference)
Card No.012-***-8901012-***-8901Matched

Result: Exact match -> auto-credit decision -> pass -> fully automatic crediting

Case 2: Name Order Reversed -> Fuzzy Match Success

DimensionApplication (Apply)Statement (Flow)Comparison Result
CurrencyHKDHKDMatched
Amount30,00030,000Matched, difference=0
NameCHAN TAI MANTAI MAN CHANExact no match, fuzzy match yes
Date04-2704-28Within -3~+2 window
Card No.012-***-5678012-***-5678Matched

Result: Name only fuzzy matched -> assisted match, awaiting operations confirmation. Explanation: Statement shows "TAI MAN CHAN" and registered name "CHAN TAI MAN" — system tokenizes by spaces then sorts: {CHAN, MAN, TAI} === {CHAN, MAN, TAI}, determined as fuzzy match.

Case 3: Amount Difference at Tolerance Boundary

DimensionApplication (Apply)Statement (Flow)Comparison Result
CurrencyHKDHKDMatched
Amount100,00099,980Matched, difference=20, exactly equals tolerance
NameWONG SIU MINGWONG SIU MINGExact match
Date04-2804-28Within window
Card No.024-***-3456024-***-3456Matched

Result: Difference exactly = HKD 20 (closed interval, equal to tolerance still counts as match) -> exact match -> auto-credit. Boundary note: If statement were 99,979 (difference 21), it would downgrade to assisted match.

Case 4: Cross-border Remittance + Large Fee

DimensionApplication (Apply)Statement (Flow)Comparison Result
CurrencyUSDUSDMatched
Amount50,00049,955Difference=45, local tolerance(3) insufficient, cross-region tolerance(60) sufficient
NameLI WEILI WEIExact match
Date04-2504-28Within window (3 day difference)
Card No.No match dataNoneSkipped

Result: Amount uses cross-region tolerance (within USD 60) -> exact match -> auto-credit decision. PM Note: The USD 45 difference comes from intermediary bank fees. Apply.real_amount will record 49,955 (actual arrival), user sees "Deposit successful USD 49,955."

Case 5: Same Amount Multiple Users -> System Refuses Auto-credit

DimensionApplication AApplication BStatement
UserUID 1001UID 2002
CurrencyHKDHKDHKD
Amount50,00050,00050,000
NameCHAN TAI MANCHAN TAI MANCHAN TAI MAN

Result: One statement matches applications from two different users -> violates "one statement one user" rule -> downgraded to assisted match, operations manually determine ownership. Real-world reason: Two users with the same name happened to apply for the same amount simultaneously. While rare, the system must guard against this situation.


Three Matching Results

ResultMeaningNext Steps
Exact matchMultiple dimensions all match, high confidence-> Enters auto-credit decision
Assisted matchSome dimensions match, needs manual confirmation-> Written to matches table, operations reviews in OA then manually credits
No matchCannot pair-> Statement waits for next matching round, or eventually becomes orphan statement

Different banks have different standards for "exact match." Some banks require currency+amount+name+card number all to match, while others only need currency+amount+name. These differences exist because each bank's statements carry different richness of information — richer info means more matching dimensions and higher confidence.

Assisted match is not failure

Assisted match means the system found a "possible match pair" but isn't confident enough. After operations review and confirmation, the deposit completes normally. Most assisted matches end up being correct — the system just doesn't dare to fully automate them.


Bank-Specific Matching Rules

Each bank's statement format and information content varies greatly: some bank statements include complete remitter name, card number, transaction remarks, while others only have amount and date. Therefore, the matching engine implements an independent Matcher class for each bank, adding bank-specific logic on top of the common five-dimension rules.

Auto-credit Capability by Bank

BankCan Auto-creditAuto-credit Statement TypesRequired DimensionsNon-auto Types
BOCHKYes (partial)FPS, online banking, CHATS, remittance inCurrency+Amount exact+Name exact+Card+Date+LimitCheque, CBS internal transfer, interest, ATM
HSBCYesAll (except eDDA)Currency+Name exact+Amount(HKD<=65/USD<=14)+Card
Hang SengYes (online banking only)WY (online banking transfer)Currency+Amount exact+Name exact+Notice type=NormalATM, GT, ZP, BP all assisted match
ICBCYes (partial)Remittance deposit, FPS, online bankingCurrency+Amount+Card+Name(EN+CN)Sub-account path, ATM, cheque
DBSYesAllCurrency+Name exact+Amount(HKD<=350/USD<=50)
EWB sub-accountYesAllCurrency+Name exact+Amount(<=40)
BANKCOMMNoAll (assisted match only)
CCB AsiaNoAll (assisted match only)
EWBNoAll (loose tolerance assisted match)
ZA sub-accountNoAll (assisted match only)
Singapore ICBC sub-accountNoAll (assisted match only)

Bank Matching Rules Details

BOCHK — Matching by Flow Type Groups

BOCHK statements carry the richest information (name, card number, remarks, flow type), enabling the most matching dimensions and highest auto-match rate. The matching engine first categorizes statements by flow type and remarks field, then applies different rule sets to each category:

Flow TypeAuto-credit ConditionsAssisted Match ConditionsAmount Tolerance
FPS transferCurrency+Amount exact+Name exact+Card+Date+LimitCurrency+Name fuzzy+DateAuto: 0~20(HKD)/0~3(USD)
Online bankingSame as FPSSame as FPSSame as FPS
CHATS interbankCurrency+Local tolerance amount+Name exact+Card+Date+LimitCurrency+Name fuzzy+DateAuto: 0~20(HKD)
Overseas REMIT INCurrency+Cross-region tolerance+Name exact+Card+Date+LimitCurrency+Name fuzzy+DateAuto: 0~420(HKD)/0~60(USD)
CBS internal transfermustFalse (cannot auto)Currency+Local tolerance+DateAssisted: 0~20(HKD)
Cheque/Interest/ATMmustFalse (cannot auto)Currency+Local tolerance+DateAssisted: 0~20(HKD)

BOCHK FPS Remarks Exemption

If BOCHK statement remarks contain FPS-related content, region check is exempted (bocFlowRemarksExemptFromRegionCheck). This is because FPS itself is Hong Kong local fast payment and doesn't need additional verification of remittance source region.

BOCHK card number cleaning rule: BOCHK statement card numbers may have a / prefix (e.g., /012345678901). The matching engine executes ltrim($card_number, '/') before comparison. If you find card numbers "look the same but don't match" when troubleshooting BOCHK matching failures, first check for the / prefix issue.

B-series amount rule details: BOCHK amount matching isn't uniform tolerance but subdivided into 4 rule tiers by statement source:

RuleApplicable Statement TypesAmount ToleranceDescription
B1Local intra-bank (FPS, intra-bank online)Exact match (difference=0)No fees for intra-bank, amounts should be exactly the same
B2Cross-border/interbank (CHATS, overseas)HKD 0~420 / USD 0~60Intermediary bank fees uncontrollable, widest tolerance
B3Online opening first depositExact match + minimum limit checkHKD >=10,000 / USD >=1,500 / CNY >=10,000
B4Local misc (ATM, bill payment, etc.)HKD 0~20 / USD 0~32Covers small fees

B3 is special — online opening users' first deposit requires not only exact amount match but also meeting the minimum limit. First deposits not meeting the minimum are blocked and downgraded to assisted match for operations confirmation.

HSBC — Dual-tier Tolerance + Card Number Verification

HSBC MT910 statements carry complete remitter information. Matching logic is relatively straightforward but has dual-tier tolerance:

Match LevelConditionsAmount Tolerance
Auto-creditCurrency+Name exact+Amount within auto tolerance+Card matchHKD: 0~65 / USD: 0~14
Assisted matchCurrency+Name fuzzy+Amount within assisted toleranceHKD: 0~420 / USD: 0~60

Key details:

  • eDDA method applications are explicitly excluded (deposit_method == HSBC_EDDA directly skipped)
  • Card number verification excludes 14-digit BOC smart account numbers
  • HSBC's auto-credit tolerance (HKD 65) is more lenient than BOCHK (HKD 20), because HSBC has a different fee deduction model for interbank transfers

Hang Seng — Six-way Dispatch by Flow Type

Hang Seng statement format is simpler. The matching engine routes through six different paths by flow type code:

Flow TypeMatch ResultMatch ConditionsNotes
ATMAssisted onlyAmount exact+Batch creation dateATM cash deposits carry no remitter info
GT (Counter)Assisted onlyAmount exact+Batch creation dateLimited counter transaction info
WY (Online banking)Can autoNotice type=Normal + Name exact + Amount exact -> auto-creditOnly type that can auto-credit
ZP (Transfer/Cheque)Assisted onlyAmount exact+Date+Name fuzzy(HKD)+UID(optional)
BP (Bill Payment)Assisted onlyAmount exact+BP number matchAdditional BP ID verification
DefaultAssisted onlyAmount fuzzy+DateFallback logic

Key details:

  • eDDA method applications are explicitly excluded (deposit_method == EDDA directly skipped)
  • WY (online banking) is the only Hang Seng type that can auto-credit, and requires notice_type = NORMAL
  • Date dimension is special: ATM/GT use batch creation time rather than standard date window, because Hang Seng statements arrive in batches

ICBC — Dual-path Dispatch

ICBC has the most complex matching logic, split into sub-account path and normal path — two completely different chains:

PathTrigger ConditionAuto-credit?Amount ToleranceSpecial Requirements
Sub-accountCN name="富途證劵國際(香港)有限公司"No (assisted only)HKD: 0~500 / USD: 0~70Sub-account history verification
Normal-autoNotice type=Normal/Mainland pre-openingYesFPS: Exact(0) / Others: 0~420/60Card+EN/CN name dual match
Normal-online userNotice type=Card bindingYesSame as aboveMinimum amount: HKD>=10000, USD>=1500
Fallback assistedOtherNo0~420/60 or exactBranched by statement type

Key details:

  • Normal path auto-credit requires both EN and CN names to match — double verification
  • FPS requires exact amount match (tolerance=0), other methods allow 420/60 cross-region tolerance
  • Only 匯款存入, FPS 轉賬, 網上轉賬存款 three statement types can trigger auto-credit
  • Card number verification auto-removes 00 prefix (ICBC card number format is special)

Other Banks

BankModeKey Characteristics
DBSSub-account+NameSub-account verification must pass; Name exact+Amount(HKD<=350/USD<=50) enables auto-credit
EWB sub-accountDual-tier toleranceAuto-credit tolerance only 40; Assisted match tolerance 100; Sub-account must verify
BANKCOMMAssisted onlyRequires sub-account history verification; Tolerance HKD 300/USD 45; Wider date window(-7~+4 days)
CCB AsiaAssisted onlyName exact match+Tolerance HKD 300/USD 45; No auto-credit support
EWBAssisted onlyStandard transfer tolerance HKD 420/USD 60; "Other Deposit" only amount exact match
ZA sub-accountAssisted onlyName exact+Amount(HKD<=350/USD<=50); Special amount direction(apply-flow)
Singapore ICBC sub-accountAssisted onlyOnly verifies Currency+Sub-account+Amount(HKD<=500/USD<=70), no name verification
Bank Flow Type Grouping Rules

BOCHK flow types (routed by type + remarks):

  • Transfer + remarks contains FPS — FPS transfer
  • Transfer + remarks contains E-BANKING — Online banking transfer
  • Transfer + remarks contains CHATS — CHATS interbank transfer
  • Transfer + remarks contains REMIT IN — Overseas remittance in
  • Transfer + remarks contains CBS TRANSFER — CBS internal transfer (cannot auto-credit)
  • Clearing Cheque — Cheque clearing (cannot auto-credit)
  • Interest / ATM Transfer — Interest/ATM (cannot auto-credit)

Hang Seng flow types (direct code matching):

  • ATM — ATM cash deposit (assisted match only)
  • GT — Counter transaction (assisted match only)
  • WY — Online banking transfer (only type that can auto-credit)
  • ZP — Transfer/Cheque (assisted match only)
  • BP — Bill Payment/Bank transfer in (assisted match only, additional BP ID verification)

ICBC flow types (matched by Chinese label):

  • 匯款存入 — Can auto-credit
  • FPS 轉賬 — Can auto-credit (amount exact match)
  • 網上轉賬存款 — Can auto-credit
  • 手機轉賬存款 / 網上轉賬存款 — Can auto-credit (eBanking path, requires CN name)
  • 存款機 / 現金 / 他行票 — Assisted match only
  • 跨行轉賬轉入 — Assisted match only
  • 櫃員機跨行轉賬存款 — ATM special rule (tolerance only 10)

See Bank Statement Collection for flow type code descriptions by bank.

If Requirements Change: Modifying a Bank's Matching Rules

Code Location: deposit/src/app/Business/Match/{BankName}Match.php

Each bank has an independent Match class inheriting from MatchBase. Core methods are match($flow, $apply) and getRuleConfig().

Common Change Scenarios:

  • Widen a bank's auto-credit tolerance -> Modify the amount comparison parameter in the corresponding Match class. E.g., HSBC HKD from 65 to 100: modify amountSimilarForAuto call parameter in HsbcMatch.php
  • Upgrade a bank from "assisted only" to "can auto-credit" -> Add logic branch returning RESULT_DEPOSIT in that bank's Match class (reference DBS or HSBC implementation)
  • Prevent a flow type from auto-crediting -> Change deposit_rule to mustFalse in the corresponding route in getRuleConfig()
  • Add matching rules for a new bank -> Create new {BankName}Match.php class, register in matching dispatcher

Key Constraints:

  • 14 Match classes share base rule functions in MatchRule.php and NewMatchRule.php. Modifying base rules (e.g., isSameAmount) affects all banks
  • Each bank's matching task runs independently (every 3 minutes each), without interfering with each other
If Requirements Change: Adjusting Matching Tolerance

Code Location:

  • Standard tolerance: deposit/src/app/Business/Match/MatchRule.php (approximately lines 30-110)
  • New version routing engine: deposit/src/app/Business/Match/NewMatchRule.php

Tolerance Function Reference Table (modifying these functions affects all banks using them):

Function NameMeaningCurrent ValueAffected Banks
isSameAmountAmount exact matchdifference=0BOCHK FPS/Hang Seng WY/ICBC FPS
localTransferSimilarAmountLocal transfer toleranceHKD 20 / USD 3BOCHK/ICBC/CCB
isDifAreaSimilarAmountCross-region transfer toleranceHKD 420 / USD 60BOCHK REMIT/HSBC assisted/EWB
amountSimilarBocoBANKCOMM/CCB AsiaHKD 300 / USD 45BANKCOMM/CCB Asia
amountSimilarForAuto (HSBC)HSBC auto-creditHKD 65 / USD 14HSBC only

Note: Modifying common tolerance functions (e.g., localTransferSimilarAmount) simultaneously affects multiple banks. Prefer overriding in bank-specific Match classes rather than modifying common functions.


Complete Auto-credit Decision Tree

Exact match doesn't equal auto-credit. The system must also pass a series of safety checks — all must pass for fully automatic crediting.

5 Basic Prerequisites

Condition 1: Amount within auto-credit limit. Each currency has an auto-credit ceiling (e.g., HKD 2 million). Deposits exceeding the limit require manual confirmation — this is the safety valve preventing abnormal large fund inflows. Limit numbers -> Deposit Quick Reference - Currency Limits

Condition 2: Statement not manually marked as rejected. If operations previously marked this statement "do not auto-process," the system respects this decision.

Condition 3: Within auto-processing business hours. Auto-credit only executes during business hours. Exact matches outside business hours are temporarily stored as assisted matches, processed when business hours resume. Specific hours -> Deposit Quick Reference - Processing Hours

Condition 4: One statement maps to only one user. If the same statement matches applications from different users, the system cannot automatically determine ownership and needs manual intervention. This typically happens when two users coincidentally transferred the same amount.

Condition 5: User's daily auto-credits don't exceed 10. Prevents mass auto-crediting to a single user in abnormal situations. 10 is a safety ceiling — normal users rarely deposit more than 10 times in a day.

Business Hours Suspension Window (2412 Rule)

Even during normal business hours, auto-credit pauses during these time windows:

  • 08:55 ~ 09:00: Pre-market reconciliation window
  • 16:05 ~ 16:10: Post-market reconciliation window

Why? At Hong Kong stock market open and close, the system reconciles securities account balances. If an auto-deposit is executing at that exact moment, it could cause account balance inconsistency during reconciliation. This 5-minute pause window ensures no fund movements interfere with reconciliation.

2412 Rule Configuration Location

deposit/src/app/Business/DepositConfigNew.php:603-641

Online Account Opening First Deposit Minimum

Online account opening users' first deposit must meet minimum amount requirements — a risk control requirement ensuring online opening users have sufficient initial funds:

CurrencyMinimumNotes
HKD10,000Approx. 1,300 USD
USD1,500
CNY10,000Approx. 10,000 HKD

First deposits not meeting the minimum are downgraded to assisted match for operations manual confirmation. Subsequent deposits have no minimum requirement — only the first deposit for online account opening is restricted.

Configuration Location

Minimum limit checks are implemented in each bank Matcher's online opening branch. Using BOCHK as example, BocMatch.php online opening path additionally checks amount >= min_amount.

Risk Control Integration

After passing the 5 basic conditions and 2412 suspension window, the system performs these additional risk checks:

Blacklist check: Calls hk-deposit-blacklist-go service. If the user or associated information hits the blacklist, the deposit's DepositType is marked HIGH_RISK(5), forcing into manual review flow. Blacklists support expiry times — some entries are temporary (e.g., user under temporary risk observation).

Whitelist verification: Calls hk-deposit-whitelist-go service. Mainly used for HK online opening users' eDDA method verification — confirming the user has passed whitelist admission.

High-risk country/SWIFT check: If the remittance source country is on the high-risk country list (determined by SWIFT code), the deposit is marked HIGH_RISK, requiring manual review. This is an AML (Anti-Money Laundering) compliance requirement.

HK online opening region restriction: Online opening user + non-FPS method + no linked HK-region bank card payment method -> auto-blocked. This is a risk control strategy preventing online opening users from depositing through non-local channels.

Complete Decision Tree

Condition not met does not equal deposit failure

Any condition not met only causes "auto-credit" to be downgraded to "assisted match" — operations can still approve crediting after confirmation. Deposits flagged HIGH_RISK by risk control are not directly rejected but require joint review by operations and risk control teams. These conditions are all safety valves, not blockers.


Complete Path After Matching

From match success to fund crediting, the process goes through SBA (Server Bank Account) deposit orchestration. SBA is the system's "internal bank" — all fund balance changes are completed through SBA Procedures, ensuring atomicity. See SBA Concepts & Data Model for details.

Matching Rule Debugging Guide

When the matching engine behaves unexpectedly (should have matched but didn't, or shouldn't have matched but did), troubleshoot along this path.

Step-by-Step Runbook: Matching Result Not As Expected

Minute 1 — Confirm matching inputs

  1. Find the corresponding Flow record (OA statement list -> search by amount/date/bank)
  2. Find the corresponding Apply record (OA application list -> search by UID/amount)
  3. Confirm both records have status = 0 (Pending) — if not 0, matching engine won't scan them

Minutes 2~5 — Compare dimension by dimension 4. Currency: Flow.currency vs Apply.currency (must be exactly the same) 5. Amount: Calculate difference = Apply.amount - Flow.amount

  • Difference < 0 -> statement larger than application, no match
  • Difference within tolerance -> should match (check that bank's tolerance table)
  • Difference exceeds tolerance -> normal no-match
  1. Name: Flow.en_name vs user's registered English name
    • Exactly the same -> exact match
    • Different order -> should trigger fuzzy match
    • Special characters/prefix -> check if normalization is working
  2. Date: Is the statement date within the application's matching window?
    • Standard window: -3 ~ +2 days
    • BOCHK window: -3 ~ +4 days
    • FPS window: -1 hour ~ +2 days
  3. Card number: Flow.customer_account vs Apply.bank_card_number (compare after cleaning)

Minutes 5~10 — Determine expected result 9. Check that bank's Matcher class rules (Bank-Specific Matching Rules) 10. Confirm that bank's flow type matching path: - Does it go to auto-credit path or assisted match path? - Is that flow type in the mustFalse list (i.e., cannot auto-credit)? 11. If all dimensions met but still no match -> check if blocked by risk control or 2412 suspension

After locating the issue:

  • If tolerance/window insufficient -> evaluate whether adjustment is needed (-> Change Guide)
  • If data issue (abnormal name format, missing card number) -> contact user to correct
  • If system bug -> record reproduction steps, escalate to deposit development team

Common Misconceptions

MisconceptionFact
"The matching engine is real-time"No. It runs in batch every 3 minutes. There's a matching cycle wait in between
"Exact match guarantees auto-credit"Not necessarily. Must still pass 5 prerequisites + risk checks; any failure downgrades to assisted match
"Assisted match means matching failed"No. Assisted match is "probably correct but system isn't confident enough." Normal crediting after operations confirms
"All banks use the same matching rules"No. 14 banks each have independent Matcher classes with significantly different rules
"Amount difference is always fees"Usually, but could also be user transferring wrong amount, or bank-side exchange rate conversion differences
"Changing tolerance only affects one bank"Depends on which function is changed. Common tolerance functions (e.g., localTransferSimilarAmount) affect all banks using them

After Reading

I want to...Go to
Troubleshoot specific matching failure issuesDeposit Troubleshooting
Look up tolerance, limit, time window numbersDeposit Quick Reference
Understand how statements enter the systemBank Statement Collection
Understand why eDDA skips the matching engineeDDA Direct Debit Deposit
Understand how SBA credits after matchingSBA Fund Orchestration
How to modify matching rulesDeposit Change Guide
Understand reversal/refund paths after matchingRefund & Reversal
Was this page helpful?

内部业务文档 · 仅限 moomoo 团队使用