Skip to content

PRD: E-invoice provider integration (iiapi / T-VAN)

ModuleTax & Invoice (CORE-10)PRD IDPRD-INV-002
StatusShippedOwnerTax & Invoice squad
Date2026-04-13Versionv1.0
Packages@nx/invoice · @nx/iiapi · @nx/t-van · @nx/coreURDCFG · INV

TL;DR

Lets a merchant connect a legal Vietnamese e-invoice provider (VNPAY / VNIS via iiapi) once, with credentials stored encrypted, then issue numbered e-invoices automatically the moment a payment succeeds. A single provider seam handles both seller tax-info lookup and invoice issuance, so every completed sale can become a compliant invoice - captured with its tax-authority code and tracked end-to-end - without manual paperwork.

1. Context & Problem

Merchants selling in Vietnam must issue legal electronic invoices and submit them to the tax authority. Before this increment KICKO resolved seller tax info through a direct T-VAN integration and had no first-class invoice package, so there was no way to connect an e-invoice provider per merchant, store its credentials safely, or turn a completed payment into an issued invoice with an auditable status.

This increment stands up a dedicated invoice package and the iiapi provider client, connecting a provider per merchant, and migrates tax-info resolution from T-VAN onto iiapi so a single provider seam handles both tax-info lookup and invoice issuance. This is the foundation for legal e-invoicing - a hard regulatory requirement for the HKD/SME segment KICKO targets.

2. Goals & Non-Goals

Goals

  • Stand up the invoice package and the iiapi provider client; connect a provider per merchant via merchantId / connection link.
  • Store provider credentials encrypted and require an explicit clientName (no implicit default client).
  • Configure issuance per invoice type (serial / category / policy) and route sale channels to a provider config, with a guided onboarding flow.
  • Drive the issuance lifecycle from a successful payment through Kafka + BullMQ queues, capturing the invoice number and tax-authority (CQT) code.
  • Process inbound provider webhooks (with a per-config webhook toggle) to update invoice status.
  • Migrate tax-info resolution from T-VAN to iiapi as the single provider seam.

Non-Goals

  • Multiple invoice providers beyond the current iiapi / T-VAN set.
  • PDF rendering of the invoice (produced provider-side).
  • Tax-rate calculation at sale time (owned by the pricing engine).
  • Tax declaration / filing automation.

3. Success Metrics

MetricTarget / signal
Issuance coverageSuccessful payments that produce an issued invoice in the configured mode
Issuance reliabilityIssuance success rate after the retry policy; failures land in the audit trail, never silently dropped
Credential safety100% of provider credentials stored encrypted; zero plaintext at rest
Tax-authority captureIssued invoices that capture an invoice number + CQT code
Webhook freshnessProvider webhooks reconcile invoice status without manual intervention

4. Personas & Use Cases

PersonaGoal in this feature
OwnerConnect a provider, configure issuance per invoice type, route channels, complete onboarding
ManagerMonitor issuance status and the audit trail; retry / adjust where allowed
CashierTrigger manual export for an order's invoice at the counter
System (payment)Emit payment success that queues issuance automatically

Core scenarios: an owner connects an iiapi provider with encrypted credentials and an explicit clientName → configures serial/category/policy per invoice type and routes each sale channel → a payment succeeds → the invoice is queued via Kafka/BullMQ, issued, and its number + CQT code captured → inbound webhooks reconcile status; tax-info lookup runs through the same iiapi seam.

5. User Stories

  • As an owner, I want to connect an e-invoice provider per merchant with encrypted credentials and an explicit client name, so issuance is secure and unambiguous.
  • As an owner, I want a guided onboarding flow to configure serial/category/policy per invoice type and route sale channels, so setup is correct without deep tax knowledge.
  • As an owner, I want a completed payment to automatically queue and issue the invoice, so compliant invoices are produced without manual work.
  • As a manager, I want issuance failures to retry per policy and be visible in an audit trail, so nothing is silently lost.
  • As a cashier, I want to manually export an order's invoice at the counter, so I can issue on demand when needed.
  • As an owner, I want a single provider seam to resolve seller tax info and issue invoices, so I configure one connection rather than two integrations.

6. Functional Requirements

#RequirementURD ref
FR-1Create a merchant invoice profile linked to the seller tax identityURD-CFG-001
FR-2Connect a provider (VNPAY / VNIS via iiapi) per merchant via merchantId / link, with credentials stored encrypted and an explicit clientName requiredURD-CFG-002
FR-3Configure per invoice type the serial, category, tax method, and issuance policyURD-CFG-003
FR-4Route each sale channel to the provider config that should issue its invoicesURD-CFG-004
FR-5Configure a retry policy (max retries + delay schedule) for failed issuanceURD-CFG-005
FR-6Share an invoice profile across branches; guided onboarding wizard for provider setupURD-CFG-006..007
FR-7Queue an invoice for issuance automatically on a successful payment, via Kafka + BullMQURD-INV-001
FR-8Issue the invoice via the provider and capture its number + tax-authority (CQT) code; track status (pending → processing → success / failed / cancelled)URD-INV-002..003
FR-9Retry a failed issuance per the configured policy; submit the issued invoice to the tax authority (CQT via T-VAN) when enabledURD-INV-004..005
FR-10Record an immutable audit-trail entry for every invoice eventURD-INV-006
FR-11Adjust, replace, or cancel an issued invoice with a reasonURD-INV-007..008
FR-12Process inbound provider webhooks (per-config webhook toggle) to update invoice statusURD-INV-009

Full requirement text and acceptance criteria live in the Tax & Invoice URD. This PRD references them rather than restating them.

7. Non-Functional Requirements

AreaRequirement
Credential securityProvider credentials are stored encrypted at rest; no plaintext secrets
Data integrityThe invoice audit trail is append-only; status changes are recorded, never overwritten
Tenancy & authzProvider connection and configs are scoped per merchant (x-merchant-id); credential changes are owner-gated
ResilienceIssuance is driven through Kafka + BullMQ queues with a configurable retry policy; failures are captured, not dropped
IdempotencyWebhook and queue processing tolerate redelivery without double-issuing
i18nUser-facing labels/statuses are bilingual ({ en, vi })

8. UX & Flows

Key screens (in apps/client): the iiapi-configs provider-connection management, the per-invoice-type serial/category/policy editor, channel routing, and the guided invoice onboarding flow.

9. Data & Domain

EntityRole
MerchantInvoiceProfileMerchant's invoicing setup, linked to the seller tax identity
InvoiceProviderThe connected provider (iiapi) per merchant - vaults encrypted credentials, clientName
InvoiceProviderConfigPer invoice-type serial / category / policy and retry settings
InvoiceConfigMappingRoutes a sale channel to the provider config that issues its invoices
InvoiceThe issued e-invoice - number, CQT code, status
InvoiceAuditTracingImmutable event trail for every invoice state change

Conceptual only - full schema and invariants in the invoice domain model.

10. Dependencies & Assumptions

Depends on

  • Seller tax identity (URD-TAX) - the invoice profile links to the merchant's MST, name, and address.
  • Payment (payment.success) - a successful payment is what queues issuance.
  • iiapi provider gateway (@nx/iiapi) - issues the legal invoice and delivers webhooks.
  • T-VAN tax-authority network (@nx/t-van) - CQT submission, validation, and the tax-info seam being migrated onto iiapi.
  • Kafka + BullMQ - the queue transport between payment success and issuance.

Assumptions

  • The merchant has registered a seller tax identity (MST).
  • The merchant holds valid provider credentials and a clientName for the connection.
  • A sale channel is routed to an active provider config before issuance.

11. Risks & Open Questions

Risk / questionMitigation / status
Provider rejects or times out during issuanceRetry policy (max retries + delay) per config; failures recorded in the audit trail
Duplicate issuance on queue / webhook redeliveryIdempotent queue and webhook processing; status tracked per invoice
Credential leakageCredentials stored encrypted; changes owner-gated
Single provider set (iiapi / T-VAN)Accepted for this increment; multi-provider is a Non-Goal, deferred to P2
T-VAN → iiapi tax-info migration regressionsSingle seam validated against existing tax-info sync before cutover

12. Release Plan & Launch Criteria

AspectPlan
PhaseP1 (foundation) - see URD feature catalog for CFG and INV
RolloutAll merchants; enabled per merchant on provider connection
MigrationTax-info resolution migrated from T-VAN to iiapi (single provider seam)
Launch criteriaConnect provider (encrypted creds + clientName) → configure per-type serial/policy → payment success queues + issues an invoice with number + CQT code → webhook reconciles status; tax-info lookup verified on iiapi
MonitoringIssuance success/failure rate, retry depth, webhook reconciliation lag, queue backlog

13. FAQ

Does issuing an invoice require manual action? No - by default a successful payment automatically queues and issues the invoice. Manual export at the counter and scheduled batch issuance are additional modes (URD-MOD).

Where are provider credentials stored? Encrypted at rest, scoped per merchant, with an explicit clientName - there is no implicit default client.

What happens if the provider rejects an issuance? It is retried per the configured policy (max retries + delay). If it still fails, the status is failed and the failure is recorded in the audit trail.

Why migrate tax-info from T-VAN to iiapi? So a single provider seam handles both seller tax-info lookup and invoice issuance - one connection to configure instead of two integrations.

Can I use a provider other than VNPAY / VNIS? Not in this increment - additional providers beyond the iiapi / T-VAN set are a Non-Goal, planned for P2.

References

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.