Transfer
Description
Initiate a direct channel transfer (merchant balance to a payee, e.g. marketing rewards, reimbursements, commission settlement).
Transfer is a direct channel capability: channel (wechat/alipay/douyin) and the corresponding channelMchNo (channel merchant number) are required.
Idempotency: the idempotency key is channel + merchant transfer number (bizTransferNo) + merchant number. Duplicate requests with the same combination are rejected (noDuplicate). A failed transfer keeps the failed record — retry by resubmitting with the same bizTransferNo (the original order is reused); no need to change the number.
Request
POST /unipay/transfer
- Auth: RSA signature (
@PaymentVerify) - Response:
DaxResult<TransferCreateResult>
Parameters
Common params same as Pay - Common Parameters. Business parameters:
| Parameter | Type | Required | Max | Description |
|---|---|---|---|---|
| channel | string | Yes | — | Transfer channel (wechat / alipay / douyin) |
| channelMchNo | string | Yes | 32 | Channel merchant number (credential assembly and channel routing) |
| bizTransferNo | string | Yes | 100 | Merchant transfer number (idempotency key, unique per merchant per channel; reuse the same number to retry a failed transfer) |
| amount | long | Yes | — | Transfer amount in cents (min 1 cent, max 100 million yuan) |
| title | string | No | 100 | Transfer title |
| reason | string | No | 200 | Transfer reason / remark |
| payeeType | string | Yes | 32 | Payee account type (see table below) |
| payeeAccount | string | Yes | 100 | Payee account |
| payeeName | string | No | 100 | Payee name (WeChat rules below) |
| attach | string | No | 500 | Merchant custom data (returned as-is in callback) |
| notifyUrl | string | No | 200 | Async notification URL |
| reportInfos | object[] | No | — | Transfer scene report info (required for some WeChat scenes, see below) |
| transferScene | string | No | 32 | Transfer scene identifier (Alipay / Douyin, see below) |
payeeType Codes (channel × payee type)
Corresponds to backend enum TransferPayeeTypeEnum. Supported values differ per channel:
| payeeType | Description | Alipay | Douyin | |
|---|---|---|---|---|
| openid | WeChat / Douyin user openid | ✅ | — | ✅ |
| user_id | Alipay user ID (starts with 2088) | — | ✅ | — |
| open_id | Alipay openid | — | ✅ | — |
| login_name | Alipay login account (phone / email) | — | ✅ | — |
| phone | Douyin phone number (passed via payeeAccount) | — | — | ✅ |
transferScene and reportInfos (channel differences)
| Channel | transferScene | reportInfos |
|---|---|---|
| Not used — the transfer scene bound in channel merchant config applies | Required for some scenes (e.g. marketing rewards): infoType is a fixed Chinese label in the WeChat protocol (e.g. 活动名称), infoContent is merchant-provided; left empty the channel does fallback validation | |
| Alipay | Transfer scene config ID (the scene opened on the channel side, e.g. 1001 general transfer) | Not used |
| Douyin | Scene enum code (channel master data, selected by the caller, e.g. 1001) | Not used |
WeChat payeeName Rules
- Amount less than 0.3 yuan: must be empty
- Amount >= 2000 yuan: required (must match the payee's real name)
- Otherwise: optional
Request Example
{
"mchNo": "M200000001",
"appId": "APP001",
"reqId": "REQ20241201040",
"reqTime": "2024-12-01 12:40:00",
"sign": "Base64Signature",
"channel": "alipay",
"channelMchNo": "2088xxxxxxxxxxxx",
"bizTransferNo": "TRANS20241201001",
"amount": 10000,
"title": "Commission settlement",
"reason": "December promotion commission",
"payeeType": "user_id",
"payeeAccount": "2088yyyyyyyyyyyy",
"transferScene": "1001",
"notifyUrl": "https://your-domain.com/notify"
}Response
DaxResult<TransferCreateResult>, the data field:
| Parameter | Type | Description |
|---|---|---|
| transferNo | string | Platform transfer number |
| bizTransferNo | string | Merchant transfer number |
| status | string | Transfer status (see table below; normal returns are processing or success) |
| confirmUrl | string | Confirm-receive URL (returned only for WeChat transfers awaiting payee confirmation; send it to the payee to open in WeChat; empty when the platform gateway URL is not configured) |
Transfer Status (PayFundStatusEnum)
| status | Description |
|---|---|
| init | Initialized (transfer order created, not yet sent to channel) |
| processing | Processing (accepted by channel / WeChat awaiting payee confirmation) |
| success | Transfer succeeded |
| fail | Transfer failed (retry by reusing the original bizTransferNo) |
| close | Transfer closed (only for channels supporting close, via the merchant panel) |
| cancel | Cancelled |
Response Example
{
"code": 0,
"msg": "success",
"data": {
"transferNo": "TF2024120112345700001",
"bizTransferNo": "TRANS20241201001",
"status": "processing"
},
"sign": "Base64Signature",
"resTime": "2024-12-01 12:40:00",
"reqId": "REQ20241201040"
}Best Practices
- Retry on failure: when channel validation fails (e.g. payee info mismatch, insufficient balance), the endpoint returns an error response and the record is marked failed — resubmit with the same
bizTransferNoto retry on the original order. - WeChat payee confirmation: after a successful initiation returns
processing, the payee must openconfirmUrl(or the platform transfer confirm page) to accept; unaccepted transfers are returned by the channel after timeout. Poll final status via Sync Transfer. - Async notification: the platform pushes the final state to
notifyUrl(eventstransfer.success/transfer.fail/transfer.close); if no notification arrives, call Sync Transfer. - Query: use Query Transfer Order for the full record; failed orders include the channel-side
errorMsg.