VAN 빌링 연동

스마트로페이 결제모듈 연동을 위한 가이드입니다.
- 해당 매뉴얼의 Parameter 들은 가맹점에 통보 없이 응답값이 추가 될 수 있습니다. 응답값 추가도 고려하여 개발 진행하시길 권장합니다 .
- Test 연동시 체크 카드는 사용자제 부탁드립니다. 체크 카드 결제시 Test 계에서는 당일 전체 취소만 가능 합니다 (부분취소 지원 불가)
- 빌링키 발급 시 해외카드는 지원되지 않습니다.(국내카드만 등록 가능)
- 스마트로 사업자번호로 제공된 테스트 Mid는 국민카드(카카오뱅크), 하나카드 결제가 불가합니다.


VAN 빌링

결제 정보를 암호화 처리 후 스마트로 VAN 망을 통해 PG사 인증서버로 전송하는 방식의 빌링 서비스입니다.
스마트로페이 SERVER IP
스마트로페이 서비스 IP 정보입니다.
구분 IP 비고
테스트 211.193.35.11 STG
운영 - 결제 211.193.35.20
운영 - 재통보 211.193.35.216
211.193.35.217
재통보 서비스 사용시

VAN 빌링 키 발급

VAN빌링키 발급 파라미터

파라미터 항목명 길이(char) 필수여부 설명
TrId 가맹점 거래 일련번호 20 필수
SspMallId 결제MALL ID 10 필수 발급받은 SspMallId
CoNo 가맹점 사업자번호 10 필수
MallUserId 회원사 고객 ID 20 필수 회원가입 시 고객 구분값으로 사용
영어 대·소문자, 숫자 사용 가능(특수문자 포함 불가)
BuyerName 구매자명 30 필수
BuyerTel 구매자연락처 40 필수 숫자만 입력
(문자 입력 시 10자 미만으로 설정 하셔야합니다. - 초과 시 승인 오류 발생)
BuyerEmail 구매자메일주소 60 필수
EdiDate 요청 거래일시 14 필수
VerifyValue 위·변조 검증값 가변 필수 SHA256 해시 암호화
EncodingType 인코딩 형식 6 선택 utf8(기본값), euckr
MallReserved 상점 예비필드 500 선택 Base64 인코딩필요
(평문으로 전달시 한글 및 특수문자가 정상적으로 전달되지 않음)
InitTitle 가맹점 Title 설정 5 선택 5자리 제한, 기본값: 결제정보등록
RtnUrlEncUse 응답 데이터 UrlEncoding 처리여부 1 선택 Y: 사용, N(기본값): 미사용
ReturnUrl 등록결과 전달 가맹점 URL 100 선택 Http 프로토콜 포함 전체 Url 설정
SkinColor UI 스타일 10 선택 RED(기본값), GREEN, BLUE, PURPLE
파라미터 항목명 길이(char) 설명
TrId 가맹점 거래 일련번호 20
SspMallId 결제MALL ID 10
CoNo 가맹점 사업자번호 10
ResultCode 등록 결과 4 성공: 0000, 실패: 그 외
ResultMsg 등록 결과 메시지 가변
AppCardCode 발급사코드 2
AppCardName 발급사명 20
AcquCardCode 매입사코드 2
AcquCardName 매입사명 20
CardMerchantNo 카드사가맹점번호 15
CardNum 카드번호 16 7~12자리 Masking 처리
BillKey 빌링키 30
BillKeyPolicy Bill-key 발급정책 16 USE_TO_ONE:고객번호 1개에 빌키 1개 발급, USER_TO_MULTI: 고객번호 1개에 빌키 다수 발급
DisplayCardNo 표시용 카드번호 20 실 카드번호 마스킹 처리
VerifyValue 위·변조 검증값 가변 SHA256 해시 암호화
BillKeyExpDate Bill-key 유효기간 4
MallReserved 가맹점예비정보 500 가맹점에서 설정한 값 전달

STEP 1 VAN빌링키 발급 요청 파라미터 설정하기
·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());
}

STEP 2 VAN빌링키 Form데이터 설정
·JSP


<html lang="ko">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="" />
<meta name="author" content="Smartro" />
<title>SmartroPAY 연동가이드</title>

<!-- 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 -->
<script src="https://tpay.smartropay.co.kr/asset/js/SmartroPAY-1.0.min.js?version=현재일자"></script>

<script type="text/javascript">
	var url = 'https://tpay.smartropay.co.kr'; // 테스트서버 URL (REAL 전환 시 https://pay.smartropay.co.kr 로 변경)

	function goPay() {

		// 스마트로페이 초기화
		smartropay.init({
			mode : 'STG', // STG: 테스트, REAL: 운영(운영서버 전환 시 변경 필수!)
			actionUri : "/ssvbill/interface.do" // 호출 Uri
		});
		// 스마트로페이 VAN빌링키 발급요청
		smartropay.payment({
			FormId : 'tranMgr' // 폼ID
		});
	}
</script>
</head>
<body>
	<form id="tranMgr" name="tranMgr" method="post">
		<!-- 각 값들을 가맹점에 맞게 설정해 주세요. -->
		<input type="text" name="TrId" maxlength="20" value="" placeholder="가맹점 거래일련번호" />
		<input type="text" name="SspMallId" maxlength="20" value="설정한 SspMallId" placeholder="" />
		<input type="text" name="MallUserId" maxlength="20" value="MallUserId" placeholder="사용자ID" />
		<input type="text" name="CoNo" maxlength="10" value="설정한 CoNo" placeholder="" />
		<input type="text" name="BuyerName" maxlength="30" value="구매자명" placeholder="" />
		<input type="text" name="BuyerTel" maxlength="30" value="01099991111" placeholder="" />
		<input type="text" name="BuyerEmail" maxlength="30" value="noname@smartro.co.kr" placeholder="" />
		<input type="text" name="ReturnUrl" size="100" class="input" value="가맹점 ReturnUrl">
		<input type="text" name="VerifyValue" maxlength="100" class="input" value="생성된 EncryptData" placeholder="위/변조방지 HASH 데이터">
		<input type="text" name="EncodingType" maxlength="14" value="" placeholder="utf-8 or euc-kr" />
		<input type="text" name="MallReserved" maxlength="100" value="" placeholder="가맹점 예비정보" />
		<input type="text" name="EdiDate" maxlength="14" value="설정한 EdiDate" placeholder="" />
		<button type="button" class="btn btn-primary" onclick="goPay();">결제하기</button>
	</form>
</body>
</html>


VAN 빌링 키 삭제

VAN빌링키 삭제 파라미터

파라미터 항목명 길이(char) 필수여부 설명
SspMallId 결제MALL ID 10 필수
TrId 가맹점 거래 일련번호 20 필수
EdiDate 전문생성일시 14 필수
BuyerName 구매자명 30 필수
MallUserId 회원사 고객 ID 20 필수 고객 구분값
BillKey 빌링키 30 필수 삭제요청할 빌링키
CoNo 가맹점 사업자번호 10 필수
EncodingType 인코딩 형식 6 선택 utf8(기본값), euckr
VerifyValue 위·변조 검증값 50 필수 SHA256 해시 암호화
파라미터 항목명 길이(char) 설명
EdiDate 전문요청일시 14
CoNo 가맹점 사업자번호 10
SspMallId 결제MALL ID 10
ResultCode 결과코드 10 성공: 0000, 실패: 그 외
ResultMsg 결과메시지 80

STEP 1 VAN빌링키 삭제 요청 파라미터 설정하기
·JSP
        
String url = "https://tapproval.smartropay.co.kr/payment/approval/ssvDell.do";		// 테스트
// String url = "https://approval.smartropay.co.kr/payment/approval/ssvDell.do";		// 운영

JSONObject body = new JSONObject();
JSONObject paramData = new JSONObject();

String merchantKey = "";  						// 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
String MallLicenseKey = "";   					// 가맹점 MallLicenseKey 설정
String EdiDate = getyyyyMMddHHmmss();
String SspMallId = "SMTSSPAY0p";   				// 테스트용 SspMallId (Real 전환 시 가맹점 SspMallId로 설정)
String TrId = getyyyyMMddHHmmss() + "000000";	// 거래 일련번호
String CoNo = "";   							// 가맹점 사업자번호 설정
String BillKey = "";  							// 삭제할 빌링키
String EncodingType = "";  						// EUC-KR or UTF-8
// 한글 인코딩
String BuyerName = URLEncoder.encode("구매자명" ,  "UTF-8");
// 검증값 SHA256 암호화(SspMallId + MallLicenseKey + CoNo + EdiDate)
String VerifyValue = encodeSHA256Base64(SspMallId + MallLicenseKey + CoNo + EdiDate);

// 요청 파라미터 (각 값들은 가맹점 환경에 맞추어 설정해 주세요.)
paramData.put("Trid", TrId);
paramData.put("EdiDate", EdiDate);
paramData.put("BuyerName", BuyerName);
paramData.put("MallUserId", "");
paramData.put("BillKey", "");
paramData.put("CoNo", CoNo);
paramData.put("EncodingType", EncodingType);  // EUC-KR or UTF-8
paramData.put("VerifyValue" ,VerifyValue);

// 날짜 생성 함수
public static String getyyyyMMddHHmmss() {
    /** yyyyMMddHHmmss Date Format **/
    SimpleDateFormat yyyyMMddHHmmss = new SimpleDateFormat("yyyyMMddHHmmss");
    return yyyyMMddHHmmss.format(new Date());
}
		
	

STEP 2 삭제 요청 및 결과 받기
·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 = 10000; // 가맹점에 맞게 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;
}
		
	

VAN 빌링키 정보 조회

VAN 빌링 키 조회 파라미터

파라미터 항목명 길이(char) 필수여부 설명
SspMallId 결제MALL ID 10 필수
MallUserId 회원사 고객 ID 20 필수
BillTokenKey 고정식 토큰(빌링키) 50 필수
파라미터 항목명 길이(char) 설명
SspMallId 결제MALL ID 10
MallUserId 회원사 고객 ID 20
ResultCode 결과코드 10 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 1 VAN 빌링키 조회 파라미터 설정 및 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 Mid = "";						// 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)

String SspMallId = "SMTSSPAY0p";		// 테스트용 SspMallId
String MallUserId = "";					// 회원사 고객 ID
String BillTokenKey = "";				// 빌링키 발급을 통해 생성된 키

// 요청 파라미터 (각 값들은 가맹점 환경에 맞추어 설정해 주세요.)
paramData.put("SspMallId", SspMallId);
paramData.put("MallUserId", MallUserId);
paramData.put("BillTokenKey", BillTokenKey);
		
	

STEP 2 VAN 빌링키 조회 결과 받기
·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 = 10000; // 가맹점에 맞게 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;
}
		
	
Example 빌링키 조회 응답 예시
MallUserId에 등록된 결제 수단 정보가 ResultData에 리스트 형태로 응답됩니다.
					
{
	"ResultCode": "0000",
	"ResultMsg": "success",
	"ResultData": [
		{
			"RegMid": "2178114493",
			"BillTokenKey": "VB25020310000000000000000000000",
			"IssuerCardCd": "07",
			"IssuerCardNm": "현대",
			"DisplayCardNo": "123456******1234",
			"CardExpire": "2806",
			"RegDt": "20241011"
		}
	]
}
					
				

(추가) AES256 암호화 함수(AES256Cipher)

·JSP
※ 암호화 실행 중 Illegal key size 예외가 발생했을 경우 여기를 클릭해 주세요.
				
import org.apache.commons.codec.binary.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;

public class AES256Cipher {

    public static byte[] ivBytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

    public static String AES_Encode(String str, String key)	throws java.io.UnsupportedEncodingException, NoSuchAlgorithmException,
                        NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException,	IllegalBlockSizeException, BadPaddingException {
        byte[] textBytes = str.getBytes("UTF-8");
        AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        SecretKeySpec newKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
        Cipher cipher = null;
        cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);
        return Base64.encodeBase64String(cipher.doFinal(textBytes));
    }

    public static String AES_Decode(String str, String key, byte[] ivBytes)	throws java.io.UnsupportedEncodingException, NoSuchAlgorithmException,
                        NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
        byte[] textBytes =  Base64.decodeBase64(str.getBytes());
        AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        SecretKeySpec newKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
        return new String(cipher.doFinal(textBytes), "UTF-8");
    }

    public static String AES_Decode(String str, String key)	throws java.io.UnsupportedEncodingException, NoSuchAlgorithmException,
                        NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException,	IllegalBlockSizeException, BadPaddingException {
    return AES_Decode(str, key, ivBytes);
    }
}