1. Payment Gateway
TrustPay
en
  • en
  • zh
  • Integration Guide
  • Signature Calculation
  • Payment Gateway
    • Risk Control – Merchant Integration
    • Enums
    • Payment Callback Specification
    • 3DS Integration Guide
    • C21 Suport Regions
      • TrustPay Supported Billing Countries and US/Canada Regions
    • Whitelist Management
      • Add Card Whitelists
      • Query Card Whitelists
      • Query Card Whitelists Task
    • Card Direct Payin
      POST
    • Cashier Payin
      POST
    • Order Refund
      POST
    • Payment Callback
      POST
    • Balance
      POST
    • Order Query
      POST
    • Fee Query
      POST
    • Refund Query
      POST
  • Dispute Management
    • Dispute Enums
    • Dispute Alert
    • Dispute Alert Callback
    • Dispute Prevention (RDR)
    • Dispute Management(Chargeback)
    • Chargeback Callback
  • Credit Card Issuer
    • Available Card
      POST
    • Open Card
      POST
    • Open/Recharge Card Callback
      POST
    • Get Card Detail
      POST
    • Card Recharge
      POST
    • Order List
      POST
    • Card List
      POST
    • Transaction List
      POST
    • Fee Query
      POST
  • Physical Card Issuer
    • Create Cardholder
    • List Cardholders
    • Assign Physical Cards
    • List Assigned Physical Cards
    • Query Card Balance
    • Query Card Transactions
    • Query Account
    • Card Charge
  • Schemas
    • VCardDetail
    • VOrderDetail
  1. Payment Gateway

3DS Integration Guide

This guide is for merchants integrating C21 3D Secure through the TrustPay direct card payment API. Continue using your existing payment request and signature process. When TrustPay returns status=20, direct the cardholder to challenge_url, then confirm the final payment result through an order query or a verified webhook notification.
Version: 29 October 2026, integration testing edition. Before testing, confirm the API base URL, merchant credentials, and availability of 3DS for your assigned channel with TrustPay. The behavior described here applies to environments where this capability has been enabled. Domains, card details, signatures, and order references in the examples are placeholders or illustrative values.

1 Integration flow#

1.
Your backend submits the order, card details, and billing information to the card payment API.
2.
If no cardholder action is required, handle the returned order status as usual. If action is required, TrustPay returns status=20 and challenge_url.
3.
Your frontend opens the URL in the cardholder's browser. The TrustPay page handles device data collection and any required bank authentication.
4.
Your backend confirms the final result through an order query or a webhook with a verified signature, then updates your order idempotently.
3DS may complete without user interaction or require an action such as entering a verification code or approving a request in a banking app. The absence of a bank challenge screen does not mean authentication failed. Returning from an authentication page does not, by itself, prove payment success.
For merchants using TrustPay hosted checkout, the checkout handles the verification page. Continue using the existing create order, open checkout, webhook, and order query flow. The examples below focus on direct card payments.

2 API conventions and authentication#

ItemRequirement
API base URLUse the environment URL provided by TrustPay, referred to below as TRUSTPAY_API_BASE
HTTP methodPOST
Request and response formatUTF-8 JSON
HeadersContent-Type: application/json and X-Api-Key: YOUR_API_KEY
Signature fieldsign in the request JSON
Amount unitMajor currency units; order_amount: 10 means USD 10, not 10 cents
Merchant identityDetermined by the API key; no additional merchant ID is required in the request bodies below
Keep your API key and secret on your backend. Your backend must sign and send payment requests and order queries.

Signature rules#

1.
Exclude the sign field.
2.
Exclude fields whose values are null or an empty string. Include numeric 0 and Boolean false.
3.
Sort the remaining fields by field name in ascending order.
4.
Join the original values as key1=value1&key2=value2. Do not URL-encode the values.
5.
Append &secret=YOUR_SECRET.
6.
Calculate the MD5 hash of the UTF-8 string and output lowercase hexadecimal.
Convert amounts from their actual JSON numeric values: for example, the number 10.00 becomes 10 in the signature string. Include nonempty fields such as payment_success_url and payment_failed_url. The request examples use scalar fields only; you do not need to add a nested browser object for this integration.
Example signature input for an order query:
order_no=MCH-3DS-20261029-001&secret=YOUR_SECRET

3 Create a card payment#

Request example#

{
  "order_no": "MCH-3DS-20261029-001",
  "order_amount": 10,
  "currency": "USD",
  "notify_url": "https://merchant.example.com/webhooks/trustpay",
  "payment_success_url": "https://merchant.example.com/payment/result?order_no=MCH-3DS-20261029-001",
  "payment_failed_url": "https://merchant.example.com/payment/result?order_no=MCH-3DS-20261029-001",
  "card_number": "TEST_CARD_NUMBER",
  "card_expiry": "2028-07",
  "card_cvv": "TEST_CVV",
  "card_holder_first_name": "Jane",
  "card_holder_last_name": "Doe",
  "card_holder_email": "jane@example.com",
  "card_holder_phone": "14155550100",
  "billing_address_street": "123 Test Street",
  "billing_city": "San Francisco",
  "billing_state": "CA",
  "billing_postal_code": "94105",
  "billing_country": "US",
  "client_ip": "PAYER_PUBLIC_IP",
  "sign": "CALCULATED_SIGNATURE"
}
Replace the card placeholders with the test card details provided by TrustPay, replace client_ip with the cardholder's actual public IP address, and then calculate the signature. The placeholder values cannot be submitted as a valid payment.
FieldRequirement and description
order_noRequired. Your merchant order reference. Keep the same reference throughout the payment flow
order_amount, currencyRequired. This C21 integration currently uses USD
card_number, card_cvvRequired. Card number and a three- or four-digit CVV
card_expiryRequired. TrustPay JSON uses YYYY-MM, for example 2028-07
card_holder_first_name, card_holder_last_nameRequired. The cardholder's first and last names
Cardholder email, phone, and billing address fieldsProvide complete details for C21. Use digits only for phone numbers and a two-letter country code. Use a valid two-letter state or province code for US and Canadian addresses
client_ipRequired when customer IP collection is enabled for the merchant. Supply the cardholder's actual IP address
notify_urlOptional, recommended. Your backend endpoint for payment result notifications
payment_success_url, payment_failed_urlOptional HTTPS URLs. The verification page can offer a return to the relevant merchant result page. Query the order through your backend after the customer returns
signRequired. Generate it using Section 2
You do not need to call a 3DS preparation endpoint before the initial payment or provide browser, three_ds_session_id, or attempt_id. TrustPay collects browser information on the verification page when needed.
Save the signed JSON as payment-request.json, then submit it from your backend:
Do not configure unconditional automatic retries for payment submissions. If a request times out, query the original order first.

4 Payment responses and order statuses#

The outer code describes the API business result. data.status describes the order status. Neither HTTP 200 nor code=880001 alone proves that a payment succeeded.

Cardholder action required#

{
  "code": 880001,
  "message": "success",
  "data": {
    "order_no": "MCH-3DS-20261029-001",
    "platform_order_no": "TRUSTPAY_ORDER_ID",
    "currency": "USD",
    "order_amount": 10,
    "paid_amount": 0,
    "fee": 0.5,
    "reserve": 1,
    "status": 20,
    "challenge_url": "https://checkout.example.com/3ds/SESSION_ACCESS_TOKEN"
  }
}
Amounts, fees, and reserve values are illustrative. Use the actual response and your configured pricing. platform_order_no is the TrustPay order ID.
Status 20, named 3ds_pending, means the payment requires cardholder action. The URL may begin with device data collection or display a bank challenge immediately. Certain recovery scenarios may ask the cardholder to re-enter the CVV. Status 20 is not a payment failure and must not trigger a new payment submission.

Successful payment example#

A successful result may be available in the initial payment response or a later order query, depending on whether further authentication is required. The following example uses the card payment response structure:
{
  "code": 880001,
  "message": "success",
  "data": {
    "order_no": "MCH-3DS-20261029-001",
    "platform_order_no": "TRUSTPAY_ORDER_ID",
    "currency": "USD",
    "order_amount": 10,
    "paid_amount": 10,
    "fee": 0.5,
    "reserve": 1,
    "status": 5
  }
}

Statuses relevant to this flow#

statusMeaningMerchant action
1Pending payment or processingShow a pending state and continue querying. Do not fulfill the order or submit another charge based on this status
20Waiting for cardholder action for 3DSOpen challenge_url in the browser and keep the original order
5Paid; funds awaiting releaseTreat the payment as successful. Fund availability follows the applicable settlement rules
6Paid; funds releasedTreat the payment as successful
17SettledThe order has reached settlement. Do not repeat fulfillment or other completed business actions
3Payment failedDisplay the failure reason. A new payment requires an explicit customer action
4Order timed outHandle the timeout without automatically submitting another charge
18Accounting review pendingKeep the result unconfirmed and contact TrustPay. Do not treat it as successful or automatically charge again
This table covers common statuses for this flow. Continue using the existing rules for refunds, reversals, disputes, and other later lifecycle events. Do not classify every unlisted status as either success or failure. Do not use status=2 as your sole success criterion for this C21 pay-in integration.

5 Handle challenge_url in the frontend#

challenge_url is the complete URL of a TrustPay hosted verification page. Use the URL returned by the API without constructing it yourself or parsing its token. Open it in the cardholder's browser; do not call it as a backend payment API. A full-page browser redirect is recommended for compatibility with bank authentication screens.
The function below illustrates response handling. Implement showMessage and refreshOrderFromMerchantBackend in your application. The input is the TrustPay response forwarded by your backend.
When your result page loads, query your backend for the order result. Do not display a paid state solely because the URL contains “success” or because the customer returned from verification.
URLRecipientPurpose
challenge_urlCardholder's browser opens a TrustPay pagePerform the required device collection or authentication
payment_success_url, payment_failed_urlMerchant frontendReturn to your result page, which then queries your backend
notify_urlMerchant backendReceive payment result webhook notifications
C21 returnUrlTrustPayReceive the bank authentication return and continue payment completion
You do not need to implement the C21 returnUrl endpoint or handle bank JWTs, stepUpUrl, DeviceData, or Authenticate3DSPayment.

6 Query orders and receive notifications#

Query the original order#

Request:
{
  "order_no": "MCH-3DS-20261029-001",
  "sign": "CALCULATED_SIGNATURE"
}
Calculate the query signature from the query request fields. Do not reuse the signature from the payment creation request.
Relevant response fields when verification is still required:
{
  "code": 880001,
  "message": "success",
  "data": {
    "order_no": "MCH-3DS-20261029-001",
    "platform_order_no": "TRUSTPAY_ORDER_ID",
    "type_id": 0,
    "merchant_id": 10001,
    "currency": "USD",
    "order_amount": 10,
    "paid_amount": 0,
    "status": 20,
    "challenge_url": "https://checkout.example.com/3ds/CURRENT_ACCESS_TOKEN"
  }
}
Other query response fields are omitted from this example. Treat 5 and 6 according to their successful payment meanings, and continue waiting for 1. During an interactive flow, consider querying every few seconds, then reducing the frequency. Stop polling completed orders and comply with the rate limits agreed for your environment.

Webhook notifications#

Continue using your existing notify_url. A separate 3DS notification endpoint is not required. Payment notifications are sent as POST JSON. Example successful payment notification:
{
  "type": 0,
  "merchant_id": 10001,
  "order_no": "MCH-3DS-20261029-001",
  "order_amount": 10,
  "paid_amount": 10,
  "balance_amount": 9.5,
  "fee": 0.5,
  "status": 5,
  "reason": "payment received",
  "pay_time": "2026-10-29T04:00:00Z",
  "sign": "CALCULATED_NOTIFICATION_SIGNATURE"
}
Verify the signature over the actual received nonempty fields using Section 2. Validate the merchant, order, and amount, record the result idempotently, and return HTTP 200. Notifications may be repeated. Acknowledge an already processed notification without repeating fulfillment or accounting actions.
balance_amount follows the existing payment notification definition; it does not mean all funds are immediately available.
Obtain status=20 and challenge_url from the payment response or order query. Do not wait for a webhook to begin verification. If a notification is not received, query the original order to confirm the result.

7 Recovery and integration testing#

SituationRequired handling
The customer closes the verification page or returns to your siteQuery the original order. If it still returns 20 with a URL, offer a “Continue verification” button
An old link expiresQuery the original order from your backend and use the currently returned link. A fresh access link does not guarantee that expired authentication material can be recovered
The order is processing with no verification linkKeep showing a pending state and continue querying. Do not construct a URL or force a new 3DS flow
HTTP timeout, 403, 502, or a channel errorKeep the original order reference and verify its result. A network error alone does not prove that no charge occurred
Status 20 is returned without a linkQuery the original order. Contact TrustPay if this persists; do not automatically charge again
Payment remains unconfirmed after authenticationContinue querying. Completing a verification code or bank challenge does not itself prove payment success
Before testing, confirm that the test account, C21 channel, and 3DS page are available. The verification page and return endpoint must be reachable from the cardholder's browser.
Cover the following scenarios during integration testing:
Payment succeeds without customer interaction.
Status 20 is returned, the customer completes verification, and the order query confirms success.
Device data collection completes and payment succeeds without a bank challenge.
The customer cancels, authentication fails, or the flow times out.
The customer closes the page and resumes verification through the original order.
A payment request times out and the original order is queried without creating a duplicate charge.
Repeated notifications do not repeat business actions.
The customer returns before final confirmation and sees a pending state.
Before going live, the merchant and TrustPay should jointly confirm that the complete flow works with the actual payment channel.
Modified at 2026-10-28 19:33:00
Previous
Payment Callback Specification
Next
TrustPay Supported Billing Countries and US/Canada Regions
Built with