<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nguyễn Hương</title>
    <description>The latest articles on DEV Community by Nguyễn Hương (@nguyenhuong2026).</description>
    <link>https://dev.to/nguyenhuong2026</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4127694%2F15c40b6f-be81-4d11-ae0e-e7d03f659f2b.jpg</url>
      <title>DEV Community: Nguyễn Hương</title>
      <link>https://dev.to/nguyenhuong2026</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nguyenhuong2026"/>
    <language>en</language>
    <item>
      <title>QR payment gateway with multi-channel balance alerts</title>
      <dc:creator>Nguyễn Hương</dc:creator>
      <pubDate>Tue, 06 Oct 2026 04:55:12 +0000</pubDate>
      <link>https://dev.to/nguyenhuong2026/qr-payment-gateway-with-multi-channel-balance-alerts-403a</link>
      <guid>https://dev.to/nguyenhuong2026/qr-payment-gateway-with-multi-channel-balance-alerts-403a</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi6tiw052gpb3z11yde6z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi6tiw052gpb3z11yde6z.png" alt=" " width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When every bank-transfer order needs someone watching the banking app
&lt;/h2&gt;

&lt;p&gt;For many online stores, accepting bank transfers is still a manual job. The customer sends the money, then a screenshot. The seller opens the banking app, scrolls through transactions, and only then confirms the order.&lt;br&gt;
This approach has four weak spots:&lt;br&gt;
• Slow: customers wait for confirmation, and orders stall outside business hours.&lt;br&gt;
• Error-prone: several orders share the same amount, and customers mistype the transfer note or send too little.&lt;br&gt;
• Risky: a screenshot does not prove the money actually reached the account.&lt;br&gt;
• Hard to coordinate: sales, warehouse and accounting all need to know the money is in, but only the account holder can see the banking app.&lt;br&gt;
PionPay's payment gateway solves this with one simple principle. Customers just scan. The moment the money lands, the balance alert is already where you work.&lt;/p&gt;
&lt;h2&gt;
  
  
  How does the PionPay payment gateway work?
&lt;/h2&gt;

&lt;p&gt;Going from scan to confirmed order takes 5 steps, and none of them are manual:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A payment QR code is created for the order. It holds the receiving account, the amount and the transfer note for that order.&lt;/li&gt;
&lt;li&gt;The customer scans it with their banking app and confirms. There is no account number or amount to type, so fewer mistakes.&lt;/li&gt;
&lt;li&gt;The money arrives in the linked bank account. PionPay records the balance change instantly.&lt;/li&gt;
&lt;li&gt;PionPay sends an alert to the channels you have set up: Telegram, Zalo, Google Sheets or a webhook on your online store.&lt;/li&gt;
&lt;li&gt;The order is confirmed automatically as soon as the customer pays. The transaction is also categorized and recorded in your income and expense log.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;PionPay connects withbanks, including VPBank, BIDV, ACB, TPBank and PGBank. All your accounts come together in a single dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feqgafvkzbzp0y4i9yidz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feqgafvkzbzp0y4i9yidz.png" alt=" " width="660" height="163"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Where do alerts go? Pick the channels that fit how you work&lt;br&gt;
Everyone in a store needs to hear about incoming money in a different way. Owners want it on their phone, accountants need records, and the website needs a signal to update orders on its own. PionPay sends each balance change to the right channel for each need.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0kirssp2websve1jh3la.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0kirssp2websve1jh3la.png" alt=" " width="798" height="236"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the Business plan, the balance sharing feature lets several people see incoming payments without anyone being given access to the banking app.&lt;br&gt;
For developers: receiving webhooks on your online store&lt;br&gt;
If you run your own website or sales software, the webhook moves orders to "Paid" automatically. Each time the balance changes, PionPay sends an HTTP request to the URL you register. The example below uses Node.js (Express). Field names are for illustration only, so follow PionPay's integration documentation when you build it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import express from "express";

const app = express();
app.use(express.json());

const processed = new Set(); // in production: a DB table with a unique key on the transaction ID

app.post("/webhooks/pionpay", async (req, res) =&amp;gt; {
  // 1. Verify the sender as described in the integration guide
  if (!isFromPionPay(req)) return res.sendStatus(401);

  // 2. Illustrative field names
  const { transactionId, amount, description } = req.body;

  // 3. Process each transaction only once
  if (processed.has(transactionId)) return res.sendStatus(200);
  processed.add(transactionId);
  res.sendStatus(200); // respond right away, run business logic afterwards

  // 4. Match the order code in the transfer note (e.g. DH123456)
  const orderCode = description?.toUpperCase().match(/DH\d{6}/)?.[0];
  if (orderCode) await markOrderPaid(orderCode, amount, transactionId);
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few tips for the integration:&lt;br&gt;
• Always verify the sender before updating an order. Do not trust every request that reaches your webhook URL.&lt;br&gt;
• Check the amount against the order total, and handle underpayments and overpayments separately.&lt;br&gt;
• Send transactions with no matching order code to a manual review queue. Never guess which order they belong to.&lt;br&gt;
Get started with the PionPay payment gateway&lt;br&gt;
Both plans include the payment gateway and Webhook/API:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Business: VND 50,000/month&lt;br&gt;
1 bank account, balance sharing, payment gateway, Webhook/API&lt;br&gt;
Individual: VND 99,000/month&lt;br&gt;
1 account, unlimited transactions, payment gateway, Webhook/API&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can start accepting payments automatically in 4 steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sign up for a PionPay account.&lt;/li&gt;
&lt;li&gt;Link the bank account that receives payments.&lt;/li&gt;
&lt;li&gt;Choose where to get alerts: Telegram, Zalo, Messenger, Google Sheets or webhook.&lt;/li&gt;
&lt;li&gt;Create a QR code for each order and send it to your customer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;From then on, customers just scan and PionPay takes care of the rest. Sign up now at pionpay.vn, or message PionPay on Facebook &lt;/p&gt;

</description>
      <category>qr</category>
      <category>webdev</category>
      <category>pionpay</category>
      <category>payment</category>
    </item>
    <item>
      <title>Xác thực OTP ngân hàng trên PionPay: kết nối mà không cần đưa mật khẩu</title>
      <dc:creator>Nguyễn Hương</dc:creator>
      <pubDate>Wed, 30 Sep 2026 03:45:11 +0000</pubDate>
      <link>https://dev.to/nguyenhuong2026/xac-thuc-otp-ngan-hang-tren-pionpay-ket-noi-ma-khong-can-dua-mat-khau-4cij</link>
      <guid>https://dev.to/nguyenhuong2026/xac-thuc-otp-ngan-hang-tren-pionpay-ket-noi-ma-khong-can-dua-mat-khau-4cij</guid>
      <description>&lt;p&gt;Khi kết nối một tài khoản ngân hàng với hệ thống thanh toán, thông tin đăng nhập luôn là điều được quan tâm nhất. PionPay chọn phương thức xác thực trực tiếp bằng OTP từ ngân hàng để bạn không phải giao tài khoản và mật khẩu ngân hàng cho bên thứ ba.&lt;/p&gt;

&lt;h2&gt;
  
  
  Xác thực OTP ngân hàng trên PionPay là gì?
&lt;/h2&gt;

&lt;p&gt;Xác thực OTP ngân hàng là phương thức kết nối tài khoản trong đó bạn xác nhận bằng mã OTP (mật khẩu dùng một lần) do chính ngân hàng gửi tới, thay vì cung cấp tài khoản và mật khẩu đăng nhập. OTP có hiệu lực rất ngắn và chỉ dùng được một lần, nên là lớp xác thực an toàn cho thao tác kết nối.&lt;/p&gt;

&lt;p&gt;Với cách này, bạn chủ động thực hiện bước xác thực, còn PionPay hạn chế tối đa việc tiếp nhận và lưu giữ thông tin đăng nhập ngân hàng của bạn trong quá trình kết nối.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quy trình kết nối bằng OTP gồm những bước nào?
&lt;/h2&gt;

&lt;p&gt;Quy trình kết nối đơn giản và do bạn tự thực hiện, gồm năm bước:&lt;/p&gt;

&lt;p&gt;Chọn ngân hàng cần kết nối trong danh sách hỗ trợ.&lt;br&gt;
Nhập các thông tin cần thiết theo yêu cầu để bắt đầu kết nối.&lt;br&gt;
Nhận mã OTP do ngân hàng gửi tới số điện thoại/kênh xác thực của bạn.&lt;br&gt;
Nhập OTP để xác thực ngay trên bước kết nối.&lt;br&gt;
Hoàn tất kết nối, tài khoản sẵn sàng nhận thông báo biến động số dư.&lt;/p&gt;

&lt;p&gt;Toàn bộ mã OTP do bạn nhận và nhập, không phải đọc hay gửi cho nhân viên nào. Đây là điểm cần nhớ để tránh nhầm với các chiêu lừa yêu cầu "đọc mã OTP".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fff4v7uadeka3hra5htul.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fff4v7uadeka3hra5htul.png" alt=" " width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Vì sao không phải đưa mật khẩu ngân hàng cho bên thứ ba lại quan trọng?
&lt;/h2&gt;

&lt;p&gt;Không đưa mật khẩu và OTP cho bên thứ ba là nguyên tắc bảo mật cơ bản mà cả ngân hàng lẫn cơ quan chức năng liên tục khuyến cáo. Cơ quan công an khuyến cáo khách hàng tuyệt đối không cung cấp cho bất kỳ ai các thông tin dịch vụ ngân hàng gồm tài khoản đăng nhập, mật khẩu và mã OTP, ngay cả khi người yêu cầu tự xưng là nhân viên ngân hàng (Nguồn: cơ quan Công an, ANTV, 2025).&lt;/p&gt;

&lt;p&gt;Ở cấp quy định, Thông tư 50/2024/TT-NHNN yêu cầu đơn vị cung cấp dịch vụ Online Banking phải hướng dẫn khách hàng bảo vệ OTP và nhận diện các tình huống lừa đảo, giả mạo (Nguồn: Thời báo Ngân hàng, 2025). Phương thức xác thực OTP trực tiếp từ ngân hàng của PionPay đi theo đúng tinh thần này: giảm số lượng thông tin nhạy cảm mà bạn phải chia sẻ khi kết nối.&lt;/p&gt;

&lt;h2&gt;
  
  
  PionPay bảo vệ thông tin đăng nhập của bạn thế nào?
&lt;/h2&gt;

&lt;p&gt;PionPay được thiết kế để hạn chế tiếp xúc với thông tin đăng nhập ngân hàng của bạn, dựa trên các nguyên tắc sau:&lt;/p&gt;

&lt;p&gt;Không yêu cầu mật khẩu ngân hàng: bạn xác thực bằng OTP do ngân hàng gửi, không phải cung cấp mật khẩu đăng nhập cho PionPay.&lt;br&gt;
Không lưu mật khẩu: hệ thống không lưu giữ mật khẩu ngân hàng của bạn.&lt;br&gt;
Không thao tác chuyển tiền: kết nối phục vụ nhận thông tin biến động số dư, không dùng để chuyển tiền trên tài khoản của bạn.&lt;br&gt;
Dữ liệu được mã hóa khi lưu và khi truyền.&lt;br&gt;
Tiêu chuẩn an toàn thông tin: PionPay đã đạt chứng chỉ ISO/IEC 27001:2022 (phạm vi phát triển, gia công và kinh doanh phần mềm).&lt;/p&gt;

&lt;p&gt;Nói cách khác, bạn được chủ động hơn trong việc bảo vệ thông tin đăng nhập, còn thao tác kết nối vẫn đơn giản.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kết nối ngân hàng an toàn hơn cùng PionPay
&lt;/h2&gt;

&lt;p&gt;Xác thực bằng OTP giúp bạn kết nối ngân hàng đơn giản hơn trong thao tác và chủ động hơn trong việc bảo vệ thông tin đăng nhập. Vào PionPay để kết nối tài khoản và bắt đầu nhận thông báo biến động số dư, hoặc gọi hotline 0981.690.369 nếu cần hỗ trợ.&lt;/p&gt;

</description>
      <category>pionpay</category>
    </item>
    <item>
      <title>What Is a Webhook? A Practical Guide (Plus a Real-World Bank Transfer Use Case)</title>
      <dc:creator>Nguyễn Hương</dc:creator>
      <pubDate>Wed, 30 Sep 2026 02:57:14 +0000</pubDate>
      <link>https://dev.to/nguyenhuong2026/what-is-a-webhook-a-practical-guide-plus-a-real-world-bank-transfer-use-case-kpd</link>
      <guid>https://dev.to/nguyenhuong2026/what-is-a-webhook-a-practical-guide-plus-a-real-world-bank-transfer-use-case-kpd</guid>
      <description>&lt;p&gt;Have you ever written something like this?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;js
setInterval(async () =&amp;gt; {
  const res = await fetch('https://api.example.com/orders/123/status');
  const { status } = await res.json();
  if (status === 'paid') {
    // Finally!
  }
}, 5000);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every 5 seconds you ask the server: "Anything new?" And 99% of the time the answer is "Nope." It wastes requests, burns resources, and is still slow.&lt;/p&gt;

&lt;p&gt;Webhooks exist to solve exactly this problem. In this post we'll cover:&lt;/p&gt;

&lt;p&gt;What a webhook is and how it works&lt;br&gt;
Webhooks vs. polling&lt;br&gt;
Building a webhook endpoint in Node.js (with signature verification)&lt;br&gt;
Best practices for reliable, secure webhooks&lt;br&gt;
A very practical use case: getting near-instant bank balance notifications with PionPay&lt;/p&gt;
&lt;h2&gt;
  
  
  1. What is a webhook?
&lt;/h2&gt;

&lt;p&gt;A webhook is an HTTP callback. When an event happens in system A, system A proactively sends an HTTP request (usually a POST) to a URL you provided, carrying data about that event.&lt;/p&gt;

&lt;p&gt;In short: instead of you asking over and over, the other system tells you when something happens.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Real-life analogy: You order something online.&lt;br&gt;
Polling = walking to the front door every 10 minutes to check if the courier has arrived.&lt;br&gt;
Webhook = leaving your phone number so the courier calls you when they're outside.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Webhooks are often called a "reverse API" or "push API", because the direction is flipped: instead of the client calling the server, the server calls the client.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. How do webhooks work?
&lt;/h2&gt;

&lt;p&gt;A webhook flow has four steps:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs2f51os6taogzxhklcta.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs2f51os6taogzxhklcta.png" alt=" " width="708" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Register: You give the provider a public URL (an endpoint) to receive data.&lt;/li&gt;
&lt;li&gt;Event happens: Someone pushes code, a payment succeeds, money lands in an account...&lt;/li&gt;
&lt;li&gt;Deliver: The provider sends a POST request with a payload (usually JSON) to your URL.&lt;/li&gt;
&lt;li&gt;Acknowledge: Your server returns a 2xx to confirm receipt. If it doesn't, most providers will retry later.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You use webhooks every day, maybe without noticing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub fires webhooks to trigger CI/CD on pushes and pull requests.&lt;/li&gt;
&lt;li&gt;Stripe fires webhooks when a payment succeeds or is refunded.&lt;/li&gt;
&lt;li&gt;Slack / Discord let you post messages into channels via incoming webhooks.&lt;/li&gt;
&lt;li&gt;Bank notification services fire webhooks when an account balance changes — more on this at the end.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  3. Polling vs. webhooks
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Facst31ispj2w9q889dcx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Facst31ispj2w9q889dcx.png" alt=" " width="703" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Webhooks don't always fully replace polling. Many solid systems use both: webhooks for real-time events, plus a periodic reconciliation job (polling) to catch anything that slipped through.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Building a webhook endpoint in Node.js
&lt;/h2&gt;

&lt;p&gt;Let's build a webhook receiver with Express. It will do the three things every production endpoint needs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Verify the signature (make sure the request really came from the provider)&lt;/li&gt;
&lt;li&gt;Be idempotent (never process the same event twice)&lt;/li&gt;
&lt;li&gt;Respond fast, and do the heavy lifting later&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Header names, signing algorithms and payload shapes vary by provider. The code below uses the most common pattern: HMAC-SHA256 with an X-Signature header. For a real integration, follow your provider's docs.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bash
npm init -y
npm install express
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;js
// server.js
const express = require('express');
const crypto = require('crypto');

const app = express();
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
const processedEvents = new Set(); // Demo only: use a DB/Redis in production

// Compare signatures with timingSafeEqual to avoid timing attacks
function isValidSignature(rawBody, signature) {
  if (!signature) return false;
  const expected = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(rawBody)
    .digest('hex');
  const a = Buffer.from(expected);
  const b = Buffer.from(signature);
  return a.length === b.length &amp;amp;&amp;amp; crypto.timingSafeEqual(a, b);
}

// Use express.raw to keep the original body bytes — required for signing
app.post('/webhooks/demo', express.raw({ type: 'application/json' }), (req, res) =&amp;gt; {
  // 1. Verify: did this really come from the provider?
  if (!isValidSignature(req.body, req.get('X-Signature'))) {
    return res.status(401).send('Invalid signature');
  }

  let event;
  try {
    event = JSON.parse(req.body.toString('utf8'));
  } catch {
    return res.status(400).send('Invalid JSON');
  }

  // 2. Idempotency: skip events we've already handled (providers may resend)
  if (processedEvents.has(event.id)) {
    return res.status(200).send('Already processed');
  }
  processedEvents.add(event.id);

  // 3. Acknowledge IMMEDIATELY, process later
  res.status(200).send('OK');

  setImmediate(() =&amp;gt; handleEvent(event));
});

async function handleEvent(event) {
  // Update orders, send emails, post to Telegram...
  console.log(`Received event ${event.type}:`, event.data);
}

app.listen(3000, () =&amp;gt; console.log('Webhook server listening on port 3000'));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why express.raw() instead of express.json()? The HMAC signature is computed over the exact raw bytes of the body. If you let Express parse the JSON and then JSON.stringify it back, key order or whitespace may change and the signature will never match. This is one of the most common bugs in first-time webhook integrations.&lt;/p&gt;

&lt;p&gt;Test it with curl&lt;/p&gt;

&lt;p&gt;Start the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bash
WEBHOOK_SECRET=my_secret node server.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In another terminal, simulate a provider sending a signed webhook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bash
WEBHOOK_SECRET=my_secret
BODY='{"id":"evt_001","type":"order.paid","data":{"orderId":"DH123","amount":150000}}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | sed 's/^.* //')

curl -X POST http://localhost:3000/webhooks/demo \
  -H "Content-Type: application/json" \
  -H "X-Signature: $SIG" \
  -d "$BODY"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What you should see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First request → OK, and the server logs Received event order.paid: { orderId: 'DH123', amount: 150000 }&lt;/li&gt;
&lt;li&gt;Send the exact same request again → Already processed (idempotency works)&lt;/li&gt;
&lt;li&gt;Change X-Signature to anything else → 401 Invalid signature&lt;/li&gt;
&lt;li&gt;Exposing localhost for real providers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Providers can't reach your localhost. During development you can use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ngrok: ngrok http 3000 gives you a public HTTPS URL that tunnels to your machine.&lt;/li&gt;
&lt;li&gt;Cloudflare Tunnel (cloudflared): similar, and free.&lt;/li&gt;
&lt;li&gt;webhook.site: just to inspect what a provider sends, before writing any code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Webhook best practices
&lt;/h2&gt;

&lt;p&gt;Receiving a request is easy. Making it reliable in production is where it gets interesting.&lt;/p&gt;

&lt;p&gt;Security&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always use HTTPS for your webhook URL.&lt;/li&gt;
&lt;li&gt;Always verify signatures (HMAC, tokens, or whatever your provider supports). Your webhook URL is public — anyone can send fake requests to it.&lt;/li&gt;
&lt;li&gt;Compare signatures in constant time (crypto.timingSafeEqual), not with ===.&lt;/li&gt;
&lt;li&gt;If the provider publishes its IP ranges, consider IP allowlisting as an extra layer.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For anything involving money: don't blindly trust the payload. Cross-check the amount and order ID against your own data before updating status.&lt;br&gt;
&lt;strong&gt;Reliability&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Return 2xx as fast as possible. Most providers time out after a few seconds. Push heavy work (calling other APIs, sending emails, multi-table writes) onto a queue (BullMQ, RabbitMQ, SQS...).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Design for idempotency. Webhooks are usually delivered at least once — the same event can arrive 2–3 times. Store the event ID (or transaction ID) in your DB with a UNIQUE constraint.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don't rely on ordering. A later event may arrive first.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run a periodic reconciliation job to catch missed events (server downtime, bad deploys...).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Observability&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log raw payloads (with sensitive data masked) for debugging.&lt;/li&gt;
&lt;li&gt;Alert when the webhook failure rate spikes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Real-world use case: bank balance notifications with PionPay
&lt;/h2&gt;

&lt;p&gt;Now for the use case where webhooks really shine, especially in Vietnam: automatic bank transfer confirmation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Vietnam, bank transfers — especially via QR codes (VietQR) — are one of the most popular ways to pay, whether for e-commerce, online courses, SaaS subscriptions or wallet top-ups. Yet confirmation is often still manual:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The customer makes a transfer&lt;/li&gt;
&lt;li&gt;The customer sends a screenshot of the receipt via chat&lt;/li&gt;
&lt;li&gt;Staff open the banking app and search for the transaction&lt;/li&gt;
&lt;li&gt;Staff update the order by hand&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result: customers wait, staff waste time, mistakes happen, and there's a real risk of fake transfer screenshots. And if someone orders at 2 AM... the order just sits there until morning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The solution: balance change webhooks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PionPay connects to your bank accounts via Open API and notifies you whenever your balance changes — via Webhook/API for system integration, or via Telegram/Messenger if you just want alerts.&lt;/p&gt;

&lt;p&gt;Here's what an automated payment confirmation flow looks like with webhooks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcul2hv4ae3q2ldsc2091.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcul2hv4ae3q2ldsc2091.png" alt=" " width="699" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No more combing through bank statements. No more waiting for screenshots. Orders get confirmed 24/7, even at 2 AM.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why PionPay?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fast: balance change notifications in about 2 seconds — no need to open a banking app or wait for an SMS.&lt;/li&gt;
&lt;li&gt;Reliable: 99.99% uptime.&lt;/li&gt;
&lt;li&gt;Multi-bank: supports 10+ Vietnamese banks including BIDV, ACB, TPBank and PGBank; manage multiple accounts from one dashboard.&lt;/li&gt;
&lt;li&gt;Secure: connects via Open API, encrypts data, never stores passwords and has no access to your account — it only receives transaction notifications.&lt;/li&gt;
&lt;li&gt;Multiple channels: Webhook/API for developers, Telegram/Messenger for operations teams.&lt;/li&gt;
&lt;li&gt;Extras: QR payment code generation, automatic transaction categorization, daily/weekly/monthly revenue tracking.
&lt;strong&gt;Get started in a few steps&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Sign up at pionpay.vn.&lt;/li&gt;
&lt;li&gt;Link your bank account via Open API.&lt;/li&gt;
&lt;li&gt;Register your webhook URL (the endpoint from section 4) in the dashboard — or connect Telegram/Messenger if you only need alerts.&lt;/li&gt;
&lt;li&gt;Write your handler: match the transfer reference to an order ID, check the amount, update the status.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every best practice from section 5 applies here, and with money involved they matter even more: verify requests, stay idempotent on the transaction ID, and always cross-check the amount before confirming an order.&lt;/p&gt;

&lt;p&gt;Ideas for what to build&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;E-commerce / landing pages: automatically mark orders as "Paid" when the money arrives.&lt;/li&gt;
&lt;li&gt;Online courses: activate student accounts right after the transfer.&lt;/li&gt;
&lt;li&gt;Wallet / account top-ups: credit balances automatically based on the transfer reference.&lt;/li&gt;
&lt;li&gt;SaaS: renew subscriptions automatically.&lt;/li&gt;
&lt;li&gt;Ops teams: post incoming payments to a Telegram group so the whole team can follow along.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. Wrapping up
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A webhook = another system calls your URL when an event happens, instead of you asking over and over (polling).&lt;/li&gt;
&lt;li&gt;A good webhook endpoint needs HTTPS, signature verification, fast responses, idempotency, and a reconciliation fallback.&lt;/li&gt;
&lt;li&gt;For bank-transfer payments in Vietnam, balance change webhooks let you confirm orders almost instantly, cut down on errors and block fake receipts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're still confirming bank transfers by hand, give PionPay a try — you can integrate it with a single endpoint like the one above.&lt;/p&gt;

&lt;p&gt;What's the worst webhook bug you've run into — missed events, duplicate processing, signature mismatches? Share it in the comments!&lt;/p&gt;

</description>
      <category>webhooks</category>
      <category>apigateway</category>
      <category>webdev</category>
      <category>node</category>
    </item>
    <item>
      <title>PionPay Officially Integrates ACB Bank API: Automated Transactions and Reconciliation for Businesses</title>
      <dc:creator>Nguyễn Hương</dc:creator>
      <pubDate>Sat, 26 Sep 2026 03:04:05 +0000</pubDate>
      <link>https://dev.to/nguyenhuong2026/pionpay-officially-integrates-acb-bank-api-automated-transactions-and-reconciliation-for-businesses-3gba</link>
      <guid>https://dev.to/nguyenhuong2026/pionpay-officially-integrates-acb-bank-api-automated-transactions-and-reconciliation-for-businesses-3gba</guid>
      <description>&lt;p&gt;Many businesses take bank transfer payments every day. For them, opening the banking app, checking each incoming transaction and matching it to an order takes a lot of time and invites mistakes. To solve this, PionPay has officially integrated the API of Asia Commercial Joint Stock Bank (ACB). Businesses with ACB accounts can now connect them directly to PionPay and manage all their transactions on one platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8aowfwb9cntfpser93iu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8aowfwb9cntfpser93iu.png" alt=" " width="799" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the ACB API integration on PionPay?
&lt;/h2&gt;

&lt;p&gt;An API integration is a direct connection between the bank's system and PionPay. Once an ACB account is linked, its transaction data flows into PionPay automatically. The system then receives and processes each transaction based on the rules the business has set up.&lt;/p&gt;

&lt;p&gt;In short: when money arrives in your ACB account, PionPay records and processes it for you. You don't have to keep watching your banking app or check payments by hand.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmyvcepgv9l6iklqifpax.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmyvcepgv9l6iklqifpax.jpg" alt=" " width="799" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What businesses get from the ACB API integration
&lt;/h2&gt;

&lt;p&gt;🏦 Direct connection to your ACB account&lt;/p&gt;

&lt;p&gt;Link your ACB bank account to PionPay through the API. You connect once, and your transaction data keeps syncing to the system from then on.&lt;/p&gt;

&lt;p&gt;💰 Automatic transaction tracking&lt;/p&gt;

&lt;p&gt;PionPay receives every transaction on your ACB account and processes it based on your settings. Your operations team no longer needs to check every balance change.&lt;/p&gt;

&lt;p&gt;🔄 Payment process automation&lt;/p&gt;

&lt;p&gt;PionPay cuts down on manual steps such as confirming transfers, updating order statuses and matching transfer descriptions. You save time, make fewer mistakes and fulfill orders faster.&lt;/p&gt;

&lt;p&gt;📊 Easier cash flow management and reconciliation&lt;/p&gt;

&lt;p&gt;All transaction data is centralized in PionPay. You can monitor cash flow, look up transaction history and handle end-of-day or end-of-period reconciliation more easily.&lt;/p&gt;

&lt;p&gt;An ACB-exclusive feature: virtual account (VA) creation&lt;/p&gt;

&lt;p&gt;PionPay also supports creating virtual accounts (VA) on ACB.&lt;/p&gt;

&lt;p&gt;Businesses often use virtual accounts to separate and identify incoming payments, for example by assigning one to each customer or each order. This makes it clearer who has paid and what each payment is for.&lt;/p&gt;

&lt;p&gt;We'll cover how VA creation on ACB works in an upcoming post, so follow the PionPay blog to stay updated!&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should use the ACB API integration on PionPay?
&lt;/h2&gt;

&lt;p&gt;Businesses and online stores that receive payments to an ACB account&lt;br&gt;
Companies with a high volume of bank transfers that need fast, accurate confirmation&lt;br&gt;
Accounting teams that want a central tool for reconciliation and cash flow management&lt;br&gt;
Businesses that want to automate payments and rely less on manual work&lt;br&gt;
Connect ACB to PionPay today&lt;/p&gt;

&lt;p&gt;If your business uses an ACB account and you want to automate transaction tracking and processing, contact PionPay for a consultation and help with setup.&lt;/p&gt;

&lt;p&gt;🌐 Website: &lt;a href="https://pionpay.vn/" rel="noopener noreferrer"&gt;PionPay.vn&lt;/a&gt;&lt;br&gt;
📞 Hotline: 0981.690.369&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>acb</category>
      <category>pionpay</category>
      <category>apigateway</category>
    </item>
    <item>
      <title>Create ACB Virtual Accounts (VA) with PionPay for Faster Cash-Flow Reconciliation</title>
      <dc:creator>Nguyễn Hương</dc:creator>
      <pubDate>Sat, 26 Sep 2026 02:59:29 +0000</pubDate>
      <link>https://dev.to/nguyenhuong2026/create-acb-virtual-accounts-va-with-pionpay-for-faster-cash-flow-reconciliation-4kd5</link>
      <guid>https://dev.to/nguyenhuong2026/create-acb-virtual-accounts-va-with-pionpay-for-faster-cash-flow-reconciliation-4kd5</guid>
      <description>&lt;p&gt;When many orders and payments flow into a single account, figuring out who paid and which order the money belongs to takes time. With PionPay, you can create Virtual Accounts (VA) on ACB to separate and manage incoming payments more clearly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F90rgxcrfns6xs0ame2ts.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F90rgxcrfns6xs0ame2ts.webp" alt=" " width="640" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a VA on ACB?
&lt;/h2&gt;

&lt;p&gt;A Virtual Account (VA) is an identifier account linked to a specific customer, order, or purpose, used to receive money. Each VA has its own unique identifier, so when funds arrive, the system immediately recognizes who the transaction belongs to. All collected funds still consolidate into your main account at ACB.&lt;/p&gt;

&lt;p&gt;Example: Branch A → VA A; Branch B → VA B; Branch C → VA C.&lt;/p&gt;

&lt;h2&gt;
  
  
  How is a VA different from a shared receiving account?
&lt;/h2&gt;

&lt;p&gt;A VA sorts incoming payments the moment money arrives, while a shared account forces you to reconcile manually afterward.&lt;/p&gt;

&lt;p&gt;Criteria    Shared account  With VA&lt;br&gt;
Identifying the payer   Relies on transfer description; error-prone Based on a unique VA identifier&lt;br&gt;
Reconciliation  Manually checking each transaction  Automatically categorized on arrival&lt;br&gt;
Multiple orders at once Confusing, easy to miss items   Each payment is clearly separated&lt;br&gt;
Money management    Centralized but hard to break down  Centralized in the main account, still traceable by source&lt;/p&gt;

&lt;p&gt;You also don't need to share your main account number with each customer.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does PionPay help you create and manage VAs?
&lt;/h2&gt;

&lt;p&gt;PionPay lets you create and manage ACB VAs directly within its platform, including:&lt;/p&gt;

&lt;p&gt;Create VAs directly, without switching between multiple places.&lt;br&gt;
Link each VA to a customer, order, or purpose according to how your business organizes its transactions.&lt;br&gt;
Receive payments through individual VAs, making transactions easier to identify and reconcile.&lt;br&gt;
How to add an ACB VA on PionPay&lt;br&gt;
Go to the bank linking section and select "Virtual Account (VA)".&lt;br&gt;
Enter a memorable name for the VA.&lt;br&gt;
Confirm the OTP to create the VA.&lt;br&gt;
Complete VA creation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should you keep in mind when using a VA?
&lt;/h2&gt;

&lt;p&gt;A VA must be issued by a bank or an entity authorized by the bank, and used in line with the product's intended purpose. Opening and using payment accounts in Vietnam is governed by Circular 17/2024/TT-NHNN; the law prohibits identity impersonation and the buying, selling, renting, or lending of payment accounts (Source: FinanOne compilation, 2026). In this feature, VAs are created on ACB through PionPay's connection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;Can I withdraw or transfer money out of a VA?&lt;br&gt;
Typically, a VA is for receiving money only; funds are credited to your main account at ACB.&lt;/p&gt;

&lt;p&gt;How many VAs can I create?&lt;br&gt;
You can create multiple VAs by customer, order, or purpose; check PionPay or ACB's regulations for specific limits.&lt;/p&gt;

&lt;p&gt;Does a VA help automate reconciliation?&lt;br&gt;
Yes. Each transaction is tied to a unique VA, so payments are categorized as soon as money arrives.&lt;/p&gt;

&lt;p&gt;Does money sent to a VA go to my main account?&lt;br&gt;
Yes. The VA identifies the source of funds, while the money remains consolidated in your main account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start creating ACB VAs with PionPay
&lt;/h2&gt;

&lt;p&gt;Go to PionPay to create an ACB VA, or call the hotline 0981.690.369 for advice on a setup that fits your business model.&lt;/p&gt;

</description>
      <category>acb</category>
      <category>webdev</category>
      <category>pionpay</category>
    </item>
    <item>
      <title>The Hidden Costs of Integrating Directly with Bank APIs</title>
      <dc:creator>Nguyễn Hương</dc:creator>
      <pubDate>Mon, 21 Sep 2026 11:01:05 +0000</pubDate>
      <link>https://dev.to/nguyenhuong2026/the-hidden-costs-of-integrating-directly-with-bank-apis-2cm6</link>
      <guid>https://dev.to/nguyenhuong2026/the-hidden-costs-of-integrating-directly-with-bank-apis-2cm6</guid>
      <description>&lt;p&gt;"How hard can it be? The bank gives us an API. We call it. Done."&lt;/p&gt;

&lt;p&gt;If you have ever said this in a planning meeting, this post is for you.&lt;/p&gt;

&lt;p&gt;Integrating directly with a bank looks like the cheapest, most hands-on option: no middleman, no extra fees, full control. But the invoice never shows up as a line item. It shows up as missed deadlines, burned-out engineers, and a product roadmap that quietly stops moving.&lt;/p&gt;

&lt;p&gt;Let's break down where the real costs hide.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Time Cost: It's Never Just One Integration
&lt;/h2&gt;

&lt;p&gt;Onboarding takes longer than coding&lt;/p&gt;

&lt;p&gt;Before you write a single line of code, you typically need to:&lt;/p&gt;

&lt;p&gt;Sign a commercial agreement and pass the bank's KYC/KYB process&lt;br&gt;
Get your legal entity, business license, and use case approved&lt;br&gt;
Request sandbox credentials (often via email, sometimes via a PDF form)&lt;br&gt;
Complete security reviews, IP whitelisting, and certificate exchange&lt;/p&gt;

&lt;p&gt;This can take weeks or months, and most of it is waiting, not building. Your engineers can't speed it up.&lt;/p&gt;

&lt;p&gt;Every bank is a different snowflake&lt;/p&gt;

&lt;p&gt;Once you're in, you discover there is no such thing as "the bank API". There are dozens of them, and they disagree on almost everything:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo0gspb8ozx4oicwx0ht2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo0gspb8ozx4oicwx0ht2.png" alt=" " width="746" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If your customers use more than one bank, you are not building one integration. You are building and maintaining N of them, each with its own quirks, its own docs (often outdated), and its own release cycle.&lt;/p&gt;

&lt;p&gt;Testing is painful&lt;/p&gt;

&lt;p&gt;Sandboxes are frequently incomplete. They don't simulate timeouts, duplicate callbacks, partial failures, or settlement delays. So you find out how the bank really behaves in production, with real money.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. The Money Cost: Beyond the Bank's Fee Schedule
&lt;/h2&gt;

&lt;p&gt;The bank may charge you little or nothing for API access. Your actual spend is elsewhere:&lt;/p&gt;

&lt;p&gt;Engineering salaries. Multiple engineers for months is a real budget line, even if it never appears as "bank integration" in finance's spreadsheet.&lt;br&gt;
Security and compliance. Certificate management, key rotation, audit logs, penetration testing, and possibly PCI or local regulatory requirements.&lt;br&gt;
Infrastructure. Static IPs, VPN or dedicated connections, HSMs or secure key storage, monitoring and alerting.&lt;br&gt;
Reconciliation tooling. Matching bank statements to your internal orders is a product in itself.&lt;br&gt;
Failed and stuck transactions. Money in limbo means support tickets, manual refunds, and angry customers.&lt;br&gt;
Opportunity cost. Every sprint spent on payment plumbing is a sprint not spent on features customers pay for.&lt;/p&gt;

&lt;p&gt;A simple mental model:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Real cost = (engineer-months × loaded salary)&lt;br&gt;
          + (compliance + infrastructure)&lt;br&gt;
          + (ongoing maintenance × years)&lt;br&gt;
          + (revenue lost from a delayed launch)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That last term is the one people forget, and it's often the biggest.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. The People Cost: Your Best Engineers Stop Building Your Product
&lt;/h2&gt;

&lt;p&gt;This is the most underestimated cost of all.&lt;/p&gt;

&lt;p&gt;Payments are a specialty. To do them safely, someone on your team has to become an expert in:&lt;/p&gt;

&lt;p&gt;Idempotency and exactly-once semantics&lt;br&gt;
Webhook signature verification and replay protection&lt;br&gt;
Settlement cycles, cut-off times, and holiday calendars&lt;br&gt;
Reversals, chargebacks, and dispute flows&lt;br&gt;
Regulatory changes that can land with only a few weeks' notice&lt;/p&gt;

&lt;p&gt;Those people are now on call for payment incidents at 2 a.m. They are reading bank PDF specs instead of talking to users. If your company sells logistics, SaaS, e-commerce, or education, payments are not your core business, but they will start consuming a core-business amount of attention.&lt;/p&gt;

&lt;p&gt;Here is a small example of code that is boring but has to be exactly right, and that you will have to write and operate yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python
def handle_bank_callback(request):
    # 1. Verify the signature (each bank does this differently)
    if not verify_signature(request.headers, request.body):
        return Response(status=401)

    payload = parse(request.body)  # JSON? XML? encrypted?

    # 2. Idempotency: banks WILL send duplicates
    if already_processed(payload.transaction_id):
        return Response(status=200)

    # 3. Map bank-specific status to your internal state machine
    status = map_status(payload.bank_code, payload.status)

    # 4. Update order, ledger, and notify user, atomically
    with db.transaction():
        update_order(payload.order_ref, status)
        write_ledger_entry(payload)

    return Response(status=200)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now multiply this by every bank, every payment method, and every edge case, and then maintain it forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The Ongoing Cost: Integration Is Not a Project, It's a Product
&lt;/h2&gt;

&lt;p&gt;Shipping the integration is only day one. After that:&lt;/p&gt;

&lt;p&gt;Banks deprecate endpoints, rotate certificates, and change fields&lt;br&gt;
New regulations require new flows&lt;br&gt;
Volumes grow and rate limits start to bite&lt;br&gt;
Adding a new bank partner means starting from scratch&lt;br&gt;
Documentation drifts from reality and nobody tells you&lt;/p&gt;

&lt;p&gt;You've effectively created an internal payments team, whether you planned to or not.&lt;/p&gt;

&lt;p&gt;So, When Does Going Direct Make Sense?&lt;/p&gt;

&lt;p&gt;To be fair, direct integration is sometimes the right call:&lt;/p&gt;

&lt;p&gt;Payments are your core business, or you're building a payment product yourself&lt;br&gt;
You have very high volume, where the fee savings outweigh the engineering cost&lt;br&gt;
You only need one or two banks, with stable, well-documented APIs&lt;br&gt;
You have (or want to build) a dedicated payments engineering team&lt;/p&gt;

&lt;p&gt;If that isn't you, consider the alternative.&lt;/p&gt;

&lt;p&gt;The Alternative: Use an Abstraction Layer Like PionPay&lt;/p&gt;

&lt;p&gt;Instead of wiring up every bank yourself, you can use a unified payment gateway to carry the heavy lifting. PionPay is one option worth considering in this category. The core value of this approach is:&lt;/p&gt;

&lt;p&gt;One integration instead of N: you work against a single, consistent API instead of learning each bank&lt;br&gt;
Normalized data models for transactions, statuses, and errors, so your callback handling code becomes much simpler&lt;br&gt;
Managed security and compliance on the provider's side, reducing the burden of certificates, keys, and audits for your team&lt;br&gt;
Faster go-live, often days or weeks instead of many months&lt;br&gt;
A focused team that keeps building the product that sets you apart, instead of acting as payment infrastructure engineers&lt;/p&gt;

&lt;p&gt;With that in place, the callback handler above can shrink to a thin layer: verify the signature once against a single standard, map one unified set of statuses, then update the order. The differences between banks are hidden behind the gateway.&lt;/p&gt;

&lt;p&gt;You do pay a fee, but compare it honestly against the full cost model above, not just the bank's price list. Before choosing any provider, check the list of supported banks and payment methods, sandbox quality, SLAs, fee structure, and developer documentation.&lt;/p&gt;

&lt;p&gt;A Quick Checklist Before You Decide&lt;/p&gt;

&lt;p&gt;Ask your team:&lt;/p&gt;

&lt;p&gt;How many banks or payment methods do we need in year one? In year three?&lt;br&gt;
Who will maintain this integration, and who is on call for it?&lt;br&gt;
How long can we afford to wait before launch?&lt;br&gt;
What would our engineers build instead if they weren't doing this?&lt;br&gt;
Do we know our real cost, including maintenance and opportunity cost?&lt;/p&gt;

&lt;p&gt;If the answers make you uneasy, that unease is the hidden cost showing itself early.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Direct bank integration isn't wrong. It's just expensive in ways that don't appear on the quote. The hidden costs are time, money, and focus, and focus is the hardest to get back.&lt;/p&gt;

&lt;p&gt;Before you commit, calculate the total cost of ownership, not just the sticker price. Then decide whether payments are something you want to build or something you'd rather use. If you lean toward the latter, take a look at &lt;a href="https://pionpay.vn/" rel="noopener noreferrer"&gt;PionPay.vn&lt;/a&gt; and run a small proof of concept to measure the real integration time for yourself.&lt;/p&gt;

&lt;p&gt;Have you integrated directly with a bank? What surprised you most? Share your war stories in the comments. 👇&lt;/p&gt;

</description>
      <category>api</category>
      <category>pionpay</category>
      <category>fintech</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What Is an API?</title>
      <dc:creator>Nguyễn Hương</dc:creator>
      <pubDate>Thu, 17 Sep 2026 05:07:48 +0000</pubDate>
      <link>https://dev.to/nguyenhuong2026/what-is-an-api-1e3h</link>
      <guid>https://dev.to/nguyenhuong2026/what-is-an-api-1e3h</guid>
      <description>&lt;p&gt;An API (Application Programming Interface) is a defined way for two pieces of software to talk to each other. Instead of one program digging through another program's internal code or database, it sends a request in an agreed-upon format and gets back a predictable response. APIs are what let your app check the weather, charge a credit card, or confirm a bank transfer — without you having to build a weather station, a payment network, or a banking system yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. What does "API" actually mean?
&lt;/h2&gt;

&lt;p&gt;Break the acronym down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application — a piece of software (a website, a mobile app, a service)&lt;/li&gt;
&lt;li&gt;Programming — the code-level interaction, not a human interface&lt;/li&gt;
&lt;li&gt;Interface — the point of contact between two systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Put together: an API is the interface through which one application exposes its functionality so other programs can use it — without needing to know how it works internally.&lt;/p&gt;

&lt;p&gt;A real-world analogy&lt;/p&gt;

&lt;p&gt;Think of a restaurant.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You (the customer) don't walk into the kitchen and cook your own food.&lt;/li&gt;
&lt;li&gt;You look at a menu (the API documentation) that tells you what's available and how to order it.&lt;/li&gt;
&lt;li&gt;You give your order to a waiter (the API), who takes your request to the kitchen.&lt;/li&gt;
&lt;li&gt;The kitchen (the internal system) prepares the food and hands it back to the waiter.&lt;/li&gt;
&lt;li&gt;The waiter brings you the food (the API response) — you never see how the kitchen actually works.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's exactly what happens when your code "calls an API": you send a request in a specific format, and you get back a specific response, without touching the internal logic of the other system.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. How does an API actually work?
&lt;/h2&gt;

&lt;p&gt;Most modern web APIs work over HTTP, the same protocol your browser uses to load web pages. The basic flow looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your app sends a request to a specific URL (called an endpoint), often with some data attached.&lt;/li&gt;
&lt;li&gt;The server processes the request — maybe it looks something up in a database, runs a calculation, or checks a bank balance.&lt;/li&gt;
&lt;li&gt;The server sends back a response, usually in a structured format like JSON.&lt;/li&gt;
&lt;li&gt;Your app reads the response and does something with it — displays it, stores it, triggers another action.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example: a weather API request might look like this—&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET https://api.example.com/weather?city=Hanoi
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the response might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hanoi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"temperature"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Partly cloudy"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You didn't need to know anything about weather satellites or forecasting models. You just asked a question in the agreed format and got a structured answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. What are the common types of APIs?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;REST APIs — the most common style for web APIs, using standard HTTP methods (GET, POST, PUT, DELETE) and usually returning JSON.&lt;/li&gt;
&lt;li&gt;Webhooks — the reverse pattern: instead of you asking a server for data, the server pushes data to you the moment something happens (e.g. "a payment was just received").&lt;/li&gt;
&lt;li&gt;GraphQL APIs — let the client specify exactly what data it needs in a single request, instead of hitting multiple fixed endpoints.&lt;/li&gt;
&lt;li&gt;SDKs/Libraries — not APIs themselves, but code wrappers that make calling an API easier in a specific programming language.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Why do APIs matter so much in modern software?
&lt;/h2&gt;

&lt;p&gt;Without APIs, every app would need to build everything from scratch: its own maps, its own payment processing, its own SMS sending, its own bank connections. APIs let teams specialize. One company builds a really good mapping service; everyone else just calls its API instead of reinventing it.&lt;/p&gt;

&lt;p&gt;This is especially visible in fintech, where connecting directly to a bank's systems involves authentication flows, security requirements, and constant maintenance as banks update their systems. That's exactly the kind of problem APIs — and specifically webhooks — are built to solve, as the next example shows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A concrete example: how a webhook API solves a real payment problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To make all of this less abstract, let's walk through a real case: confirming that a bank transfer actually arrived.&lt;/p&gt;

&lt;p&gt;If you're building a sales website in Vietnam, customers often pay by direct bank transfer instead of a card. The naive way to confirm payment is for someone on your team to open the bank app, check the balance, and manually match a transaction to an order. That doesn't scale, and it's exactly the kind of repetitive, error-prone task APIs exist to remove.&lt;/p&gt;

&lt;p&gt;This is where PionPay.vn comes in, and it's a good illustration of the webhook pattern described above. Instead of your app repeatedly asking a bank "has this payment arrived yet?" (which would mean building and maintaining a direct integration with every bank's own API), PionPay.vn already maintains those bank connections for you. When a transfer lands in a linked account, PionPay's webhook sends a request straight to your system, the moment it happens.&lt;/p&gt;

&lt;p&gt;In practice, your endpoint might receive something like this, example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"event"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"transaction.received"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bank_account"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"linked-account-id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;250000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VND"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"transaction_time"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-09-17T09:12:03+07:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reference"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ORDER-4821"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your code doesn't need to know anything about how PionPay.vn talked to the bank, what authentication flow was involved, or how the balance change was detected. You just receive a predictable payload, match reference to an order in your database, and mark it as paid — the same "menu and waiter" pattern from earlier in this post, just applied to money instead of food.&lt;/p&gt;

&lt;p&gt;This is also a nice example of why webhooks specifically (rather than a regular request/response API) make sense here: payment timing is unpredictable. A webhook lets the bank-integration layer notify you the instant something happens, instead of your app wastefully polling "any news?" every few seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Common beginner questions about APIs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is an API the same as a database?&lt;/strong&gt; No. A database stores data. An API is a way to access functionality or data — sometimes that data comes from a database, but the API is the messenger, not the storage.&lt;/p&gt;

&lt;p&gt;**Do I need to know a specific programming language to use an API? **No — APIs are language-agnostic. You can call the same API from Python, JavaScript, Go, or almost any language, as long as it can send HTTP requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's an API key, and why do I need one?&lt;/strong&gt; An API key is a unique identifier that tells the server who's making the request. It's used for authentication (proving you're allowed to use the API) and often for rate-limiting (making sure one user doesn't overload the service).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the difference between an API and a webhook?&lt;/strong&gt; With a normal API, your app has to ask ("is there new data?"). With a webhook, the other system tells you the moment something happens, without you having to ask repeatedly. Webhooks are especially common for real-time events like payment confirmations, form submissions, or status updates.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>api</category>
      <category>fintech</category>
      <category>pionpay</category>
    </item>
    <item>
      <title>PionPay: Skip Individual Bank API Integrations — Just Hook into PionPay’s Webhook</title>
      <dc:creator>Nguyễn Hương</dc:creator>
      <pubDate>Wed, 16 Sep 2026 11:20:37 +0000</pubDate>
      <link>https://dev.to/nguyenhuong2026/pionpay-skip-individual-bank-api-integrations-just-hook-into-pionpays-webhook-3om6</link>
      <guid>https://dev.to/nguyenhuong2026/pionpay-skip-individual-bank-api-integrations-just-hook-into-pionpays-webhook-3om6</guid>
      <description>&lt;p&gt;If you’re a developer maintaining an e-commerce platform or a payment system in Vietnam, building direct API integrations with multiple banks is slow, resource-draining, and a endless maintenance burden. PionPay has already built and maintained that integration layer with various banks across Vietnam. All you need to do is attach PionPay’s webhook to your existing payment flow and start receiving real-time transfer confirmations — no need to connect to each bank's API individually.&lt;/p&gt;

&lt;p&gt;Pricing: 99,000 VND/month per linked bank account.&lt;br&gt;
Website: pionpay.vn · Fanpage: facebook.com/pionpay · Hotline: 0981.690.369&lt;/p&gt;

&lt;p&gt;We are currently opening early access for developers to integrate, stress-test, and share feedback before our broader rollout.&lt;/p&gt;

&lt;p&gt;Contact our fanpage to claim a free trial package!&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Problem: Direct Bank API Integration is an "Engineering Tax" for Every Dev Team
&lt;/h2&gt;

&lt;p&gt;If you’ve ever tried connecting a sales system directly to a Vietnamese bank’s API, you know it’s not a weekend project. Every bank comes with its own authentication flows, quirks, and incomplete documentation. Multiply that by the number of banks your customers actually use, and you’ll end up wasting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real engineering hours on integrations — work that has nothing to do with your core product.&lt;/li&gt;
&lt;li&gt;Continuous maintenance every time a bank changes something on their end.&lt;/li&gt;
&lt;li&gt;Extra infrastructure just to poll or listen for balance f
luctuations reliably.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. What PionPay Actually Does
&lt;/h2&gt;

&lt;p&gt;PionPay takes care of the integration work across multiple Vietnamese banks for you. Instead of connecting to each bank individually, you only need to connect to a single webhook.&lt;br&gt;
Here’s how the workflow looks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You link a bank account with PionPay (via the PionPay dashboard).&lt;/li&gt;
&lt;li&gt;PionPay monitors balance fluctuations for that account via direct bank API connections — no screen scraping involved.&lt;/li&gt;
&lt;li&gt;When money arrives, PionPay instantly detects and verifies the transaction.&lt;/li&gt;
&lt;li&gt;PionPay sends a confirmation payload to your system via webhook in rea
l-time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On your side, integration is as simple as: receiving the webhook payload, matching it with the order, and marking it as paid. That’s it. No dealing with bank authentication flows, no polling logic, and zero maintenance per bank.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Where This Webhook Fits in Your Tech Stack
&lt;/h2&gt;

&lt;p&gt;PionPay is designed to sit alongside your existing tools without replacing your current stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Website / POS&lt;/li&gt;
&lt;li&gt;Telegram&lt;/li&gt;
&lt;li&gt;Zalo (Bots &amp;amp; Zalo OA)&lt;/li&gt;
&lt;li&gt;Lark&lt;/li&gt;
&lt;li&gt;Google Sheets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most dev teams, the primary integration point is simply: Webhook -&amp;gt; Your Order/Payment System. Other channels (Telegram, Zalo, Sheets) are optional add-ons if you want notifications dispatched elsewhere.&lt;/p&gt;

&lt;p&gt;**Pricing: Per Linked Account, Not Per Transaction&lt;/p&gt;

&lt;p&gt;This is an important detail when scoping your integration:&lt;br&gt;
99,000 VND/month per linked bank account.**&lt;/p&gt;

&lt;p&gt;This means your cost scales with the number of bank accounts you need PionPay to monitor — not with transaction volume. If your business collects payments into a single account, that’s one fixed line item. If you collect through multiple accounts (e.g., by branch or business unit), each linked account is billed separately.&lt;/p&gt;

&lt;p&gt;Full pricing details: pionpay.vn&lt;/p&gt;

&lt;h2&gt;
  
  
  4. How to Start Testing
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Visit pionpay.vn to register and get your API/webhook access keys.&lt;/li&gt;
&lt;li&gt;Link a test bank account (or a real account with low risk during trial).&lt;/li&gt;
&lt;li&gt;Point the webhook to a test endpoint and confirm you’re receiving valid payloads.&lt;/li&gt;
&lt;li&gt;Hook it into a sample order-matching workflow.&lt;/li&gt;
&lt;li&gt;Share your feedback in the comments below, or reach out via our fanpage/hotline above.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  5. Frequently Asked Questions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Do I need to integrate with each bank individually?&lt;br&gt;
No — that’s the main purpose of PionPay. PionPay handles and maintains those integrations; you only consume a single webhook.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Is the pricing based on transaction volume?&lt;br&gt;
No. It is a flat fee of 99,000 VND/month per linked bank account, regardless of how many transactions process through it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Is banking data processed securely?&lt;br&gt;
PionPay has achieved ISO/IEC 27001:2022 certification for Information Security Management Systems.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>api</category>
      <category>webhook</category>
      <category>fintech</category>
      <category>webdev</category>
    </item>
    <item>
      <title>PionPay: Không cần tự kết nối API từng ngân hàng — Chỉ cần gắn webhook của PionPay</title>
      <dc:creator>Nguyễn Hương</dc:creator>
      <pubDate>Wed, 16 Sep 2026 11:11:39 +0000</pubDate>
      <link>https://dev.to/nguyenhuong2026/pionpay-khong-can-tu-ket-noi-api-tung-ngan-hang-chi-can-gan-webhook-cua-pionpay-267c</link>
      <guid>https://dev.to/nguyenhuong2026/pionpay-khong-can-tu-ket-noi-api-tung-ngan-hang-chi-can-gan-webhook-cua-pionpay-267c</guid>
      <description>&lt;p&gt;Nếu bạn là developer đang duy trì một website bán hàng hoặc hệ thống thanh toán tại Việt Nam, việc tự kết nối trực tiếp với API của từng ngân hàng vừa chậm, vừa tốn nguồn lực, vừa là thứ bạn phải bảo trì mãi mãi. PionPay đã xây và duy trì sẵn lớp tích hợp đó với nhiều ngân hàng tại Việt Nam. Bạn chỉ cần gắn webhook của PionPay vào luồng thanh toán hiện có và bắt đầu nhận xác nhận chuyển khoản real-time — không cần tự đi kết nối API với từng ngân hàng.&lt;/p&gt;

&lt;p&gt;Chi phí: 99.000đ/tháng cho mỗi tài khoản ngân hàng liên kết.&lt;/p&gt;

&lt;p&gt;Website: pionpay.vn · Fanpage: facebook.com/pionpay · Hotline: 0981.690.369&lt;/p&gt;

&lt;p&gt;Chúng tôi đang mở để developer tích hợp, stress-test và góp ý trước khi ra mắt rộng rãi hơn.&lt;/p&gt;

&lt;p&gt;Liên hệ fanpage để được tặng gói trải nghiệm!&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Vấn đề: tự kết nối API ngân hàng là một "khoản thuế" cho mọi team dev
&lt;/h2&gt;

&lt;p&gt;Nếu bạn từng thử kết nối trực tiếp một hệ thống bán hàng với API của ngân hàng Việt Nam, bạn sẽ hiểu đó không phải việc làm trong một cuối tuần. Mỗi ngân hàng có luồng xác thực riêng, có những điểm khó chịu riêng, tài liệu thì thiếu chỗ này chỗ kia. Nhân số đó lên với số lượng ngân hàng khách hàng của bạn thực sự dùng, và bạn sẽ tốn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thời gian engineering thật sự cho việc tích hợp — thứ chẳng liên quan gì đến sản phẩm cốt lõi của bạn&lt;/li&gt;
&lt;li&gt;Bảo trì liên tục mỗi khi ngân hàng thay đổi gì đó phía họ&lt;/li&gt;
&lt;li&gt;Hạ tầng thêm chỉ để poll hoặc lắng nghe biến động số dư một cách đáng tin cậy&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. PionPay thực sự làm gì
&lt;/h2&gt;

&lt;p&gt;PionPay đã làm sẵn công việc tích hợp với nhiều ngân hàng tại Việt Nam. Thay vì bạn tự kết nối với từng ngân hàng, bạn chỉ cần kết nối với một webhook duy nhất.&lt;/p&gt;

&lt;p&gt;Quy trình như sau:&lt;/p&gt;

&lt;p&gt;Bạn liên kết một tài khoản ngân hàng với PionPay (qua dashboard của PionPay).&lt;br&gt;
PionPay theo dõi biến động số dư của tài khoản đó thông qua kết nối API ngân hàng trực tiếp — không phải scraping màn hình.&lt;br&gt;
Khi có tiền về, PionPay phát hiện và xác nhận giao dịch.&lt;br&gt;
PionPay gửi xác nhận đến hệ thống của bạn qua webhook, theo thời gian thực.&lt;/p&gt;

&lt;p&gt;Về phía bạn, công việc tích hợp chỉ là: nhận payload từ webhook, đối chiếu với đơn hàng, đánh dấu đã thanh toán. Vậy là xong. Không cần xử lý luồng xác thực ngân hàng, không cần logic polling, không phải bảo trì riêng cho từng ngân hàng.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Webhook này nằm ở đâu trong stack của bạn
&lt;/h2&gt;

&lt;p&gt;PionPay được thiết kế để nằm cạnh những công cụ bạn đang dùng, không thay thế stack hiện có:&lt;/p&gt;

&lt;p&gt;Website / POS&lt;br&gt;
Telegram&lt;br&gt;
Zalo (Bot và Zalo OA)&lt;br&gt;
Lark&lt;br&gt;
Google Sheets&lt;/p&gt;

&lt;p&gt;Với hầu hết team dev, điểm tích hợp quan trọng nhất đơn giản là: webhook → hệ thống đơn hàng/thanh toán của bạn. Những kênh còn lại (Telegram, Zalo, Sheets) chỉ là tùy chọn nếu bạn muốn thông báo được đẩy thêm đến nơi khác.&lt;/p&gt;

&lt;p&gt;Chi phí: tính theo số tài khoản liên kết, không tính theo giao dịch&lt;/p&gt;

&lt;p&gt;Đây là chi tiết cần nói rõ vì nó ảnh hưởng đến cách bạn scope việc tích hợp:&lt;/p&gt;

&lt;p&gt;99.000đ/tháng cho mỗi tài khoản ngân hàng liên kết.&lt;/p&gt;

&lt;p&gt;Nghĩa là chi phí tăng theo số lượng tài khoản ngân hàng bạn cần PionPay theo dõi — không tăng theo số lượng giao dịch. Nếu doanh nghiệp bạn thu tiền vào một tài khoản duy nhất, đó là một dòng chi phí. Nếu bạn thu tiền qua nhiều tài khoản (VD theo chi nhánh, theo đơn vị kinh doanh), mỗi tài khoản liên kết sẽ được tính riêng.&lt;/p&gt;

&lt;p&gt;Chi tiết bảng giá: pionpay.vn&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Cách bắt đầu test
&lt;/h2&gt;

&lt;p&gt;Truy cập pionpay.vn để đăng ký và lấy API/webhook access.&lt;br&gt;
Liên kết một tài khoản ngân hàng test (hoặc tài khoản thật với mức rủi ro giới hạn trong lúc thử).&lt;br&gt;
Trỏ webhook đến một endpoint test và xác nhận bạn nhận payload đúng.&lt;br&gt;
Gắn vào một luồng đối chiếu đơn hàng mẫu.&lt;br&gt;
Chia sẻ kết quả ở phần bình luận bên dưới, hoặc liên hệ qua fanpage/hotline ở trên.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Một số câu hỏi bạn có thể đang thắc mắc
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Tôi có cần tự tích hợp với từng ngân hàng không? &lt;br&gt;
Không — đó chính là mục đích của PionPay. PionPay duy trì các tích hợp đó; bạn chỉ cần tiêu thụ một webhook duy nhất.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Chi phí có tính theo số lượng giao dịch không? &lt;br&gt;
Không. Là 99.000đ/tháng cho mỗi tài khoản ngân hàng liên kết, bất kể có bao nhiêu giao dịch chạy qua tài khoản đó.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dữ liệu ngân hàng có được xử lý an toàn không? &lt;br&gt;
PionPay đã đạt chứng chỉ ISO/IEC 27001:2022, về hệ thống quản lý an toàn thông tin.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>api</category>
      <category>webhook</category>
      <category>fintech</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
