Skip to content

SBA Funds Orchestration

About This Page

What: What SBA is, the Procedure data model and key fields, full state machines for Deposit and Withdrawal (with Operations focus), detailed BST Deposit/Withdrawal Orchestration flows, SBA service API overview, async task queues and polling, deduplication and idempotency, Freeze-Transfer-Release pattern, Procedure lookup and troubleshooting guide, and common exception scenarios with resolution steps Audience: Product managers and Operations staff who need to understand internal funds Orchestration logic Prerequisites: System Architecture & Data FlowReading time: 12 minutes Owner: Deposit & Withdrawal Product Team

Key takeaway: SBA is the central Orchestration system for all funds operations — every Deposit/Withdrawal creates a Procedure record that follows a standard "Freeze → Transfer → Release" flow. Understanding the Procedure state machine is the foundation for troubleshooting funds exceptions.


What Is a Procedure

Every Deposit or Withdrawal creates a Procedure record in the SBA Orchestration system. It is the complete tracking entity for a funds operation from creation to completion (or failure/cancellation) — think of it as a "funds operation work order."

Relationship Between Procedure and Business Layer

Procedures don't appear out of thin air — they are created by the business layer (Deposit service / Withdrawal service) at specific points:

Business ObjectSBA ObjectCreation TriggerAssociation
Apply (Deposit application)ProcedureCashDepositBank Statement Matching succeeds + auto-crediting conditions metsba_procedure_id field in the Apply record
Task (Withdrawal task)ProcedureCashWithdrawAll three Withdrawal Approval steps pass (Remittance stage)sba_list association table (Task ID ↔ Procedure ID)

PM perspective: Users see Apply (Deposit) or Task (Withdrawal) in the App, and Operations see the same in CRM. Procedure is a "behind-the-scenes actor" — you only need to examine it when investigating funds flow details. But when "money didn't arrive" or "money was deducted but not transferred out," Procedure is the key to pinpointing the issue.

Key Fields

FieldBusiness MeaningCommon Operations Use
idProcedure unique ID, globally incrementingPrimary key for CRM search and troubleshooting
biz_typeBusiness type: cash_deposit (Deposit) or cash_withdraw (Withdrawal)Distinguish between Deposit/Withdrawal Procedures
nn_uidUser ID (NiuNiu ID)Link to a specific user
marketTrading market: 1=HK, 2=US, 4=A-Share ConnectBST requires separate Procedures per market
trade_acc_idTrading account IDA user may have multiple trading accounts
statusMain status — indicates which major stage of the lifecycle the Procedure is inStatus filter on CRM list page
ext_statusSub-status — finer-grained tracking within the same main statusKey to locating "which step it's stuck at"
versionOptimistic lock version number, increments by 1 on each update, prevents concurrent write overwritesRefresh and retry when CRM shows "version conflict" error
transaction_dateSettlement date (trading day format YYYYMMDD), determines which trading day the credit belongs toRoot cause of cross-day Withdrawal delays
reasonTerminal reason — only populated on failure/rejection/cancellationInvestigating "why did this Withdrawal fail"

Version Conflict Handling

CRM Operations staff occasionally encounter a "version conflict" error when operating on a Procedure. This is the optimistic lock mechanism — it means the system (scheduled tasks, bank callbacks, etc.) was also updating this Procedure while you were operating on it.

Resolution: Refresh the page to get the latest version, then retry. If conflicts persist (>3 times), concurrent tasks are frequently updating — wait 10–30 seconds and try again. Never bypass the version check by modifying the database directly.

Audit Trail (Flow)

Every time a Procedure undergoes a status change, SBA writes a Flow record (audit log). The operation history shown when clicking "View History" in CRM comes from this table.

FieldMeaningOperations Use
procedure_idAssociated Procedure IDQuery full change history by Procedure ID
from_status / to_statusMain status before and after the changeVerify whether the status transition is expected
from_ext_status / to_ext_statusSub-status before and after the changePinpoint exact change details
operatorWho performed it (system = automatic / staff_xxxx = CRM Operations)Distinguish system actions from manual actions
remarkNotesReason provided by Operations during manual actions
created_atChange timestamp (millisecond precision)Timeline for issue investigation

Flow records cannot be modified or deleted — they are the complete audit trail for Deposit and Withdrawal operations.

Troubleshooting tip: When a Procedure is in an abnormal state, view Flow records sorted by created_at descending and find the last change — the pre-change status, operator, and timestamp often directly pinpoint the root cause.

Full Status Code Reference

All Procedure main status + sub-status combinations → Withdrawal Data Dictionary § SBA Procedure Status Codes


Deposit Procedure State Machine

The Deposit state machine is relatively simple (6 states), because the complexity lies in the Matching engine — once Matching is complete, the Procedure only handles the final crediting step.

Status Descriptions and Operations Focus

Main StatusSub-StatusBusiness MeaningTerminal?Operations Focus
newwaitingProcedure created, awaiting automatic/manual decisionNoNormal state, system processes within seconds. If it lingers (>1 minute), check if SBA service is healthy
newmanual_confirmTriggered high-risk or specific rules, requires CRM Operations reviewNoAction required — process in the CRM Deposit review queue. Before reviewing, confirm: is the amount reasonable, is the user on the blacklist, does the Bank Statement match
pending(empty)Review passed, executing Risk Control asset change (adding funds)NoTransitional state, usually completes in milliseconds. If stuck, the Risk Control system may be experiencing issues
end_okdeposit_okDeposit successful, funds credited to Securities AccountYesNormal terminal state. User can see the balance increase in the App
end_reject(empty)Rejected — CRM review denied or Risk Control asset change failedYesCheck the reason field for the rejection reason. If it's a Risk Control change failure (not a manual rejection), escalate to technical team
end_reversedeposit_okCredited funds have been reversed (withdrawn back)YesHigh-risk operation — only perform when confirming a Deposit error (e.g., duplicate crediting, fraud). User balance will decrease after Reversal

Scenarios That Trigger Manual Review

The following situations cause a Deposit Procedure to enter manual_confirm, requiring CRM Operations handling:

#ScenarioDecision RuleOperations Handling
1High-risk Depositdeposit_type = HIGH_RISK(5)Verify user identity and source of funds; approve after confirming no risk
2Abnormal Depositdeposit_type = ABNORMAL(3)Check Bank Statement details; manually match after confirming amount and source
3Pre-Approval Depositdeposit_type = PRE_APPROVAL(2)Verify whether pre-Approval conditions are met
4Blacklist hitDeposit blacklist matchConfirm whether it's a false positive; reject if not
5Large DepositExceeds auto-crediting thresholdApprove after verifying source legitimacy

BST Deposit Orchestration Detailed Flow

BST Deposit skips the Matching engine — the bank pushes results directly or they are obtained via polling, and SBA directly creates a Procedure and credits the account. Below is the complete system flow for Airstar BST Deposit:

CMB/CMBC BST Deposit differs in Phase 2: no polling is needed — the bank pushes results in real time via an SM2 Socket bidirectional link, reducing latency from "seconds to minutes" down to "seconds."

BST Deposit requires that the Bank Card has completed BST authorization (Mandate status = OPEN). For the authorization flow and Bank Card management → Bank Cards & Authorization § BST Authorization

Deposit Extended Fields (ProcedureCashDeposit)
FieldMeaningOperations Use
transaction_idNon-BST: Bank Statement ID; BST: business IDKey identifier for reconciliation with the bank
amountDeposit amountConfirm amount is reasonable during review
ccyCurrency (HKD / USD / CNH)Confirm currency matches the Bank Statement
is_bs_transfer0=non-BST; 1=BST ChannelDistinguish BST Deposit from regular Deposit processing logic
transfer_methodTransType code (101/102/201-304, etc.)Identifies the source bank and Channel
deposit_typeDeposit mode: NORMAL(1) / PRE_APPROVAL(2) / ABNORMAL(3) / TRANS_AUTO(4) / HIGH_RISK(5) / NORMAL_HOLD(11)Determines whether manual review is required
hold_typeFreeze type (NORMAL_HOLD mode only): 1=EXCHANGE / 2=CASH_OUT / 17=CASH_INPurpose of funds Freeze
apply_idFreeze ID (32-character unique identifier, required for NORMAL_HOLD mode)Links to Freeze record
sourceDeposit source: 1=initiated by moomoo; 2=initiated by bankBank-initiated Deposits processed via AsbBstCreateFromBankJob
bank_ref_idBank-side reference number (ASBBST + sequence)Unique identifier for bank reconciliation

Full TransType table → Deposit Quick Reference § TransType

The Deposit Procedure state is relatively simple — the complexity lies in the Matching engine, and the Procedure only handles the final crediting. The Withdrawal Procedure that follows is far more complex, as it must handle Freeze, deduction, bank transfer, and failure rollback.


Withdrawal Procedure State Machine

The Withdrawal state machine is the most complex in the entire system (17 states), because it must handle Freeze, deduction, transfer, failure rollback, cross-trading-day delays, and many other scenarios.

Three-Phase Overview

PhaseStatuses InvolvedWhat HappensKey PM QuestionUser Perception
1. Freezenew(freeze)new(waiting)System Freezes the user's available balance"Has the user's balance decreased?"Available balance decreases, but total assets remain the same (frozen amount is still in the account)
2. Reviewnew(waiting)new(manual_confirm)new(confirmed)Automatic/manual review"Can the user cancel?"Can cancel during Freeze stage; cannot cancel once deduction begins after review
3. Deduction + Transfernew(blank)pending(deduct_done)pending(transfer_auto/manual)Balance formally deducted, transfer instruction sent to bank"Money deducted but not at the bank?"Balance deducted, waiting for bank processing
4. Resultend_ok / end_reject / end_cancelBank confirms success or failure"When will the user receive the money?"end_ok = bank confirmed, funds remitted

Happy Path

Most Withdrawals follow this path — Freeze → Deduction → Transfer → Success:

Beyond the happy path, Withdrawals may encounter failure, cancellation, cross-trading-day delays, and other exception branches — these paths deserve the most attention when troubleshooting:

Exception and Rollback Paths

Key Status Descriptions and Operations Focus

Main StatusSub-StatusMeaningTerminal?Operations Focus
newfreezeInitial state — waiting to Freeze user balanceNoCompletes in milliseconds. If it stays for >30 seconds, check if Risk Control system is responding
newwaitingFreeze successful, waiting for scheduled script or manual processingNoRegular Withdrawals are automatically picked up by scheduled scripts; BST Withdrawals auto-enter deduction. If lingering, check scheduled tasks
newmanual_confirmRequires CRM manual reviewNoAction required — Withdrawal review queue. Before reviewing, confirm: Withdrawal amount vs. available balance, target Bank Card belongs to the user, whether Risk Control rules were triggered
newconfirmedManual review passed, pending deductionNoTransitional state. System automatically enters the deduction flow
new(empty)Pending deduction (new_blank)NoDeduction in progress. If stuck for >1 minute, the Risk Control asset change API may have timed out
pendingdeduct_doneDeduction complete, pending transfer method confirmationNoCritical checkpoint — deduction is complete, cannot roll back to Freeze. BST auto-enters transfer; online banking/FPS enters manual transfer
pendingtransfer_autoBST auto-transfer in progressNoBST Channel is sending the transfer instruction to the bank. Airstar requires polling for results (up to 10 times); CMB/CMBC push in real time
pendingtransfer_manualManual transfer in progress (online banking / FPS / wire, etc.)NoAction required — after completing the transfer in the bank's online banking portal, click "Confirm Transfer Complete" (SetManualTransferDone) in CRM
pendingreturnTransfer failed, pending funds restorationNoSystem automatically restores the deducted amount to the user's account. If restoration fails, critical alert — user's money has "disappeared"
pendingunfreezeWithdrawal cancelled, unfreezing in progressNoSystem automatically releases the frozen amount. If unfreezing fails, the user's balance will be "stuck"
pendingmove_nextNon-trading hours, deferred to next trading dayNoTriggered when BST Withdrawal is submitted outside trading hours. Procedure returns to new(freeze) and restarts the flow
pendingwaiting_tradeWaiting for trading day to arriveNoWithdrawals submitted on weekends/holidays wait here. Automatically enters terminal state when trading day arrives
pendingtransfer_rejectRejected/cancelled, awaiting terminal state confirmationNoTransitional state. System automatically sets the final reject or cancel
end_oktransfer_doneWithdrawal successfulYesBank confirmed remittance successful. User should receive funds within 1–3 business days
end_reject(empty)Withdrawal failedYesCheck the reason field. Funds have been automatically restored to the user's account
end_cancel(empty)Withdrawal cancelledYesUser-initiated or Operations-initiated cancellation. Funds have been automatically unfrozen
end_reversetransfer_doneCompleted Withdrawal has been reversedYesExtremely high-risk operation — only use when the bank confirms remittance failure/return

pending_move Loop Mechanism

pending_move is a unique looping state: BST Withdrawals submitted outside trading hours are moved to the next trading day by the MoveNextTransactionDay operation — the Procedure returns to new(freeze) and restarts the Freeze-Deduction-Transfer flow.

ScenarioExampleProcedure BehaviorUser Perception
BST Withdrawal submitted at 18:00 on FridayTrading hours have endedpending_move → next Monday new(freeze)Submitted Friday, processed Monday
Submitted the day before a holidaySame logicDeferred to the first trading day after the holidayProcessed on the first trading day after the holiday
Submitted after 16:30 on a trading dayPast the daily cutoff timeDeferred to next day new(freeze)Processed next day
Consecutive holidays (e.g., Chinese New Year)Friday → next Tuesday is the first trading dayMay loop through pending_move multiple timesProcessed after the holiday ends

Common User Question

"Why was my Friday Withdrawal not received until Monday?" — Because BST Channels depend on trading days, and Withdrawals submitted outside trading hours are deferred to the next trading day. This is not a system error; it is normal business logic.

Suggested Operations response: "Your Withdrawal has been accepted. Since BST Channels process during trading hours, it will be automatically processed on the next trading day (Monday), with an estimated arrival in 1–2 business days."

Trading Day Rules

Rules the system uses to determine "whether we are currently in trading hours":

MarketTrading DaysCutoff TimeAfter Cutoff
HK (Hong Kong equities)Monday–Friday, excluding HK public holidays16:15 HKTWithdrawal deferred to next trading day
US (US equities)Monday–Friday, excluding US public holidays04:00 HKT next day (corresponding to 16:00 ET)Withdrawal deferred to next trading day
HKCC (Stock Connect)Stock Connect trading days (excluding both HK and Shanghai/Shenzhen holidays)16:15 HKTWithdrawal deferred to next trading day

Public holiday source: The system maintains a trading calendar (updated by the settlement team at the end of each year), covering HKEx, NYSE, and SSE/SZSE market closures. The transaction_date field is automatically calculated by SBA based on the current time and the trading calendar.

Troubleshooting tip: If a Withdrawal triggers pending_move during daytime on a business day, check whether the trading calendar includes that day (it may be a temporary closure or the trading calendar may not have been updated).

BST Withdrawal Orchestration Detailed Flow

Below is the complete system flow for Airstar BST Withdrawal from user initiation to funds arrival:

Online banking / FPS Withdrawal differs in Phase 3: instead of auto-transfer, it enters pending(transfer_manual) and waits for Operations to complete the transfer manually in the bank's corporate online banking portal before confirming.

Withdrawal Extended Fields (ProcedureCashWithdraw)
FieldMeaningOperations Use
amountWithdrawal amountVerify amount is reasonable during review
feeTransaction fee (currently all 0)
ccyCurrencyConfirm currency matches user's selection
transfer_methodChannel key: auto_bs / hase / hsbc / boc_fps / cgb_fps_api, etc.Determine which Withdrawal Channel is used
transfer_dest_bankTarget bank codeVerify target bank information
transfer_dest_cardTarget Bank Card numberVerify receiving account number
bank_launched0=initiated by moomoo; 1=initiated by bank (BST-specific)Distinguish who initiated this Withdrawal
transfer_ref_idBank-side reference number (CMB=bank_tx_seq, CMBC=OrgRefNo, Airstar=ASBBST+sequence)Key identifier for bank reconciliation
settled_amountCash portion amountFor margin account Withdrawals, distinguishes cash vs. margin portion
margin_amountMargin (loan) portion amountMonitor during margin Withdrawals
payee_namePayee name (CMBC BST uses English name)Verify payee identity
request_idBank-side request ID (Airstar)Primary key for polling results

Full Channel code table → Withdrawal Data Dictionary § Withdrawal Channel Codes

Now that you understand the state machine, the next step is to learn what operations Operations staff can perform on Procedures in CRM — each CRM button corresponds to an SBA API.


SBA Service API Overview

These are the operation APIs exposed by the SBA Orchestration system — they correspond to buttons in CRM. Understanding "which button calls which API" helps troubleshoot "why a button click had no effect."

Deposit Procedure Operations

OperationWho TriggersEffectPrerequisite StatusCRM MappingPermission Required
CashDepositCreateDeposit service (automatic)Creates a Deposit Procedure, starts crediting flowAuto-triggered, no CRM buttonSystem automatic
CashDepositManualConfirmCRM OperationsApproves review, continues creditingnew(manual_confirm)Deposit Review → "Approve"Frontline Operations
CashDepositManualRejectCRM OperationsRejects review, Procedure → end_rejectnew(manual_confirm)Deposit Review → "Reject"Frontline Operations
CashDepositReverseCRM OperationsReverses a completed Deposit, funds withdrawn from Securities Accountend_okDeposit Details → "Reverse"Supervisor level

Reversal Operation Warning

CashDepositReverse directly deducts the credited amount from the user's Securities Account. Before executing, you must confirm:

  1. It is genuinely an erroneous credit — e.g., duplicate crediting, fraud, bank refund
  2. The user's current available balance is sufficient for deduction — if the user has already used the deposited funds for trading or Withdrawal, insufficient available balance will cause the Reversal to fail
  3. The user has been notified — the user's balance will decrease after Reversal, so prior communication is required

Reversals are irreversible. An erroneous Reversal requires re-initiating the Deposit flow.

Withdrawal Procedure Operations

OperationWho TriggersEffectPrerequisite StatusCRM MappingPermission Required
CashWithdrawCreateWithdrawal service (automatic)Creates a Withdrawal Procedure, starts FreezeAuto-triggeredSystem automatic
CashWithdrawStartTransferCRM Operations / automaticConfirms transfer parameters are correct, starts transfernew(blank) or pending(deduct_done)"Start Transfer"Frontline Operations
CashWithdrawRejectCRM OperationsRejects Withdrawal, triggers unfreeze rollbackAny status in the new phase"Reject"Frontline Operations
CashWithdrawManualConfirmCRM OperationsManual review approvednew(manual_confirm)"Approve"Frontline Operations
CashWithdrawManualRejectCRM OperationsManual review rejectednew(manual_confirm)"Reject Review"Frontline Operations
SetManualTransferDoneCRM OperationsConfirms manual transfer (online banking / wire, etc.) is completepending(transfer_manual)"Confirm Transfer Complete"Frontline Operations
SetManualTransferFailedCRM OperationsConfirms manual transfer failed, triggers funds restorationpending(transfer_manual)"Transfer Failed"Frontline Operations
CashWithdrawForceProcessCRM OperationsForce-processes a stuck ProcedureAny non-terminal status"Force Process"Supervisor level
CashWithdrawCancelCRM OperationsCancels Withdrawal, Procedure → end_cancelnew phase (after Freeze, before deduction)"Cancel Withdrawal"Supervisor level
MoveNextTransactionDayCRM Operations / scheduled taskDefers processing to the next trading daypending(deduct_done) / pending(transfer_manual)"Defer to Next Trading Day"Frontline Operations
CashWithdrawReverseCRM OperationsReverses a completed Withdrawalend_ok"Reverse"Supervisor level

Button Not Available?

Whether a CRM button is clickable depends on the Procedure's current status. For example, "Approve" is only available in the new(manual_confirm) state — if the Procedure has already entered the pending phase, the button will be grayed out.

Troubleshooting "button click had no effect":

  1. Check whether the Procedure's current status + ext_status match the operation's prerequisite status
  2. Check whether version is up to date — refresh the page and retry
  3. Check operator permissions — certain operations (e.g., Reversal) require specific roles

CRM operations ultimately trigger SBA's interactions with the bank. But banks don't respond synchronously — next, let's look at how SBA manages bank interactions through async task queues.


Async Task Queue Pattern

Most interactions between the Deposit/Withdrawal system and banks are asynchronous — after sending an instruction, you don't get the result immediately. SBA manages these async flows through task queues.

Execution Pattern

  1. Create Job: Receives the business request, assembles parameters, sends instruction to the bank
  2. Result Job: Periodically polls the bank API to query processing results
  3. Retry mechanism: Has an explicit maximum retry count; exceeding it marks the job as an exception and triggers an alert
  4. Idempotency: Uses procedure_id + request_id to ensure the same instruction is not executed twice

Airstar BST Task Chain Details

Airstar BST is a typical async polling pattern — each operation consists of a creation task and a result-polling task:

Deposit task chain:

Task NameMax RetriesPoll IntervalResponsibilityFailure Handling
AsbBstCreateJobSend Deposit request to Airstar, obtain request_idMark as failed, notify user
AsbBstCreateFromBankJobProcess bank-initiated Deposits (source=2)Mark as exception, pending manual verification
AsbBstCreateResultJob60~3 seconds eachPoll bank for Deposit result — the key factor determining crediting speed60 polls with no result → Feishu alert + manual intervention
AsbBstCreateRetryJobRetry temporarily failed Deposit requestsRetry failure → mark as terminal failure
AsbBstDepositJobAfter Deposit succeeds, execute SBA accounting (CashDepositCreate)Accounting failure → critical alert

Withdrawal task chain:

Task NameMax RetriesPoll IntervalResponsibilityFailure Handling
AsbBstTransfer10~5 seconds eachSend Withdrawal request and poll for result10 polls with no result → Feishu alert
SyncAsbBstWithdrawEvery 2 hoursPeriodically pull bank-initiated Withdrawal requestsPull failure → retry

Bank-initiated transactions (source=2) processing logic:

DirectionPull TaskPull WindowProcessing Method
DepositFetchBankRequestEvery 2 minutesAfter pulling, creates AsbBstCreateFromBankJob for processing
WithdrawalSyncAsbBstWithdrawEvery 2 hoursAfter pulling, compares against local records; creates Withdrawal Procedures for new entries

Polling Timeout Troubleshooting

When a user reports "Deposit/Withdrawal is stuck in processing," follow these steps:

  1. Check authorization status: Is the Mandate OPEN (status=2)? If not → re-authorization needed
  2. Check retry count: View retry_count in the Job record — Deposit max 60 (about 3 minutes), Withdrawal max 10 (about 50 seconds)
  3. Check bank response: If the Job record contains a bank error code, use that to pinpoint the issue
  4. Retries exhausted with no result: Contact Airstar Bank to verify the bank-side status
  5. Bank-initiated transactions (source=2): Check whether FetchBankRequest / SyncAsbBstWithdraw pull tasks are running normally

CMB/CMBC SM2 Socket Tasks

CMB and CMBC do not use polling — they communicate in real time via SM2-encrypted Socket bidirectional links:

DimensionCMB (cmb_stock_trans)CMBC (ms_stock_bank_transaction)
ConnectionSM2 Socket persistent connectionSM2 Socket persistent connection
DepositBank pushes → received in real timeBank pushes → received in real time
Withdrawalmoomoo sends → bank pushes resultmoomoo sends → bank pushes result
HeartbeatScheduled heartbeat keepaliveScheduled heartbeat keepalive
Disconnection recoverysync_bst_data_helper compensationAuto-reconnect + re-pull unprocessed records
Typical latencySub-secondSub-second
Operations intervention probabilityLow (unless Socket disconnects)Low (unless Socket disconnects)

Async Mode Comparison Across Banks

BankCommunication MethodPolling Required?User Wait TimeOperations Intervention Probability
Airstar BSTREST API (JSON)Yes (Deposit 60 / Withdrawal 10)Seconds to minutesMedium
CMB BSTSM2 Socket bidirectional linkNo (real-time push)Sub-secondLow
CMBC BSTSM2 Socket bidirectional linkNo (real-time push)Sub-secondLow
HSBC eDDAREST APIYesT+0 to T+1Medium
Hang Seng eDDAREST APIYesT+0 to T+1Medium

PM perspective: Banks that require polling result in longer user wait times and higher probability of Operations intervention during exceptions. This is why Airstar BST, though also "fully automated," may take longer from submission to crediting compared to CMB/CMBC.

Specific Job names and retry counts → BST Overview § Scheduled Tasks


Deduplication and Idempotency

The biggest fear in funds operations is "duplication" — a Deposit credited twice, a Withdrawal deducted twice. SBA establishes deduplication safeguards at multiple layers.

Three-Layer Deduplication

LayerMechanismDeduplication KeyWhat It Prevents
1. Business layerApply/Task uniquenessDeposit: flow_id + bank_type; Withdrawal: task_idPrevents duplicate Procedure creation from the same Bank Statement/task
2. SBA layerProcedure creation idempotencyprocedure_id + request_idPrevents duplicate creation from SRPC timeout retries
3. Bank layerBank-side reference numberAirstar: ASBBST prefix + sequence; CMB: bank_tx_seq; CMBC: OrgRefNoPrevents duplicate transfer instructions sent to the bank

Airstar Deduplication Example

Airstar BST's bank_ref_id uses an ASBBST prefix + globally incrementing sequence (e.g., ASBBST000012345), ensuring:

  • Deposit: The same request_id will not result in duplicate crediting — even if AsbBstDepositJob is executed repeatedly
  • Withdrawal: The same bank_ref_id will not result in duplicate transfer instructions to the bank — even if AsbBstTransfer retries on timeout

Concurrency Control

MechanismImplementationScenario
Optimistic lockProcedure's version field, update with WHERE version = ?Prevents CRM Operations and system scheduled tasks from simultaneously updating the same Procedure
Distributed lockRedis lock, key = procedure:{id}Prevents the same Procedure from being processed concurrently by multiple Workers
Idempotency checkDeposit: check if transaction_id already exists; Withdrawal: check if a Procedure for task_id already existsPrevents duplicate creation

Deduplication ensures "no extra operations." The Freeze pattern that follows ensures "no errors" — until the bank confirms success, the user's funds are always safely locked.


Freeze-Transfer-Release Pattern

Withdrawal is not as simple as "just transfer the money out." SBA uses a Freeze-Transfer-Release three-step pattern to ensure funds safety.

Why Freeze First

Between the time the system sends a Withdrawal instruction and the bank confirms success, there is a time window (ranging from seconds to hours). If funds are not frozen during this window:

  • The user could simultaneously initiate another Withdrawal or trade
  • The account could end up with a negative balance
  • Funds contention could occur

Freezing "reserves" the funds during this time window, ensuring they are not used by other operations.

Impact of Freeze on User Assets

Asset MetricBefore FreezeAfter Freeze (Withdrawal in progress)Withdrawal SucceedsWithdrawal Fails (Unfrozen)
Total assets100,000100,000 (unchanged)90,000 (decreased)100,000 (restored)
Available balance100,00090,000 (decreased by 10,000)90,000100,000 (restored)
Frozen amount010,00000

During Withdrawal processing, the user sees "available balance" decrease while "total assets" remain unchanged — this is normal Freeze behavior.

Three Outcomes

OutcomeFreeze HandlingUser PerceptionOperations Action
SuccessFreeze released, funds formally deductedBalance decreases, user receives arrival notificationNo action needed
FailureFreeze released, funds restored to availableBalance restored, user receives Withdrawal failure notificationInvestigate failure reason, notify user if necessary
TimeoutFreeze maintained, awaiting confirmationBalance not restored, user may contact customer serviceMust manually confirm bank-side status before deciding to release or deduct

Timeout Handling Flow

Timeout is the trickiest scenario — funds may have already reached the user's Bank Card (bank-side success), but moomoo hasn't received confirmation yet:

StepActionDescriptionTimeout Threshold
1Receive timeout alertFeishu notifies OperationsAirstar: after 10 polls (~50 seconds)
2Contact bank to confirmVerify the final bank-side status of this remittance
3aBank confirms successExecute SetManualTransferDone in CRM, release Freeze + formally deduct
3bBank confirms failureExecute SetManualTransferFailed in CRM, release Freeze + rollback funds
3cBank is also unsureMaintain Freeze, continue following up. Never release the Freeze prematurely

Freeze Exceptions Are Critical Alerts

If a Withdrawal fails but the Freeze is not properly released (system exception), the user's funds will be "stuck" — the balance shows as decreased but the Withdrawal didn't succeed either. This is a P0 critical alert item (Monitoring & Alerting System), requiring Operations to manually release the Freeze using CashWithdrawForceProcess.

Steps:

  1. Locate the Procedure in CRM
  2. Confirm bank-side status (not transferred / already transferred / uncertain)
  3. If bank has not transferred: CashWithdrawForceProcess → select "Rollback" → release Freeze + restore balance
  4. If bank has already transferred: CashWithdrawForceProcess → select "Complete" → release Freeze + formally deduct
  5. If bank is uncertain: do not take action, continue following up with the bank

Freeze type codes → Withdrawal Rules Handbook § Freeze Types


Procedure Lookup and Troubleshooting Guide

When a user reports "Deposit didn't arrive" or "Withdrawal is stuck in processing," Procedure is the core of issue resolution. Below are the investigation paths for Operations in CRM:

Deposit Issue Investigation

Withdrawal Issue Investigation

StepCheck ItemWhere to CheckNormal ValueException Handling
1Withdrawal Task statusCRM → Withdrawal ManagementDONE / PROCESSINGPENDING = Approval not complete
2SBA Procedure statusCRM → SBA Managementend_okLocate based on current status (see status table above)
3Procedure ext_statusProcedure detailstransfer_donePinpoint exactly which step it's stuck at
4Flow audit recordsProcedure → View HistoryStatuses progressing normally over timeFind the last Flow entry to identify the bottleneck
5reason fieldProcedure detailsEmpty (when successful)Non-empty = check the specific rejection/failure reason
6transfer_ref_idProcedure detailsBank reference numberKey identifier for bank reconciliation

Key Search Fields

Search MethodFieldUse Case
By usernn_uid (NiuNiu ID)View all Deposit/Withdrawal Procedures for a specific user
By ProcedureidDirectly locate by known Procedure ID
By bank referencetransfer_ref_id / transaction_idUsed during bank reconciliation
By timecreated_at + statusBatch investigation of exception Procedures in a time range
By Channeltransfer_methodInvestigate overall issues with a specific Channel

Common Exception Scenarios

Deposit Exceptions

#ScenarioSymptomsPossible CausesOperations Handling
1Procedure stuck at new(waiting)Deposit request created but not credited for a long timeSBA service exception; triggered manual review rule but not flaggedCheck SBA Deposit Orchestration service logs; view Flow records to confirm whether any status changes occurred

Scenario 1 Suggested Response

"Your Deposit is being processed. The system is performing funds verification, which usually completes within a few minutes. If you still have not received the funds after 30 minutes, please provide your NiuNiu ID and we will prioritize the follow-up."

| 2 | Risk Control change failure | Procedure goes from pendingend_reject | Risk Control system rejection (internal rule triggered); asset change API exception | Check the reason field, contact the Risk Control team to confirm the cause | | 3 | Duplicate Deposit | Multiple Procedures created for the same Bank Statement | Deduplication mechanism failed (network timeout retry); bank pushed duplicate Bank Statements | Reverse the excess Deposits (CashDepositReverse), keeping the correct one | | 4 | Bank refund (BST) | Airstar Bank returns REFUNDED status | Bank-side Risk Control interception; insufficient balance in user's bank account | Confirm that credited funds have been reversed; notify user of the reason | | 5 | Deposit amount mismatch | Bank Statement amount doesn't match application amount | User manually changed the amount during transfer; cross-bank fees deducted | Route to manual Matching, confirm the actual credited amount | | 6 | BST Deposit polling timeout | Airstar Deposit with no result after 60 polls | Bank system delay; network exception | Check retry_count in AsbBstCreateResultJob; contact Airstar Bank to verify |

Withdrawal Exceptions

#ScenarioSymptomsPossible CausesOperations Handling
1Freeze failureProcedure goes from new(freeze)pending(transfer_reject)Insufficient available balance; Risk Control Freeze API exceptionCheck user's available balance; if balance is sufficient but still fails, contact Risk Control team
2Deduction failureProcedure goes from new(blank)pending(transfer_reject)Risk Control asset change API timeout; Freeze released but deduction not completedCheck if Risk Control system is healthy; view Flow records to pinpoint the deduction failure point
3Bank rejects transferProcedure enters pending(return)Incorrect Bank Card details (card number/SWIFT); bank-side Risk Control interception; receiving account exceptionCheck the bank error code; confirm Bank Card details are correct; funds automatically restored
4Freeze not releasedWithdrawal fails but user balance not restoredUnfreeze request failed to send; Risk Control system did not properly handle the releaseCritical alert — use CashWithdrawForceProcess to force-release
5Polling timeout (Airstar)Procedure stuck at pending(transfer_auto)Bank system delay; network exceptionContact Airstar Bank to confirm bank-side status, then manually set success or failure accordingly
6Cross-day delayBST Withdrawal pending(move_next)Submitted outside trading hours (normal behavior)Explain trading day rules to the user. Withdrawals outside trading hours are deferred to the next trading day

Scenario 6 Suggested Response

"Your Withdrawal has been accepted. Since BST Channels process during trading hours, your Withdrawal will be automatically processed on the next trading day (Monday), with an estimated arrival in 1–2 business days. Thank you for your patience."

| 7 | Manual transfer not confirmed | Procedure stuck at pending(transfer_manual) for a long time | Operations has not completed the transfer in online banking; transfer completed but confirmation was forgotten | Confirm whether the transfer has been completed; if so, click "Confirm Transfer Complete" |

Scenario 7 Suggested Response

"Your Withdrawal is being processed. Our Operations team is completing the bank transfer. It is expected to be completed today; the arrival time depends on the receiving bank's processing speed (typically 1–3 business days)."

| 8 | Restoration failure | pending(return) stuck without transitioning to terminal state for a long time | Risk Control restoration API exception | Critical alert — user's money has "disappeared." Contact the technical team to investigate the restoration failure |


Next Steps

I want to...Go to
Learn about detailed BST bank comparisonsBST Overview
See the overall architecture and data flowSystem Architecture & Data Flow
Look up SBA Procedure status codesWithdrawal Data Dictionary
See Withdrawal Freeze and limit rulesWithdrawal Rules Handbook
Check Operations guidesManual Matching Guide, Withdrawal Approval Guide
Was this page helpful?

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