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:
- Matching didn't work, want to investigate? -> Five Matching Dimensions + Troubleshooting - Scenario 1
- Want to adjust a bank's tolerance rules? -> Change Guide - Adjusting Tolerance
- Want to see a specific bank's matching logic? -> Bank-Specific Matching Rules
- Want to know why auto-credit was blocked? -> Auto-credit Decision Tree
- Want to look up specific tolerance numbers? -> Quick Reference - Tolerance
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
- Fetches all pending bank statements from the Flow table
- Fetches all pending match deposit applications from the Apply table
- Compares each statement against candidate applications across five dimensions
- 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 classdeposit/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
| Dimension | Application (Apply) | Statement (Flow) | Comparison Result |
|---|---|---|---|
| Currency | HKD | HKD | Matched |
| Amount | 50,000 | 50,000 | Matched, difference=0, within tolerance |
| Name | CHAN TAI MAN | CHAN TAI MAN | Exact match |
| Date | 04-28 10:00 | 04-28 10:02 | Within window (2 min difference) |
| Card No. | 012-***-8901 | 012-***-8901 | Matched |
Result: Exact match -> auto-credit decision -> pass -> fully automatic crediting
Case 2: Name Order Reversed -> Fuzzy Match Success
| Dimension | Application (Apply) | Statement (Flow) | Comparison Result |
|---|---|---|---|
| Currency | HKD | HKD | Matched |
| Amount | 30,000 | 30,000 | Matched, difference=0 |
| Name | CHAN TAI MAN | TAI MAN CHAN | Exact no match, fuzzy match yes |
| Date | 04-27 | 04-28 | Within -3~+2 window |
| Card No. | 012-***-5678 | 012-***-5678 | Matched |
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
| Dimension | Application (Apply) | Statement (Flow) | Comparison Result |
|---|---|---|---|
| Currency | HKD | HKD | Matched |
| Amount | 100,000 | 99,980 | Matched, difference=20, exactly equals tolerance |
| Name | WONG SIU MING | WONG SIU MING | Exact match |
| Date | 04-28 | 04-28 | Within window |
| Card No. | 024-***-3456 | 024-***-3456 | Matched |
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
| Dimension | Application (Apply) | Statement (Flow) | Comparison Result |
|---|---|---|---|
| Currency | USD | USD | Matched |
| Amount | 50,000 | 49,955 | Difference=45, local tolerance(3) insufficient, cross-region tolerance(60) sufficient |
| Name | LI WEI | LI WEI | Exact match |
| Date | 04-25 | 04-28 | Within window (3 day difference) |
| Card No. | No match data | None | Skipped |
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
| Dimension | Application A | Application B | Statement |
|---|---|---|---|
| User | UID 1001 | UID 2002 | — |
| Currency | HKD | HKD | HKD |
| Amount | 50,000 | 50,000 | 50,000 |
| Name | CHAN TAI MAN | CHAN TAI MAN | CHAN 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
| Result | Meaning | Next Steps |
|---|---|---|
| Exact match | Multiple dimensions all match, high confidence | -> Enters auto-credit decision |
| Assisted match | Some dimensions match, needs manual confirmation | -> Written to matches table, operations reviews in OA then manually credits |
| No match | Cannot 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
| Bank | Can Auto-credit | Auto-credit Statement Types | Required Dimensions | Non-auto Types |
|---|---|---|---|---|
| BOCHK | Yes (partial) | FPS, online banking, CHATS, remittance in | Currency+Amount exact+Name exact+Card+Date+Limit | Cheque, CBS internal transfer, interest, ATM |
| HSBC | Yes | All (except eDDA) | Currency+Name exact+Amount(HKD<=65/USD<=14)+Card | — |
| Hang Seng | Yes (online banking only) | WY (online banking transfer) | Currency+Amount exact+Name exact+Notice type=Normal | ATM, GT, ZP, BP all assisted match |
| ICBC | Yes (partial) | Remittance deposit, FPS, online banking | Currency+Amount+Card+Name(EN+CN) | Sub-account path, ATM, cheque |
| DBS | Yes | All | Currency+Name exact+Amount(HKD<=350/USD<=50) | — |
| EWB sub-account | Yes | All | Currency+Name exact+Amount(<=40) | — |
| BANKCOMM | No | — | — | All (assisted match only) |
| CCB Asia | No | — | — | All (assisted match only) |
| EWB | No | — | — | All (loose tolerance assisted match) |
| ZA sub-account | No | — | — | All (assisted match only) |
| Singapore ICBC sub-account | No | — | — | All (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 Type | Auto-credit Conditions | Assisted Match Conditions | Amount Tolerance |
|---|---|---|---|
| FPS transfer | Currency+Amount exact+Name exact+Card+Date+Limit | Currency+Name fuzzy+Date | Auto: 0~20(HKD)/0~3(USD) |
| Online banking | Same as FPS | Same as FPS | Same as FPS |
| CHATS interbank | Currency+Local tolerance amount+Name exact+Card+Date+Limit | Currency+Name fuzzy+Date | Auto: 0~20(HKD) |
| Overseas REMIT IN | Currency+Cross-region tolerance+Name exact+Card+Date+Limit | Currency+Name fuzzy+Date | Auto: 0~420(HKD)/0~60(USD) |
| CBS internal transfer | mustFalse (cannot auto) | Currency+Local tolerance+Date | Assisted: 0~20(HKD) |
| Cheque/Interest/ATM | mustFalse (cannot auto) | Currency+Local tolerance+Date | Assisted: 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:
| Rule | Applicable Statement Types | Amount Tolerance | Description |
|---|---|---|---|
| B1 | Local intra-bank (FPS, intra-bank online) | Exact match (difference=0) | No fees for intra-bank, amounts should be exactly the same |
| B2 | Cross-border/interbank (CHATS, overseas) | HKD 0~420 / USD 0~60 | Intermediary bank fees uncontrollable, widest tolerance |
| B3 | Online opening first deposit | Exact match + minimum limit check | HKD >=10,000 / USD >=1,500 / CNY >=10,000 |
| B4 | Local misc (ATM, bill payment, etc.) | HKD 0~20 / USD 0~32 | Covers 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 Level | Conditions | Amount Tolerance |
|---|---|---|
| Auto-credit | Currency+Name exact+Amount within auto tolerance+Card match | HKD: 0~65 / USD: 0~14 |
| Assisted match | Currency+Name fuzzy+Amount within assisted tolerance | HKD: 0~420 / USD: 0~60 |
Key details:
- eDDA method applications are explicitly excluded (
deposit_method == HSBC_EDDAdirectly 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 Type | Match Result | Match Conditions | Notes |
|---|---|---|---|
| ATM | Assisted only | Amount exact+Batch creation date | ATM cash deposits carry no remitter info |
| GT (Counter) | Assisted only | Amount exact+Batch creation date | Limited counter transaction info |
| WY (Online banking) | Can auto | Notice type=Normal + Name exact + Amount exact -> auto-credit | Only type that can auto-credit |
| ZP (Transfer/Cheque) | Assisted only | Amount exact+Date+Name fuzzy(HKD)+UID(optional) | — |
| BP (Bill Payment) | Assisted only | Amount exact+BP number match | Additional BP ID verification |
| Default | Assisted only | Amount fuzzy+Date | Fallback logic |
Key details:
- eDDA method applications are explicitly excluded (
deposit_method == EDDAdirectly 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:
| Path | Trigger Condition | Auto-credit? | Amount Tolerance | Special Requirements |
|---|---|---|---|---|
| Sub-account | CN name="富途證劵國際(香港)有限公司" | No (assisted only) | HKD: 0~500 / USD: 0~70 | Sub-account history verification |
| Normal-auto | Notice type=Normal/Mainland pre-opening | Yes | FPS: Exact(0) / Others: 0~420/60 | Card+EN/CN name dual match |
| Normal-online user | Notice type=Card binding | Yes | Same as above | Minimum amount: HKD>=10000, USD>=1500 |
| Fallback assisted | Other | No | 0~420/60 or exact | Branched 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
00prefix (ICBC card number format is special)
Other Banks
| Bank | Mode | Key Characteristics |
|---|---|---|
| DBS | Sub-account+Name | Sub-account verification must pass; Name exact+Amount(HKD<=350/USD<=50) enables auto-credit |
| EWB sub-account | Dual-tier tolerance | Auto-credit tolerance only 40; Assisted match tolerance 100; Sub-account must verify |
| BANKCOMM | Assisted only | Requires sub-account history verification; Tolerance HKD 300/USD 45; Wider date window(-7~+4 days) |
| CCB Asia | Assisted only | Name exact match+Tolerance HKD 300/USD 45; No auto-credit support |
| EWB | Assisted only | Standard transfer tolerance HKD 420/USD 60; "Other Deposit" only amount exact match |
| ZA sub-account | Assisted only | Name exact+Amount(HKD<=350/USD<=50); Special amount direction(apply-flow) |
| Singapore ICBC sub-account | Assisted only | Only 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 containsFPS— FPS transferTransfer+ remarks containsE-BANKING— Online banking transferTransfer+ remarks containsCHATS— CHATS interbank transferTransfer+ remarks containsREMIT IN— Overseas remittance inTransfer+ remarks containsCBS 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-creditFPS 轉賬— 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
amountSimilarForAutocall parameter inHsbcMatch.php - Upgrade a bank from "assisted only" to "can auto-credit" -> Add logic branch returning
RESULT_DEPOSITin that bank's Match class (reference DBS or HSBC implementation) - Prevent a flow type from auto-crediting -> Change
deposit_ruletomustFalsein the corresponding route ingetRuleConfig() - Add matching rules for a new bank -> Create new
{BankName}Match.phpclass, register in matching dispatcher
Key Constraints:
- 14 Match classes share base rule functions in
MatchRule.phpandNewMatchRule.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 Name | Meaning | Current Value | Affected Banks |
|---|---|---|---|
isSameAmount | Amount exact match | difference=0 | BOCHK FPS/Hang Seng WY/ICBC FPS |
localTransferSimilarAmount | Local transfer tolerance | HKD 20 / USD 3 | BOCHK/ICBC/CCB |
isDifAreaSimilarAmount | Cross-region transfer tolerance | HKD 420 / USD 60 | BOCHK REMIT/HSBC assisted/EWB |
amountSimilarBoco | BANKCOMM/CCB Asia | HKD 300 / USD 45 | BANKCOMM/CCB Asia |
amountSimilarForAuto (HSBC) | HSBC auto-credit | HKD 65 / USD 14 | HSBC 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:
| Currency | Minimum | Notes |
|---|---|---|
| HKD | 10,000 | Approx. 1,300 USD |
| USD | 1,500 | — |
| CNY | 10,000 | Approx. 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
- Find the corresponding Flow record (OA statement list -> search by amount/date/bank)
- Find the corresponding Apply record (OA application list -> search by UID/amount)
- 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
- Name:
Flow.en_namevs user's registered English name- Exactly the same -> exact match
- Different order -> should trigger fuzzy match
- Special characters/prefix -> check if normalization is working
- 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
- Card number:
Flow.customer_accountvsApply.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
| Misconception | Fact |
|---|---|
| "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 issues | Deposit Troubleshooting |
| Look up tolerance, limit, time window numbers | Deposit Quick Reference |
| Understand how statements enter the system | Bank Statement Collection |
| Understand why eDDA skips the matching engine | eDDA Direct Debit Deposit |
| Understand how SBA credits after matching | SBA Fund Orchestration |
| How to modify matching rules | Deposit Change Guide |
| Understand reversal/refund paths after matching | Refund & Reversal |