Channel Execution Manual
About This Page
What: The complete technical execution process for each withdrawal channel from Remittance through to bank confirmation Audience: Product managers who need to understand "how money gets from system to bank", and those evaluating the impact of channel modifications Prerequisites: Withdrawal LifecycleReading time: 5 minutes Owner: Withdrawal Product Manager
Key Takeaway: All withdrawal channels ultimately execute through SBA orchestration. BST channels are fully automated (seconds~minutes to arrive), non-BST channels require ops to manually operate in bank online banking and then confirm completion.
SBA Orchestration: The Central Hub for Funds
All withdrawal channels ultimately execute through SBA (Server Bank Account). SBA is the internal fund orchestration system — responsible for orchestrating freeze, deduction, transfer instructions, and tracking their status.
SBA Procedure State Machine
Each withdrawal corresponds to a Procedure (orchestration flow) in SBA:
SBA Sub-status (ext_status)
There are only 5 main statuses, but sub-statuses are the key to precisely tracking progress. Below are the most commonly used sub-statuses; for the complete list see Withdrawal Data Dictionary § SBA Sub-status.
| Main Status | Sub-status | PM Perspective |
|---|---|---|
| new | waiting | User can still cancel the withdrawal in the App at this point |
| new | manual_confirm | Requires ops confirmation in CRM |
| pending | deduct_done | Funds deducted, waiting to initiate transfer |
| pending | transfer_auto | BST: System is sending instruction to bank |
| pending | transfer_manual | Non-BST: Waiting for ops to operate in bank online banking |
| pending | transfer_done | Bank confirmed receipt of instruction |
| pending | transfer_reject | Bank rejected the withdrawal instruction |
| end_ok | transfer_done | Withdrawal complete |
User Cancellation Window
Users can only cancel the withdrawal in the App when ext_status = waiting. Once it enters deduct_done, funds have been deducted and the user cannot cancel on their own — only ops can initiate a reversal.
If requirements change: Extending SBA sub-statuses
Code location: withdraw/src/app/Business/SOA/Srpc/WithdrawRPC.php defines all EXT_STATUS_* constants
Sub-statuses are the protocol between SBA (Python service) and withdrawal service (PHP). Modifying sub-statuses requires both sides to update in sync.
BST Channel
BST is the only channel that takes the fully automated path.
BST Authorization Prerequisite
Users must first complete BST authorization (Mandate) before using BST:
| Bank | Authorization Model | Characteristics |
|---|---|---|
| CMB/CMBC | Traditional BST agreement | Only "signed/unsigned" two states |
| Airstar | Mandate authorization | 6 states; one authorization binds 3 markets (HK/US/HKCC) |
Authorization status must be OPEN for deposit/withdrawal. The Confirm step validates this.
Execution Methods
| Bank | Service | Protocol | Result Retrieval |
|---|---|---|---|
| CMB | cmb_stock_trans | Socket binary | Real-time push |
| CMBC | ms_stock_bank_transaction | Socket binary | Real-time push |
| Airstar | Airstar BST API | REST + JSON | Polling |
BST withdrawal follows a Freeze-Transfer-Release three-step process:
- SBA freezes an equivalent amount in the user's available balance
- Sends withdrawal instruction to bank
- Upon receiving result: success deducts and releases freeze; failure rolls back and releases
Result Retrieval Methods
CMB/CMBC and Airstar obtain bank results in completely different ways:
CMB/CMBC: Results are pushed in real-time via Socket bidirectional link, typically completing in seconds. On timeout (callback code -5), automatically switches to backup exit_server for retry.
Airstar: Results obtained via REST API in two-phase polling:
| Phase | Event | Strategy | Cumulative Duration |
|---|---|---|---|
| Fast polling | AsbBstTransfer | Query every 5 seconds, max 10 times | ~50 seconds |
| Fallback sync | SyncAsbBstWithdraw | Continuously sync incomplete instructions within 2-hour window | Up to 2 hours |
| Timeout | — | Mark abnormal, requires ops to manually query Airstar API | — |
What is exit_server
exit_server is the Socket communication address for CMB/CMBC BST. Each bank is configured with primary and backup addresses; when the primary times out, the system automatically switches to the backup for retry.
Balance Deduction
When Remittance executes, it first calls autoOut() to deduct the withdrawal balance from the auto_settings table:
- Below
alarm_amount→ Sends Feishu alert - Below
stop_amount→ Automatically closes auto-withdrawal for that currency; all subsequent degrade to manual
Deduction happens before the bank transfer — even if the bank rejects, the balance has been deducted. Ops must manually restore.
BST Exception Handling
| Exception | Trigger | System Behavior | Ops Action |
|---|---|---|---|
| CMB/CMBC timeout (-5) | Socket timeout | Switch to backup exit_server for retry | Usually no intervention needed |
| CMB/CMBC rejection (-6) | Bank rejection | Mark as failed | Contact bank to confirm reason |
| Airstar polling timeout | Still PENDING after 10 polls | Enter 2-hour fallback sync | Wait, monitor alerts |
| Airstar sync timeout | Still PENDING after 2 hours | Mark abnormal | Manually query Airstar API |
| Airstar instruction failure | Returns FAILED | Release frozen funds | Check 140630xxx error code |
| Authorization exception | Mandate not OPEN | Confirm step blocks advancement | Guide user to re-authorize |
Online Banking Channel (HSBC / Hang Seng)
Ops transfers via bank corporate online banking, confirms completion in CRM.
eDDI ≠ Withdrawal
eDDA/eDDI is a deposit protocol (direct debit for deposit). HSBC/Hang Seng withdrawals go through corporate online banking, not eDDI.
Flow:
- Confirm step calls
startTransfer()→ SBA returnstransfer_manual - Ops sees "pending remittance" task in CRM
- Ops logs into bank corporate online banking and executes transfer
- After successful transfer, clicks confirm at CRM Remittance step
- Task → DONE
FPS Channel
BOC / Standard Chartered FPS
Standard semi-auto flow, similar to the online banking channel — ops triggers then confirms in CRM.
FPS limit: HKD / CNH amounts < 1 million use FPS. >= 1 million upgrades to CHATS/RTGS.
Payee name requirement: FPS channel must use full name (unlike CHATS/TT which can use abbreviated names).
CGB FPS (Batch Submission + Async Polling)
CGB FPS is the closest to fully automated among semi-auto channels — it has an API interface but requires ops to trigger:
Polling interval (increasing):
| Attempt Range | Interval |
|---|---|
| 1~100 | 10 seconds |
| 101~200 | 20 seconds |
| 201~300 | 30 seconds |
| 301~1000 | 40 seconds |
Maximum polling can reach hours. Data stored in task_cgb_fps table.
If requirements change: Connecting a new FPS channel
- Create Go service to interface with bank FPS API
- Create new
XxxFpsBiz.phpin PHP (referenceCgbFpsBiz.php) - Create new polling event
SyncXxxFpsResult - Add channel constant in
Method.php - Create new
task_xxx_fpstable for API status storage
Traditional Channels
CHATS/RTGS (File Export)
Withdrawal through Hong Kong interbank clearing system; ops exports file then uploads to bank system.
Trigger conditions:
- Virtual bank + USD withdrawal
- Virtual bank + HKD/CNH amount >= 1 million
- Fall-through when non-BST bank + FPS unavailable
Fee: USD $8 / HKD $25 / CNY $25 (user prompted with popup when confirming withdrawal, requires explicit user consent).
Flow:
- Ops selects pending remittance tasks in CRM
- System generates RTGS/CHATS format file
- Ops uploads file to bank system (offline operation)
- Bank completes processing, confirm in CRM
File notes:
- Payee name: Can use abbreviated name
FUTU SECURITIES INTL (HK) LTD(full name not required) - Payee name limited to 140 characters (truncated with warning if exceeded)
- Amount unit is cents (multiplied by 100)
- Name obtained from
nick_listtable, English name preferred
If requirements change: Adjusting file format
Code location: withdraw/src/app/Business/Withdraw/ExportRTGSCHATSFile.php
The file format is a fixed format required by the bank; modifications need bank confirmation.
Cross-border Wire Transfer (tele_transfer / ewb)
Purely manual channel. Ops operates cross-border remittance in bank online banking, then confirms in CRM. setTransferDone() passes method = null (SBA routes by configuration).
NSS Name Screening: Cross-border wire transfers require passing NSS (Name Screening Service) to check the payee name before execution, confirming it's not on sanctions lists. Withdrawals failing NSS require manual escalation, with ops contacting the compliance team.
Payee name rule: Cross-border wire/TT can use abbreviated name FUTU SECURITIES INTL (HK) LTD.
Cheque (check)
The most traditional channel with the slowest arrival time.
Operational flow:
- Ops issues cheque based on withdrawal task information
- Requires 2 authorized signatories (dual-signature policy)
- Delivered to bank daily in the afternoon by designated staff
- Record cheque number (
check_extratable) - Confirm in CRM
Applicable scenario: Final fall-through option when same-bank transfer, FPS, and CHATS/RTGS are all unavailable.
Channel Comparison Summary
| Dimension | BST | CGB FPS | Other FPS/Online Banking | Traditional |
|---|---|---|---|---|
| startTransfer timing | Remittance | Confirm | Confirm | Confirm |
| SBA ext_status | transfer_auto | transfer_manual | transfer_manual | transfer_manual |
| Result retrieval | Push (CMB/CMBC) / Polling (Airstar) | Polling (1000 times) | CRM manual confirm | CRM manual confirm |
| Completion trigger | Auto-complete | Polling auto-complete | Ops confirmation | Ops confirmation |
| Maximum wait | Seconds (CMB/CMBC) / ~2 hours (Airstar) | Hours | Depends on ops | Depends on ops |
| Requires ops | No (fully automated) | Trigger submission | Bank operation + confirm | Bank operation + confirm |
If requirements change: Making a manual channel semi-automated
Core transformation: Replace CRM manual confirmation with API polling. Reference the CGB FPS pattern:
- Interface with bank API (submit transfer + query status)
- Create polling queue event
- Remittance step takes async path for that channel
startTransfer()timing and SBA ext_status do not need changes
Channel Method Groups
Method groups in the code determine CRM display and operation patterns:
| Group | Included Channels | Purpose |
|---|---|---|
| allEBankMethod() | manual, boc, hase, hsbc, boc_fps, cgb_fps_api, chats_rtgs, sc | Online banking class (8 types) |
| allTeleMethod() | tele_transfer, ewb | Cross-border wire class (2 types) |
| allSetMethod() | Online banking class + check (9 types) | Confirm step selectable channels |
| allTabMethod() | allSetMethod + ewb + tele_transfer (11 types) | CRM Tab pages |
| all() | All 12 types | All withdrawal channels |
Why auto_bs is not in allSetMethod
BST is automatically routed by the system and does not require ops manual selection. Only when method = null does ops need to select a channel from allSetMethod.
Common Misconceptions
| Misconception | Fact |
|---|---|
| "SBA is a bank" | No. SBA (Server Bank Account) is the internal fund orchestration system, responsible for freeze, deduction, transfer instruction orchestration and status tracking. All withdrawal channels ultimately execute through SBA |
| "All BST banks use the same technology" | No. CMB/CMBC use Socket bidirectional link (SM2 encryption, real-time result push); Airstar uses REST API (JSON, polling for results). Timeout handling and polling strategies are completely different |
| "HSBC/Hang Seng withdrawals use eDDA" | They do not. eDDA/eDDI is only for deposit direct debit. HSBC/Hang Seng withdrawals go through corporate online banking transfer, unrelated to eDDA |
| "FPS withdrawal is fully automated" | No. CGB FPS has an API interface but still requires ops to trigger submission; BOC/SCB FPS is entirely manually operated. Only BST is fully automated |
What to Read Next
| I want to... | Go to |
|---|---|
| Understand the complete flow from approval to execution | Withdrawal Lifecycle |
| See auto-withdrawal conditions and limit rules | Withdrawal Rules Manual |
| Troubleshoot a channel exception | Withdrawal Troubleshooting |
| Push a channel-related requirement change | Withdrawal Change Guide |
| Look up SBA status codes, callback codes | Withdrawal Data Dictionary |
| Deep dive into the three BST banks | BST Overview |