Integrate the UI SDK (Frontend)
Besides redirecting users directly to the Checkout URL, Tingee provides a Frontend SDK that lets you embed the payment experience directly in your website as a Popup (Modal). This keeps customers on your site and optimizes your conversion rate.
1. Install the SDK
Add the SDK with a <script> tag in your HTML (e.g. the index.html of your React/Vue/Angular app). Use the URL for the environment you are developing against (UAT or PROD):
UAT environment:
<script src="https://uat-payment-gateway.tingee.vn/js/tingee.js"></script>
PROD environment:
<script src="https://payment-gateway.tingee.vn/js/tingee.js"></script>
2. Global Setup
For your app to run smoothly, configure the SDK only once, right when your app starts.
Use Tingee.Setup(config) to define the event listeners (callbacks) shared across your whole website.
// Initialize at startup (e.g. in index.js, main.ts, or App.tsx)
window.Tingee.Setup({
// Display settings (optional)
size: 'medium', // 'small' | 'medium' | 'large' (default 'medium')
// Transaction succeeded
onSuccess: function(data) {
console.log("Thanh toán thành công!", data);
window.location.href = "/checkout/success";
},
// Transaction failed / expired
onFailed: function(error) {
console.error("Giao dịch thất bại hoặc hết hạn", error);
},
// The user cancelled (clicked the X button)
onCancelled: function() {
console.log("Người dùng đã hủy thanh toán.");
},
// The payment window closed (whether the payment succeeded or failed)
onClose: function() {
console.log("Popup thanh toán đã được đóng.");
}
});
3. Open the payment window
After your Backend calls the Create payment link API and returns the Checkout URL, just call Tingee.Url.Open() to show the popup.
// checkoutUrl comes from your backend API (e.g. https://pay.tingee.vn/checkout?token=xxx&s=yyy)
const checkoutUrl = "https://pay.tingee.vn/checkout?...";
// Show the Popup
window.Tingee.Url.Open(checkoutUrl);
(You can also pass a configuration object as the second argument of Open to override the global configuration for this transaction only).
4. Framework integration examples
Below are examples of the Global Setup and the Open call for popular frontend frameworks:
- React
- Angular
- Vue 3
import React, { useEffect } from 'react';
// If you use TypeScript, you may need a global declaration to avoid errors
// declare global { interface Window { Tingee: any; } }
export default function App() {
// 1. Global configuration when the app starts
useEffect(() => {
// Make sure the script in index.html has finished loading
if (window.Tingee) {
window.Tingee.Setup({
size: 'medium',
onSuccess: (data: any) => {
console.log("Thanh toán thành công", data);
// Navigate with React Router
// navigate('/success');
},
onCancelled: () => console.log("Khách hàng hủy"),
});
}
}, []);
// 2. Pay button handler
const handlePayment = async () => {
try {
// Simulate calling your internal API to get the Checkout URL
const response = await fetch('/api/create-payment');
const { checkoutUrl } = await response.json();
// Open the Popup
if (window.Tingee) {
window.Tingee.Url.Open(checkoutUrl);
} else {
alert("Không tìm thấy SDK Tingee!");
}
} catch (error) {
console.error("Lỗi tạo thanh toán", error);
}
};
return (
<div>
<h1>Giỏ hàng</h1>
<button onClick={handlePayment}>Thanh toán ngay</button>
</div>
);
}
import { Component, OnInit } from '@angular/core';
declare var Tingee: any; // Declaration to avoid TypeScript errors
@Component({
selector: 'app-root',
template: `
<h1>Giỏ hàng</h1>
<button (click)="handlePayment()">Thanh toán ngay</button>
`
})
export class AppComponent implements OnInit {
// 1. Global configuration when the app starts
ngOnInit() {
if (typeof Tingee !== 'undefined') {
Tingee.Setup({
size: 'medium',
onSuccess: (data: any) => {
console.log("Thanh toán thành công", data);
// this.router.navigate(['/success']);
},
onCancelled: () => console.log("Khách hàng hủy")
});
}
}
// 2. Pay button handler
async handlePayment() {
try {
// Simulate calling your internal API to get the Checkout URL
const checkoutUrl = await this.paymentService.createLink();
// Open the Popup
Tingee.Url.Open(checkoutUrl);
} catch (error) {
console.error("Lỗi tạo thanh toán", error);
}
}
}
<script setup>
import { onMounted } from 'vue';
// 1. Global configuration when the app starts
onMounted(() => {
if (window.Tingee) {
window.Tingee.Setup({
size: 'medium',
onSuccess: (data) => {
console.log("Thanh toán thành công", data);
// router.push('/success');
},
onCancelled: () => console.log("Khách hàng hủy"),
});
}
});
// 2. Pay button handler
const handlePayment = async () => {
try {
// Simulate calling your internal API to get the Checkout URL
const response = await fetch('/api/create-payment');
const { checkoutUrl } = await response.json();
// Open the Popup
window.Tingee.Url.Open(checkoutUrl);
} catch (error) {
console.error("Lỗi tạo thanh toán", error);
}
};
</script>
<template>
<div>
<h1>Giỏ hàng</h1>
<button @click="handlePayment">Thanh toán ngay</button>
</div>
</template>
5. Benefits of using the SDK
- Users never leave the page: The whole QR scan or card entry happens in the popup, and users always see your website in the background.
- Event-driven: Your website knows exactly when the user closes the popup or when the payment succeeds, so it can update the interface right away (e.g. cart, notifications) without reloading the page.