Order Fulfillment
After a user completes a payment, your system needs to receive a confirmation signal and deliver the goods or services (i.e., "Fulfillment").
Due to the asynchronous nature of blockchain transactions, frontend redirects cannot serve as the final basis for payment success. Webhook is the only authoritative way to confirm payment status and perform order fulfillment.
Fulfillment Flow Overview
GStable settlement speed is extremely fast (usually within 30-40 seconds), so we recommend adopting the following standard fulfillment logic:
- Listen to Webhook: Configure an endpoint on your server to receive POST requests.
- Verify Signature: Ensure the request comes from GStable to prevent forgery.
- Check Status: Decide timing of fulfillment based on event type (
paidorcompleted). - Execute Business Logic: Update order status in the database, send email, or issue entitlements.
Core Event States
In the Checkout flow, you primarily need to focus on session related lifecycle events.
1. Payment Success (session.paid)
- Trigger Timing: User has completed the transfer on-chain, and the transaction has been confirmed by the blockchain.
- Fund Status: Funds have been transferred out of the user's wallet and are undergoing cross-chain routing or consolidation.
- Recommended Action:
- Lock Inventory: Prevent overselling.
- Instant Delivery: For low-risk digital goods (such as game items, e-books), fulfillment can be done at this stage without waiting for final fund arrival.
2. Settlement Completed (session.completed)
- Trigger Timing: Funds have successfully reached the merchant's configured collection wallet address.
- Fund Status: Secure in Pocket. The transaction process is completely finished.
- Recommended Action:
- High-Value Fulfillment: For shipping physical goods, large amount top-ups, etc., it is recommended to wait for this event.
- Financial Reconciliation: Use this as the basis for revenue recognition.
Thanks to our non-custodial full-chain payment architecture, it typically takes only 30 to 40 seconds from session.paid to session.completed.
Webhook Data Structure
When an event triggers, your server will receive a POST request containing the following JSON structure.
The data structure in Payload is completely consistent with the data returned by the Query Payment Session interface.
Example: Settlement Completed Event (session.completed)
{
"eventId": "evt_i4NWz4J3QkWugyq1",
"eventType": "session.completed",
"businessType": "session",
"occurrence": "2026-01-04 02:52:38",
"isSubscribable": true,
"payload": {
// --- Session Details (Corresponds to session object in API response) ---
"sessionData": {
"sessionId": "sess_example_payment_01",
"sessionType": "chk",
"businessId": "",
"businessType": "",
"clientCode": "clt_l8ZBnpOSV9pVlaLK0dP5jsq5NzfqN3Vc",
"payer": "0xUserWalletAddress...", // Payer Wallet Address
"payerEmail": "user@example.com",
"payerEmailRequired": 1,
"paidToken": "0xTokenAddress...", // Token contract actually paid by user
"receiptId": "rcpt_txUdSs2ASditQhrr",
"recipient": "0xMerchantWalletAddress...",
"settlementToken": "polygon::usdc",
"feeModel": 1,
"amount": 15000000, // Order Amount (Micro-USD)
"lineItems": {
"items": [
{
"lineItemId": "li_example_item_03",
"itemType": "product",
"quantity": 1,
"unitPrice": 10000000,
"productData": { "productName": "Premium Membership" }
}
// ...
]
},
"expirationTime": 1767343946,
"successUrl": "https://yoursite.com/order/success",
"paymentUrl": "https://pay.gstable.io/checkout/sess_...",
"signedOnce": 1,
"initiateTx": "0xSourceTxHash...",
"completeTx": "0xTargetTxHash...",
"paymentSucceededTime": "2025-12-25 07:26:35",
"settlementSucceededTime": "2025-12-25 07:27:10",
"createAt": "2026-01-02 07:52:26",
"status": "completed",
"metadata": {
"internalOrderId": "ord_8823_xyz"
}
},
// --- Transaction Details (Corresponds to transaction object in API response) ---
"transaction": {
"orderId": "0x8a7f...",
"channelId": "da1e3483",
"orderType": 7106155,
"from": "0xUserWalletAddress...",
"to": "0xPlatformContractAddress...",
"metaData": "0x",
"totalValue": 15000000, // User Payment Total
"paymentValue": 15000000, // Order Face Value
"feeValue": 30000, // Fee (Micro-USD)
"netValue": 14970000, // Merchant Net Receipt (Micro-USD)
"sourceTx": "0xSourceTxHash...",
"targetTx": "0xTargetTxHash...",
"executeTime": "2025-12-25 07:26:35",
"finalizeTime": "2025-12-25 07:26:35"
}
}
}
Key Field Analysis
eventId: Global unique identifier for the event. Recommended for idempotency handling (i.e., if the sameeventIdis received, ignore processing to prevent duplicate shipping).payload.sessionData.metadata: Custom data you passed when creating the Session. This is the key to associating the Webhook notification with the order in your local database (internalOrderId).payload.transaction.netValue: Merchant actual received amount (Micro-USD). Please use this field for financial reconciliation.
Security & Handling
To ensure fund security, you must verify the signature of all Webhook requests on your server.
1. Verify Signature
GStable will include x-gstable-signature in the request Header. You need to use the Signing Secret obtained from the Dashboard to calculate the HMAC-SHA256 signature and compare it.
2. Idempotency Handling
Network fluctuations may cause Webhook retries. Be sure to record processed eventIds.
app.post('/webhook', (req, res) => {
// 1. Verify Signature (Refer to Webhook Development Docs)
verifySignature(req);
const event = req.body;
// 2. Idempotency Check
if (isEventProcessed(event.eventId)) {
return res.send({ received: true });
}
// 3. Process Business Logic
if (event.eventType === 'session.completed') {
const session = event.payload.sessionData;
const transaction = event.payload.transaction;
const orderId = session.metadata.internalOrderId;
const receivedAmount = transaction.netValue; // Actual received amount
// Execute Fulfillment: Update Database, Ship
fulfillOrder(orderId, receivedAmount);
}
// 4. Record Event Processed
recordEvent(event.eventId);
res.send({ received: true });
});
For detailed verification code implementation (Node.js, Python, Go, etc.) and the complete event type list, please refer to the dedicated Webhook development documentation.
Summary
You have now completed the Checkout integration!
- You created a payment session via API.
- The user completed payment on the hosted page.
- Your server confirmed receipt and completed order fulfillment via Webhook.
Now, you can go to the Dashboard to view transaction data, or continue to explore more advanced features.