T-VAN Integration
T-VAN (Tax Value Added Network) integration provides direct connection to Vietnam's Tax Authority (CQT) for tax information queries and invoice submission compliance.
Overview
| Attribute | Value |
|---|---|
| Package | @nx/t-van |
| Status | Production |
| Purpose | Direct CQT integration for tax compliance |
| Features | Tax info lookup, Invoice validation |
Key Features
- Tax information lookup - Query business tax registration details
- Invoice validation - Verify invoice authenticity with CQT
- Multi-provider support - Connect to various T-VAN providers
- Compliance ready - Meet Decree 123/2020 and 70/2025 requirements
Quick Start
1. Configure your application
typescript
// application.ts
import { NxTVanComponent, TVanBindingKeys, ITVanOptions } from '@nx/t-van';
class MyApplication extends BaseApplication {
preConfigure() {
// Configure T-VAN clients
this.bind<ITVanOptions>({ key: TVanBindingKeys.TVAN_CLIENT_OPTIONS })
.toValue({
enableControllers: true,
clients: [
{
name: 'default',
provider: 'VIETTEL',
apiKey: process.env.TVAN_API_KEY,
secretKey: process.env.TVAN_SECRET_KEY,
taxCode: process.env.COMPANY_TAX_CODE,
isProduction: process.env.NODE_ENV === 'production',
},
],
});
// Load T-VAN component
this.component(NxTVanComponent);
}
}2. Set environment variables
bash
# T-VAN Configuration
APP_ENV_TVAN_API_KEY=your-api-key
APP_ENV_TVAN_SECRET_KEY=your-secret-key
APP_ENV_TVAN_TAX_CODE=0123456789
APP_ENV_TVAN_PROVIDER=VIETTEL
APP_ENV_TVAN_IS_PRODUCTION=falseArchitecture
Component Structure
NxTVanComponent
Tax VAN integration component
Custom Bindings
TVanClientProvider→Client factory
TVanClientRegistry→Multi-client registry
Services
TVanService→Core T-VAN operations
Controllers
TVanInvoiceController→Invoice-related endpoints
TVanTaxInfoController→Tax info lookup endpoints
Integration Flow
BANA
Application
→API Call
T-VAN
Provider
→Forward
CQT
Tax Authority
1Application sends Tax Info Request to T-VAN Provider
2T-VAN forwards request to CQT (Tax Authority)
3CQT returns response to T-VAN Provider
4T-VAN returns processed result to Application
API Reference
Lookup Tax Information
Query business registration details from CQT:
typescript
import { inject } from '@venizia/ignis';
import { TVanService } from '@nx/t-van';
class TaxController {
constructor(
@inject({ key: 'services.TVanService' })
private tvanService: TVanService,
) {}
async lookupTaxInfo(taxCode: string) {
const result = await this.tvanService.getTaxInfo({
taxCode: taxCode,
});
return {
taxCode: result.taxCode,
companyName: result.companyName,
address: result.address,
representative: result.representative,
status: result.status, // ACTIVE, SUSPENDED, CLOSED
registrationDate: result.registrationDate,
};
}
}Response Example:
json
{
"taxCode": "0123456789",
"companyName": "CÔNG TY TNHH ABC",
"address": "123 Nguyễn Huệ, Quận 1, TP.HCM",
"representative": "Nguyễn Văn A",
"status": "ACTIVE",
"registrationDate": "2020-01-15",
"businessType": "Retail",
"phoneNumber": "028-1234-5678"
}Validate Invoice
Verify an invoice exists and is valid with CQT:
typescript
async validateInvoice(invoiceNumber: string, sellerTaxCode: string) {
const result = await this.tvanService.validateInvoice({
invoiceNumber: invoiceNumber,
sellerTaxCode: sellerTaxCode,
invoiceDate: new Date('2024-01-15'),
});
return {
isValid: result.isValid,
invoiceStatus: result.status, // VALID, CANCELLED, REPLACED
totalAmount: result.totalAmount,
buyerTaxCode: result.buyerTaxCode,
};
}Batch Tax Info Lookup
Query multiple businesses at once:
typescript
async batchLookup(taxCodes: string[]) {
const results = await this.tvanService.batchGetTaxInfo({
taxCodes: taxCodes,
});
return results.map(r => ({
taxCode: r.taxCode,
companyName: r.companyName,
status: r.status,
found: r.found,
}));
}REST API Endpoints
When enableControllers: true, these endpoints are available:
Tax Info Endpoints
http
# Get tax information by tax code
GET /api/t-van/tax-info/:taxCode
# Batch lookup
POST /api/t-van/tax-info/batch
Content-Type: application/json
{
"taxCodes": ["0123456789", "9876543210"]
}Invoice Endpoints
http
# Validate invoice
POST /api/t-van/invoice/validate
Content-Type: application/json
{
"invoiceNumber": "AA/24E0001234",
"sellerTaxCode": "0123456789",
"invoiceDate": "2024-01-15"
}Multi-Client Configuration
Support multiple T-VAN providers or accounts:
typescript
this.bind<ITVanOptions>({ key: TVanBindingKeys.TVAN_CLIENT_OPTIONS })
.toValue({
enableControllers: true,
clients: [
// Primary provider
{
name: 'primary',
provider: 'VIETTEL',
apiKey: process.env.VIETTEL_API_KEY,
isDefault: true,
},
// Backup provider
{
name: 'backup',
provider: 'VNPT',
apiKey: process.env.VNPT_API_KEY,
},
],
});Using Specific Client
typescript
// Use default client
const info = await this.tvanService.getTaxInfo({ taxCode });
// Use specific client
const info = await this.tvanService.getTaxInfo({ taxCode }, {
clientName: 'backup',
});Tax Status Reference
Business Status
| Status | Description | Can Issue Invoices |
|---|---|---|
ACTIVE | Operating normally | Yes |
SUSPENDED | Temporarily suspended | No |
CLOSED | Permanently closed | No |
PENDING | Registration pending | No |
Invoice Status
| Status | Description |
|---|---|
VALID | Invoice is valid and accepted |
CANCELLED | Invoice has been cancelled |
REPLACED | Invoice replaced by another |
NOT_FOUND | Invoice not found in CQT |
Error Handling
Common Errors
| Error Code | Description | Solution |
|---|---|---|
TVAN_001 | Invalid tax code format | Tax code must be 10 or 13 digits |
TVAN_002 | Tax code not found | Verify tax code exists |
TVAN_003 | Connection timeout | Retry or check network |
TVAN_004 | Provider error | Check provider status |
TVAN_005 | Rate limit exceeded | Wait and retry |
Error Handling Example
typescript
try {
const info = await this.tvanService.getTaxInfo({ taxCode });
return info;
} catch (error) {
if (error.code === 'TVAN_002') {
return { found: false, message: 'Tax code not registered' };
}
throw error;
}Vietnam Tax Compliance
When to Use T-VAN
| Use Case | T-VAN Feature |
|---|---|
| Verify customer tax code | Tax info lookup |
| Validate supplier invoices | Invoice validation |
| Check business legitimacy | Tax info lookup |
| Pre-invoice verification | Tax info lookup |
Compliance Requirements
| Requirement | T-VAN Support |
|---|---|
| Verify buyer tax code before B2B invoice | Tax info lookup |
| Validate received invoices | Invoice validation |
| Check supplier status | Tax info lookup |
Best Practices
Caching Tax Info
typescript
// Tax info doesn't change frequently - cache it
const CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hours
async getTaxInfoCached(taxCode: string) {
const cached = await this.cache.get(`tax:${taxCode}`);
if (cached) return cached;
const info = await this.tvanService.getTaxInfo({ taxCode });
await this.cache.set(`tax:${taxCode}`, info, CACHE_TTL);
return info;
}Batch Operations
typescript
// More efficient than individual lookups
const taxCodes = orders.map(o => o.customerTaxCode).filter(Boolean);
const uniqueTaxCodes = [...new Set(taxCodes)];
const taxInfoMap = await this.tvanService.batchGetTaxInfo({
taxCodes: uniqueTaxCodes,
});Related
- Tax & Invoice Module - Business requirements
- IIAPI Integration - E-Invoice management
- System Overview - Vietnam tax compliance context