Overview
After the user completes payment, Oceanpayment sends an asynchronous payment notification to the noticeUrl provided in the merchant’s request. The notification contains the order number, payment status, payment time, and other transaction details for the merchant to verify and update the order status.
Before You Begin
For details about notification retries, retry intervals, and merchant response requirements, see Oceanpayment’s Notification Retry Mechanism and Specifications.
Payment Status Updates
The same order may first receive a payment failure notification and later receive a payment success notification. When the success notification is received, merchants should treat it as the latest payment status. Update the order status based on the order number, payment ID, payment status, and payment time in the notification.
- Oceanpayment sends a payment result notification for the order to the merchant’s
noticeUrl. - After verifying the signature, the merchant updates the order to the latest status and proceeds with any follow-up actions, such as confirming the order or arranging shipment.
Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
notice_type | string | Notification type
| transaction |
push_dateTime | string | Push time
| 2026-10-01 10:00:00 |
response_type | string | Callback type
| 1 |
account | string | Oceanpayment account number | 995149 |
terminal | string | Oceanpayment terminal number | 99514901 |
signValue | string | Security signature used to verify transaction integrity, SHA256 encrypted | e14328dc67b203de5048d999f3ccd054d1bad550a0821381ce508176329cb7ee |
methods | string | Payment method | Credit Card |
order_number | string | Merchant order number | NO123456789 |
card_country | string | Card issuing country | US |
order_currency | string | Transaction currency
| USD |
order_amount | string | Transaction amount
| 0.1 |
order_notes | string | Order notes, returned as-is | Remark |
card_number | string | Card number
| 411111***1111 |
card_type | string | Card type | Visa |
payment_country | string | Customer IP country | US |
payment_id | string | Oceanpayment unique payment ID | 20261030094706490119917358 |
quickpay_id | string | QuickPay ID (UUID format)
| 7c910aaf-4760-4467-bd23-d8157e01844b |
payment_status | string | Transaction status
| 1 |
payment_authType | string | Transaction type
| 0 |
payment_details | string | Payment details
| 80000:Transaction Approved |
payment_solutions | string | Solutions for failed payment
| Contact the merchant website to confirm the payment result |
payment_risk | string | Failed risk rules in format
| PriorChannel=0.0; |
payment_amount | string | Actual paid amount by customer | 0.1 |
payment_exchangeRate | string | Exchange rate | 0.85358155 |
pay_barCode | string | Order barcode | 4500011583202610306638447730 |
auth_reason | string | PreAuth operation reason | Confirm authorization |
order_operator | string | Operator handling pre-auth in backend | Operator |
auth_code | string | Credit card authorization code
| 1793325793759R9 |
pay_userId | string | Customer ID | USER_9D7A2F6C1B84 |
card_cvvResultCode | string | Returned CVV Code and Description | 01 |
Payment Status
In the asynchronous notification parameters, payment_status indicates the payment result status. For details about each status, see the Payment Status documentation.
Response Code
In the asynchronous notification parameters, payment_details contains the payment details for the transaction in the format [Code: Payment Details]. For code descriptions, see Payment Response Codes.
XML Response Example
<?xml version="1.0" encoding="UTF-8"?>
<response>
<notice_type>transaction</notice_type>
<push_dateTime></push_dateTime>
<response_type>1</response_type>
<account>995149</account>
<terminal>99514901</terminal>
<signValue>0B1FAEDCD3DE9FB72F13A0DB80955479B00F2E6F7A4BF5C84A3403C1EAE489BE</signValue>
<methods>Credit Card</methods>
<order_number>NO12345678</order_number>
<card_type>Visa</card_type>
<card_country>US</card_country>
<order_currency>USD</order_currency>
<order_amount>1.99</order_amount>
<order_notes></order_notes>
<card_number>411111***1111</card_number>
<payment_country>CN</payment_country>
<payment_id>180808092746539010540</payment_id>
<payment_authType>0</payment_authType>
<payment_status>1</payment_status>
<payment_details>Successful test transaction</payment_details>
<payment_solutions></payment_solutions>
<payment_risk></payment_risk>
<payment_amount>1.00</payment_amount>
<payment_exchangeRate></payment_exchangeRate>
<pay_userId></pay_userId>
<pay_barCode>5b87b4528d3a66e4a59e51577960d552461c997a32c71e3c</pay_barCode>
<auth_reason></auth_reason>
<order_operator></order_operator>
</response>
Notification Parsing Example
Notifications are sent to the noticeUrl provided in the transaction request.
- PHP
- Java
- Python
- Go
- Node.js
// Get XML of push input stream
$xml_str = file_get_contents("php://input");
// Check whether the returned input stream is XML
if(xml_parser($xml_str)){
$xml = simplexml_load_string($xml_str);
// Assign the push parameters to $_REQUEST
$_REQUEST['response_type'] = (string)$xml->response_type;
$_REQUEST['account'] = (string)$xml->account;
$_REQUEST['terminal'] = (string)$xml->terminal;
$_REQUEST['payment_id'] = (string)$xml->payment_id;
$_REQUEST['order_number'] = (string)$xml->order_number;
$_REQUEST['order_currency'] = (string)$xml->order_currency;
$_REQUEST['order_amount']= (string)$xml->order_amount;
$_REQUEST['payment_status']= (string)$xml->payment_status;
$_REQUEST['payment_details'] = (string)$xml->payment_details;
$_REQUEST['signValue'] = (string)$xml->signValue;
$_REQUEST['order_notes'] = (string)$xml->order_notes;
$_REQUEST['card_number'] = (string)$xml->card_number;
$_REQUEST['payment_authType'] = (string)$xml->payment_authType;
$_REQUEST['payment_risk'] = (string)$xml->payment_risk;
$_REQUEST['methods'] = (string)$xml->methods;
$_REQUEST['payment_country'] = (string)$xml->payment_country;
$_REQUEST['payment_solutions'] = (string)$xml->payment_solutions;
}
// Check whether it is XML
function xml_parser($str){
$xml_parser = xml_parser_create();
if(!xml_parse($xml_parser,$str,true)){
xml_parser_free($xml_parser);
return false;
}else {
return true;
}
}
import org.w3c.dom.*;
import javax.xml.parsers.*;
import org.xml.sax.InputSource;
import java.io.StringReader;
import java.util.*;
String[] fields = {
"response_type", "account", "terminal", "payment_id",
"order_number", "order_currency", "order_amount",
"payment_status", "payment_details", "signValue",
"order_notes", "card_number", "payment_authType",
"payment_risk", "methods", "payment_country",
"payment_solutions"
};
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
Document document = factory.newDocumentBuilder()
.parse(new InputSource(new StringReader(xmlString)));
Map<String, String> data = new HashMap<>();
for (String field : fields) {
NodeList nodes = document.getElementsByTagName(field);
data.put(field, nodes.getLength() > 0
? nodes.item(0).getTextContent()
: "");
}
// Example: Reading Fields
String paymentId = data.get("payment_id");
String paymentStatus = data.get("payment_status");
import xml.etree.ElementTree as ET
fields = [
"response_type", "account", "terminal", "payment_id",
"order_number", "order_currency", "order_amount",
"payment_status", "payment_details", "signValue",
"order_notes", "card_number", "payment_authType",
"payment_risk", "methods", "payment_country",
"payment_solutions",
]
root = ET.fromstring(xml_string)
data = {
field: root.findtext(field, default="")
for field in fields
}
# Example: Reading Fields
payment_id = data["payment_id"]
payment_status = data["payment_status"]
package main
import "encoding/xml"
type PaymentNotification struct {
ResponseType string `xml:"response_type"`
Account string `xml:"account"`
Terminal string `xml:"terminal"`
PaymentID string `xml:"payment_id"`
OrderNumber string `xml:"order_number"`
OrderCurrency string `xml:"order_currency"`
OrderAmount string `xml:"order_amount"`
PaymentStatus string `xml:"payment_status"`
PaymentDetails string `xml:"payment_details"`
SignValue string `xml:"signValue"`
OrderNotes string `xml:"order_notes"`
CardNumber string `xml:"card_number"`
PaymentAuthType string `xml:"payment_authType"`
PaymentRisk string `xml:"payment_risk"`
Methods string `xml:"methods"`
PaymentCountry string `xml:"payment_country"`
PaymentSolutions string `xml:"payment_solutions"`
}
var data PaymentNotification
err := xml.Unmarshal([]byte(xmlString), &data)
if err != nil {
// XML parsing failed.
}
// Example: Reading Fields
paymentID := data.PaymentID
paymentStatus := data.PaymentStatus
npm install fast-xml-parser
const { XMLParser } = require("fast-xml-parser");
const parser = new XMLParser({
ignoreAttributes: true,
trimValues: false,
});
const parsed = parser.parse(xmlString);
// Assume the XML root element is <response>.
// If the actual root element has a different name, update "response" accordingly.
const data = parsed.response;
const fields = [
"response_type", "account", "terminal", "payment_id",
"order_number", "order_currency", "order_amount",
"payment_status", "payment_details", "signValue",
"order_notes", "card_number", "payment_authType",
"payment_risk", "methods", "payment_country",
"payment_solutions",
];
for (const field of fields) {
data[field] ??= "";
}
// Example: Reading Fields
const paymentId = data.payment_id;
const paymentStatus = data.payment_status;
Signature Security Verification
| Type | Signature Structure |
|---|---|
| Payments | account+terminal+order_number+order_currency+order_amount+order_notes+card_number+payment_id+ payment_authType+payment_status+payment_details+payment_risk+secureCode |
Signature Verification Example
- PHP
- Java
- Python
- Go
- Node.js
$_REQUEST['signValue'] = (string)$xml->signValue;
// Get the local secureCode value
$secureCode = {secureCode};
$local_signValue = hash("sha256",$_REQUEST['account'].$_REQUEST['terminal'].$_REQUEST['order_number'].$_REQUEST['order_currency'].$_REQUEST['order_amount'].$_REQUEST['order_notes'].$_REQUEST['card_number'].$_REQUEST['payment_id'].$_REQUEST['payment_authType'].$_REQUEST['payment_status'].$_REQUEST['payment_details'].$_REQUEST['payment_risk'].$secureCode);
// Encrypted string validation
if (strtolower($local_signValue) == strtolower($_REQUEST['signValue'])) {
if ($_REQUEST['payment_status'] == 1) {
// Payment successful
}elseif($_REQUEST['payment_status'] == 0){
// Payment failed
}elseif($_REQUEST['payment_status'] == -1){
// Pending
if ($_REQUEST['payment_authType'] == 1){
// Pre-authorization pending
}else{
//Payment failed
}
}
}else{
// Validation failed
}
echo "receive-ok";
exit;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Map;
public class PaymentNotification {
static String value(Map<String, String> data, String key) {
return data.getOrDefault(key, "");
}
static String sha256(String text) throws Exception {
byte[] hash = MessageDigest.getInstance("SHA-256")
.digest(text.getBytes(StandardCharsets.UTF_8));
StringBuilder hex = new StringBuilder();
for (byte b : hash) {
hex.append(String.format("%02x", b));
}
return hex.toString();
}
static void handle(Map<String, String> data, String secureCode) throws Exception {
String signingText =
value(data, "account") +
value(data, "terminal") +
value(data, "order_number") +
value(data, "order_currency") +
value(data, "order_amount") +
value(data, "order_notes") +
value(data, "card_number") +
value(data, "payment_id") +
value(data, "payment_authType") +
value(data, "payment_status") +
value(data, "payment_details") +
value(data, "payment_risk") +
secureCode;
String localSignValue = sha256(signingText);
String receivedSignValue = value(data, "signValue");
if (localSignValue.equalsIgnoreCase(receivedSignValue)) {
String status = value(data, "payment_status");
String authType = value(data, "payment_authType");
if ("1".equals(status)) {
// Payment successful
} else if ("0".equals(status)) {
// Payment failed
} else if ("-1".equals(status)) {
if ("1".equals(authType)) {
// Pre-authorization pending
} else {
// Payment failed
}
}
} else {
// Validation failed
}
return "receive-ok"
}
}
import hashlib
import hmac
def handle_payment_notification(data: dict, secure_code: str):
fields = [
"account",
"terminal",
"order_number",
"order_currency",
"order_amount",
"order_notes",
"card_number",
"payment_id",
"payment_authType",
"payment_status",
"payment_details",
"payment_risk",
]
signing_text = "".join(data.get(field, "") for field in fields) + secure_code
local_sign_value = hashlib.sha256(signing_text.encode("utf-8")).hexdigest()
received_sign_value = data.get("signValue", "")
if hmac.compare_digest(local_sign_value.lower(), received_sign_value.lower()):
status = data.get("payment_status", "")
auth_type = data.get("payment_authType", "")
if status == "1":
# Payment successful
pass
elif status == "0":
# Payment failed
pass
elif status == "-1":
if auth_type == "1":
# Pre-authorization pending
pass
else:
# Payment failed
pass
else:
# Validation failed
pass
return "receive-ok"
package main
import (
"crypto/sha256"
"encoding/hex"
"encoding/xml"
"io"
"log"
"net/http"
"os"
"strings"
)
type PaymentNotification struct {
Account string `xml:"account"`
Terminal string `xml:"terminal"`
OrderNumber string `xml:"order_number"`
OrderCurrency string `xml:"order_currency"`
OrderAmount string `xml:"order_amount"`
OrderNotes string `xml:"order_notes"`
CardNumber string `xml:"card_number"`
PaymentID string `xml:"payment_id"`
PaymentAuthType string `xml:"payment_authType"`
PaymentStatus string `xml:"payment_status"`
PaymentDetails string `xml:"payment_details"`
PaymentRisk string `xml:"payment_risk"`
SignValue string `xml:"signValue"`
}
func notifyHandler(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
body, err := io.ReadAll(r.Body)
if err != nil {
log.Printf("Failed to read the notification body.: %v", err)
writeAck(w)
return
}
var data PaymentNotification
if err := xml.Unmarshal(body, &data); err != nil {
log.Printf("Failed to parse the notification XML.: %v", err)
writeAck(w)
return
}
secureCode := os.Getenv("SECURE_CODE")
signingText := data.Account +
data.Terminal +
data.OrderNumber +
data.OrderCurrency +
data.OrderAmount +
data.OrderNotes +
data.CardNumber +
data.PaymentID +
data.PaymentAuthType +
data.PaymentStatus +
data.PaymentDetails +
data.PaymentRisk +
secureCode
hash := sha256.Sum256([]byte(signingText))
localSignValue := hex.EncodeToString(hash[:])
if strings.EqualFold(localSignValue, data.SignValue) {
switch data.PaymentStatus {
case "1":
// Payment successful
case "0":
// Payment failed
case "-1":
if data.PaymentAuthType == "1" {
// Pre-authorization pending
} else {
// Payment failed
}
}
} else {
// Validation failed
}
writeAck(w)
}
func writeAck(w http.ResponseWriter) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("receive-ok"))
}
func main() {
http.HandleFunc("/payment/notify", notifyHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
const crypto = require("crypto");
function handlePaymentNotification(data, secureCode) {
const fields = [
"account",
"terminal",
"order_number",
"order_currency",
"order_amount",
"order_notes",
"card_number",
"payment_id",
"payment_authType",
"payment_status",
"payment_details",
"payment_risk",
];
const signingText =
fields.map((field) => data[field] ?? "").join("") + secureCode;
const localSignValue = crypto
.createHash("sha256")
.update(signingText, "utf8")
.digest("hex");
const receivedSignValue = data.signValue ?? "";
const signValid =
localSignValue.toLowerCase() === receivedSignValue.toLowerCase();
if (signValid) {
const { payment_status: status, payment_authType: authType } = data;
if (status === "1") {
// Payment successful
} else if (status === "0") {
// Payment failed
} else if (status === "-1") {
if (authType === "1") {
// Pre-authorization pending
} else {
// Payment failed
}
}
} else {
// Validation failed
}
return "receive-ok";
}