Configure IPN URL
IPN URL is configured on the merchant management page in SePay:
- Log in to SePay
- Go to Payment Gateway → Configuration → IPN
- Enter your endpoint URL to receive IPN
- Save configuration
The IPN URL must be a public HTTPS endpoint that SePay can reach from the internet (not localhost or an internal IP such as 127.0.0.1, 192.168.x), and the endpoint must return HTTP status code 200 to confirm successful receipt. When developing locally, expose your endpoint with ngrok, localtunnel, cloudflared or similar so SePay can call it.
Request from SePay to Merchant
https://your-url (url you configured in IPN)Headers:
X-Secret-Key: <secret_key>
Content-Type: application/json
X-Secret-Key: Secret key for authentication (only available when merchant configures auth type = SECRET_KEY)
Parameter list
Example request body:
{
"timestamp": 1757058220,
"notification_type": "ORDER_PAID",
"order": {
"id": "e2c195be-c721-47eb-b323-99ab24e52d85",
"order_id": "NPSETVI00101000042R",
"order_status": "CAPTURED",
"order_currency": "VND",
"order_amount": "50000.00",
"order_invoice_number": "SUB_202509_001",
"custom_data": [],
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"ip_address": "14.xxx.xxx.xxx",
"order_description": "Premium package recurring payment for September 2025"
},
"transaction": {
"id": "384c66dd-41e6-4316-a544-b4141682595c",
"payment_method": "CARD",
"transaction_id": "68ba94ac80123",
"transaction_type": "PAYMENT",
"transaction_date": "2025-09-01 00:00:15",
"transaction_status": "APPROVED",
"transaction_amount": "50000",
"transaction_currency": "VND",
"authentication_status": "AUTHENTICATION_SUCCESSFUL",
"card_number": "4111XXXXXXXX1111",
"card_holder_name": "NGUYEN VAN A",
"card_expiry": "12/26",
"card_funding_method": "CREDIT",
"card_brand": "VISA"
},
"customer": {
"id": "bae12d2f-0580-4669-8841-cc35cf671613",
"customer_id": "CUST_001"
}
}Handle IPN endpoint:
Route::post('/payment/ipn', function(Request $request) {// Verify secret keyif ($request->header('X-Secret-Key') !== $secretKey) {return response()->json(['error' => 'Unauthorized'], 401);}$data = $request->json()->all();if ($data['notification_type'] === 'ORDER_PAID') {$order = Order::where('invoice_number', $data['order']['order_invoice_number'])->first();$order->status = 'paid';$order->save();}// Return 200 to acknowledge receiptreturn response()->json(['success' => true], 200);});
The merchant Secret Key and how to regenerate it
The Payment Gateway has two different Secret Keys:
| Key | Where to find it | What it is for |
|---|---|---|
| Merchant Secret Key | Payment Gateway → Configuration → Merchant information | Signs the payment form you send to checkout/init and authenticates API calls over Basic Auth (merchant_id:secret_key). Generated by SePay, in the form spsk_live_... (LIVE) or spsk_test_... (Test mode). |
| IPN Secret Key | Payment Gateway → Configuration → IPN | Authenticates the IPN that SePay sends to your system, using the Auth Type set on the IPN tab. You choose it yourself. |
The two keys are independent: regenerating the merchant Secret Key does not change the Secret Key on the IPN tab, and vice versa.
When to regenerate
The merchant Secret Key is displayed only once, when it is created. After that the Merchant information page shows * characters only. Regenerate the key if you have lost it, or if it may have leaked (for example it was committed to Git, sent over chat, or someone who held it has left the company).
Steps
Only a SuperAdmin or Admin account of the company can do this.
- Go to Payment Gateway → Configuration → Merchant information (Cổng thanh toán → Cấu hình → Thông tin đơn vị).
- Check the Test Mode switch in the top right corner. You can only regenerate the key of the environment currently selected; to regenerate the LIVE key, turn Test Mode off first.
- Click Tạo lại (Regenerate) on the Secret Key row.
- In the confirmation dialog, check the environment badge (
LIVEorTest mode). - Type your merchant code (Merchant ID, shown under the merchant name) into the confirmation field, then click Tạo lại Secret Key (Regenerate Secret Key).
- Copy the new key from the dialog that opens, then click Tôi đã lưu key (I have saved the key).
As soon as you click Tạo lại Secret Key, the old key no longer works. Until your system switches to the new key:
- A payment form signed with the old key is rejected, and your customer cannot reach the payment page.
- An API call using the old key returns
401.
Regenerate at a quiet time, and have every place that stores the key ready to update before you click.
Once the dialog is closed, the key is no longer shown anywhere in the interface. If you close it before saving, you have to regenerate again, and the key you just created stops working too.
After regenerating
The new key works immediately for both the checkout pages and the API; there is no period in which both keys work. Update the new key everywhere the old one was used:
- Environment variables or configuration files on your server.
- The WooCommerce or Haravan plugin, or any other CMS integration.
- PHP / Node.js SDK configuration.
- Internal services that sign payment forms themselves.
Limits and common errors
| Situation | Message | What to do |
|---|---|---|
| More than 3 regenerations within 1 hour in the same environment (LIVE and Test mode are counted separately) | "Bạn đã tạo lại Secret Key quá nhiều lần, vui lòng thử lại sau khoảng N phút." (too many regenerations, try again in about N minutes) | Wait the number of minutes in the message, then try again. |
| The environment changed after you opened the page (for example Test Mode was switched in another tab) | "Bạn đang ở môi trường ... Vui lòng tải lại trang rồi thử lại." (you are in environment ..., reload the page and try again) | Reload the page, check the Test Mode switch, then repeat the steps. |
| A colleague regenerated the key just before you | "Secret Key vừa được tạo lại bởi người khác..." (the Secret Key was just regenerated by someone else) | Open Nhật ký người dùng (User log) to see who regenerated it, and get the new key from them. Do not regenerate again, or the key they hold stops working. |
| No response in time (slow connection) | "Yêu cầu quá hạn, Secret Key có thể đã được tạo lại..." (request timed out, the Secret Key may have been regenerated) | Open Nhật ký người dùng (User log) and look for a "Tạo lại Secret Key cổng thanh toán" entry from just now. If it is there, the key changed but you never received the new one, so regenerate once more. If not, simply try again. |
Each regeneration is recorded in the User log: who did it, when, and in which environment. The log never contains the key.