PNS (Payment Notification Service)

If the app that uses ONE store's IAP V5 initiates payment or payment cancellation transactions through the ONE store payment system, ONE store passes a notification to the pre-configured Developer Center Server. The PNS (Payment Notification Service) can be used as a means to check the loss of payment information that may occur on mobile, and makes a push notification on payment and payment cancellation, respectively.

  • Since the payment notification may also be lost or the server that sends and receives notifications may fail, developers must not use the push notification they receive as a ground for providing in-app products.

  • The developers are required to provide the in-app products based on the payment completion response which is made for the payment request of the app. The payment notification is used for customer service purposes, including payment confirmation and withdrawal of items.

  • If you want to check the payment with a server-to-server, do not use PNS notification and we recommend using related server APIs like getPurchaseDetail or getPurchaseDetailByProduct.

  • ONE store can perform a payment test for verification and monitoring purposes, and the test results will be sent the same notification upon payment/cancellation. The payment test details are periodically cancelled by ONE store.

  • You can set up the developer's service server which receives the payment notification by selecting an in-app product on the 'Developer Center > Apps > My Applications' page and clicking the 'Payment Notification' button on the 'In-App' menu.

  • Payment Notification Message Format (ONE store → the developer's service server)

    Parameter Name:TypeRequiredDescription

    msgVersion

    Y

    The message version

    • Development(SANDBOX) : 2.0.0D

    • Commercial : 2.0.0

    packageName : String

    Y

    the package name of the app

    productId : String

    Y

    the In-App product ID

    messageType : String

    Y

    ONE store sends the fixed message: "SINGLE_PAYMENT_TRANSACTION"

    purchaseId : String

    Y

    the purchase ID

    developerPayload : String

    N

    the payment unique identifier that is provided by the developer

    purchaseTimeMillis : Long

    Y

    the time when the payment is completed on the ONE store payment system(timestamp:Long)

    purcahseState : enum

    Y

    • COMPLETED : paid

    • CANCELED : cancelled

    price : Number

    Y

    total payment amount

    productName : String

    N

    It will be passed if the developer's service sets the customized in-app product name upon purchase request.

    paymentTypeList : object[]

    Y

    payment information

    paymentMethod : String

    Y

    payment method (the paymentMethod is defined below this table)

    amount : Number

    Y

    payment amount

    billingKey

    N

    the billingkey for the extension features

    isTestMdn

    N

    ONE store test billing (true : test, false : normal billing/canceling case) This parameter helps you to identify the ONE store test billing. ONE store may purchase your In-App products for the review or test purpose and those purchases are canceled by ONE store. In this case, you will receive PNS messages with this parameter set to 'true'.

    signature : String

    Y

    signature of this message

  • Payment Notification Message Sample

{
  "msgVersion": "2.0.0.D",
  "packageName":"com.onestore.pns",
  "productId":"0900001234",
  "messageType":"SINGLE_PAYMENT_TRANSACTION",
  "purchaseId":"SANDBOX3000000004564",
  "developerPayload":"OS_000211234",
  "purchaseTimeMillis":24431212233,
  "purchaseState":"COMPLETED",
  "price":10000,
  "productName":"GOLD100(+20)"
  "paymentTypeList":[
    {
      "paymentMethod":"DCB",
      "amount":3000
    },
    {
      "paymentMethod":"ONESTORECASH",
      "amount":7000
    }
  ],
  "billingKey" : "36FED4C6E4AC9E29ADAF356057DB98B5CB92126B1D52E8757701E3A261AF49CCFBFC49F5FEF6E277A7A10E9076B523D839E9D84CE9225498155C5065529E22F5",
  "isTestMdn" : true,
  "signature":   "BwJdUVT/iFFT1MKIFZTdkD/y5+b8h4hCuVB3zVrYcT7pMf1wuWrXNZK9ZA1FhUlWPa7C10Do4CDr8k28QOejGOCgiit5RYzL1tF5eRjFkY66oD3qfNvexkt5wwVjJP5EYyzqwCDVkbx004eGUX46LzaxVV7i137e4KyUrdk9Q5c="
}
  • paymentMethod of ONE store

paymentMethod

name

description

DCB

Direct carrier billing

Direct carrier billing

PHONEBILL

Mobile Micro-Payment

Mobile Micro-Payment

ONEPAY

ONE pay

mobile payment service(Card) by ONE store

ONEPAYBANKACCT

ONE pay Bank Account

mobile payment service(account) by ONE store

ONEPAYDCB

ONE pay Direct carrier billing

mobile payment service(DCB) by ONE store

ONEPAYPHONEBILL

ONE pay Mobile Micro-Payment

mobile payment service(PHONBILL) by ONE store

CREDITCARD

Credit card

credit/debit card payment

11PAY

11Pay

mobile payment service by SK planet

NAVERPAY

Naver pay

mobile payment service by NAVER

CULTURELAND

Culture Cash

TMEMBERSHIP

T membership

membership point of SK telecom

KTMEMBERSHIP

KT membership

membership point of KT

LGMEMBERSHIP

U+ membership

membership point of LG U+

OCB

OK Cashbag

GAMECASH

Game Cas

ONE store Game Cash

ONESTORECASH

ONE store Cash

ONE store Cash

ONESTORECOUPON

ONE store Coupon

ONE store Coupon

TMONEY

T Money

T Money

  • How to check the validity of the signature

    • Using the codes below, you can verify that the signature is valid.

    • The public key in the source code means the License key provided by ONE store development center(Apps > In-App > Credentials).

    • For more information, refer to the 'Issue License Key' in the Preparatory Work page.

JAVA

import java.security.PublicKey;
    
import org.apache.commons.codec.binary.Base64;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ObjectNode;
    
    
public class SignatureVerifier {
    
    private static final String SIGN_ALGORITHM = "SHA512withRSA";
    private ObjectMapper mapper = new ObjectMapper();
    
    
    boolean verify(String rawMsg, PublicKey key) throws Exception {
        // get the signature from the JSON message
        JsonNode root = mapper.readTree(rawMsg);
        String signature = root.get("signature").getValueAsText();
        ((ObjectNode)root).remove("signature");
           
        // check the validity of the signature
        Signature sign = Signature.getInstance(SIGN_ALGORITHM);
        sign.initVerify(key);
        sign.update(root.toString().getBytes("UTF-8"));
        return sign.verify(Base64.decodeBase64(signature));
    }
}

PHP

<?php
function formatPublicKey($publicKey) {
    $BEGIN= "-----BEGIN PUBLIC KEY-----";
    $END = "-----END PUBLIC KEY-----";
   
    $pem = $BEGIN . "\n";
    $pem .= chunk_split($publicKey, 64, "\n");
    $pem .= $END . "\n";
   
    return $pem;
}
   
function formatSignature($signature) {
    return base64_decode(chunk_split($signature, 64, "\n"));
}
   
// Sample message
$sampleMessage = '{"msgVersion":"2.0.0.D","purchaseId":"SANDBOX3000000004564","developerPayload":"OS_000211234","packageName":"com.onestore.pns","productId":"0900001234","messageType":"SINGLE_PAYMENT_TRANSACTION","purchaseMillis":24431212233,"purchaseState":"COMPLETED","price":20000,"productName":"한글은?GOLD100(+20)","paymentTypeList":[{"paymentMethod":"DCB","amount":3000},{"paymentMethod":"ONESTORECASH","amount":7000}],"billingKey":"36FED4C6E4AC9E29ADAF356057DB98B5CB92126B1D52E8757701E3A261AF49CCFBFC49F5FEF6E277A7A10E9076B523D839E9D84CE9225498155C5065529E22F5","isTestMdn":true,"signature":"MNxIl32ws+yYWpUr7om+jail4UQxBUXdNX5yw5PJKlqW2lurfvhiqF0p4XWa+fmyV6+Ot63w763Gnx2+7Zp2Wgl73TWru5kksBjqVJ3XqyjUHDDaF80aq0KvoQdLAHfKze34cJXKR/Qu8dPHK65PDH/Vu6MvPVRB8TvCJpkQrqg="}';
   
// Sample public key
$publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMzpWJoK1GSOrr4juma5+sREYjdCW8/xSd9+6z6PAkUH5af97wy8ecfkLtP9LK5VskryfDlcOjfu0BgmHYntAqKT7B4KWk8jWbJ8VHUpp30H95UbcnCRFDqpEtwYzNA5gNMYKtAdbL41K8Fbum0Xqxo65pPEI4UC3MAG96O7X1WQIDAQAB";
   
   
// Parse JSON message
$jsonArr = json_decode($sampleMessage, true);
   
// Extract and remove signature
$signature = $jsonArr["signature"];
unset($jsonArr["signature"]);
$originalMessage = json_encode($jsonArr, JSON_UNESCAPED_UNICODE);
   
// Veify
$formattedKey = formatPublicKey($publicKey);
$formattedSign = formatSignature($signature);
$hash_algorithm = 'sha512';
   
$success = openssl_verify($originalMessage, $formattedSign, $formattedKey, $hash_algorithm);
if ($success == 1) {
    echo "verified";
}
else {
    echo "unverified";
}
?>

Python

# -*- coding: utf-8 -*-
   
import json
from base64 import b64decode
from collections import OrderedDict
   
from Crypto.Hash import SHA512
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
   
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
   
hash = "SHA-512"
   
   
def verify(message, signature, pub_key):
    signer = PKCS1_v1_5.new(pub_key)
    digest = SHA512.new()
    digest.update(message)
    return signer.verify(digest, signature)
   
   
jsonData = json.loads(rawMsg, encoding='utf-8', object_pairs_hook=OrderedDict)
signature = jsonData['signature']
del jsonData['signature']
originalMessage = json.dumps(jsonData, ensure_ascii=False, encoding='utf-8', separators=(',', ':'))
   
RSA.importKey(publickey).publickey()
print(verify(originalMessage, b64decode(signature), RSA.importKey(publickey).publickey()))

Last updated