※ 이 사이트는 Internet Explorer 10 이하 버전은 지원하지 않습니다. 최신 브라우저로 업데이트해 주세요.
VAN 빌링 연동
스마트로페이 결제모듈 연동을 위한 가이드입니다.
- 해당 매뉴얼의 Parameter 들은 가맹점에 통보 없이 응답값이 추가 될 수 있습니다. 응답값 추가도 고려하여 개발 진행하시길 권장합니다 .
- Test 연동시 체크 카드는 사용자제 부탁드립니다.체크 카드 결제시 Test 계에서는 당일 전체 취소만 가능 합니다 (부분취소 지원 불가)
- 빌링키 발급 시 해외카드는 지원되지 않습니다.(국내카드만 등록 가능)
- 스마트로 사업자번호로 제공된 테스트 Mid는 국민카드(카카오뱅크), 하나카드 결제가 불가합니다.
VAN 빌링
결제 정보를 암호화 처리 후 스마트로 VAN 망을 통해 PG사 인증서버로 전송하는 방식의 빌링 서비스입니다.
USE_TO_ONE:고객번호 1개에 빌키 1개 발급, USER_TO_MULTI: 고객번호 1개에 빌키 다수 발급
DisplayCardNo
표시용 카드번호
20
실 카드번호 마스킹 처리
VerifyValue
위·변조 검증값
가변
SHA256 해시 암호화
BillKeyExpDate
Bill-key 유효기간
4
MallReserved
가맹점예비정보
500
가맹점에서 설정한 값 전달
STEP 1VAN빌링키 발급 요청 파라미터 설정하기
·JSP
String Mid = ""; // 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
String SspMallId = "SMTSSPAY0p" // VAN빌링키 테스트용 SspMallId (REAL 전환 시 가맹점 SspMallId로 변경)
String MallLicenseKey = ""; // 가맹점 MallLicenseKey 설정
String CoNo = ""; // 가맹점 사업자번호 설정
String EdiDate = getyyyyMMddHHmmss();
String EncryptData = encodeSHA256Base64(SspMallId + MallLicenseKey + CoNo + EdiDate);
String today = getyyyyMMddHHmm(); // 현재일자. 캐시방지용으로 사용
/* SHA256 암호화 */
public static final String encodeSHA256Base64(String strPW) {
String passACL = null;
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (Exception e) {
e.printStackTrace();
}
md.update(strPW.getBytes());
byte[] raw = md.digest();
byte[] encodedBytes = Base64.encodeBase64(raw);
passACL = new String(encodedBytes);
return passACL;
}
/* 현재일자 */
public static final String getyyyyMMddHHmmss() {
SimpleDateFormat yyyyMMddHHmmss = new SimpleDateFormat("yyyyMMddHHmmss");
return yyyyMMddHHmmss.format(new Date());
}
/* 현재일자 */
public static final String getyyyyMMddHHmm() {
SimpleDateFormat yyyyMMddHHmm = new SimpleDateFormat("yyyyMMddHHmm");
return yyyyMMddHHmm.format(new Date());
}
$Mid = ""; // 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
$SspMallId = "SMTSSPAY0p" // VAN빌링키 테스트용 SspMallId (REAL 전환 시 가맹점 SspMallId로 변경)
$MallLicenseKey = ""; // 가맹점 MallLicenseKey 설정
$CoNo = ""; // 가맹점 사업자번호 설정
$EdiDate = date("YmdHis");
$EncryptData = base64_encode(hash('sha256', $SspMallId.$MallLicenseKey.$CoNo.$EdiDate, true));
$today = date("YmdHi"); // 현재일자. 캐시방지용으로 사용
smartroMid = "" ' 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
SspMallId = "SMTSSPAY0p" // VAN빌링키 테스트용 SspMallId (REAL 전환 시 가맹점 SspMallId로 변경)
MallLicenseKey = ""; // 가맹점 MallLicenseKey 설정
CoNo = ""; // 가맹점 사업자번호 설정
EdiDate = Year(Now()) & right("0"&Month(Now()),2) & right("0"&Day(Now()),2) & right("0"&Hour(Now()),2) & right("0"&Minute(Now()),2) & right("0"&Second(Now()),2)
EncryptData = CryptoUtil.Sha256Encrypt(SspMallId & MallLicenseKey & CoNo & EdiDate)
today = Year(Now()) & right("0"&Month(Now()),2) & right("0"&Day(Now()),2) & right("0"&Hour(Now()),2) & right("0"&Minute(Now()),2) ' 현재일자. 캐시방지용으로 사용
const crypto = require('crypto');
// 발급받은 테스트 MID 설정 (운영 전환 시 실제 값 사용)
const Mid = "";
const SspMallId = ""; // VAN 빌링키 테스트용 SspMallId (REAL 전환 시 가맹점 SspMallId로 변경)
const MallLicenseKey = ""; // 가맹점 MallLicenseKey 설정
const CoNo = ""; // 가맹점 사업자번호 설정
const EdiDate = getyyyyMMddHHmmss(); // 현재 일자 (yyyyMMddHHmmss 형식)
const EncryptData = encodeSHA256Base64(SspMallId + MallLicenseKey + CoNo + EdiDate); // SHA256 + Base64 인코딩
const today = getyyyyMMddHHmm(); // 현재 일자 (캐시 방지용)
// SHA256 암호화 + Base64 인코딩 함수
function encodeSHA256Base64(data) {
const hash = crypto.createHash('sha256');
hash.update(data);
return Buffer.from(hash.digest()).toString('base64'); // 해시 결과를 Base64로 인코딩
}
// 현재 일자 (yyyyMMddHHmmss 형식)
function getyyyyMMddHHmmss() {
const now = new Date();
return now.toISOString().replace(/[-T:Z.]/g, '').slice(0, 14); // 'YYYYMMDDHHMMSS' 형식으로 변환
}
// 현재 일자 (yyyyMMddHHmm 형식)
function getyyyyMMddHHmm() {
const now = new Date();
return now.toISOString().replace(/[-T:Z.]/g, '').slice(0, 12); // 'YYYYMMDDHHMM' 형식으로 변환
}
// 결과 출력
console.log("EncryptData:", EncryptData);
console.log("today", today);
console.log("EdiDate", EdiDate);
- Python 모듈 소스의 경우 Django(v.5.0.7)를 기반으로 작성되었습니다.
import hashlib
import base64
import datetime
Mid = "" # 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
SspMallId = "" # VAN 빌링키 테스트용 SspMallId(Real 전환 시 운영 SspMallId로 변경)
MallLicenseKey = "" # 가맹점 MallLicenseKey 설정
CoNo = "" # 가맹점 사업자번호 설정
EdiDate = "" # EdiDate
today = "" # 현재일자, 캐시방지용으로 사용
# EdiDate 생성
def getyyyyMMddHHmmss():
return datetime.datetime.now().strftime("%Y%m%d%H%M%S")
EdiDate = getyyyyMMddHHmmss()
# today 생성
def getyyyyMMddHHmm():
return datetime.datetime.now().strftime("%Y%m%d%H%M")
today = getyyyyMMddHHmm()
# EncryptData 생성
def encodeSHA256Base64(strPW):
sha256_object = hashlib.sha256()
sha256_object.update(strPW.encode())
return base64.b64encode(sha256_object.digest()).decode("utf-8")
EncryptData = encodeSHA256Base64(SspMallId + MallLicenseKey + CoNo + EdiDate)
STEP 2VAN빌링키 Form데이터 설정
·JSP
SmartroPAY 연동가이드
import { useEffect } from 'react';
function Pay() {
// PC/Mobile 구분하여 도메인 변경 필요
// PC 환경에서 호출시 https://tpay.smartropay.co.kr/asset/js/SmartroPAY-1.0.min.js?version=현재일자
// Mobile 환경에서 호출시 https://tmpay.smartropay.co.kr/asset/js/SmartroPAY-1.0.min.js?version=현재일자
// 운영 전환 시 도메인 변경
// PC : tpay.smartropay.co.kr -> pay.smartropay.co.kr
// Mobile : tmpay.smartropay.co.kr -> mpay.smartropay.co.kr
// script 캐시방지를 위해 ?version=today를 추가 ex) SmartroPAY-1.0.min.js?version=20230101
useEffect(() => {
const script = document.createElement('script');
script.src = `https://tpay.smartropay.co.kr/asset/js/SmartroPAY-1.0.min.js?version=`;
script.type = 'text/javascript';
document.head.appendChild(script);
return () => {
document.head.removeChild(script);
}
}
, []);
// 스마트로 페이 응답은 POST로 응답됩니다.
// POST 응답을 받을 수 있는 서버 url을 넣어주세요.
const ReturnUrl = "";
const goPay = () => {
window.smartropay.init({
mode : 'STG', // STG: 테스트, REAL: 운영(운영서버 전환 시 변경 필수!)
actionUri : '/ssvbill/interface.do'
});
// 스마트로페이 VAN빌링키 발급요청
window.smartropay.payment({
FormId : 'tranMgr' // 폼ID
});
}
return(
<>
0000 : success
PR01 : 멤버 정보 미존재
PA50 : 발급정보없음
* 그 외 응답 - 통합코드 조회 참고
ResultMsg
결과메시지
80
ResultData
*ResultCode=0000 시 응답
빌링키 상세 조회리스트
가변
하단 응답 예시 참고
파라미터
항목명
길이(char)
설명
RegMid
등록 Mid
10
BillTokenKey
고정식토큰(빌링키)
50
IssuerCardCd
발급사 코드
2
IssuerCardNm
발급사명
10
DisplayCardNo
표시용 카드번호
20
마스킹되어 전달
CardExpire
빌링키 유효기간
4
YYMM
실제 카드 유효기간 -2개월로 응답
RegDt
빌링키 등록 일자
8
YYYYMMDD
STEP 1VAN 빌링키 조회 파라미터 설정 및 UrlCall 조회 요청하기
·JSP
String url = "https://tapproval.smartropay.co.kr/payment/approval/vanBillKeyInquiry.do"; // 테스트
// String url = "https://approval.smartropay.co.kr/payment/approval/vanBillKeyInquiry.do"; // 운영
JSONObject body = new JSONObject();
JSONObject paramData = new JSONObject();
String MallLicenseKey = ""; // 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
String SspMallId = ""; // 테스트용 SspMallId
String MallUserId = ""; // 회원사 고객 ID
String BillTokenKey = ""; // 빌링키 발급을 통해 생성된 키
// 요청 파라미터 (각 값들은 가맹점 환경에 맞추어 설정해 주세요.)
paramData.put("SspMallId", SspMallId);
paramData.put("MallUserId", MallUserId);
paramData.put("BillTokenKey", BillTokenKey);
$url = "https://tapproval.smartropay.co.kr/payment/approval/vanBillKeyInquiry.do"; // 테스트
//$url = "https://approval.smartropay.co.kr/payment/approval/vanBillKeyInquiry.do"; // 운영
$MallLicenseKey = ""; // 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
$Mid = ""; // 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
$SspMallId = "SMTSSPAY0p"; // 테스트용 SspMallId
$MallUserId = ""; // 회원사 고객 ID
$BillTokenKey = ""; // 발급받은 빌링키
$paramData = array(
'SspMallId' => $SspMallId,
'MallUserId' => $MallUserId,
'BillTokenKey' => $BillTokenKey
);
url = "https://tapproval.smartropay.co.kr/payment/approval/vanBillKeyInquiry.do" ' 테스트
'url = "https://approval.smartropay.co.kr/payment/approval/vanBillKeyInquiry.do" ' 운영
MallLicenseKey = "" ' 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
Mid = "" ' 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
SspMallId = "SMTSSPAY0p" ' 테스트용 SspMallId
MallUserId = ""; ' 회원사 고객 ID
BillTokenKey = "" ' 발급받은 빌링키
Set paramData = jsObject()
paramData("SspMallId") = SspMallId
paramData("MallUserId") = MallUserId
paramData("BillTokenKey") = BillTokenKey
const axios = require('axios');
const crypto = require('crypto');
const domainUrl = 'https://tapproval.smartropay.co.kr/'; // 테스트 URL
// const domainUrl = 'https://approval.smartropay.co.kr/'; // 운영 URL
// AES256 암호화 함수
function AES256Encode(data, key) {
const iv = Buffer.alloc(16, 0);
const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv);
let encrypted = cipher.update(data, 'utf8', 'base64');
encrypted += cipher.final('base64');
return encrypted;
}
async function inquiry() {
const restRequestUrl = domainUrl + 'payment/approval/vanBillKeyInquiry.do';
const MallLicenseKey = ''; // 발급받은 테스트 상점키 설정
const Mid = ''; // 발급받은 테스트 Mid 설정
const SspMallId = ''; // 테스트용 SspMallId
const MallUserId = ''; // 회원사 고객 ID
const BillTokenKey = ''; // 빌링키 발급을 통해 생성된 키
const body = {
SspMallId: SspMallId,
MallUserId: MallUserId,
BillTokenKey: BillTokenKey
};
// JSON 데이터 AES256 암호화
const sendObject = {
EncData: AES256Encode(JSON.stringify(body), merchantKey.substring(0, 32)),
Mid: Mid
};
// .... STEP2 요청 및 결과 받기
from django.shortcuts import render
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
import json
import requests
import base64
from Cryptodome.Cipher import AES
from Cryptodome import Random
@csrf_exempt
def inquiry(request):
# 빌링키 조회 요청
# 운영 : https://approval.smartropay.co.kr/payment/approval/vanBillKeyInquiry.do
# 테스트 : https://tapproval.smartropay.co.kr/payment/approval/vanBillKeyInquiry.do
Mid = "" # 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
MallLicenseKey = "" # 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
SspMallId = "" # 발급받은 SspMallId
MallUserId = "" # MallUserId
BillTokenKey = "" # 빌링키 발급을 통해 생성된 키
# 요청 파라미터 (각 값들은 가맹점 환경에 맞추어 설정해 주세요.)
paramData = {
'SspMallId' : SspMallId,
'MallUserId' : MallUserId,
'BillTokenKey' : BillTokenKey
}
# .... STEP2 요청 및 결과 받기
STEP 2VAN 빌링키 조회 결과 받기
·JSP
// json 데이터 AES256 암호화
try {
body.put("EncData", AES256Cipher.AES_Encode(paramData.toString(), MallLicenseKey.substring(0,32)));
body.put("SspMallId", SspMallId);
} catch(Exception e){
e.printStackTrace();
}
HashMap<String, Object> result = callApi(body, url);
public HashMap<String, Object> callApi(JSONObject json, String callUrl) {
StringBuilder responseBody = null;
HashMap<String, Object> result = new HashMap<>();
// http urlCall 승인 요청 및 TrAuthKey 유효성 검증
int connectTimeout = 1000;
int readTimeout = 20000; // 원천사 별로 최대 응답 시간이 상이하므로 가맹점 환경에 맞게 Timeout 설정
URL url = null;
HttpsURLConnection connection = null;
try {
SSLContext sslCtx = SSLContext.getInstance("TLSv1.2");
sslCtx.init(null, null, new SecureRandom());
url = new URL(callUrl);
System.out.println(" url " + url.toString());
connection = (HttpsURLConnection)url.openConnection();
connection.setSSLSocketFactory(sslCtx.getSocketFactory());
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Accept", "application/json");
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setConnectTimeout(connectTimeout);
connection.setReadTimeout(readTimeout);
OutputStreamWriter osw = new OutputStreamWriter(new BufferedOutputStream(connection.getOutputStream()) , "utf-8" );
char[] bytes = json.toString().toCharArray();
osw.write(bytes,0,bytes.length);
osw.flush();
osw.close();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
String line = null;
responseBody = new StringBuilder();
while ((line = br.readLine()) != null) {
System.out.println(" response " + line);
responseBody.append(line);
}
br.close();
// 결제결과
result = new ObjectMapper().readValue(responseBody.toString(), HashMap.class);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}