ST Pay Merchant APIST Pay Merchant API
Guide
API
Error codes
Back office
AI-assisted integration
  • 繁體中文
  • 简体中文
  • English
Guide
API
Error codes
Back office
AI-assisted integration
  • 繁體中文
  • 简体中文
  • English
  • Getting started

    • Overview
    • Request and response format
    • Authentication and IP whitelist
    • Signature
    • Merchant back office
    • AI-assisted integration
  • API

    • Create a collection order
    • Create a payout order
    • Order query
    • Callback notifications
  • Reference

    • Order status and amounts
    • Duplicate requests and confirming results
    • Error codes
    • Bank codes
    • Go-live checklist

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_mode determines what is returned:
    • url: Returns the ST Pay payment page URL payment_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_limit is returned.

Request fields

FieldRequiredFormatDescription
api_identityYesStringThe API identity issued by ST Pay
merchant_order_noYes1–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_idEither one1–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_nameEither one1–200 characters; Chinese characters, English letters, and spaces onlyThe 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
amountYesAmount stringThe original amount. The per-transaction minimum and maximum are checked against this amount (excluding the tail)
channel_typeYesfps or bank_transferChannel type
response_modeYesurl or jsonResponse mode; see above
languageNozh-TW, zh-CN, or enLanguage 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_urlYesURL, up to 500 charactersThe 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
timestampYesyyyy-MM-dd HH:mm:ssThe 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
signYes64 lowercase hexadecimal charactersSee 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

FieldPresent whenDescription
order_noAlwaysST Pay order number
merchant_order_noAlwaysThe merchant order number you sent
statusAlwaysAlways pending
payment_urlurl modePayment page URL; see Payment page
channel_typejson modefps or bank_transfer
bank_namejson mode with bank_transferName of the receiving bank
bank_codejson mode with bank_transferCode of the receiving bank (a string; leading zeros are preserved)
account_nojson modeFull receiving account number
account_namejson modeReceiving account name
payable_amountAlwaysThe payable amount, equal to the original amount plus the identification tail. The payer must transfer this amount
expires_atAlwaysExpiry time, equal to the order creation time plus 30 minutes
signAlwaysResponse 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 language you 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.

Next
Create a payout order