CGB (China Guangfa Bank)
About This Page
What: CGB's FPS API batch withdrawal channel, FPS message types, and batch processing mechanism Audience: PMs needing to understand CGB integration details Prerequisites: Bank Capability MatrixReading time: 2 minutes Owner: Withdrawal Product Manager
Key takeaway: CGB FPS withdrawal uses a batch submission model — multiple withdrawals are packaged into one batch, the system polls for each result, up to 1500 times (spanning several hours).
Capability Overview
| Capability | Supported | Protocol/Channel | Core Service |
|---|---|---|---|
| Deposit Statements | ❌ | — | — |
| FPS Withdrawal API | ✅ | Form-URLEncoded HTTP POST (XML payload) | cgb_fps_service (Go) |
| FPS Deposit | ✅ | FPS collection | — |
| eDDA/eDDI | ❌ | — | — |
| BST | ❌ | — | — |
CGB is the only bank supporting FPS API batch withdrawal — multiple withdrawals can be submitted at once for bank batch processing.
Withdrawal: FPS API
Withdrawal Method
| Dimension | Description |
|---|---|
| Method Code | TRANSFER_METHOD_CGB_FPS_API = 'cgb_fps_api' |
| Classification | Electronic bank method (allEBankMethod) |
| Name | FPS API (CGB) |
FPS Message Types
CGB FPS completes the withdrawal lifecycle through 4 message types:
| Message Type | Purpose | Direction |
|---|---|---|
| 2063 | Single withdrawal request | moomoo → CGB |
| 2064 | Batch withdrawal request | moomoo → CGB |
| 2065 | Single withdrawal query | moomoo → CGB |
| 2066 | Batch withdrawal query | moomoo → CGB |
Single Withdrawal (2063)
| Parameter | Description | Example |
|---|---|---|
| Remote Type | Region | 01=Hong Kong, 02=Macau |
| Remit Currency | Remittance currency | HKD/CNY/MOP |
| Payee Account Type | Payee account type | BBAN/SVID/MOBN/AIIN/EMAL |
| Transaction Status | Transaction status | 0=Success, 1=Failed, 2=Processing |
Batch Withdrawal (2064)
CGB's unique batch capability, submitting up to 2000 withdrawals at once:
| Parameter | Description |
|---|---|
| Customer Batch No | Batch number (20 digits) |
| All Count | Total count (max 2000) |
| Records | Multiple Fps2064Record entries |
| Batch Status | 1=Failed, 2=Processing |
Batch Withdrawal Data Flow
Status Code Mapping
Status codes have different meanings across message types — pay attention to the distinction:
| Status Code | 2063 (Single Request) | 2065 (Single Query) | 2066 (Batch Query) |
|---|---|---|---|
| 0 | Success | Processing | Failed |
| 1 | Failed | Success | Success |
| 2 | Processing | Failed | Processing |
Note
2063 and 2065/2066 status codes have reversed meanings — in 2063, 0=Success, but in 2065, 0=Processing. Always distinguish the request type during development.
Error Handling
Batch query (2066) returns detailed information for each item:
- Success Count: Number of successful items
- Fail Count: Number of failed items
- Each failure includes an error reason code and error description
- Distinguishes payer errors (Error Type=0) from payee errors (Error Type=1)
Channel Interface Details
Channel Interface Overview
| Dimension | Description |
|---|---|
| Protocol Type | Form-URLEncoded HTTP POST (XML payload) |
| Authentication | SM2 National Crypto signing |
| Data Format | XML (UTF-8) |
| Port | 9091 (HTTPS) |
| Timeout | 30 seconds |
| Core Service | cgb_fps_service (Go) |
SM2 Signing Configuration
CGB uses the SM2 national crypto algorithm for request signing, involving the following keys:
| Key | Path | Format |
|---|---|---|
| Futu private key | conf/keys/futu.pvk | PKCS#8 |
| Futu public key | conf/keys/futu.puk | — |
| Bank public key | conf/keys/gfs.tst.puk | — |
| User ID | 16-byte string | "1234567812345678" |
Signing flow: Use Futu's private key to SM2-sign the request XML, Base64-encode the signature result and place it in the SIGN block; bank responses are verified using the bank's public key.
Interface 1: 2063 Single Withdrawal (FPS Single Payment)
Request COMMHEAD (Common Message Header):
| Field | Description | Example |
|---|---|---|
TRANCODE | Transaction code | "2063" |
CIFMASTER | Customer master number | "1000001287" |
ENTSEQNO | Sequence number (≤20 digits) | Financial unique sequence |
ENTUSERID | User ID | "100001" |
TRANDATE | Transaction date | "YYYYMMDD" |
TRANTIME | Transaction time | "HHMMSS" |
Request BODY:
| Field | Type | Required | Description |
|---|---|---|---|
REMITTYPE | string | ✅ | Remittance type. Values "01"=Hong Kong, "02"=Macau |
PAYACC | string | ✅ | Payer account. e.g. "3597601080012948" |
REMITCUR | string | ✅ | Currency. Values Hong Kong: "HKD" / "CNY", Macau: "HKD" / "MOP" |
REMITAMOUNT | decimal(16,2) | ✅ | Amount. e.g. "1000.00" |
PAYEEACTYPE | string | ✅ | Payee account type. Values "BBAN" / "SVID" / "MOBN" / "AIIN" / "EMAL" |
BENEFCORPACCT | string | ✅ | Payee account/ID. Format depends on PAYEEACTYPE |
PAYEEBANK | string | ✅ | Payee bank code. Values "359"=internal HK, or FPS bank code |
BENEFCORPNAME | string(≤140) | ✅ | Payee name |
PAYPURS | string | ✅ | Payment purpose. Values "CXBSNS"=Business, "CXSALA"=Salary, "CXMRCH"=Merchant, "CXPSNL"=Personal |
REMITMEMO | string | ❌ | Memo. ≤34 Chinese characters / 102 English characters |
MEMO | string | ❌ | Note. ≤50 Chinese characters / 150 English characters |
SIGN Block:
| Field | Description |
|---|---|
CSTID | Customer ID (16 bytes) |
SIGNVALUE | Base64-encoded SM2 signature |
Response:
| Field | Description |
|---|---|
RETCODE | Communication code: "000"=Success |
ERRORCODE | Business code: "0000"=Success |
ERRORMESSAGE | Error description |
TRACENO | Bank tracking number |
TRANSTATUS | "0"=Success, "1"=Failed, "2"=Processing |
Interface 2: 2064 Batch Withdrawal (FPS Batch Payment)
Building on the 2063 single payment, the following batch-specific fields are added:
| Field | Description |
|---|---|
CUSTOMERBATCHNO | Batch number (≤20 digits, globally unique) |
ALLCOUNT | Total count (≤2000) |
ALLAMOUNT | Total amount (decimal precise calculation, no floating point errors allowed) |
RECORD.CUSTOMERSALARYSEQ | Detail sequence number (20 characters, unique within batch) |
Each RECORD contains the same PAYEEACTYPE, BENEFCORPACCT, REMITAMOUNT fields as the 2063 single payment.
Batch Amount Validation
ALLAMOUNT must strictly equal the sum of all detail REMITAMOUNT values. The system uses decimal type for precise calculation, avoiding floating point errors that would cause the bank to reject the entire batch.
Interface 3: 2065 Single Query
| Field | Description |
|---|---|
ORIGENTSEQNO | Original sequence number (= ENTSEQNO from 2063 request) |
STARTRANSDATE | Query start date |
ENDTRANSDATE | Query end date |
Response TRANSTATUS: "0"=Processing, "1"=Success, "2"=Failed
Different Status Code Meanings
Note that 2065 query status codes have completely opposite meanings from 2063 request status codes: in 2063, "0"=Success, but in 2065, "0"=Processing. Always distinguish the request type during development and troubleshooting.
Interface 4: 2066 Batch Query
| Field | Description |
|---|---|
CUSTOMERBATCHNO | Batch number (= batch number from 2064 request) |
BATCHSTATUS | "0"=Failed, "1"=Complete, "2"=Processing |
SUCCESSCOUNT | Success count |
FAILCOUNT | Failure count |
Each detail's TRANSTATUS has the same meaning as 2065 ("0"=Processing, "1"=Success, "2"=Failed).
2066 Dual-Layer Status
The 2066 response contains two layers of status: BATCHSTATUS (batch level: 0=Failed, 1=Success, 2=Processing) and TRANSTATUS (detail level: 0=Processing, 1=Success, 2=Failed). The detail-level status has the same meaning as 2065, but is opposite to the batch-level meaning.
Idempotency Rules
CGB has strict idempotency checks for duplicate requests:
| Scenario | Behavior | Scope |
|---|---|---|
Duplicate CUSTOMERBATCHNO | Entire batch rejected | Entire batch |
Duplicate CUSTOMERSALARYSEQ within batch | Only that item fails | Single detail |
Historical duplicate CUSTOMERSALARYSEQ | That item fails | Single detail |
Idempotency Design Recommendations
CUSTOMERBATCHNOshould use "date + business sequence" format to ensure global uniquenessCUSTOMERSALARYSEQshould use the withdrawal order ID to ensure no duplicates across batches- When retrying, a new
CUSTOMERBATCHNOmust be used; the old batch number cannot be reused
Configuration
| Parameter | Value | Description |
|---|---|---|
pay_acc_hkd | "3597601080012948" | HKD payment account |
pay_acc_cny | "3597601080012939" | CNY payment account |
batch_max_count | 3 | Max items per batch (bank limit 1999, conservative setting) |
Why is batch_max_count set to 3?
Although the bank supports up to 2000 items per batch, the actual operation sets it to 3 because: withdrawals typically require per-item review and tracking, and overly large batches increase troubleshooting difficulty; if a batch fails and needs retry, smaller batches have a more controllable impact scope.
moomoo-Side Adaptation
DBQueue Asynchronous Submission: The withdrawal service doesn't call CGB API directly. Instead, it writes withdrawal instructions to DBQueue, which cgb_fps_service consumes asynchronously and submits to the bank.
Fallback Query: The system continuously polls via the DBQueue mechanism, checking incomplete transaction status every 15 seconds, with up to 1500 retries (covering approximately 6 hours).
Status Mapping (TRANSTATUS → Internal Status):
| TRANSTATUS (2065/2066) | Meaning | Internal Status |
|---|---|---|
0 | Processing | pending |
1 | Success | success |
2 | Failed | failed |
Change Guide
| Change Requirement | Modification Location | Description |
|---|---|---|
| Modify batch limit | cgb_fps_service → batch construction logic | Adjust 2000 item limit |
| Add payee account type | cgb_fps_service → 2063 request parameters | Add Payee Account Type |
| Modify query frequency | cgb_fps_service → polling configuration | Adjust 2066 query interval |
| Add currency support | cgb_fps_service → request parameters | Add Remit Currency options |
| Modify withdrawal approval template | Task.php → $stepTemplates | Adjust CGB withdrawal approval flow |
Common Customer Complaints Top 3
| # | User Feedback | Cause | CS Script |
|---|---|---|---|
| 1 | "FPS withdrawal failed" | Bank system busy (A014) or incorrect payee information | "The transfer temporarily failed, the system is automatically retrying, please wait" |
| 2 | "Withdrawal status shows unknown" | Batch query returned UNKNOWN status | "Your withdrawal is being confirmed, we will update the status as soon as possible" |
| 3 | "Withdrawal amount doesn't match application" | Batch amount aggregation calculation difference | "Please verify your withdrawal records, contact customer service if there's a discrepancy" |
Monitoring & Alerts
| Alert Item | Trigger Condition | Severity | Handling Steps |
|---|---|---|---|
| Batch send timeout | 2064 batch request unresponsive | High | System auto-degrades to single (2063) resend, check degradation logs |
| Signature verification failure | SIGN_ERROR | High | Check signing key configuration, confirm keys haven't been replaced |
| Status code misjudgment alert | 2063/2065 vs 2064/2066 status code meaning differences | Medium | Confirm message type then re-evaluate, refer to status code reversal |
After Reading
| I want to... | Go to |
|---|---|
| See CGB's position among all banks | Bank Capability Matrix |
| Understand CGB withdrawal's full approval flow | Withdrawal Lifecycle |
| Compare with another FPS withdrawal bank | SCB |
| Check FPS message type error codes | Unified Error Code Center |