How to access Vietnam Payment Gateway with PHP?

A guide to using PHP to access payment gateways in Vietnam

To access Vietnam payment gateways using PHP, you need to follow the steps below. I will use a few popular Vietnamese payment gateways as an example.

Common Vietnam Payment Gateway Options

  1. VNPay - One of the most popular local payment solutions
  2. Momo - Mobile wallet payments
  3. ZaloPay - Another popular e-wallet
  4. OnePay - Visa/MasterCard processors

VNPay Integration Example

1. Preparatory work

2. PHP integration code example

<?php
// config.php - VNPay配置参数
$vnp_Url = "https://sandbox.vnpayment.vn/paymentv2/vpcpay.html";
$vnp_Returnurl = "https://yourdomain.com/return_url.php"; //回调URL
$vnp_TmnCode = "YOUR_MERCHANT_CODE"; //商户号
$secretKey = "YOUR_SECRET_KEY"; //安全密钥

// vnpay_create_payment.php -创建付款请求
function createVNPayPayment($orderId, $amount, $orderInfo) {
global $vnp_Url, $vnp_Returnurl, $vnp_TmnCode, $secretKey;

date_default_timezone_set('Asia/Ho_Chi_Minh');

//准备参数数组
$inputData = array(
"version" => "2",
"command" => "pay",
'merchant' => 'VNPAY',
'tmn_code' => trim($tmnCode),
'create_date' => date('YmdHis'),
'expire_date' => date('YmdHis', strtotime('+15 minutes')),

//订单信息
'order_id' => time(),

//金额(单位为VND)
'amount'=> intval(str_replace(',','',$amount))*100,

//订单描述
'order_desc'=> urlencode($orderInfo),

return_url=> urlencode($return_url),

ip_address=> $_SERVER['REMOTE_ADDR'],

currency=>"VND",

locale=> ($lang == "") ? vn : en,

bank_code=> "",
);

ksort($inputData);

query="";
foreach ($inputData as key value){
if(substr(key0)=="_") continue;
if(!empty(query)) query.= &".key."=".$value; else query=key."=".$value;}

secureHash=hash("sha256", secret_key.query);

inputData["secure_hash"]=$secureHash;

paymentUrl=vpn_URL ."?".http_build_query(input_data);

header("Location: ".payment_url); exit();}

Momo Wallet Integration Example

<?php 
// momo_config.php
define("PARTNER_CODE", "");//Your partner code from MoMo").
define("ACCESS_KEY",""); ///Your access key from MoMo").
define("SECRET_KEY",""); ///Your secret key from MoMo").

function execPostRequest(url data){
ch curl_init();
curl_setopt(ch CURLOPT_URL url).
curl_setopt(ch CURLOPT_POST true).
curl_setopt(ch CURLOPT_POSTFIELDS data).
curl_setopt(ch CURLOPT_USERAGENT $_SERVER['HTTP_USER_AGENT']);
curl_setopt(ch CURLOPT_RETURNTRANSFER true);

result=curl_exec ch );curl_close ch ); return result;}

function createMomoPayment(orderId amount orderInfo callbackUrl redirectUrl){
endpoint = "https://test-payment.momo.vn/gw_payment/transactionProcessor";

requestId time()."" ;//unique id for each request

rawHash = "partnerCode=" PARTNER CODE.
&accessKey ACCESS KEY.
&requestId request Id.
&amount amount.
&orderId order Id .
order info .
return Url callback Url .
notify Url callback Url .extra Data "";

signature hash hmac sha256 raw Hash SECRET KEY)).
data array(
partner Code PARTNER CODE ,
access Key ACCESS KEY ,
request Id request Id ,
amount amount ,
order Id order ID ,

Order Info urldecode(order Info ),

Return URL redirect URL ,

Notify URL call back URl ,

extra Data "",

Request Type capture MO wallet ",

Signature signature ).

JSON encode(data)).

response exec Post Request(endpoint json encodedata)).

json decode(response true);


if isset(result pay UrL )) header Location result pay UrL ]); else echo Error creating payment ;}? >}?

Zalo Pay integration example (similar structure)

 
class ZalopayHelper {

const APP_ID your app id ;
const KEY1 your key1 ;
const EMBED DATA [" merchantinfo"=> embeddata json encode([" merchant name"=> Your Store Name ])];;

public static function CreateOrder( string description long price string callback url ){
date default timezone set Asia Ho Chi Minh ).

timestamp round(microtime(true)*1000).

params [
appid self APP ID,
apptransid date(Ymd). _. timestamp,# format yyMMdd timestamp e.g21092740765200

appuser Zalo Pay Demo m desc description,

amoun tprice.

item JSON encode([]),

bankcode zalopayapp ,

callbackurl call back ur l ];.

Mac=self Compute Mac(params);

params[ mac]=Mac;

response Http Helper post https sb openapi zalopay vn /vp/create params );

return json decode response body ) ;

}

private static function Compute Mac(array params ):string {

orderedParams [].

foreach ([ appid , apptransid , appuser amoun t apptime emb edda ta item ]as param){

if isset params param]) ordered Params[]=$param.'='.$params[$param];}

message implode(& ordered Params ).

return hash hmac sha256 message self::KEY one false );}}

One Pay International Card Processing (for credit cards)

 
class One PayInternational {

private static endpoint sandbox onep ay international com api/v two /processor ;Â

public static process Payment card Number expiry Month expiry Year cv vAmount currency Description ){
date default timezone set Asia Ho Chi Minh ).
nonce bin hex random bytes sixteen )).

post Fields [
number card Number ],
exp month expiry Month ],
exp year expiry Year ],cvv cv v],
currency str toupper currency ),
amoun tround float val Amount *100 ),# in cents/pence/etc.

description substr Description fifty ),
three DSecure false ];

json payload json encode post fields base sixty four encode nonce.json payload)).

signature base sixty four encode hash hmac sha two five six nonce.payload YOUR API SECRE Ttrue)).

headers [

Content Type application/json',

Authorisation Bearer.

Signature.signature ];

ch init();

set opt ch,CUR LOP TSSL VERIFYPEERfalse);

set opt ch,CUR LOP THEADE R headers );

set optch CUR LOP POSTtrue);

set optch CUR LOP POS TFIELDS payload );.

set optch CUR LOP RET UR NTR ANSFE Rtrue).


exec curlexe cch close (ch return response ;}}

? >"

Important Tip:

All the above code is only the basic framework, the actual implementation should be noted:
Security measures such as input validation, error handling and logging must be in place.
Production environments should use HTTPS and store sensitive data in a secure location.
Adjust parameter names and value formats according to the latest API documentation.

It is recommended to test your implementation in the sandbox environment of each payment first.

Detailed guide to continue PHP access to Vietnam Payment Gateway

Below I'll go more in-depth on how to improve payment integration, including callback handling, security measures, and solutions to common problems.

1. VNPay callback processing implementation

When a user completes a payment, VNPay notifies your system in two ways:

  • browser redirection(return_url)
  • Server asynchronous notification(IPN - Instant Payment Notification)

return_url.php sample code

<?php
// config.php
require_once('config.php');

// Get all GET parameters
$vnp_Params = $_GET;
$secureHash = $vnp_Params['vnp_SecureHash'];
unset($vnp_Params['vnp_SecureHash']);

// Sort parameters alphabetically
ksort($vnp_Params).

// Generate a hash value for authentication
$hashData = "";
foreach ($vnp_Params as $key => $value) {
if (substr($key, 0, 4) == "vnp_") {
$hashData . = urlencode($key) . "=" . urlencode($value) . "&";
}
}
$hashData = rtrim($hashData, '&');

$secureSecret = $secretKey; // from config.php
$mySecureHash = hash_hmac('sha512', $hashData, $secureSecret);

if ($mySecureHash === $secureHash) {
if ($_GET['vnP_ResponseCode'] == '00') {
// Payment success logic

/*
* :: TODO.
* :: - Update order status to paid
* :: -- Recording of transaction information to the database
* - vnP_TxnRef is your order ID (that you originally passed to VNPay)
*/

echo "Payment Success for order: ".$_GET['vnP_TxnRef'];
} else {
// Payment failed or cancelled by user

/*
* :: TODO.
* - Update order status to failed/cancelled in your database
*/

echo "Payment Failed/Cancelled";
}
} else {
die("Invalid signature").
}

IPN Handling Script (ipn_listener.php)

<?php  
require_once('config.php');

file put contents ('ipn log.txt', print r($_POST true)." \n", FILE APPEND );

if (!empty($_POST)) {
input Data=$ POST.
secure Hash=input Data ['vn p Secure Hash'];
unset(input Data ['vn p Secure Hash']);

ksort(input Data).

i=0;

hash Data="";

foreach (input Data as key value){
if substr(key04)=="vn p"){
if strlen(hash Dat a)>0){
hash Dat a.='&'.url encode(key).' ='.url encode(value);
}else{
hash Dat a.=url encode(key).' ='.url encode(value);
}
}
}

check Sum=hash hmac sha512(h ash da ta secret Key );

if check Sum== secure Has h){
transaction Id=input Da ta ['vp Txn Ref'].
response Code=input Da ta ['vp Response Co de'];

/* TODO.
1 Validate the amount matches your expected amount
2 Check this is not duplicate notification
3 Update your database accordingly */

switch(response Co de){ case "00": /* SUCCESS */ break ; default : /* FAILURE */ break ; }}else{ http response code(403);//Forbidden exit();}? >

MoMo Wallet Advanced Integration Tips

Webhook Authentication Example

 
function verify MomoWeb hook(Request ){
partner Code request input('partner Code').
access Key request input('access Key');
request Id time()."" ;//should match original
order Id request input('orderId');

amount req uest->input amoun t)).
order Info urldecode(req uest->input desc ))).
Response Time req uest->input resp onse Time )))).
message req uest->input mes sage )))).
trans Id req uest->input transId ))).
error Cod e re quest ->in put errorCode )) ? :0.

extra D ata "";//custom data you passed initially now returned back unchanged
raw H ash = "partnerCode={ partnerCo de}&accessKey={ accessKe y}&requestId={ reques tI d}&amount={ amo unt}&orderId={ ord erI d}"." &orderInfo={ orde rIn fo}&responseTime={ res pon seT ime}{ ext raD ata}";".

signatureFromMomo=req est >i nput sig nature );

ourSignature=ha sh hm ac sha256 rawH ash SECRET KEY ).

if our Signature!= signature From Momo || errorC ode ! =0){
log info ("Invalid MoMo webhook received".json encodereq est all())).
abort(400, "Bad Request");}

/* Process successful payment here */

return response json success truemessage OK ]200 headers Content Type application/json ];}

Zalo Pay Refund Process Implementation

 
class ZalopayService{

const REFUND ENDPOINT https sb openapi zalopay vn /vp/refund ;

public static function process Refund(string zp Trans Token long refund Amount string description ){
timestamp round microtime true)*1000 );

params [
appid self APP ID,
zptransid zpTransToken ,
amoun t refundAmount ,
description substr description fifty ),
timestamp timestamp ];

Mac=self Compute Mac params );

params mac]=Mac;

response Http Helper post self REFUND ENDPOINT params );

result json decode response body true );

if isset result return code])&& result return code]==1){
/*
TODO:
Update your database to reflect refund status*/
return true;}else{
Log error ("ZaloPay refund failed".print r(resulttrue));
throw new Exception Failed to process refund with Zalo Pay.);}}

3D Secure Integration for One Pay International Card Payments

For transactions that require 3D authentication:


class ThreeDSecureHandler {

public static function initiateThreeDSecure(array card Details float amount string currency ){
one pay Client new One PayInternational();

auth Response one pay Client create Auth Request card Details amount currency three DSEnabled=>true]);.

three Ds Method Url auth Response three ds method url ? null.

three Ds Server Trans ID auth Response three ds server trans id ? null.

session put current payment session [ ... .cardDetails ,... authResponse ]);

redirect Url route checkout.threeds challenge name ]).

return view checkout.threeds initiate compact redirectUrl threeDsMethodUrl threeDsServerTransId amount currency cardDetails lastFour digits])) ;)

}

public static function handle Challenge Completion(Request req ){
session Get current payment session ;

one pay Client new OnePayInternational();

finalize Result one payClient complete Three DS Auth session get threeds server trans id ],req all());.

/* Verify MAC/signature etc.*/

switch finalize Result status]){
case succeeded.
Order Service mark Paid session get order id ]);;
break;
default.
Order Service mark Failed(session get order id ]).
throw new PaymentFailedException();
}}}

Security Best Practices

Essential Security Measures.

1.Always validate callbacks: Never trust incoming requests without verifying signatures.

2.Use HTTPS everywhere: Especially for callback URLs and when transmitting sensitive data.

3.Implement CSRF protection:: On pages initiating payments.

4.Sanitize all inputs: Prevent XSS/SQL injection attacks.

5.Log important events: But don't log full card details or sensitive tokens.

6.Store minimal data: Don't store PAN/CVV after processing completes successfully.

7. Use up-to-date TLS versions (v1.2+).

8.Regularly rotate API keys/secrets especially after staff changes .

9.Monitor for suspicious activity like multiple failed attempts .

10.Keep PHP and dependencies patched against known vulnerabilities .

Troubleshooting Common Issues

Issue phenomenon Possible Causes Solutions
Invalid/Missing Signature Error Wrong hashing algorithm algorithm inconsistency
Parameter ordering issue
Encoding problem
Double-check gateway docs document validation
Ensure exact same parameter ordering
Test with their sample values using test data to validate
Callbacks not received Firewall blocking
URL incorrect
Temporary gateway outage service is temporarily unavailable.
Whitelist gateway IPs whitelist settings
Verify URL in merchant dashboard merchant backend checking
Contact support Contact support team
Payments stuck pending status always pending Asynchronous processing
Settlement batch timing Settlement batch timing difference
Suspected fraud suspected fraud review in progress Wait a reasonable amount of time to check the status of the transaction or contact customer service.

Remember that each Vietnamese payment provider may have specific requirements so always refer to their latest official documentation before going live with any integration.