Create a collection order
POST /api/v1/collect/orders
Create a collection order and get the payment details to give to the payer.
The payer must transfer the payable amount (payable_amount), not the original amount you sent
ST Pay adds an identification tail of 0.01 to 0.99 to the original amount. For example, if the original amount is 1000.00, the payable amount might be 1000.37. ST Pay uses this exact amount to identify which order a payment belongs to. If you use json mode to display the payment screen yourself, show the payable amount clearly and remind the payer to transfer exactly this amount.
- The order expires 30 minutes after it is created (
expires_at). If no payment has been credited by then, the system rejects the order and sends a failure Callback. response_modedetermines what is returned:url: Returns the ST Pay payment page URLpayment_url. Redirect the payer to this page.json: Returns the receiving account details, and you display the payment screen yourself.
- A single member can have at most 10 pending (
pending) collection orders at the same time. Beyond that,user_active_orders_limitis returned.
Request fields
| Field | Required | Format | Description |
|---|---|---|---|
api_identity | Yes | String | The API identity issued by ST Pay |
merchant_order_no | Yes | 1–200 characters; English letters, digits, _, - | Your order number. It must be unique among your collection orders, regardless of the status of the existing order |
merchant_user_id | Either one | 1–200 characters; English letters, digits, _, - | The unique identifier of the paying member in your system. When it is sent, it is used to determine whether orders belong to the same member |
payer_name | Either one | 1–200 characters; Chinese characters, English letters, and spaces only | The payer's real name. When merchant_user_id is not sent, the name is used to determine whether orders belong to the same member (case-insensitive, ignoring all whitespace). It must not contain digits or punctuation; for example, the hyphen in Chan Tai-man will be rejected |
amount | Yes | Amount string | The original amount. The per-transaction minimum and maximum are checked against this amount (excluding the tail) |
channel_type | Yes | fps or bank_transfer | Channel type |
response_mode | Yes | url or json | Response mode; see above |
language | No | zh-TW, zh-CN, or en | Language of the payment page: Traditional Chinese, Simplified Chinese, or English. Defaults to zh-TW if omitted or empty. Affects only the payment page in url mode |
callback_url | Yes | URL, up to 500 characters | The Callback for this order is sent to this URL. It cannot be changed after the order is created. Both http and https are accepted; it must not be a local or private network address. See Callback URL |
timestamp | Yes | yyyy-MM-dd HH:mm:ss | The time the request is sent (UTC+8). Rejected if it differs from the ST Pay server time by more than 5 minutes. See Request and response format |
sign | Yes | 64 lowercase hexadecimal characters | See Signature |
You must send at least one of merchant_user_id and payer_name. An empty string or a value consisting only of whitespace is treated as not sent. If neither is sent, missing_member_identity is returned. If both are sent, merchant_user_id is used to identify the member, and the name is used for display only.
Request example
{
"api_identity": "qp_Xk3vT9aLm2QwE7rB1nZc",
"merchant_order_no": "MO20261013-0001",
"merchant_user_id": "U10086",
"payer_name": "王小明",
"amount": "1000.00",
"channel_type": "fps",
"response_mode": "url",
"callback_url": "https://shop.example.com/qpay/callback",
"timestamp": "2026-10-13 10:00:00",
"sign": "566fac06060d54d7450b41b6858b1ddf33df9d37117ab8a8c495ce748469f2b2"
}
Response fields
| Field | Present when | Description |
|---|---|---|
order_no | Always | ST Pay order number |
merchant_order_no | Always | The merchant order number you sent |
status | Always | Always pending |
payment_url | url mode | Payment page URL; see Payment page |
channel_type | json mode | fps or bank_transfer |
bank_name | json mode with bank_transfer | Name of the receiving bank |
bank_code | json mode with bank_transfer | Code of the receiving bank (a string; leading zeros are preserved) |
account_no | json mode | Full receiving account number |
account_name | json mode | Receiving account name |
payable_amount | Always | The payable amount, equal to the original amount plus the identification tail. The payer must transfer this amount |
expires_at | Always | Expiry time, equal to the order creation time plus 30 minutes |
sign | Always | Response signature, computed with the key used for this request. See Verifying responses. Use account_no and payment_url only after the signature verifies |
Response example: url mode
{
"code": "OK",
"message": "成功",
"data": {
"order_no": "C202610131000051230000",
"merchant_order_no": "MO20261013-0001",
"status": "pending",
"payment_url": "https://pay.vincoterra.com/pay/QzIwMjYxMDEzMTAwMDA1MTIzMDAwMA.v3Kd9QeLr7Zp1sWm4XyT8bN2cF6hJ0aG5uE-iOkRtYw",
"payable_amount": "1000.37",
"expires_at": "2026-10-13 10:30:05",
"sign": "7e876d9780d033c6224f52015eb15e1d1a9bbda9b75764fff0cdbf3d36b183ee"
}
}
Response example: json mode, bank transfer
The request is "merchant_order_no": "MO20261013-0002", "payer_name": "Chan Tai Man", "amount": "2000.00", "channel_type": "bank_transfer", "response_mode": "json", "callback_url": "https://shop.example.com/qpay/callback", "timestamp": "2026-10-13 10:01:17", and the signature is e20f45942090246543ab7bd95a1fecd52011699382a93637529c2aa987767848.
{
"code": "OK",
"message": "成功",
"data": {
"order_no": "C202610131001178820000",
"merchant_order_no": "MO20261013-0002",
"status": "pending",
"channel_type": "bank_transfer",
"bank_name": "The Hongkong and Shanghai Banking Corporation Limited",
"bank_code": "004",
"account_no": "123-456789-001",
"account_name": "WONG KA YAN",
"payable_amount": "2000.58",
"expires_at": "2026-10-13 10:31:17",
"sign": "4cd29b8f52d256516363af07eccfb821caaef52a10777cdc5495b809447aa175"
}
}
In json mode with the fps channel, there is no bank_name or bank_code, and account_no is the FPS receiving account.
Payment page
When you use url mode:
- The page shows the payable amount, channel type, receiving account number and account name, and expiry time. For bank transfers, it also shows the bank name and bank code.
- The payable amount, bank code, account number, and account name each have a "Copy" button.
- Once the order has ended (success, rejected, or expired), the page shows only "This order has ended" and no longer shows the receiving details. If the payer still has the page open, it switches to this automatically; no refresh is needed.
- The page is shown in the
languageyou specified when creating the order. The payer cannot change it. - The URL itself is an access credential: anyone who has the URL can see the full receiving account number. Give it only to the payer of that order, and do not write it into public logs, analytics tools, or shareable links.
- Use the returned URL exactly as it is. Do not modify it or build it yourself; any change causes the page to show 「找不到頁面」 ("page not found").
Possible errors
invalid_signature, timestamp_expired, ip_not_allowed, merchant_disabled, missing_parameter, invalid_parameter, invalid_amount, missing_member_identity, invalid_callback_url, amount_out_of_range, merchant_order_no_duplicate, user_active_orders_limit, channel_full, no_available_card, internal_error. For details, see Error codes.