Go live
When your integration works end to end in development, a few steps move it to production: link your real bank account, connect your real e-invoice account, switch keys and environment, make sure your handlers are strict, then test with a small real transfer. This page walks through each step and ends with what to watch once you are live.
Before you start
Make sure the whole flow works in development:
- A payment created from your checkout reaches
paidafter a simulated transfer. - Your IPN handler verifies the signature, updates the order once, and answers
2xx. - Partial payments, overpayments, expiry and late money behave the way you want (see the test scenarios).
- If you issue invoices, a sandbox invoice reaches
issued.
Nothing carries over between environments: bank accounts, matching settings, payments, invoice providers and integration keys all have to exist in production too.
1. Link your real bank account
Switch the dashboard to production (the environment bar on top of the Payments pages, Switch to production), then open Payments settings → Bank accounts → Add bank account and pick your bank:
| Bank | What you need |
|---|---|
| MB Bank | The account number, the holder's name as MB has it, and the national ID or tax code the account was opened with. MB texts a code to the holder's registered phone |
| BIDV | Register BIDV's balance notification service for the account at BIDV, then add the account. It activates when BIDV sends its first message |
| ACB | The account number. The holder then consents on ACB's page; the consent lasts up to 180 days |
| Pay2S | The account linked on Pay2S, a Hook pointing at the URL shown in the form, and the Hook's token |
The details are in Bank connections. Then set the matching settings for the production account again: the payment code prefix, your own order code format, and which transfers transaction.received reports.
The person who receives the bank's code or consents on the bank's page must be the account holder, or someone they authorized. Plan the link for a time they are available.
2. Connect your e-invoice provider
If you issue invoices, open Payments settings → Invoice providers in production and connect your real Mắt Bão account: the tax code, API user and password from "Cấu hình API" in the Mắt Bão portal. Pick the template and series registered for your business, and choose what happens when a paid order asks for an invoice: stop at the draft, or send it for approval.
Then send the connection's callback URL to Mắt Bão support, so that changes made on their side reach Ha Tang at once. See E-invoices.
3. Switch keys and environment
| Setting | Development | Production |
|---|---|---|
| Environment | Hatang-Environment: development or SDK environment: "development" | Remove the header and the option (or send production) |
| IPN secret key | sk_test_… | sk_… from Payments settings → Integration keys in production |
| Webhook secret | whsec_… | The same endpoint serves both environments; keep its secret |
| API key | ht_… with payments:read, payments:write | The same key works; create a separate one per server if you prefer |
Keep these values in configuration, not in code:
HATANG_API_KEY=ht_123...
HATANG_SECRET_KEY=sk_123... # production secret key, for IPN
HATANG_WEBHOOK_SECRET=whsec_123... # webhook endpoint secret
# HATANG_ENVIRONMENT unset in production
4. Check your endpoints
- Your
ipn_urland webhook endpoint are https on the public internet, answer2xxwithin 10 seconds (15 for webhooks), and do not redirect. - They read the raw body for verification (no JSON middleware before it).
- The webhook endpoint is subscribed to the events you need, for example
payment.succeeded,payment.overpaid,transaction.received,bank_connection.revoked,invoice.failed. - Trust the signature, not the caller's IP address.
5. Make your handlers strict
Your handler must:
- Verify the signature with the production key, and reject anything that does not verify.
- Check
environmentisproduction; a development payment must never unlock a real order. - Compare
paid_amountwith the order total. - Dedupe on the IPN
idor the webhooksvix-id. - Move the order forward only, whatever order the calls arrive in.
Before you hand over goods after the payer returns to return_url, confirm on the server with GET /payments/{id} or the SDK's payments.verify().
6. Test with a small real transfer
- Create a payment in production for a small amount, for example 10,000 VND, with your real
ipn_url. - Pay it from your own banking app by scanning the QR.
- Check that the payment becomes
paid(for ACB, allow up to 10 minutes: Ha Tang reads its history on that cycle), that your IPN arrived (GET /payments/{id}/ipn-deliveries), and that the transfer is listed under Payments → Transactions. - If the order asked for an invoice, check it reaches
issuedand has a number. - Then test the mistakes: pay a second small payment without the code and confirm that
transaction.receivedarrives withpayment_id: null.
The money lands in your own account; nothing needs refunding through Ha Tang.
7. Watch it once you are live
| What to watch | Where |
|---|---|
| IPN calls that keep failing | GET /payments/{id}/ipn-deliveries (status: "exhausted"), and the payment page |
| Webhook deliveries that fail | GET /webhooks/{id}/deliveries, and Webhooks in the dashboard |
| A bank account that stops working | bank_connection.revoked and bank_connection.needs_reauth webhooks; the account's status and last transaction under Bank accounts |
| ACB consent expiry | The connection's consent.expires_at; link the account again before it passes |
| Stuck calls to banks or the invoice provider | Payments → Integration health |
| Invoices that failed or were rejected | invoice.failed, invoice.tax_rejected webhooks, and the alert emails Ha Tang sends to owners and admins |
| Money in without an invoice | Payments → Invoice reconciliation, and the daily email at 08:00 |
| Transfers the bank never reported | Import a statement for the missing days |
Launch checklist
- The real bank account is linked and
activein production. - The production account's matching settings are set.
- The e-invoice provider is connected in production, with the right template, and Mắt Bão has the callback URL.
- The production secret key and the webhook secret are configured on your server.
- The
Hatang-Environment: developmentheader (or the SDK option) is gone from production. - Your handlers check the signature,
environment, the amount and duplicates, and move orders forward only. - The IPN and webhook URLs are public
httpsand answer2xxwithin 10 seconds. - A small real transfer went through end to end.
- Someone watches failed deliveries,
bank_connection.*events and invoice alerts.