A Node.js application should create a payment from its backend, save the returned reference and send only a checkout URL to the browser. After the customer attempts payment, the backend checks that same order. The gateway can report payment status; your application remains responsible for the cart, buyer identity and delivery.
Prepare a local purchase first
Authenticate the buyer and load the product from your database. Calculate the price on the server rather than accepting an amount sent by a browser form. Save a local purchase in a pending state with its product snapshot and buyer ID. Require an active Trust Gateway merchant setup and keep the API key in a server environment variable or secret store. Never ship it through a Vite or React client variable. The key storage guide explains the boundary.
Call the create endpoint from Express
This compact example demonstrates the upstream request. It assumes purchase has already been loaded for the authenticated buyer and that purchase.price came from trusted application data. Add your own database transaction, input handling and error response around it.
const key = process.env.TRUST_GATEWAY_API_KEY;
if (!key) throw new Error('Gateway configuration unavailable');
const response = await fetch('https://trustgateway.in/api/v1/orders/create', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-API-Key': key },
body: JSON.stringify({ amount: purchase.price.toFixed(2) }),
signal: AbortSignal.timeout(30000)
});
const result = await response.json();
if (!response.ok || !result.success || !result.data?.order_id) {
throw new Error('Checkout creation failed');
}
const order = result.data;
// Save order.order_id, order.amount, order.requested_amount,
// order.expires_at and order.checkout_url against purchase.id.
const checkout = new URL(order.checkout_url, 'https://trustgateway.in');
if (checkout.origin !== 'https://trustgateway.in') {
throw new Error('Unexpected checkout destination');
}
The returned checkout path is hosted by Trust Gateway. Persist the mapping before redirecting the buyer, so your server knows which purchase to check later. Keep the requested amount and exact payable amount separately; a matching adjustment can change the latter. Read the INR and paise guide before comparing money values.
Verify from the saved reference
When the customer returns or presses a “Check payment” control, load the purchase under their authenticated session. Your backend then calls GET /api/v1/orders/status/:order_id using its X-API-Key. Use the order ID stored with the purchase, never an arbitrary order ID from a query string. Require an HTTP success, paid: true, the expected order reference and the exact payable amount before fulfilment. Convert values to integer paise for comparisons.
The public checkout status is useful for displaying progress, but merchant-specific payment details require authorization. The status API documentation shows the supported response. An app redirect alone does not confirm money received.
Handle a timeout as an unknown result
If the create call times out, do not tell the customer definitely that no order exists. The request could have succeeded while its response was lost. Mark the local attempt for review and avoid a blind second create loop. If you did save a gateway reference, verify that reference before offering a new checkout. Network and JSON errors should produce a clear customer message without exposing raw upstream responses or the key.
Make delivery idempotent
Use a database transaction and unique gateway-order constraint when converting the local purchase from pending to paid. Queue delivery once. A repeated status check or webhook should see the same paid purchase and should not issue a second licence, credit or shipment. Test a duplicate callback, customer refresh, expired QR and delayed confirmation before launch. The webhook recovery guide covers retries separately.
