KOVAN PG 통합 연동 가이드
결제연동(SimplePay)과 정산/지급대행 API를 하나의 문서에서 확인하세요. 모든 통신은 TLS 1.2를 사용하며, HMAC-SHA256 해시를 통해 무결성을 검증합니다.
1.2
문서 구성
결제창 호출 방식 권장사항
부모창(parent window)을 정상적으로 참조하지 못해
인증 결과 전달이 실패하는 오류가 발생할 수 있습니다.
팝업 방식은 결제창이 독립된 최상위 window로 열리므로 ISP/페이북 등 카드사 인증 팝업과의 parent-child 통신이 안정적으로 동작합니다.
window.open('', 'pgPopup', opts).focus();
form.target = 'pgPopup';
form.submit();
도메인 정보
결제 연동 (SimplePay)
정산/지급대행 API
현금영수증/리모트결제/매출전표
공통사항 & 보안
모든 API 연동에서 공통으로 적용되는 인증 방식과 보안 규칙입니다.
API_KEY (암호화 Key)
상점 계약 체결 시 PG사에서 부여하는 32자리 고유키입니다. 반드시 서버 사이드에서만 사용하고, 절대 클라이언트에 노출되어서는 안 됩니다.
유효성 검증 Hash 값 (HMAC-SHA256)
각 API 전문의 요청/응답 시 무결성 검증을 위해 HMAC-SHA256 알고리즘으로 Base64-Encoded Hash값을 생성해야 합니다.
// [생성규칙] message: orderno + orderdt + ordertm + reqamt
// secretKey: API_KEY (상점 별 고유키 값)
String message = "ORDER12345201706051322385000";
String secretKey = "ef5df61805ea166bb16867a9bf566082";
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(
secretKey.getBytes("UTF-8"), "HmacSHA256"
);
sha256_HMAC.init(secret_key);
String hashValue = Base64.encodeBase64String(
sha256_HMAC.doFinal(message.getBytes("UTF-8"))
);
// 결과: YFiOzc2rY46gJb6OMM7nfz7W0l4mhhJzsbmWMYxYbc4=
// [생성규칙] message: orderno + orderdt + ordertm + reqamt
$message = "ORDER12345201706051322385000";
$secretKey = "ef5df61805ea166bb16867a9bf566082";
$hmac = hash_hmac('sha256', $message, $secretKey, true);
$hashValue = base64_encode($hmac);
// 결과: YFiOzc2rY46gJb6OMM7nfz7W0l4mhhJzsbmWMYxYbc4=
string message = "ORDER12345201706051322385000"; string secretKey = "ef5df61805ea166bb16867a9bf566082"; UTF8Encoding encoding = new UTF8Encoding(); byte[] keyBytes = encoding.GetBytes(secretKey); HMACSHA256 hmacsha256 = new HMACSHA256(keyBytes); byte[] messageBytes = encoding.GetBytes(message); byte[] hashmessage = hmacsha256.ComputeHash(messageBytes); string hashValue = Convert.ToBase64String(hashmessage);
TLS 통신 프로토콜
User-Agent 규칙
권장 형식: 서비스명, 버전, 플랫폼, 연락처를 포함한 식별 가능한 UA를 사용하세요.
금지 사항: CR/LF 제어문자, 비ASCII 문자(이모지/한글), 과도한 길이
결제처리 Flow
결제요청부터 승인완료까지의 전체 프로세스를 확인하세요.
parent window를 찾지 못해
"부모창이 없습니다" 오류와 함께 결제가 중단됩니다.
반드시 window.open() 팝업 방식으로 연동하시기 바랍니다.
결제요청 처리 Flow
가맹점 사이트에서 고객이 상품구매를 요청합니다.
결제요청 정보를 PG결제서버로 전송합니다. 요청금액 변조 방지를 위한 checkHash 값을 함께 전송합니다.
PG결제서버에서 제공하는 통합결제 페이지를 표시합니다.
고객이 통합결제 페이지를 통해 신용카드 결제 정보를 입력합니다.
PG결제서버에서 입력된 결제 정보에 따른 인증페이지를 표시합니다.
인증페이지에서 고객이 인증정보를 입력하여 인증 요청을 합니다.
인증 요청을 하면 PG결제서버가 인증 결과를 받아 통합결제 페이지에 표시합니다.
통합결제 페이지에서 인증 결과를 확인하여 결제 승인을 요청합니다.
PG결제서버가 승인 결과를 Return URL로 전달합니다.
취소요청 처리 Flow
가맹점 서버에서 PG결제서버로 승인취소를 요청합니다.
PG결제서버에서 승인취소 결과를 전달합니다.
결제요청
온라인 결제 페이지로 고객을 이동시켜 결제를 진행하는 API입니다.
URL 정보
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| mid | 상점 ID | AN | FIX 15 | Y | PG에서 부여한 상점 ID예시: M20161206113241 |
| rUrl | Return URL | ANS | Max 1024 | Y | 결제 결과를 Return받을 URL예시 : http://localhost/result.pay |
| rMethod | Return Http메소드 | A | Max 10 | Y | 결제 결과를 Return 받을 Http 메소드 예시 : POST |
| payGroup | 결제 그룹 | A | FIX 3 | Y | 결제 그룹. GEP(일반), KKP(카카오페이), NVP(네이버페이), APP(애플페이), TSP(토스페이), SSP(삼성페이), PCP(페이코), LTP(엘페이), SGP(SGP페이) |
| payType | 결제수단 | AS | Max 2 | Y | 결제 수단. GEP: CC,BA,VA / KKP: CC,VO / NVP: CC,VO / APP: CC / TSP: CC,VO / SSP: CC / PCP: CC,VO / LTP: CC / SGP: CC |
| buyItemnm | 상품명 | AN | Max 80 | Y | 상점 구매 상품명예시: 오이비누 |
| buyReqamt | 상품가격 | N | Max 8 | Y | 상점 구매금액. 반드시 숫자만 포함 예시: 5000 |
| buyItemcd | 상품 코드 | AN | Max 10 | Y | 상점 판매상품코드예시: oiSoap |
| buyerid | 구매자 ID | AN | Max 20 | O | 상점 구매자 ID 카카오페이의 경우 필수예시: gildonghong |
| buyernm | 구매자명 | A | Max 50 | Y | 상점 구매자명예시: 홍길동 |
| buyerEmail | 구매자e-mail | ANS | Max 50 | O | 상점 구매자 Email 주소예시: gildong2@naver.com |
| orderno | 주문번호 | AN | Max 20 | Y | 상점 주문번호 예시: T2017010100001 |
| orderdt | 주문 일자 | N | FIX 8 | Y | 상점 주문 일자 (YYYYMMDD) |
| ordertm | 주문 시간 | N | FIX 6 | Y | 상점 주문 시간 (HHMMSS) |
| taxExemptYn | 비과세 구분 | A | 1 | O | 복합과세 Y / 비과세거래 D / 면세거래 F /그외 일반(기본) |
| taxExemptAmt | 면세/비과세금액 | N | Max 8 | O | 비과세금액/면세금액. 부가세 = (buyReqamt - taxExemptAmt) / 11 |
| checkHash | 무결성 검증 Hash | ANS | Max 128 | Y | HMAC-SHA256 Base64-Encoded. message: orderno+orderdt+ordertm+buyReqamt / secretKey: API KEY |
| reserved01 | 가맹점예약필드1 | AN | Max 1024 | O | 응답 시 반환됨 |
| reserved02 | 가맹점예약필드2 | AN | Max 1024 | O | 응답 시 반환됨 |
| returnAppUrl | Return App Scheme Uri | ANS | Max 1024 | O | 모바일APP 결제의 경우 필수 |
| 신용카드 전용 | |||||
| cardCode | 카드사코드 | ANS | - | O | 결제 카드사코드 리스트 1107,1101 |
| quota | 할부 개월 수 | N | FIX 2 | O | 결제 할부 개월 수 |
| billYn | BillKey 등록 여부 | A | 1 | O | BillKey 발급 요청 시 Y 설정. 결제 후 BILL_KEY가 응답에 포함됨 |
| billKey | BillKey 결제 | A | 1 | O | 카드번호 대체 BillKey를 이용한 결제 시 Y 설정 |
| 가상계좌 전용 | |||||
| bankCode | 은행 코드 | ANS | - | O | 결제 은행 코드 |
| trend | 종료일시 | N | FIX 14 | O | 입금종료일시 (YYYYMMHH24MISS) |
RESULT_CODE, RESULT_MSG, DRESULT_CODE, DRESULT_MSG,
PAY_METHOD, TID, ORDERNO, RESERVED01, RESERVED02
| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| 공통부 | ||||
| RESULT_CODE | 결제결과코드 | String | Max 20 | 결과코드표 참조 |
| RESULT_MSG | 결제결과메시지 | String | Max 1024 | |
| DRESULT_CODE | 가맹점결과코드 | String | Max 20 | |
| DRESULT_MSG | 가맹점결과메시지 | String | Max 1024 | |
| PAY_METHOD | 결제수단 | String | FIX 2 | CC/BA/VA/VO |
| TID | PG거래고유번호 | String | Max 15 | PG사 거래고유번호 |
| ORDERNO | 주문번호 | String | Max 20 | 상점 주문번호 |
| RESERVED01 | 가맹점예약필드1 | String | Max 1024 | |
| RESERVED02 | 가맹점예약필드2 | String | Max 1024 | |
| CHECK_HASH | 무결성 검증 Hash | String | Max 128 | message: RESULT_CODE+TID+ORDERNO / secretKey : API KEY |
| 신용카드 추가 항목 | ||||
| APPROVNO | 결제승인번호 | String | Max 20 | |
| APPRODT | 결제승인일자 | String | FIX 8 | YYYYMMDD |
| APPROTM | 결제승인시간 | String | FIX 6 | HHMMSS |
| APPROAMT | 결제승인금액 | Numeric | Max 15 | |
| ISSUE_CODE | 발급사코드 | String | FIX 4 | |
| ISSUE_NAME | 발급사명 | String | Max 20 | |
| PURCHASE_CODE | 매입사코드 | String | FIX 4 | |
| PURCHASE_NAME | 매입사명 | String | Max 20 | |
| QUOTA_MONTHS | 할부개월수 | String | FIX 2 | |
| NOINT | 무이자구분 | String | FIX 1 | |
| CHECKCD | 카드구분 | String | FIX 2 | 신용카드 N / 체크카드 C |
| CARD_NO | 카드번호 | String | Max 16 | 마스킹 처리된 카드번호 |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "성공",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "성공",
"PAY_METHOD": "CC", "TID": "210728130414390", "ORDERNO": "ORDER12345",
"RESERVED01": "가맹점예약필드 1", "RESERVED02": "가맹점예약필드 2",
"CHECK_HASH": "3zhVYYVtEflnMMkn8P3J7u3eKjeLyt64doJw81O2fzA=",
"APPROVNO": "63586137", "APPRODT": "20210728", "APPROTM": "113855",
"APPROAMT": "5000", "ISSUE_CODE": "1102", "ISSUE_NAME": "현대카드",
"PURCHASE_CODE": "1102", "PURCHASE_NAME": "현대카드",
"QUOTA_MONTHS": "00", "NOINT": "N", "CHECKCD": "N",
"CARD_NO": "489016**********"
}| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| 공통부 (RESULT_CODE, RESULT_MSG, DRESULT_CODE, DRESULT_MSG, PAY_METHOD, TID, ORDERNO, RESERVED01, RESERVED02) | ||||
| APPROVNO | 결제승인번호 | String | Max 20 | |
| APPRODT | 결제승인일자 | String | FIX 8 | YYYYMMDD |
| APPROTM | 결제승인시간 | String | FIX 6 | HHMMSS |
| APPROAMT | 결제승인금액 | Numeric | Max 15 | |
| ISSUE_CODE | 발급사코드 | String | FIX 4 | |
| ISSUE_NAME | 발급사명 | String | Max 20 | |
| PURCHASE_CODE | 매입사코드 | String | FIX 4 | |
| PURCHASE_NAME | 매입사명 | String | Max 20 | |
| QUOTA_MONTHS | 할부개월수 | String | FIX 2 | |
| NOINT | 무이자구분 | String | FIX 1 | |
| CHECKCD | 카드구분 | String | FIX 2 | 신용카드 N / 체크카드 C |
| CARD_NO | 카드번호 | String | Max 16 | 마스킹 처리된 카드번호 |
| MID | 상점ID | String | FIX 15 | 카카오페이 전용 |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "성공",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "성공",
"PAY_GROUP": "KKP", "PAY_METHOD": "CC",
"TID": "210728130414386", "ORDERNO": "ORDER12345",
"RESERVED01": "가맹점예약필드 1", "RESERVED02": "가맹점예약필드 2",
"APPROVNO": "33709377", "APPRODT": "20210728", "APPROTM": "113541",
"APPROAMT": "5000", "ISSUE_CODE": "1107", "ISSUE_NAME": "신한카드",
"PURCHASE_CODE": "1107", "PURCHASE_NAME": "신한카드",
"QUOTA_MONTHS": "00", "NOINT": "N", "CHECKCD": "C",
"CARD_NO": "510737**********", "MID": "M20200203113418"
}| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| 공통부 (RESULT_CODE, RESULT_MSG, DRESULT_CODE, DRESULT_MSG, PAY_METHOD, TID, ORDERNO, RESERVED01, RESERVED02) | ||||
| PAY_GROUP | 결제그룹 | String | FIX 3 | KKP |
| APPRODT | 결제승인일자 | String | FIX 8 | YYYYMMDD |
| APPROTM | 결제승인시간 | String | FIX 6 | HHMMSS |
| APPROAMT | 결제승인금액 | Numeric | Max 15 | |
| MID | 상점ID | String | FIX 15 | |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "성공",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "성공",
"PAY_GROUP": "KKP", "PAY_METHOD": "VO",
"TID": "210728130414388", "ORDERNO": "ORDER12345",
"RESERVED01": "가맹점예약필드 1", "RESERVED02": "가맹점예약필드 2",
"APPRODT": "20210728", "APPROTM": "113730",
"APPROAMT": "5000", "MID": "M20200203113418"
}| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| 공통부 (RESULT_CODE, RESULT_MSG, DRESULT_CODE, DRESULT_MSG, PAY_METHOD, TID, ORDERNO, RESERVED01, RESERVED02) | ||||
| APPROVNO | 결제승인번호 | String | Max 20 | |
| APPRODT | 결제승인일자 | String | FIX 8 | YYYYMMDD |
| APPROTM | 결제승인시간 | String | FIX 6 | HHMMSS |
| APPROAMT | 결제승인금액 | Numeric | Max 15 | |
| ISSUE_CODE | 발급사코드 | String | FIX 4 | |
| ISSUE_NAME | 발급사명 | String | Max 20 | |
| PURCHASE_CODE | 매입사코드 | String | FIX 4 | |
| PURCHASE_NAME | 매입사명 | String | Max 20 | |
| QUOTA_MONTHS | 할부개월수 | String | FIX 2 | |
| NOINT | 무이자구분 | String | FIX 1 | |
| CHECKCD | 카드구분 | String | FIX 2 | 신용카드 N / 체크카드 C |
| CARD_NO | 카드번호 | String | Max 16 | 마스킹 처리된 카드번호 |
| MID | 상점ID | String | FIX 15 | 상점ID (카카오페이만) |
| CHECK_HASH | 무결성 검증 Hash | String | Max 128 | message: RESULT_CODE+TID+ORDERNO |
| VAN_RECV_KEY | VAN고유키 | String | Max 20 | |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "성공",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "성공",
"PAY_GROUP": "NVP", "PAY_METHOD": "CC",
"TID": "210728130414386", "ORDERNO": "ORDER12345",
"RESERVED01": "가맹점예약필드 1", "RESERVED02": "가맹점예약필드 2",
"APPROVNO": "33709377", "APPRODT": "20210728", "APPROTM": "113541",
"APPROAMT": "5000", "ISSUE_CODE": "1107", "ISSUE_NAME": "신한카드",
"PURCHASE_CODE": "1107", "PURCHASE_NAME": "신한카드",
"QUOTA_MONTHS": "00", "NOINT": "N", "CHECKCD": "C",
"CARD_NO": "510737**********", "MID": "M20200203113418",
"CHECK_HASH": "3zhVYYVtEflnMMkn8P3J7u3eKjeLyt64doJw81O2fzA=",
"VAN_RECV_KEY": ""
}| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| 공통부 (RESULT_CODE, RESULT_MSG, DRESULT_CODE, DRESULT_MSG, PAY_METHOD, TID, ORDERNO, RESERVED01, RESERVED02) | ||||
| PAY_GROUP | 결제그룹 | String | FIX 3 | NVP |
| APPRODT | 결제승인일자 | String | FIX 8 | YYYYMMDD |
| APPROTM | 결제승인시간 | String | FIX 6 | HHMMSS |
| APPROAMT | 결제승인금액 | Numeric | Max 15 | |
| MID | 상점ID | String | FIX 15 | |
| BUY_REQAMT | 상품가격 | Numeric | Max 15 | |
| RESULT_DET_CODE | 결제결과 상세코드 | String | Max 20 | |
| RESULT_DET_MSG | 결제결과 상세메시지 | String | Max 1024 | |
| PAY_KEY | 인증추적키 | String | Max 255 | |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "성공",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "성공",
"PAY_GROUP": "NVP", "PAY_METHOD": "VO",
"TID": "210728130414388", "ORDERNO": "ORDER12345",
"RESERVED01": "가맹점예약필드 1", "RESERVED02": "가맹점예약필드 2",
"APPRODT": "20210728", "APPROTM": "113730",
"APPROAMT": "5000", "MID": "M20200203113418",
"BUY_REQAMT": "5000",
"RESULT_DET_CODE": "EC0000", "RESULT_DET_MSG": "성공"
}| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| 공통부 (RESULT_CODE, RESULT_MSG, DRESULT_CODE, DRESULT_MSG, PAY_METHOD, TID, ORDERNO, RESERVED01, RESERVED02) | ||||
| MID | 상점ID | String | FIX 15 | 상점 |
| BANK_CD | 은행코드 | String | FIX 3 | 결제 은행코드 |
| BANK_NM | 은행명 | String | Max 20 | 결제 은행명 |
| ACCT_NO | 계좌번호 | String | Max 20 | 결제 계좌번호 |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "성공",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "성공",
"TID": "210728130414394", "ORDERNO": "ORDER12345",
"RESERVED01": "가맹점예약필드 1", "RESERVED02": "가맹점예약필드 2",
"MID": "M20200203113418",
"BANK_CD": "002", "BANK_NM": "산업은행", "ACCT_NO": "08724"
}| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| 공통부 (RESULT_CODE, RESULT_MSG, DRESULT_CODE, DRESULT_MSG, PAY_METHOD, TID, ORDERNO, RESERVED01, RESERVED02) | ||||
| CHECK_HASH | 무결성 검증 Hash | String | Max 128 | message: RESULT_CODE+TID+ORDERNO |
| TRBEGIN | 입금시작일 | String | FIX 14 | YYYYMMDDHHMMSS |
| TREND | 입금종료일 | String | FIX 14 | YYYYMMDDHHMMSS |
| BUY_REQAMT | 결제금액 | String | Max 15 | |
| BANK_CD | 은행코드 | String | FIX 3 | |
| BANK_NM | 은행명 | String | Max 20 | |
| ACCT_NO | 계좌번호 | String | Max 20 | 발급된 가상계좌번호 |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "성공",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "성공",
"PAY_METHOD": "VA", "TID": "210728130414389", "ORDERNO": "ORDER12345",
"RESERVED01": "가맹점예약필드 1", "RESERVED02": "가맹점예약필드 2",
"CHECK_HASH": "M/N65K6T1Zc5XEBl5tERsENX/tGLzM+13w/ECb2kWXY=",
"TRBEGIN": "20210728113820", "TREND": "20210807113806",
"BUY_REQAMT": "5000",
"BANK_CD": "020", "BANK_NM": "우리은행", "ACCT_NO": "27995319418878"
}billYn=Y를 함께 전송하면, 승인 후 응답에 BILL_KEY가 포함됩니다.발급된 BILL_KEY는 이후 카드번호 없이 반복 결제에 사용할 수 있습니다.
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| 공통 요청 파라미터 (결제요청 참고) | |||||
| mid | 상점 ID | AN | FIX 15 | Y | 예시: M20260114117276 |
| payGroup | 결제 그룹 | A | FIX 3 | Y | GEP |
| payType | 결제수단 | AS | Max 2 | Y | CC |
| orderno | 주문번호 | AN | Max 20 | Y | 예시: ORDER20260429093952 |
| orderdt | 주문 일자 | N | FIX 8 | Y | YYYYMMDD |
| ordertm | 주문 시간 | N | FIX 6 | Y | HHMMSS |
| checkHash | 무결성 검증 Hash | ANS | Max 128 | Y | HMAC-SHA256 Base64. message: orderno+orderdt+ordertm+buyReqamt |
| BILLKEY 발급 전용 | |||||
| billYn | BillKey 등록 여부 | A | 1 | Y | BillKey 발급 시 반드시 Y 설정 |
mid=M20260114117276 payGroup=GEP payType=CC orderno=ORDER20260429093952 orderdt=20260429 ordertm=093952 buyItemnm=테스트_상품 buyReqamt=1004 buyItemcd=item buyerid=kovan_Dev buyernm=코밴_Dev buyerEmail=test@kovan.com reserved01=reserved01 reserved02=reserved02 checkHash=G/Z/kOICS67b6eomKmU2kA2ODfOw7AHnGivjXHHRUS4= apiKey=62a67bdc5e98b08e8c67cd3dd2a00b25 afterApprovYn=N billYn=Y rurl=http://220.117.220.108:50500/auth/response.action rmethod=POST
| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| 공통부 | ||||
| RESULT_CODE | 결과코드 | String | Max 20 | 0000 성공 |
| RESULT_MSG | 결과메시지 | String | Max 1024 | |
| DRESULT_CODE | 가맹점결과코드 | String | Max 20 | EC0000 성공 |
| DRESULT_MSG | 가맹점결과메시지 | String | Max 1024 | |
| MID | 상점 ID | String | FIX 15 | |
| PAY_METHOD | 결제수단 | String | FIX 2 | CC |
| CHECK_HASH | 무결성 검증 Hash | String | Max 128 | |
| RESERVED01 | 가맹점예약필드1 | String | Max 1024 | |
| RESERVED02 | 가맹점예약필드2 | String | Max 1024 | |
| BILLKEY 발급 추가 항목 | ||||
| ISSUE_CODE | 발급사코드 | String | FIX 4 | 예시: 1108 |
| ISSUE_NAME | 발급사명 | String | Max 20 | 예시: NH농협카드 |
| BILL_KEY | BillKey | String | Max 50 | 발급된 BillKey. 이후 반복 결제에 사용 예시: bk8718565260429 |
{
"RESULT_CODE": "0000",
"RESULT_MSG": "정상완료",
"DRESULT_CODE": "EC0000",
"DRESULT_MSG": "SUCCESS",
"MID": "M20260114117276",
"PAY_METHOD": "CC",
"CHECK_HASH": "G/Z/kOICS67b6eomKmU2kA2ODfOw7AHnGivjXHHRUS4=",
"ISSUE_CODE": "1108",
"ISSUE_NAME": "NH농협카드",
"BILL_KEY": "bk8718565260429",
"RESERVED01": "reserved01",
"RESERVED02": "reserved02"
}billKey 파라미터로 전달하여 카드번호 없이 결제를 진행합니다.최초 BILLKEY 발급 시 저장한
BILL_KEY 값을 그대로 사용합니다.POST /payment/directApproval.pay
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| 공통 요청 파라미터 (결제요청 참고) | |||||
| mid | 상점 ID | AN | FIX 15 | Y | 예시: M20260114117276 |
| payGroup | 결제 그룹 | A | FIX 3 | Y | GEP |
| payType | 결제수단 | AS | Max 2 | Y | CC |
| orderno | 주문번호 | AN | Max 20 | Y | 예시: ORDER20260429093952 |
| orderdt | 주문 일자 | N | FIX 8 | Y | YYYYMMDD |
| ordertm | 주문 시간 | N | FIX 6 | Y | HHMMSS |
| checkHash | 무결성 검증 Hash | ANS | Max 128 | Y | HMAC-SHA256 Base64. message: orderno+orderdt+ordertm+buyReqamt |
| BILLKEY 결제 전용 | |||||
| billKey | BillKey | A | 1 | Y | BillKey 결제 시 Y 설정. 발급받은 BILL_KEY를 카드번호 대체로 사용 |
mid=M20260114117276 payGroup=GEP payType=CC orderno=ORDER20260429093952 orderdt=20260429 ordertm=093952 buyItemnm=테스트_상품 buyReqamt=1004 buyItemcd=item buyerid=kovan_Dev buyernm=코밴_Dev buyerEmail=test@kovan.com reserved01=reserved01 reserved02=reserved02 checkHash=G/Z/kOICS67b6eomKmU2kA2ODfOw7AHnGivjXHHRUS4= apiKey=62a67bdc5e98b08e8c67cd3dd2a00b25 afterApprovYn=N billKey=Y rurl=http://220.117.220.108:50500/auth/response.action rmethod=POST
| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| 공통부 | ||||
| RESULT_CODE | 결과코드 | String | Max 20 | 0000 성공 |
| RESULT_MSG | 결과메시지 | String | Max 1024 | |
| DRESULT_CODE | 가맹점결과코드 | String | Max 20 | EC0000 성공 |
| DRESULT_MSG | 가맹점결과메시지 | String | Max 1024 | |
| MID | 상점 ID | String | FIX 15 | |
| PAY_METHOD | 결제수단 | String | FIX 2 | CC |
| CHECK_HASH | 무결성 검증 Hash | String | Max 128 | |
| RESERVED01 | 가맹점예약필드1 | String | Max 1024 | |
| RESERVED02 | 가맹점예약필드2 | String | Max 1024 | |
| BILLKEY 결제 추가 항목 | ||||
| ISSUE_CODE | 발급사코드 | String | FIX 4 | 예시: 1108 |
| ISSUE_NAME | 발급사명 | String | Max 20 | 예시: NH농협카드 |
| BILL_KEY | BillKey | String | Max 50 | 결제에 사용된 BillKey 예시: bk8718565260429 |
{
"RESULT_CODE": "0000",
"RESULT_MSG": "정상완료",
"DRESULT_CODE": "EC0000",
"DRESULT_MSG": "SUCCESS",
"MID": "M20260114117276",
"PAY_METHOD": "CC",
"CHECK_HASH": "G/Z/kOICS67b6eomKmU2kA2ODfOw7AHnGivjXHHRUS4=",
"ISSUE_CODE": "1108",
"ISSUE_NAME": "NH농협카드",
"BILL_KEY": "bk8718565260429",
"RESERVED01": "reserved01",
"RESERVED02": "reserved02"
}간편결제 오픈예정
애플페이, 토스페이, 삼성페이, 페이코, 엘페이, SGP페이 연동 가이드입니다. 연동 전문 포맷은 네이버페이 기준을 따릅니다.
URL 정보
APP(애플페이): CC |
TSP(토스페이): CC, VO |
SSP(삼성페이): CC |
PCP(페이코): CC, VO |
LTP(엘페이): CC |
SGP(SGP페이): CC
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| mid | 상점 ID | AN | FIX 15 | Y | PG에서 부여한 상점 ID |
| payGroup | 결제 그룹 | A | FIX 3 | Y | APP / TSP / SSP / PCP / LTP / SGP |
| payType | 결제수단 | AS | Max 2 | Y | CC 또는 VO (수단별 지원 여부 상단 참고) |
| orderno | 주문번호 | AN | Max 20 | Y | 상점 주문번호 |
| orderdt | 주문 일자 | N | FIX 8 | Y | YYYYMMDD |
| ordertm | 주문 시간 | N | FIX 6 | Y | HHMMSS |
| buyItemnm | 상품명 | AN | Max 80 | Y | 상점 구매 상품명 |
| buyReqamt | 상품가격 | N | Max 8 | Y | 결제금액 (숫자만) |
| buyItemcd | 상품 코드 | AN | Max 10 | Y | 상점 판매상품코드 |
| buyerid | 구매자 ID | AN | Max 20 | O | 상점 구매자 ID |
| buyernm | 구매자명 | A | Max 50 | Y | 상점 구매자명 |
| buyerEmail | 구매자 e-mail | ANS | Max 50 | O | 상점 구매자 Email |
| checkHash | 무결성 검증 Hash | ANS | Max 128 | Y | HMAC-SHA256 Base64. message: orderno+orderdt+ordertm+buyReqamt |
| reserved01 | 가맹점예약필드1 | AN | Max 1024 | O | 응답 시 반환됨 |
| reserved02 | 가맹점예약필드2 | AN | Max 1024 | O | 응답 시 반환됨 |
| rUrl | Return URL | ANS | Max 1024 | Y | 결제 결과를 Return 받을 URL |
| rMethod | Return Http 메소드 | A | Max 10 | Y | POST |
RESULT_CODE, RESULT_MSG, DRESULT_CODE, DRESULT_MSG,
PAY_METHOD, TID, ORDERNO, RESERVED01, RESERVED02
| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| 공통부 (RESULT_CODE, RESULT_MSG, DRESULT_CODE, DRESULT_MSG, PAY_METHOD, TID, ORDERNO, RESERVED01, RESERVED02) | ||||
| APPROVNO | 결제승인번호 | String | Max 20 | |
| APPRODT | 결제승인일자 | String | FIX 8 | YYYYMMDD |
| APPROTM | 결제승인시간 | String | FIX 6 | HHMMSS |
| APPROAMT | 결제승인금액 | Numeric | Max 15 | |
| ISSUE_CODE | 발급사코드 | String | FIX 4 | |
| ISSUE_NAME | 발급사명 | String | Max 20 | |
| PURCHASE_CODE | 매입사코드 | String | FIX 4 | |
| PURCHASE_NAME | 매입사명 | String | Max 20 | |
| QUOTA_MONTHS | 할부개월수 | String | FIX 2 | |
| NOINT | 무이자구분 | String | FIX 1 | |
| CHECKCD | 카드구분 | String | FIX 2 | 신용카드 N / 체크카드 C |
| CARD_NO | 카드번호 | String | Max 16 | 마스킹 처리된 카드번호 |
| MID | 상점ID | String | FIX 15 | |
| CHECK_HASH | 무결성 검증 Hash | String | Max 128 | message: RESULT_CODE+TID+ORDERNO |
| VAN_RECV_KEY | VAN고유키 | String | Max 20 | |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "성공",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "성공",
"PAY_GROUP": "APP", "PAY_METHOD": "CC",
"TID": "210728130414391", "ORDERNO": "ORDER12345",
"RESERVED01": "가맹점예약필드 1", "RESERVED02": "가맹점예약필드 2",
"APPROVNO": "33709377", "APPRODT": "20210728", "APPROTM": "113541",
"APPROAMT": "5000", "ISSUE_CODE": "1107", "ISSUE_NAME": "신한카드",
"PURCHASE_CODE": "1107", "PURCHASE_NAME": "신한카드",
"QUOTA_MONTHS": "00", "NOINT": "N", "CHECKCD": "N",
"CARD_NO": "510737**********", "MID": "M20200203113418",
"CHECK_HASH": "3zhVYYVtEflnMMkn8P3J7u3eKjeLyt64doJw81O2fzA=",
"VAN_RECV_KEY": ""
}| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| 공통부 (RESULT_CODE, RESULT_MSG, DRESULT_CODE, DRESULT_MSG, PAY_METHOD, TID, ORDERNO, RESERVED01, RESERVED02) | ||||
| APPROVNO | 결제승인번호 | String | Max 20 | |
| APPRODT | 결제승인일자 | String | FIX 8 | YYYYMMDD |
| APPROTM | 결제승인시간 | String | FIX 6 | HHMMSS |
| APPROAMT | 결제승인금액 | Numeric | Max 15 | |
| ISSUE_CODE | 발급사코드 | String | FIX 4 | |
| ISSUE_NAME | 발급사명 | String | Max 20 | |
| PURCHASE_CODE | 매입사코드 | String | FIX 4 | |
| PURCHASE_NAME | 매입사명 | String | Max 20 | |
| QUOTA_MONTHS | 할부개월수 | String | FIX 2 | |
| NOINT | 무이자구분 | String | FIX 1 | |
| CHECKCD | 카드구분 | String | FIX 2 | 신용카드 N / 체크카드 C |
| CARD_NO | 카드번호 | String | Max 16 | 마스킹 처리된 카드번호 |
| MID | 상점ID | String | FIX 15 | |
| CHECK_HASH | 무결성 검증 Hash | String | Max 128 | message: RESULT_CODE+TID+ORDERNO |
| VAN_RECV_KEY | VAN고유키 | String | Max 20 | |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "성공",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "성공",
"PAY_GROUP": "TSP", "PAY_METHOD": "CC",
"TID": "210728130414392", "ORDERNO": "ORDER12345",
"RESERVED01": "가맹점예약필드 1", "RESERVED02": "가맹점예약필드 2",
"APPROVNO": "33709377", "APPRODT": "20210728", "APPROTM": "113541",
"APPROAMT": "5000", "ISSUE_CODE": "1107", "ISSUE_NAME": "신한카드",
"PURCHASE_CODE": "1107", "PURCHASE_NAME": "신한카드",
"QUOTA_MONTHS": "00", "NOINT": "N", "CHECKCD": "N",
"CARD_NO": "510737**********", "MID": "M20200203113418",
"CHECK_HASH": "3zhVYYVtEflnMMkn8P3J7u3eKjeLyt64doJw81O2fzA=",
"VAN_RECV_KEY": ""
}| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| 공통부 (RESULT_CODE, RESULT_MSG, DRESULT_CODE, DRESULT_MSG, PAY_METHOD, TID, ORDERNO, RESERVED01, RESERVED02) | ||||
| PAY_GROUP | 결제그룹 | String | FIX 3 | TSP |
| APPRODT | 결제승인일자 | String | FIX 8 | YYYYMMDD |
| APPROTM | 결제승인시간 | String | FIX 6 | HHMMSS |
| APPROAMT | 결제승인금액 | Numeric | Max 15 | |
| MID | 상점ID | String | FIX 15 | |
| BUY_REQAMT | 상품가격 | Numeric | Max 15 | |
| RESULT_DET_CODE | 결제결과 상세코드 | String | Max 20 | |
| RESULT_DET_MSG | 결제결과 상세메시지 | String | Max 1024 | |
| PAY_KEY | 인증추적키 | String | Max 255 | |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "성공",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "성공",
"PAY_GROUP": "TSP", "PAY_METHOD": "VO",
"TID": "210728130414393", "ORDERNO": "ORDER12345",
"RESERVED01": "가맹점예약필드 1", "RESERVED02": "가맹점예약필드 2",
"APPRODT": "20210728", "APPROTM": "113730",
"APPROAMT": "5000", "MID": "M20200203113418",
"BUY_REQAMT": "5000",
"RESULT_DET_CODE": "EC0000", "RESULT_DET_MSG": "성공"
}| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| 공통부 (RESULT_CODE, RESULT_MSG, DRESULT_CODE, DRESULT_MSG, PAY_METHOD, TID, ORDERNO, RESERVED01, RESERVED02) | ||||
| APPROVNO | 결제승인번호 | String | Max 20 | |
| APPRODT | 결제승인일자 | String | FIX 8 | YYYYMMDD |
| APPROTM | 결제승인시간 | String | FIX 6 | HHMMSS |
| APPROAMT | 결제승인금액 | Numeric | Max 15 | |
| ISSUE_CODE | 발급사코드 | String | FIX 4 | |
| ISSUE_NAME | 발급사명 | String | Max 20 | |
| PURCHASE_CODE | 매입사코드 | String | FIX 4 | |
| PURCHASE_NAME | 매입사명 | String | Max 20 | |
| QUOTA_MONTHS | 할부개월수 | String | FIX 2 | |
| NOINT | 무이자구분 | String | FIX 1 | |
| CHECKCD | 카드구분 | String | FIX 2 | 신용카드 N / 체크카드 C |
| CARD_NO | 카드번호 | String | Max 16 | 마스킹 처리된 카드번호 |
| MID | 상점ID | String | FIX 15 | |
| CHECK_HASH | 무결성 검증 Hash | String | Max 128 | message: RESULT_CODE+TID+ORDERNO |
| VAN_RECV_KEY | VAN고유키 | String | Max 20 | |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "성공",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "성공",
"PAY_GROUP": "SSP", "PAY_METHOD": "CC",
"TID": "210728130414394", "ORDERNO": "ORDER12345",
"RESERVED01": "가맹점예약필드 1", "RESERVED02": "가맹점예약필드 2",
"APPROVNO": "33709377", "APPRODT": "20210728", "APPROTM": "113541",
"APPROAMT": "5000", "ISSUE_CODE": "1107", "ISSUE_NAME": "신한카드",
"PURCHASE_CODE": "1107", "PURCHASE_NAME": "신한카드",
"QUOTA_MONTHS": "00", "NOINT": "N", "CHECKCD": "N",
"CARD_NO": "510737**********", "MID": "M20200203113418",
"CHECK_HASH": "3zhVYYVtEflnMMkn8P3J7u3eKjeLyt64doJw81O2fzA=",
"VAN_RECV_KEY": ""
}| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| 공통부 (RESULT_CODE, RESULT_MSG, DRESULT_CODE, DRESULT_MSG, PAY_METHOD, TID, ORDERNO, RESERVED01, RESERVED02) | ||||
| APPROVNO | 결제승인번호 | String | Max 20 | |
| APPRODT | 결제승인일자 | String | FIX 8 | YYYYMMDD |
| APPROTM | 결제승인시간 | String | FIX 6 | HHMMSS |
| APPROAMT | 결제승인금액 | Numeric | Max 15 | |
| ISSUE_CODE | 발급사코드 | String | FIX 4 | |
| ISSUE_NAME | 발급사명 | String | Max 20 | |
| PURCHASE_CODE | 매입사코드 | String | FIX 4 | |
| PURCHASE_NAME | 매입사명 | String | Max 20 | |
| QUOTA_MONTHS | 할부개월수 | String | FIX 2 | |
| NOINT | 무이자구분 | String | FIX 1 | |
| CHECKCD | 카드구분 | String | FIX 2 | 신용카드 N / 체크카드 C |
| CARD_NO | 카드번호 | String | Max 16 | 마스킹 처리된 카드번호 |
| MID | 상점ID | String | FIX 15 | |
| CHECK_HASH | 무결성 검증 Hash | String | Max 128 | message: RESULT_CODE+TID+ORDERNO |
| VAN_RECV_KEY | VAN고유키 | String | Max 20 | |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "성공",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "성공",
"PAY_GROUP": "PCP", "PAY_METHOD": "CC",
"TID": "210728130414395", "ORDERNO": "ORDER12345",
"RESERVED01": "가맹점예약필드 1", "RESERVED02": "가맹점예약필드 2",
"APPROVNO": "33709377", "APPRODT": "20210728", "APPROTM": "113541",
"APPROAMT": "5000", "ISSUE_CODE": "1107", "ISSUE_NAME": "신한카드",
"PURCHASE_CODE": "1107", "PURCHASE_NAME": "신한카드",
"QUOTA_MONTHS": "00", "NOINT": "N", "CHECKCD": "N",
"CARD_NO": "510737**********", "MID": "M20200203113418",
"CHECK_HASH": "3zhVYYVtEflnMMkn8P3J7u3eKjeLyt64doJw81O2fzA=",
"VAN_RECV_KEY": ""
}| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| 공통부 (RESULT_CODE, RESULT_MSG, DRESULT_CODE, DRESULT_MSG, PAY_METHOD, TID, ORDERNO, RESERVED01, RESERVED02) | ||||
| PAY_GROUP | 결제그룹 | String | FIX 3 | PCP |
| APPRODT | 결제승인일자 | String | FIX 8 | YYYYMMDD |
| APPROTM | 결제승인시간 | String | FIX 6 | HHMMSS |
| APPROAMT | 결제승인금액 | Numeric | Max 15 | |
| MID | 상점ID | String | FIX 15 | |
| BUY_REQAMT | 상품가격 | Numeric | Max 15 | |
| RESULT_DET_CODE | 결제결과 상세코드 | String | Max 20 | |
| RESULT_DET_MSG | 결제결과 상세메시지 | String | Max 1024 | |
| PAY_KEY | 인증추적키 | String | Max 255 | |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "성공",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "성공",
"PAY_GROUP": "PCP", "PAY_METHOD": "VO",
"TID": "210728130414396", "ORDERNO": "ORDER12345",
"RESERVED01": "가맹점예약필드 1", "RESERVED02": "가맹점예약필드 2",
"APPRODT": "20210728", "APPROTM": "113730",
"APPROAMT": "5000", "MID": "M20200203113418",
"BUY_REQAMT": "5000",
"RESULT_DET_CODE": "EC0000", "RESULT_DET_MSG": "성공"
}| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| 공통부 (RESULT_CODE, RESULT_MSG, DRESULT_CODE, DRESULT_MSG, PAY_METHOD, TID, ORDERNO, RESERVED01, RESERVED02) | ||||
| APPROVNO | 결제승인번호 | String | Max 20 | |
| APPRODT | 결제승인일자 | String | FIX 8 | YYYYMMDD |
| APPROTM | 결제승인시간 | String | FIX 6 | HHMMSS |
| APPROAMT | 결제승인금액 | Numeric | Max 15 | |
| ISSUE_CODE | 발급사코드 | String | FIX 4 | |
| ISSUE_NAME | 발급사명 | String | Max 20 | |
| PURCHASE_CODE | 매입사코드 | String | FIX 4 | |
| PURCHASE_NAME | 매입사명 | String | Max 20 | |
| QUOTA_MONTHS | 할부개월수 | String | FIX 2 | |
| NOINT | 무이자구분 | String | FIX 1 | |
| CHECKCD | 카드구분 | String | FIX 2 | 신용카드 N / 체크카드 C |
| CARD_NO | 카드번호 | String | Max 16 | 마스킹 처리된 카드번호 |
| MID | 상점ID | String | FIX 15 | |
| CHECK_HASH | 무결성 검증 Hash | String | Max 128 | message: RESULT_CODE+TID+ORDERNO |
| VAN_RECV_KEY | VAN고유키 | String | Max 20 | |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "성공",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "성공",
"PAY_GROUP": "LTP", "PAY_METHOD": "CC",
"TID": "210728130414397", "ORDERNO": "ORDER12345",
"RESERVED01": "가맹점예약필드 1", "RESERVED02": "가맹점예약필드 2",
"APPROVNO": "33709377", "APPRODT": "20210728", "APPROTM": "113541",
"APPROAMT": "5000", "ISSUE_CODE": "1107", "ISSUE_NAME": "신한카드",
"PURCHASE_CODE": "1107", "PURCHASE_NAME": "신한카드",
"QUOTA_MONTHS": "00", "NOINT": "N", "CHECKCD": "N",
"CARD_NO": "510737**********", "MID": "M20200203113418",
"CHECK_HASH": "3zhVYYVtEflnMMkn8P3J7u3eKjeLyt64doJw81O2fzA=",
"VAN_RECV_KEY": ""
}| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| 공통부 (RESULT_CODE, RESULT_MSG, DRESULT_CODE, DRESULT_MSG, PAY_METHOD, TID, ORDERNO, RESERVED01, RESERVED02) | ||||
| APPROVNO | 결제승인번호 | String | Max 20 | |
| APPRODT | 결제승인일자 | String | FIX 8 | YYYYMMDD |
| APPROTM | 결제승인시간 | String | FIX 6 | HHMMSS |
| APPROAMT | 결제승인금액 | Numeric | Max 15 | |
| ISSUE_CODE | 발급사코드 | String | FIX 4 | |
| ISSUE_NAME | 발급사명 | String | Max 20 | |
| PURCHASE_CODE | 매입사코드 | String | FIX 4 | |
| PURCHASE_NAME | 매입사명 | String | Max 20 | |
| QUOTA_MONTHS | 할부개월수 | String | FIX 2 | |
| NOINT | 무이자구분 | String | FIX 1 | |
| CHECKCD | 카드구분 | String | FIX 2 | 신용카드 N / 체크카드 C |
| CARD_NO | 카드번호 | String | Max 16 | 마스킹 처리된 카드번호 |
| MID | 상점ID | String | FIX 15 | |
| CHECK_HASH | 무결성 검증 Hash | String | Max 128 | message: RESULT_CODE+TID+ORDERNO |
| VAN_RECV_KEY | VAN고유키 | String | Max 20 | |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "성공",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "성공",
"PAY_GROUP": "SGP", "PAY_METHOD": "CC",
"TID": "210728130414398", "ORDERNO": "ORDER12345",
"RESERVED01": "가맹점예약필드 1", "RESERVED02": "가맹점예약필드 2",
"APPROVNO": "33709377", "APPRODT": "20210728", "APPROTM": "113541",
"APPROAMT": "5000", "ISSUE_CODE": "1107", "ISSUE_NAME": "신한카드",
"PURCHASE_CODE": "1107", "PURCHASE_NAME": "신한카드",
"QUOTA_MONTHS": "00", "NOINT": "N", "CHECKCD": "N",
"CARD_NO": "510737**********", "MID": "M20200203113418",
"CHECK_HASH": "3zhVYYVtEflnMMkn8P3J7u3eKjeLyt64doJw81O2fzA=",
"VAN_RECV_KEY": ""
}현금영수증 API 승인/취소
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| mid | 상점 ID | AN | FIX 15 | Y | PG에서 부여한 상점 ID |
| orderno | 주문번호 | AN | Max 20 | Y | 상점 주문번호 |
| orderdt | 주문 일자 | N | FIX 8 | Y | YYYYMMDD |
| ordertm | 주문 시간 | N | FIX 6 | Y | HHMMSS |
| approveAmt | 승인 요청 금액 | N | MAX 9 | Y | |
| checkHash | 무결성검증 | ANS | Max 128 | Y | message: orderno+orderdt+ordertm+approveAmt |
| customerType | 발급유형 | String | FIX 2 | Y | 소득공제: 00 / 지출증빙: 10 |
| idInfo | 발급정보 | String | MAX 30 | Y | 핸드폰번호, 사업자번호 등 현금영수증 발급 정보 |
| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| RESULT_CODE | 처리 결과 코드 | String | Max 20 | 결제처리결과 코드 표 참조 |
| RESULT_MSG | 처리 결과 메시지 | String | Max 1024 | |
| DRESULT_CODE | 가맹점결과코드 | String | Max 20 | |
| DRESULT_MSG | 가맹점결과메시지 | String | Max 1024 | |
| TID | PG거래고유번호 | String | Max 15 | |
| TAX | 세금 | Numeric | MAX 8 | 승인금액에 대한 세금 |
| CLRAMT | 공급가액 | Numeric | MAX 8 | 승인금액 – 세금 |
| ORDERNO | 상점주문번호 | String | Max 20 | |
| MID | 상점ID | String | FIX 15 | |
| APPROV_NO | 승인번호 | String | FIX 9 | |
| APPROV_AMT | 승인금액 | Numeric | - |
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| mid | 상점 ID | String | FIX 15 | Y | 상점 별로 부여되는 상점 ID |
| tid | PG원거래고유번호 | String | Max 15 | Y | 결제승인 시 PG사 원거래고유번호 |
| cancelAmt | 취소금액 | Numeric | Max 8 | Y | -5000 형식. 반드시 숫자만 포함 |
| checkHash | 유효성 검증 Hash | String | Max 128 | Y | message: tid+mid+cancelAmt |
| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| RESULT_CODE | 처리 결과 코드 | String | Max 20 | 결제처리결과 코드 표 참조 |
| RESULT_MSG | 처리 결과 메시지 | String | Max 1024 | |
| DRESULT_CODE | 가맹점결과코드 | String | Max 20 | |
| DRESULT_MSG | 가맹점결과메시지 | String | Max 1024 | |
| TID | PG거래고유번호 | String | Max 15 | |
| TAX | 세금 | Numeric | MAX 8 | 승인금액에 대한 세금 |
| CLRAMT | 공급가액 | Numeric | MAX 8 | 승인금액 – 세금 |
| ORDERNO | 상점주문번호 | String | Max 20 | |
| MID | 상점ID | String | FIX 15 | |
| APPROV_NO | 승인번호 | String | FIX 9 | |
| APPROV_AMT | 승인금액 | Numeric | - |
결제취소 요청
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| mid | 상점 ID | String | FIX 15 | Y | 상점 별로 부여되는 상점 ID |
| payGroup | 결제그룹 | String | FIX 3 | Y | Default: GEP |
| payType | 결제수단 | String | FIX 2 | Y | 결제수단 코드 |
| tid | PG원거래고유번호 | String | Max 15 | Y | 결제승인 시 PG사 원거래고유번호 |
| cancelAmt | 취소금액 | Numeric | Max 8 | Y | 반드시 숫자만 포함 |
| checkHash | 유효성 검증 Hash | String | Max 128 | Y | message: tid+mid+cancelAmt |
| cancelReason | 취소 사유 | String | Max 200 | Y | 취소사유 |
| cancelRequester | 취소 요청자 | String | FIX 1 | Y | 1: 구매자, 2: 가맹점 관리자 |
| reserved01 | 가맹점예약필드1 | String | Max 1024 | O | |
| reserved02 | 가맹점예약필드2 | String | Max 1024 | O | |
| taxExemptYn | 비과세 구분 | String | FIX 1 | O | 복합과세 Y / 비과세 D / 면세 F |
| taxExemptAmt | 면세/비과세금액 | String | MAX 8 | O | 반드시 숫자만 포함 |
| 가상계좌 취소 추가 항목 | |||||
| refundBank | 환불계좌 은행코드 | String | FIX 3 | Y | 은행코드표 참조 |
| refundAcctno | 환불계좌 번호 | String | MAX 20 | Y | |
| refundAcctholder | 환불계좌 예금주명 | String | MAX 20 | Y | |
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| RESULT_CODE | 처리 결과 코드 | String | Max 20 | 결제처리결과 코드 표 참조 | |
| RESULT_MSG | 처리 결과 메시지 | String | Max 1024 | ||
| DRESULT_CODE | 가맹점결과코드 | String | Max 20 | ||
| DRESULT_MSG | 가맹점결과메시지 | String | Max 1024 | ||
| TID | PG거래고유번호 | String | Max 15 | ||
| CANCEL_AMT | 취소금액 | Numeric | MAX 8 | 승인금액에 대한 세금 | |
| RESERVED01 | 가맹점예약필드1 | String | Max 1024 | ||
| RESERVED02 | 가맹점예약필드2 | String | Max 1024 |
{
"RESULT_CODE": "EC0000",
"RESULT_MSG": "정상결제취소",
"DRESULT_CODE": "EC0000",
"DRESULT_MSG": "성공",
"TID": "201605280001",
"CANCEL_AMT": "5000"
}
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| mid | 상점 ID | String | FIX 15 | Y | 상점별로 부여되는 상점 ID |
| payType | 결제수단 | String | FIX 2 | Y | 결제수단 |
| vanTid | PG원거래고유번호 | String | Max 18 | Y | 결제승인시 VAN사 거래일련번호 |
| cancelAmt | 취소금액 | Numeric | Max 8 | Y | 반드시 숫자만 포함 (양수) |
| checkHash | 유효성 검증 Hash | String | Max 128 | Y | message: vanTid+mid+cancelAmt |
| reserved01 | 가맹점예약필드1 | String | Max 1024 | O | |
| reserved02 | 가맹점예약필드2 | String | Max 1024 | O | |
| taxExemptYn | 비과세 구분 | String | FIX 1 | O | 비과세거래: Y / 일반: N |
| taxExemptAmt | 비과세금액 | String | MAX 8 | O | 반드시 숫자만 포함 |
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| RESULT_CODE | 처리 결과 코드 | String | Max 20 | 결제처리결과 코드 표 참조 | |
| RESULT_MSG | 처리 결과 메시지 | String | Max 1024 | ||
| DRESULT_CODE | 가맹점결과코드 | String | Max 20 | ||
| DRESULT_MSG | 가맹점결과메시지 | String | Max 1024 | ||
| VAN_TID | VAN원거래고유번호 | String | Max 15 | ||
| CANCEL_AMT | 취소금액 | Numeric | MAX 8 | 승인금액에 대한 세금 | |
| RESERVED01 | 가맹점예약필드1 | String | Max 1024 | ||
| RESERVED02 | 가맹점예약필드2 | String | Max 1024 |
{
"RESULT_CODE": "EC0000",
"RESULT_MSG": "정상결제취소",
"DRESULT_CODE": "EC0000",
"DRESULT_MSG": "성공",
"VAN_TID": "201605280001",
"CANCEL_AMT": "5000"
}
결제내역 조회
· tid 또는 orderno를 알고 있을 경우: 두 항목 중 1개 필수
· tid, orderno를 모를 경우: approv_amt, approvdt, approv_no 3개 항목 필수
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| mid | 상점 ID | String | FIX 15 | Y | 상점 별로 부여되는 상점 ID |
| payGroup | 결제그룹 | String | FIX 3 | Y | Default: GEP |
| paymethod | 결제수단 | String | FIX 2 | Y | 결제수단 코드 |
| tid | PG원거래고유번호 | String | Max 15 | O | 결제승인 시 PG사 원거래고유번호 |
| orderno | 가맹점고유번호 | String | Max 20 | O | 상점 주문번호 |
| approv_amt | 결제승인금액 | Numeric | Max 8 | O | tid/orderno 없을 때 필수 |
| approvdt | 승인일자 | String | FIX 8 | O | 결제승인일자 (YYYYMMDD) |
| approv_no | 승인번호 | String | Max 15 | O | 결제승인번호 |
| checkHash | 유효성 검증 Hash | String | Max 128 | Y | message: tid+mid+cancelAmt |
| reserved01 | 가맹점예약필드1 | String | Max 1024 | O | |
| reserved02 | 가맹점예약필드2 | String | Max 1024 | O |
| 항목ID | 항목명 | 타입 | 설명 | |
|---|---|---|---|---|
| RESULT_CODE | 처리 결과 코드 | String | Max 20 | 결제처리결과 코드 표 참조 |
| RESULT_MSG | 처리 결과 메시지 | String | Max 1024 | |
| DRESULT_CODE | 가맹점결과코드 | String | Max 20 | |
| DRESULT_MSG | 가맹점결과메시지 | String | Max 1024 | |
| PAY_METHOD | 결제수단 | String | 결제 수단 코드 | |
| TID | PG원거래고유번호 | String | 결제승인시 PG사 원거래고유번호 | |
| ORDERNO | 상점주문번호 | String | 상점 주문번호 | |
| MID | 상점ID | String | PG에서 부여한 상점 ID | |
| BUY_ITEMNM | 상품명 | String | 상점 구매 상품명 | |
| TRANS_STATUS_NM | 거래상태명 | String | 거래 상태 명칭 | |
| TRANS_STATUS | 거래상태 | String | 거래 상태 코드표 참조 | |
| APPROAMT | 승인금액 | Numeric | 숫자만 포함 | |
| CANCEL_AMT | 취소금액 | Numeric | 취소 금액의 합계 | |
| APPRODT | 승인일자 | String | yyyy-MM-dd hh:mm:ss | |
| CANCEL_DT | 취소일자 | String | yyyy-MM-dd hh:mm:ss | |
| RESERVED01 | 가맹점예약필드1 | String | Max 1024 | |
| RESERVED02 | 가맹점예약필드2 | String | Max 1024 |
{
"RESULT_CODE":"EC0000",
"RESULT_MSG":"성공",
"RESULT_DET_CODE":"EC0000",
"RESULT_DET_MSG":"성공",
"data":
[
{"PAY_METHOD":"CC","TID":"220310130423508",
"ORDERNO":"ORDER220310000005",
"RESERVED01":"2475","RESERVED02":"",
"MID":"M20201104113435","BUY_ITEMNM":"테스트상품",
"TRANS_STATUS_NM":"승인","TRANS_STATUS":"20",
"APPROAMT":1004,"CANCEL_AMT":-500,
"APPRODT":"2022-03-10 19:55:59",
"CANCEL_DT":"2022-03-10 20:00:34"}
]
}
매출전표 조회
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| mid | 상점 ID | String | FIX 15 | Y | 상점 별로 부여되는 상점 ID |
| payGroup | 결제그룹 | String | FIX 3 | Y | Default: GEP |
| payMethod | 결제수단 | String | FIX 2 | Y | 결제수단 코드 |
| tid | PG원거래고유번호 | String | Max 15 | Y | 결제승인 시 PG사 원거래고유번호 |
| amt | 결제승인금액 | Numeric | Max 8 | Y | 승인: 1004 / 취소: -1004 |
| text_tr | 승인,취소구분 | String | FIX 2 | O | 승인: 00 / 취소: 99 |
| checkHash | 유효성 검증 Hash | String | Max 128 | Y | message: tid+mid+amt |
| orderno | 주문번호 | String | Max 20 | O | 상점 주문번호 |
리모트 결제
문자 메시지 또는 URL을 통해 고객에게 결제 링크를 전송하는 서비스입니다.
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| mid | 대표ID | String | FIX 15 | Y | PG에서 부여한 상점 ID |
| orderno | 주문번호 | String | Max 20 | Y | 상점 주문번호 |
| orderdt | 주문 일자 | Number | FIX 8 | Y | YYYYMMDD |
| ordertm | 주문 시간 | Number | FIX 6 | Y | HHMMSS |
| buyReqamt | 상품가격 | N | Max 8 | Y | 상점 구매금액. 반드시 숫자만 |
| checkHash | 무결성 검증 Hash | String | Max 128 | Y | message: orderno+orderdt+ordertm+buyReqamt |
| phoneNum | 휴대폰번호 | Number | Max 15 | Y | '-' 제외 숫자만 |
| buyItemnm | 상품명 | String | Max 60 | Y | 상점 판매 상품명 |
| buyernm | 구매자 명 | String | Max 50 | O | 상점 구매자명 |
| goodsInfo | 상품추가정보 | String | Max 50 | O | 상점 판매 상품 추가 정보 |
| payAbleTime | 결제 유효기간 | Number | Max 5 | O | 분 단위 (기본 1시간) |
| 항목ID | 항목명 | 타입 | 설명 |
|---|---|---|---|
| RESULT_CODE | 결제결과코드 | String | 결과코드표 참조 |
| RESULT_MSG | 결제결과메시지 | String |
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| mid | 대표ID | String | FIX 15 | Y | PG에서 부여한 상점 ID |
| orderno | 주문번호 | String | Max 20 | Y | 상점 주문번호 |
| orderdt | 주문 일자 | Number | FIX 8 | Y | YYYYMMDD |
| ordertm | 주문 시간 | Number | FIX 6 | Y | HHMMSS |
| buyReqamt | 상품가격 | N | Max 8 | Y | 상점 구매금액. 반드시 숫자만 |
| checkHash | 무결성 검증 Hash | String | Max 128 | Y | message: orderno+orderdt+ordertm+buyReqamt |
| phoneNum | 휴대폰번호 | Number | Max 15 | Y | '-' 제외 숫자만 |
| buyItemnm | 상품명 | String | Max 60 | Y | 상점 판매 상품명 |
| buyernm | 구매자 명 | String | Max 50 | O | 상점 구매자명 |
| goodsInfo | 상품추가정보 | String | Max 50 | O | 상점 판매 상품 추가 정보 |
| payAbleTime | 결제 유효기간 | Number | Max 5 | O | 분 단위 (기본 1시간) |
| langType | 언어 | String | FIX 3 | O | KOR 한국어, ENG 영어 (기본 KOR) |
| 항목ID | 항목명 | 타입 | 설명 |
|---|---|---|---|
| REQ_URL | 결제 URL | String | 결제 URL (실패 시 공백) |
| RESULT_CODE | 결제결과코드 | String | 결과코드표 참조 |
| RESULT_MSG | 결제결과메시지 | String |
결제 Notification
결제승인 완료 시 계약정보에 등록된 Notify URL로 승인정보를 통지하는 기능입니다. 실시간 Return 응답과는 별개로 Background 프로세스에 의해 가맹점 서버로 통지됩니다.
준비사항
· KOVAN PG WAS와 가맹점 WEB 서버 간 방화벽 오픈 (운영/테스트 별도 작업 필요)
· HTTP/POST 방식의 Notification 전용 웹 서버 프로세스 필요
· Notify URL은 계약정보에 등록 필요 (PG 담당자 문의)
·
CHECK_HASH는 일부 결제수단(계좌이체 등)에서 null로 수신될 수 있습니다. null 여부를 반드시 확인 후 검증하세요.· 오프라인 VAN방식의 경우
mid(소문자), payGroup, payMethod, ORDER_NO 등 소문자 필드가 혼재하여 수신됩니다. 대소문자 구분 없이 파싱하세요.·
APPROVDT / APPROVAMT / APPROVTM과 APPRODT / APPROAMT / APPROTM 두 가지 형태가 동시에 포함될 수 있습니다.
| 항목ID | 타입 | 설명 | 예시값 |
|---|---|---|---|
| RESULT_CODE | String | 결과코드. 성공: EC0000 | EC0000 |
| RESULT_MSG | String | 결과메시지 | SUCCESS |
| DRESULT_CODE | String | 사용자 결과코드 | EC0000 |
| DRESULT_MSG | String | 사용자 결과메시지 | SUCCESS |
| PAY_GROUP | String | 결제그룹 | GEP |
| PAY_METHOD | String | 결제수단 | CC |
| TID | String | PG 거래고유번호 | 260105130562200 |
| ORDERNO | String | 상점 주문번호 | ORDER20260105105237 |
| RESERVED01 | String | 가맹점예약필드1 | reserved01 |
| RESERVED02 | String | 가맹점예약필드2 | reserved02 |
| CHECK_HASH | String | 무결성 검증 Hash. message: RESULT_CODE+TID+ORDERNO | rmKd+h8AM8Tu... |
| VAN_RECV_KEY | String | VAN 거래고유키 (없을 경우 빈 문자열) | |
| APPROVNO | String | 카드사 승인번호 | 21676259 |
| APPRODT | String | 결제승인일자 (YYYYMMDD) | 20260105 |
| APPROTM | String | 결제승인시간 (HHMMSS) | 105240 |
| APPROAMT | String | 결제승인금액 | 1004 |
| ISSUE_CODE | String | 발급사코드 | 1104 |
| ISSUE_NAME | String | 발급사명 | 삼성카드 |
| PURCHASE_CODE | String | 매입사코드 | 1104 |
| PURCHASE_NAME | String | 매입사명 | 삼성카드 |
| QUOTA_MONTHS | String | 할부개월수. 일시불: 00 | 00 |
| NOINT | String | 무이자구분. 무이자: Y / 일반: N | N |
| CHECKCD | String | 카드구분. 신용: N / 체크: C | N |
| CARD_NO | String | 마스킹 처리된 카드번호 | 536148********** |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "SUCCESS",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "SUCCESS",
"PAY_GROUP": "GEP", "PAY_METHOD": "CC",
"TID": "260105130562200", "ORDERNO": "ORDER20260105105237",
"RESERVED01": "reserved01", "RESERVED02": "reserved02",
"CHECK_HASH": "rmKd+h8AM8Tuhz8KGWGUT6aLK4vi/1gzWgUZCiuQB/I=",
"VAN_RECV_KEY": "",
"APPROVNO": "21676259", "APPRODT": "20260105", "APPROTM": "105240",
"APPROAMT": "1004", "ISSUE_CODE": "1104", "ISSUE_NAME": "삼성카드",
"PURCHASE_CODE": "1104", "PURCHASE_NAME": "삼성카드",
"QUOTA_MONTHS": "00", "NOINT": "N", "CHECKCD": "N",
"CARD_NO": "536148**********"
}CHECK_HASH가 null로 수신됩니다. 계좌이체 Notification에서는 Hash 검증을 생략하고 RESULT_CODE와 TID로 처리하세요.| 항목ID | 타입 | 설명 | 예시값 |
|---|---|---|---|
| RESULT_CODE | String | 결과코드. 성공: EC0000 | EC0000 |
| RESULT_MSG | String | 결과메시지 | 성공 |
| DRESULT_CODE | String | 사용자 결과코드 | EC0000 |
| DRESULT_MSG | String | 사용자 결과메시지 | SUCCESS |
| PAY_GROUP | String | 결제그룹 | GEP |
| PAY_METHOD | String | 결제수단 | BA |
| TID | String | PG 거래고유번호 | 260107130562229 |
| ORDERNO | String | 상점 주문번호 | ORDER20260107110442 |
| MID | String | 상점ID | M20200203113418 |
| RESERVED01 | String | 가맹점예약필드1 | reserved01 |
| RESERVED02 | String | 가맹점예약필드2 | reserved02 |
| CHECK_HASH | String | 무결성 검증 Hash. 계좌이체는 null로 수신 | null |
| BANK_CD | String | 은행코드 (은행 코드표 참조) | 050 |
| BANK_NM | String | 은행명 | 상호저축은행 |
| ACCT_NO | String | 계좌번호 (마스킹) | 45678 |
| ESCR_FLAG | String | 에스크로 여부 |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "성공",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "SUCCESS",
"PAY_GROUP": "GEP", "PAY_METHOD": "BA",
"TID": "260107130562229", "ORDERNO": "ORDER20260107110442",
"MID": "M20200203113418",
"RESERVED01": "reserved01", "RESERVED02": "reserved02",
"CHECK_HASH": null,
"BANK_CD": "050", "BANK_NM": "상호저축은행",
"ACCT_NO": "45678", "ESCR_FLAG": ""
}PAY_GROUP: KKP로 구분하세요. 실패 시에는 MID와 공통 결과 필드만 수신됩니다.| 항목ID | 타입 | 설명 | 예시값 |
|---|---|---|---|
| RESULT_CODE | String | 결과코드 | EC0000 |
| RESULT_MSG | String | 결과메시지 | SUCCESS |
| DRESULT_CODE | String | 사용자 결과코드 | EC0000 |
| DRESULT_MSG | String | 사용자 결과메시지 | SUCCESS |
| PAY_GROUP | String | 결제그룹 | KKP |
| PAY_METHOD | String | 결제수단 | CC |
| TID | String | PG 거래고유번호 | 260201130562925 |
| ORDERNO | String | 상점 주문번호 | ORDER20260201202653 |
| MID | String | 상점ID | M20200203113418 |
| RESERVED01 | String | 가맹점예약필드1 | reserved01 |
| RESERVED02 | String | 가맹점예약필드2 | reserved02 |
{
"MID": "M20200203113418",
"TID": "260201130562925",
"PAY_GROUP": "KKP", "PAY_METHOD": "CC",
"ORDERNO": "ORDER20260201202653",
"RESULT_CODE": "EC1029",
"RESULT_MSG": "원천사 결제(취소) 결과실패([-780]approval failure![PG하위몰 사업자번호 오류])",
"DRESULT_CODE": "EC1029",
"DRESULT_MSG": "원천사 결제(취소) 결과실패([-780]approval failure![PG하위몰 사업자번호 오류])",
"RESERVED01": "reserved01", "RESERVED02": "reserved02"
}APPROAMT/APPRODT/APPROTM과 APPROVAMT/APPROVDT/APPROVTM 두 가지 형태의 필드가 동시에 수신됩니다. 두 필드 모두 파싱하여 처리하세요.| 항목ID | 타입 | 설명 | 예시값 |
|---|---|---|---|
| RESULT_CODE | String | 결과코드. 성공: EC0000 | EC0000 |
| RESULT_MSG | String | 결과메시지 | SUCCESS |
| DRESULT_CODE | String | 사용자 결과코드 | EC0000 |
| DRESULT_MSG | String | 사용자 결과메시지 | SUCCESS |
| PAY_GROUP | String | 결제그룹 | KKP |
| PAY_METHOD | String | 결제수단 | VO |
| TID | String | PG 거래고유번호 | 260409130565072 |
| ORDERNO | String | 상점 주문번호 | ORDER20260409113324 |
| MID | String | 상점ID | M20200203113418 |
| RESERVED01 | String | 가맹점예약필드1 | reserved01 |
| RESERVED02 | String | 가맹점예약필드2 | reserved02 |
| APPROAMT | String | 결제승인금액 | 1004 |
| APPRODT | String | 결제승인일자 (YYYYMMDD) | 20260409 |
| APPROTM | String | 결제승인시간 (HHMMSS) | 113736 |
| APPROVAMT | String | 결제승인금액 (중복 필드, 동시 수신) | 1004 |
| APPROVDT | String | 결제승인일자 (중복 필드, 동시 수신) | 20260409 |
| APPROVTM | String | 결제승인시간 (중복 필드, 동시 수신) | 113736 |
{
"MID": "M20200203113418",
"TID": "260409130565072",
"PAY_GROUP": "KKP", "PAY_METHOD": "VO",
"ORDERNO": "ORDER20260409113324",
"RESULT_CODE": "EC0000", "RESULT_MSG": "SUCCESS",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "SUCCESS",
"RESERVED01": "reserved01", "RESERVED02": "reserved02",
"APPROAMT": "1004", "APPRODT": "20260409", "APPROTM": "113736",
"APPROVAMT": "1004", "APPROVDT": "20260409", "APPROVTM": "113736"
}PAY_GROUP: NVP로 구분하세요.| 항목ID | 타입 | 설명 | 예시값 |
|---|---|---|---|
| RESULT_CODE | String | 결과코드 | EC0000 |
| RESULT_MSG | String | 결과메시지 | SUCCESS |
| DRESULT_CODE | String | 사용자 결과코드 | EC0000 |
| DRESULT_MSG | String | 사용자 결과메시지 | SUCCESS |
| PAY_GROUP | String | 결제그룹 | NVP |
| PAY_METHOD | String | 결제수단 | CC |
| TID | String | PG 거래고유번호 | 260116130562552 |
| ORDERNO | String | 상점 주문번호 | ORDER20260116085029 |
| RESERVED01 | String | 가맹점예약필드1 | reserved01 |
| RESERVED02 | String | 가맹점예약필드2 | reserved02 |
| CHECK_HASH | String | 무결성 검증 Hash | 70+UtK3FU/WQ... |
| VAN_RECV_KEY | String | VAN 거래고유키 (빈 문자열 가능) | |
| APPROVNO | String | 카드사 승인번호 | 87101195 |
| APPRODT | String | 결제승인일자 (YYYYMMDD) | 20260116 |
| APPROTM | String | 결제승인시간 (HHMMSS) | 085102 |
| APPROAMT | String | 결제승인금액 | 1004 |
| ISSUE_CODE | String | 발급사코드 | 1110 |
| ISSUE_NAME | String | 발급사명 | 우리카드 |
| PURCHASE_CODE | String | 매입사코드 | 1110 |
| PURCHASE_NAME | String | 매입사명 | 우리카드 |
| QUOTA_MONTHS | String | 할부개월수. 일시불: 00 | 00 |
| NOINT | String | 무이자구분 | N |
| CHECKCD | String | 카드구분. 신용: N / 체크: C | C |
| CARD_NO | String | 마스킹 처리된 카드번호 | 537699********** |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "SUCCESS",
"DRESULT_CODE": "EC0000", "DRESULT_MSG": "SUCCESS",
"PAY_GROUP": "NVP", "PAY_METHOD": "CC",
"TID": "260116130562552", "ORDERNO": "ORDER20260116085029",
"RESERVED01": "reserved01", "RESERVED02": "reserved02",
"CHECK_HASH": "70+UtK3FU/WQopAcae+/EiQui3yw8a9u4r9nyVMfvws=",
"VAN_RECV_KEY": "",
"APPROVNO": "87101195", "APPRODT": "20260116", "APPROTM": "085102",
"APPROAMT": "1004", "ISSUE_CODE": "1110", "ISSUE_NAME": "우리카드",
"PURCHASE_CODE": "1110", "PURCHASE_NAME": "우리카드",
"QUOTA_MONTHS": "00", "NOINT": "N", "CHECKCD": "C",
"CARD_NO": "537699**********"
}MID와 공통 결과 필드 + RESERVED01/02만 수신됩니다. 승인 필드(APPROAMT 등)는 포함되지 않습니다.| 항목ID | 타입 | 설명 | 예시값 |
|---|---|---|---|
| RESULT_CODE | String | 결과코드 | EC1029 |
| RESULT_MSG | String | 결과메시지 (실패 시 원천사 오류 메시지 포함) | 원천사 결제(취소) 결과실패(...) |
| DRESULT_CODE | String | 사용자 결과코드 | EC1029 |
| DRESULT_MSG | String | 사용자 결과메시지 | 원천사 결제(취소) 결과실패(...) |
| PAY_GROUP | String | 결제그룹 | NVP |
| PAY_METHOD | String | 결제수단 | VO |
| TID | String | PG 거래고유번호 | 251121130561398 |
| ORDERNO | String | 상점 주문번호 | ORDER20251121160018 |
| MID | String | 상점ID | M20200203113418 |
| RESERVED01 | String | 가맹점예약필드1 | reserved01 |
| RESERVED02 | String | 가맹점예약필드2 | reserved02 |
{
"MID": "M20200203113418",
"TID": "251121130561398",
"PAY_GROUP": "NVP", "PAY_METHOD": "VO",
"ORDERNO": "ORDER20251121160018",
"RESULT_CODE": "EC1029",
"RESULT_MSG": "원천사 결제(취소) 결과실패([NotEnoughAccountBalance]계좌 잔고가 충전 후 결제할 금액보다 부족합니다.)",
"DRESULT_CODE": "EC1029",
"DRESULT_MSG": "원천사 결제(취소) 결과실패([NotEnoughAccountBalance]계좌 잔고가 충전 후 결제할 금액보다 부족합니다.)",
"RESERVED01": "reserved01", "RESERVED02": "reserved02"
}APPROVAMT / APPROVDT / APPROVTM 필드를 사용합니다. 온라인의 APPROAMT/APPRODT/APPROTM과 다르니 주의하세요. 또한 EID, OPG_ID 필드가 추가로 수신됩니다.| 항목ID | 타입 | 설명 | 예시값 |
|---|---|---|---|
| RESULT_CODE | String | 결과코드. 성공: EC0000 | EC0000 |
| RESULT_MSG | String | 결과메시지 | SUCCESS |
| PAY_GROUP | String | 결제그룹 | GEP |
| PAY_METHOD | String | 결제수단 | CC |
| TID | String | PG 거래고유번호 | 260223130563309 |
| ORG_TID | String | 원거래 TID | 260223130563309 |
| MID | String | 상점ID | M20200203113418 |
| EID | String | 가맹점ID | E20200203113529 |
| OPG_ID | String | VAN 단말기ID | 1047401493 |
| APPROVNO | String | 카드사 승인번호 | 83447351 |
| APPROVDT | String | 결제승인일자 (YYYYMMDD) ※온라인과 필드명 다름 | 20260223 |
| APPROVTM | String | 결제승인시간 (HHMMSS) ※온라인과 필드명 다름 | 162701 |
| APPROVAMT | Number | 결제승인금액 ※숫자형(Integer)으로 수신 | 5004 |
| ISSUE_CODE | String | 발급사코드 | 1104 |
| PURCHASE_CODE | String | 매입사코드 | 1104 |
| CHECKCD | String | 카드구분. 신용: N / 체크: C | N |
| CARD_NO | String | 마스킹 처리된 카드번호 (앞 6자리 + * 마스킹) | 536148********** |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "SUCCESS",
"PAY_GROUP": "GEP", "PAY_METHOD": "CC",
"TID": "260223130563309", "ORG_TID": "260223130563309",
"MID": "M20200203113418", "EID": "E20200203113529",
"OPG_ID": "1047401493",
"APPROVNO": "83447351",
"APPROVDT": "20260223", "APPROVTM": "162701",
"APPROVAMT": 5004,
"ISSUE_CODE": "1104", "PURCHASE_CODE": "1104",
"CHECKCD": "N", "CARD_NO": "536148**********"
}mid, payGroup, payMethod, ORDER_NO 등을 별도로 파싱해야 합니다.또한
APPROAMT + APPROVAMT, APPROTM + APPROVTM, APPROVNO + APPRONO 등 중복 필드가 동시 수신됩니다.ISSUE_CODE에 6자리 코드(예: 112672)가 수신되는 경우가 있습니다.
| 항목ID | 타입 | 설명 | 예시값 |
|---|---|---|---|
| RESULT_CODE | String | 결과코드. 성공: EC0000 | EC0000 |
| RESULT_MSG | String | 결과메시지 | SUCCESS |
| MID | String | 상점ID (대문자) | M20200203113418 |
| mid | String | 상점ID (소문자, 중복 수신) | M20200203113418 |
| TID | String | PG 거래고유번호 | 260106130562218 |
| ORG_TID | String | 원거래 TID | 260106130562218 |
| ORDER_NO | String | 주문번호 (VAN방식 전용 필드명) | 260106130562218 |
| payGroup | String | 결제그룹 (소문자) | GEP |
| payMethod | String | 결제수단 (소문자) | CC |
| APPROVNO | String | 카드사 승인번호 | 21137313 |
| APPRONO | String | 카드사 승인번호 (중복 필드) | 21137313 |
| APPRODT | String | 결제승인일자 (YYYYMMDD) | 20251224 |
| APPROVDT | String | 결제승인일자 (중복 필드) | 20251224 |
| APPROTM | String | 결제승인시간 (HHMMSS) | 111300 |
| APPROVTM | String | 결제승인시간 (중복 필드) | 111300 |
| APPROAMT | String | 결제승인금액 | 72000 |
| APPROVAMT | String | 결제승인금액 (중복 필드) | 72000 |
| BUY_REQAMT | String | 구매요청금액 | 72000 |
| ISSUE_CODE | String | 발급사코드 (6자리 코드 수신 가능) | 112672 |
| PURCHASE_CODE | String | 매입사코드 | 1106 |
| CHECKCD | String | 카드구분. 신용: N / 체크: C | C |
| CARD_NO | String | 마스킹 처리된 카드번호 | 518185********** |
{
"RESULT_CODE": "EC0000", "RESULT_MSG": "SUCCESS",
"MID": "M20200203113418", "mid": "M20200203113418",
"TID": "260106130562218", "ORG_TID": "260106130562218",
"ORDER_NO": "260106130562218",
"payGroup": "GEP", "payMethod": "CC",
"APPROVNO": "21137313", "APPRONO": "21137313",
"APPRODT": "20251224", "APPROVDT": "20251224",
"APPROTM": "111300", "APPROVTM": "111300",
"APPROAMT": "72000", "APPROVAMT": "72000",
"BUY_REQAMT": "72000",
"ISSUE_CODE": "112672", "PURCHASE_CODE": "1106",
"CHECKCD": "C", "CARD_NO": "518185**********"
}| 항목ID | 타입 | 길이(byte) | 설명 |
|---|---|---|---|
| RESULT_CODE | String | Max 20 | 결과코드. 성공: EC0000 |
| RESULT_MSG | String | Max 1024 | 결과메시지 |
| DRESULT_CODE | String | Max 20 | 사용자 결과코드 |
| DRESULT_MSG | String | Max 1024 | 사용자 결과메시지 |
| PAY_METHOD | String | FIX 2 | 결제수단 (CC / VO) |
| PAY_GROUP | String | FIX 3 | 결제그룹 (GEP / KKP / NVP) |
| TID | String | FIX 15 | PG 취소 거래고유번호 |
| CANCEL_AMT | Numeric | Max 20 | 취소금액 |
| APPROAMT | Numeric | Max 15 | 원거래 승인금액 |
| VAN_RECV_KEY | String | Max 20 | VAN 거래고유키 |
| PCH_TID | String | Max 15 | 매입요청고유번호 |
| EID | String | FIX 15 | 가맹점ID |
| MID | String | FIX 15 | 상점ID |
| RESERVED01 | String | Max 1024 | 가맹점예약필드1 (원 결제요청 시 전달한 값) |
| RESERVED02 | String | Max 1024 | 가맹점예약필드2 (원 결제요청 시 전달한 값) |
| 항목ID | 타입 | 길이(byte) | 설명 |
|---|---|---|---|
| RESULT_CODE | String | Max 20 | 결과코드. 성공: EC0000 |
| RESULT_MSG | String | Max 1024 | 결과메시지 |
| PAY_METHOD | String | FIX 2 | 결제수단 (CC / VO) |
| PAY_GROUP | String | FIX 3 | 결제그룹 (GEP / KKP / NVP) |
| TID | String | FIX 15 | PG 취소 거래고유번호 |
| CANCEL_AMT | Numeric | Max 20 | 취소금액 |
| VAN_RECV_KEY | String | Max 20 | VAN 거래고유키 |
| EID | String | FIX 15 | 가맹점ID |
| MID | String | FIX 15 | 상점ID |
| OPG_ID | String | FIX 15 | VAN TID |
| ORG_TID | String | FIX 15 | VAN 원거래 고유번호 |
| 항목ID | 타입 | 길이(byte) | 설명 |
|---|---|---|---|
| TID | String | FIX 15 | PG사 거래고유번호 |
| PAY_METHOD | String | FIX 2 | VA |
| TEXT_TR | String | FIX 2 | 입금: 00 / 입금취소: 99 |
| ORDERNO | String | Max 20 | 상점 주문번호 |
| TRANSDT | String | FIX 14 | 거래일자 (YYYYMMDDHHMMSS) |
| RESULT | String | FIX 2 | 처리결과코드. 성공: 00 |
| RESULT_MSG | String | Max 1024 | 처리결과메시지. 성공: Success |
정산 내역 조회
승인 대사 및 정산 대사 데이터를 조회하는 API입니다.
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| id | 상점ID/가맹점ID | String | FIX 15 | Y | 상점 별로 부여되는 상점 ID 및 상위 가맹점 ID |
| stmtReqDt | 대사요청일 | String | FIX 8 | Y | 요청 일시 (YYYYMMDD) |
| stmtType | 대사타입 | String | FIX 1 | Y | 0: 승인대사, 1: 정산대사 |
| ediDate | 전문요청일시 | String | FIX 14 | Y | 요청시 일시 (yyyymmddhhmmss) |
| encData | 해쉬암호화값 | String | FIX 256 | Y | id + ediDate + api key를 이용한 키 |
| 항목ID | 항목명 | 타입 | 설명 |
|---|---|---|---|
| resultCd | 결과코드 | String | 성공: 0000 |
| resultMsg | 결과메시지 | String | 실패시에만 표시 |
| id | 해당ID | String | 요청한 ID |
| stmtDt | 대사일 | String | 요청한 일자 |
| stmtType | 대사타입 | String | 0: 승인대사, 1: 정산대사 |
| mbsNo | 사업자번호 | String | 가맹점의 사업자번호 |
| stmtCnt | 대사건수 | String | 대사 합계 건수 |
| stmtSumAmt | 대사 합계 금액 | String | 대사 합계 금액 |
| stmtData (JSONArray) | |||
| Mid | 상점ID | String(15) | |
| appDtm | 승인일시 | String(14) | YYYYMMDDHHMMSS 형식 |
| canDtm | 취소일시 | String(14) | YYYYMMDDHHMMSS 형식 |
| payMethod | 결제수단 | String(10) | CARD | BANK | VACNT |
| trxStCd | 거래상태코드 | String(1) | 0:승인, 1:전취소, 2:후취소, 3:부분취소 |
| goodsNm | 상품명 | String(100) | 상품이름 |
| goodsAmt | 상품금액 | String(15) | 결제금액 |
| remainAmt | 잔액 | String(15) | 부분취소 후 남은 금액 |
| quotaMon | 할부개월 | String(2) | 할부 개월 수 |
| appNo | 승인번호 | String(10) | 카드사, 은행 승인번호 |
| acqCardCd | 매입사코드 | String(4) | 신용카드: 카드사코드 / 계좌이체·가상계좌: 은행코드 |
| appCardCd | 발급사코드 | String(4) | 카드사 코드 |
| ezpAuthCd | 간편결제코드 | String(4) | 간편 결제사 코드 (미사용 시 공백) |
| cardType | 카드타입 | String(1) | 0: 체크 / 1: 신용 |
| cartMid | 카트MID | String(10) | 장바구니 거래 시 MID (미사용 시 공백) |
| cartTid | 카트TID | String(30) | 장바구니 거래 시 TID (미사용 시 공백) |
| Tid | PG거래번호 | String(30) | 거래번호 |
| Otid | 원거래 PG거래번호 | String(30) | 부분취소 시 원거래 번호 |
| ordNo | 주문번호 | String(40) | 가맹점 주문번호 |
| ordNm | 주문자명 | String(30) | 주문자 이름 |
| ordTel | 주문자연락처 | String(20) | 주문자 연락처 |
| mbsUsrId | 고객ID | String(20) | 가맹점 고객 ID |
| trxCd | 에스크로여부 | String(1) | 0: 일반 / 1: 에스크로 |
| mbsReserved | 가맹점예약필드 | String(500) | 가맹점 예약 필드 |
| 항목ID | 항목명 | 타입 | 설명 |
|---|---|---|---|
| Mid | 상점ID | String(15) | |
| stmtDt | 입금일 | String(8) | YYYYMMDD 형식 |
| txtDt | 결제일 | String(8) | 승인/취소 일 (YYYYMMDD) |
| payMethod | 결제수단 | String(10) | CARD | BANK | VACNT |
| fnCd | 금융사코드 | String(4) | 신용카드: 매입사 / 계좌이체·가상계좌: 금융사 |
| appNo | 승인번호 | String(10) | 카드사, 은행 승인번호 |
| amt | 금액 | String(15) | 결제금액 (취소 시 마이너스) |
| fee | 수수료 | String(15) | 취소 시 마이너스 |
| vat | VAT | String(15) | 취소 시 마이너스 |
| refundFee | 환불 수수료 | String(15) | |
| refundFeeVat | 환불 수수료 VAT | String(15) | |
| smsFee | SMS 수수료 | String(15) | |
| stmtAmt | 입금액 | String(15) | 최종입금 금액 (취소 시 마이너스) |
| cartMid | 카트MID | String(10) | 장바구니 거래 시 MID (미사용 시 공백) |
| cartTid | 카트TID | String(30) | 장바구니 거래 시 TID (미사용 시 공백) |
| tid | PG거래번호 | String(30) | 거래번호 |
| otid | 원거래 PG거래번호 | String(30) | 부분취소 시 원거래 번호 |
| ordNo | 주문번호 | String(40) | 가맹점 주문번호 |
| trxStCd | 거래상태코드 | String(1) | 0:승인, 2:후취소, 3:부분취소 |
| remainAmt | 잔액 | String(15) | 부분취소 후 남은 금액 |
| goodsNm | 상품명 | String(100) | 상품명 |
| ordNm | 주문자명 | String(30) | 주문자 이름 |
| mbsUsrId | 고객ID | String(20) | 가맹점 고객 ID |
| mbsReserved | 가맹점예약필드 | String(500) | 가맹점 예약 필드 |
지급대행 가맹점 관리
지급대행 가맹점 등록, 수정, 조회 API입니다.
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| id | 대표ID | String | FIX 15 | Y | 지급대행을 관리하는 대표ID (KOVANPG 발급 EID) |
| editDate | 전문요청일시 | String | FIX 14 | Y | 요청시 일시 (yyyymmddhhmmss) |
| encData | 해쉬암호화값 | String | FIX 256 | Y | id + ediDate + api key를 이용한 키 |
| oid | 가맹점ID | String | 30 | Y | 가맹점에서 관리하는 가맹점 ID |
| shopNm | 상점명 | String | 100 | Y | |
| phone | 전화번호 | String | 20 | Y | 상점 전화번호 |
| csPhone | CS 전화번호 | String | 20 | O | CS 전화번호 |
| 이메일주소 | String | 30 | Y | 메일주소 |
| 항목ID | 항목명 | 타입 | 설명 |
|---|---|---|---|
| resultCd | 결과코드 | String | 성공: 0000 |
| resultMsg | 결과메시지 | String | 실패시에만 표시 |
| data (JSONArray) | |||
| id | 대표ID | String | 요청한 ID (PG가 발급한 EID) |
| oid | 상점ID-가맹점 | String | 가맹점에서 요청한 상점ID |
| rid | 상점ID-PG | String | PG에서 발급한 상점ID |
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| id | RID | String | FIX 15 | Y | 지급대행용 RID |
| editDate | 전문요청일시 | String | FIX 14 | Y | 요청시 일시 (yyyymmddhhmmss) |
| encData | 해쉬암호화값 | String | FIX 256 | Y | id + ediDate + api key를 이용한 키 |
| oid | 가맹점ID | String | 30 | Y | 가맹점에서 관리하는 가맹점 ID |
| shopNm | 상점명 | String | 100 | Y | |
| phone | 전화번호 | String | 20 | Y | 상점 전화번호 |
| csPhone | CS 전화번호 | String | 20 | O | CS 전화번호 |
| 이메일주소 | String | 30 | Y | 메일주소 |
| 항목ID | 항목명 | 타입 | 설명 |
|---|---|---|---|
| resultCd | 결과코드 | String | 성공: 0000 |
| resultMsg | 결과메시지 | String | 실패시에만 표시 |
| data (JSONArray) | |||
| id | 대표ID (RID) | String(15) | 수정된 가맹점의 RID |
| oid | 상점ID-가맹점 | String(30) | 가맹점에서 요청한 상점ID |
| shopNm | 상점명 | String(100) | |
| phone | 전화번호 | String(20) | 상점 전화번호 |
| csPhone | CS 전화번호 | String(20) | CS 전화번호 |
| 이메일주소 | String(30) | 메일주소 | |
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| id | RID | String | FIX 15 | Y | 지급대행용 RID |
| editDate | 전문요청일시 | String | FIX 14 | Y | 요청시 일시 (yyyymmddhhmmss) |
| encData | 해쉬암호화값 | String | FIX 256 | Y | id + ediDate + api key를 이용한 키 |
| oid | 가맹점ID | String | 30 | Y | 가맹점에서 관리하는 가맹점 ID |
| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| resultCd | 결과코드 | String | Max 4 | 성공: 0000, 실패: 그외 |
| resultMsg | 결과메시지 | String | Max 100 | 실패시에만 표시 |
| data (JSONArray) | ||||
| id | 대표ID (RID) | String | 15 | 조회된 가맹점의 RID |
| oid | 상점ID-가맹점 | String | 30 | 가맹점에서 요청한 상점ID |
| shopNm | 상점명 | String | 100 | |
| phone | 전화번호 | String | 20 | 상점 전화번호 |
| csPhone | CS 전화번호 | String | 20 | CS 전화번호 |
| 이메일주소 | String | 30 | 메일주소 | |
지급대행 계좌 관리
지급대행 가맹점의 정산 계좌를 등록, 수정, 조회하는 API입니다.
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| id | RID | String | FIX 15 | Y | 지급대행용 RID |
| editDate | 전문요청일시 | String | FIX 14 | Y | 요청시 일시 (yyyymmddhhmmss) |
| encData | 해쉬암호화값 | String | FIX 256 | Y | id + ediDate + api key를 이용한 키 |
| oid | 가맹점ID | String | 30 | Y | 가맹점에서 관리하는 가맹점 ID |
| bankCd | 은행코드 | String | 3 | Y | 은행코드 참조 |
| acctNm | 예금주 | String | 30 | Y | |
| acctNo | 계좌번호 | String | 50 | Y |
| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| resultCd | 결과코드 | String | Max 4 | 성공: 0000, 실패: 그외 |
| resultMsg | 결과메시지 | String | Max 100 | 실패시에만 표시 |
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| id | RID | String | FIX 15 | Y | 지급대행용 RID |
| editDate | 전문요청일시 | String | FIX 14 | Y | 요청시 일시 (yyyymmddhhmmss) |
| encData | 해쉬암호화값 | String | FIX 256 | Y | id + ediDate + api key를 이용한 키 |
| oid | 가맹점ID | String | 30 | Y | 가맹점에서 관리하는 가맹점 ID |
| bankCd | 은행코드 | String | 3 | Y | 은행코드 참조 |
| acctNm | 예금주 | String | 30 | Y | |
| acctNo | 계좌번호 | String | 50 | Y |
| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| resultCd | 결과코드 | String | Max 4 | 성공: 0000, 실패: 그외 |
| resultMsg | 결과메시지 | String | Max 100 | 실패시에만 표시 |
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| id | RID | String | FIX 15 | Y | 지급대행용 RID |
| editDate | 전문요청일시 | String | FIX 14 | Y | 요청시 일시 (yyyymmddhhmmss) |
| encData | 해쉬암호화값 | String | FIX 256 | Y | id + ediDate + api key를 이용한 키 |
| oid | 가맹점ID | String | 30 | Y | 가맹점에서 관리하는 가맹점 ID |
| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| resultCd | 결과코드 | String | Max 4 | 성공: 0000, 실패: 그외 |
| resultMsg | 결과메시지 | String | Max 100 | 실패시에만 표시 |
| acctStatus | 계좌 등록 상태 | String | 10 | 계좌상태코드 참조 (REG_REQ, REG_CONF 등) |
| bankCd | 은행코드 | String | 3 | 은행코드 참조 |
| acctNm | 예금주 | String | 30 | |
| acctNo | 계좌번호 | String | 50 |
지급 요청/취소/조회
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| id | 대표ID | String | FIX 15 | Y | 지급대행을 관리하는 대표ID (EID) |
| ediDate | 전문요청일시 | String | FIX 14 | Y | 요청시 일시 (yyyymmddhhmmss) |
| encData | 해쉬암호화값 | String | FIX 256 | Y | id + ediDate + api key를 이용한 키 |
| payReqCnt | 지급요청건수 | String | 5 | Y | 지급요청건수 |
| payReqList (배열) | |||||
| rid | PG 상점ID | String | 30 | O | PG에서 부여한 지급대행 가맹점 ID |
| oid | 상점ID(가맹점) | String | 30 | Y | 지급대행 대상 상점 ID |
| shopNm | 상점명 | String | 100 | Y | |
| payReqDt | 지급일 | String | 8 | Y | YYYYMMDD |
| payReqAmt | 지급액 | String | 15 | Y | |
| shopSeqNo | 요청일련번호 | String | 50 | O | 가맹점 요청 일련번호 |
| bankCd | 은행코드 | String | 3 | Y | 빈 값일 경우 가맹점 등록 시 계좌 정보 참조 |
| acctNm | 예금주 | String | 30 | Y | |
| acctNo | 계좌번호 | String | 50 | Y | |
| memo | 메모 | String | 35 | O | 다중 지급 요청 시 가장 최근 메모 적용 |
| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| id | 대표ID | String | FIX 15 | 요청한 EID |
| respDate | 전문응답일시 | String | FIX 14 | 응답 일시 (yyyymmddhhmmss) |
| payResultCnt | 응답건수 | String | 5 | |
| resCode | 응답코드 | String | 4 | 0000: 성공 / 0010: 해시 불일치 / 0020: 지급 요청금액 오류 |
| resMsg | 응답메시지 | String | Max 100 | 실패시에만 표시 |
| payResultList (JSONArray) | ||||
| oid | 상점ID | String | 30 | 지급대행 대상 상점 ID |
| rid | 상점ID-PG | String | FIX 15 | PG에서 발급한 상점ID |
| shopNm | 상점명 | String | 100 | |
| bankCd | 은행코드 | String | 3 | 은행 코드표 참조 |
| shopSeqNo | 요청일련번호 | String | - | 가맹점 요청 일련번호 |
| acctNm | 예금주 | String | 30 | |
| acctNo | 계좌번호 | String | 50 | |
| payReqDt | 지급일 | String | 8 | YYYYMMDD |
| payReqAmt | 지급액 | String | 15 | |
| resultCdDetail | 결과코드 | String | Max 4 | 성공: 0000, 실패: 그외 |
| resultMsgDetail | 결과메시지 | String | Max 100 | 실패시에만 표시 |
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| id | 대표ID | String | FIX 15 | Y | EID |
| ediDate | 전문요청일시 | String | FIX 14 | Y | yyyymmddhhmmss |
| encData | 해쉬암호화값 | String | FIX 256 | Y | |
| orgEdiDate | (원)지급요청일 | String | 8 | Y | 원 지급요청전문의 ediDate |
| canType | 취소구분 | String | 10 | Y | 전체: ALL / 단일: TARGET |
| oid | 상점ID | String | 30 | O | canType TARGET 시 필요 |
| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| id | 대표ID | String | FIX 15 | 요청한 EID |
| respDate | 전문응답일시 | String | FIX 14 | 응답 일시 (yyyymmddhhmmss) |
| canResultCnt | 응답건수 | String | 5 | |
| resCode | 응답코드 | String | 4 | 0000: 성공 / 0010: 해시 불일치 / 0020: 조회조건 오류 |
| resMsg | 응답메시지 | String | Max 100 | 실패시에만 표시 |
| canResultList (JSONArray) | ||||
| oid | 상점ID | String | 30 | 지급대행 대상 상점 ID |
| rid | 상점ID-PG | String | FIX 15 | PG에서 발급한 상점ID |
| shopNm | 상점명 | String | 100 | |
| bankCd | 은행코드 | String | 3 | 은행 코드표 참조 |
| shopSeqNo | 요청일련번호 | String | - | 가맹점 요청 일련번호 |
| acctNm | 예금주 | String | 30 | |
| acctNo | 계좌번호 | String | 50 | |
| payReqDt | 지급일 | String | 8 | YYYYMMDD |
| payReqAmt | 지급액 | String | 15 | |
| resultCdDetail | 결과코드 | String | Max 4 | 성공: 0000, 실패: 그외 |
| resultMsgDetail | 결과메시지 | String | Max 100 | 실패시에만 표시 |
| 항목ID | 항목명 | 타입 | 길이(byte) | 필수 | 설명 |
|---|---|---|---|---|---|
| id | 대표ID | String | FIX 15 | Y | EID |
| ediDate | 전문요청일시 | String | FIX 14 | Y | |
| encData | 해쉬암호화값 | String | FIX 256 | Y | |
| payDateFrom | 시작일 | String | 8 | Y | yyyymmdd |
| payDateTo | 종료일 | String | 8 | Y | yyyymmdd |
| schType | 조회구분 | String | 10 | Y | 전체: ALL / 단일: TARGET |
| oid | 상점ID | String | 30 | O | schType TARGET 시 필요 |
| 항목ID | 항목명 | 타입 | 길이(byte) | 설명 |
|---|---|---|---|---|
| id | 대표ID | String | FIX 15 | 요청한 EID |
| respDate | 전문응답일시 | String | FIX 14 | 응답 일시 (yyyymmddhhmmss) |
| payResultCnt | 응답건수 | String | 5 | |
| resCode | 응답코드 | String | 4 | 0000: 성공 / 0010: 해시 불일치 / 0020: 조회조건 오류 |
| resMsg | 응답메시지 | String | Max 100 | 실패시에만 표시 |
| payResultList (JSONArray) | ||||
| oid | 상점ID | String | 30 | 지급대행 대상 상점 ID |
| rid | 상점ID-PG | String | FIX 15 | PG에서 발급한 상점ID |
| shopNm | 상점명 | String | 100 | |
| bankCd | 은행코드 | String | 3 | 은행 코드표 참조 |
| shopSeqNo | 요청일련번호 | String | - | 가맹점 요청 일련번호 |
| acctNm | 예금주 | String | 30 | |
| acctNo | 계좌번호 | String | 50 | |
| payReqDt | 지급일 | String | 8 | YYYYMMDD |
| payReqAmt | 지급액 | String | 15 | |
| resultCdDetail | 결과코드 | String | Max 4 | 성공: 0000, 실패: 그외 |
| resultMsgDetail | 결과메시지 | String | Max 100 | 실패시에만 표시 |
코드표
결제수단 코드
카드사 코드
cardCode (결제요청), acqCardCd / appCardCd (정산 API), 차액정산 카드사 코드 모두 동일한 코드 체계를 사용합니다.
거래상태 코드
TRANS_STATUS — 결제내역 조회 응답에서 사용합니다. (TRANS_STATUS_NM에 상태명도 함께 반환됩니다.)
은행 코드
계좌 상태 코드
결제처리결과 코드
결과코드(가맹점): RESULT_CODE / 결과메시지(가맹점): RESULT_MSG
결과코드(사용자): DRESULT_CODE / 결과메시지(사용자): DRESULT_MSG
모바일 연동
모바일 웹뷰 및 앱 결제 연동 시 필요한 카드사/은행 앱 스키마와 패키지 목록입니다.
등록하지 않으면 앱이 설치되어 있어도 스토어로 이동하거나 오류가 발생합니다.
iOS — URL 스키마 목록 (Info.plist)
Info.plist의 LSApplicationQueriesSchemes에 아래 스키마를 추가하세요. 누락 시 콘솔에 canOpenURL: failed for URL 오류가 발생합니다.
<key>LSApplicationQueriesSchemes</key>
<array>
<!-- 토스 -->
<string>supertoss</string>
<!-- 국민카드 -->
<string>kb-acp</string>
<string>liivbank</string>
<string>newliiv</string>
<string>kbbank</string>
<!-- 농협카드 -->
<string>nhappcardansimclick</string>
<string>nhallonepayansimclick</string>
<string>nonghyupcardansimclick</string>
<!-- 롯데카드 -->
<string>lottesmartpay</string>
<string>lotteappcard</string>
<!-- 삼성카드 -->
<string>mpocket.online.ansimclick</string>
<string>mpocket.ansimclick.cert</string>
<string>vguardstart</string>
<string>samsungpay</string>
<string>monimopay</string>
<string>monimopayauth</string>
<!-- 신한카드 -->
<string>shinhan-sr-ansimclick</string>
<string>smshinhanansimclick</string>
<!-- 우리카드 -->
<string>com.wooricard.wcard</string>
<string>newsmartpib</string>
<!-- 씨티카드 -->
<string>citispay</string>
<string>citicardappkr</string>
<string>citimobileapp</string>
<!-- 하나카드 -->
<string>cloudpay</string>
<string>hanawalletmembers</string>
<!-- 현대카드 -->
<string>hdcardappcardansimclick</string>
<string>smhyundaiansimclick</string>
<!-- ISP/페이북 -->
<string>ispmobile</string>
<!-- 카카오 -->
<string>kakaotalk</string>
<string>kakaobank</string>
<!-- 네이버페이 -->
<string>naversearchapp</string>
<!-- 간편결제 -->
<string>shinsegaeeasypayment</string>
<string>payco</string>
<string>lpayapp</string>
<string>bankpay</string>
<string>paynow</string>
</array>
Android — 패키지 목록 (AndroidManifest.xml)
AndroidManifest.xml의 <queries> 섹션에 아래 패키지를 추가하세요. Android 11(API 30) 이상에서 패키지 공개 상태 정책으로 인해 누락 시 카드사 앱 설치 여부 확인이 불가합니다.
<queries>
<!-- 간편결제 -->
<package android:name="viva.republica.toss" /> <!-- 토스 -->
<package android:name="com.kakao.talk" /> <!-- 카카오톡/카카오페이 -->
<package android:name="com.kakaobank.channel" /> <!-- 카카오뱅크 -->
<package android:name="com.nhn.android.search" /> <!-- 네이버페이 -->
<package android:name="com.samsung.android.spay" /> <!-- 삼성페이 -->
<package android:name="com.samsung.android.spaylite" /> <!-- 삼성페이 Lite -->
<package android:name="net.ib.android.smcard" /> <!-- 모니모페이 -->
<package android:name="com.ssg.serviceapp.android.egiftcertificate" /> <!-- SSGPAY -->
<package android:name="com.nhnent.payapp" /> <!-- PAYCO -->
<package android:name="com.lottemembers.android" /> <!-- L.POINT -->
<package android:name="com.lguplus.paynow" /> <!-- 페이나우 -->
<package android:name="com.kftc.bankpay.android" /> <!-- 뱅크페이 -->
<!-- 신한카드 -->
<package android:name="com.shinhan.smartcaremgr" /> <!-- 신한 슈퍼SOL -->
<package android:name="com.shcard.smartpay" /> <!-- 신한페이판 -->
<package android:name="com.shinhancard.smartshinhan" /> <!-- 신한페이판 공동인증서 -->
<package android:name="com.mobiletoong.travelwallet" /> <!-- 신한 트래블월렛 -->
<package android:name="com.TouchEn.mVaccine.webs" /> <!-- TouchEn mVaccine -->
<!-- 삼성카드 -->
<package android:name="kr.co.samsungcard.mpocket" /> <!-- 삼성카드 -->
<package android:name="kr.co.shiftworks.vguardweb" /> <!-- V-Guard -->
<!-- 현대카드 -->
<package android:name="com.hyundaicard.appcard" /> <!-- 현대카드 -->
<package android:name="com.lumensoft.touchenappfree" /> <!-- 현대카드 공동인증서 -->
<!-- 국민카드 -->
<package android:name="com.kbcard.cxh.appcard" /> <!-- KB Pay -->
<package android:name="com.kbstar.liivbank" /> <!-- Liiv -->
<package android:name="com.kbstar.reboot" /> <!-- Liiv Reboot -->
<package android:name="com.kbstar.kbbank" /> <!-- 스타뱅킹 -->
<package android:name="kvp.jjy.MispAndroid320" /> <!-- ISP/페이북 -->
<!-- 농협카드 -->
<package android:name="nh.smart.nhallonepay" /> <!-- 올원페이 -->
<!-- 롯데카드 -->
<package android:name="com.lcacApp" /> <!-- 롯데카드(디지로카) -->
<!-- 하나카드 -->
<package android:name="com.hanaskcard.paycla" /> <!-- 하나카드 -->
<package android:name="com.hanaskcard.rocomo.potal" /> <!-- 하나카드 -->
<package android:name="kr.co.hanamembers.hmscustomer" /> <!-- 하나멤버스 -->
<!-- 씨티카드 -->
<package android:name="kr.co.citibank.citimobile" /> <!-- 씨티모바일 -->
<!-- 우리카드 -->
<package android:name="com.wooricard.wpay" /> <!-- 우리페이 -->
<package android:name="com.wooricard.smartapp" /> <!-- 우리WON카드 -->
<package android:name="com.wooribank.smart.npib" /> <!-- 우리WON뱅킹 -->
<!-- 보안앱 -->
<package android:name="com.ahnlab.v3mobileplus" /> <!-- V3 모바일플러스 -->
</queries>
Chrome 80+ SameSite 쿠키 이슈
해결 방법: 가맹점 사이트에 SSL 적용 후 쿠키 생성 시 아래 설정을 추가하세요.
SameSite=None; Secure; HttpOnly
차액 정산 서비스
대표 가맹점이 하위 가맹점을 대신하여 결제를 요청하는 구조에서 발생하는 수수료 차액을 정산하는 서비스입니다.
서비스 개요
하위몰이 중소/영세 등급이고 결제를 요청하는 대표 가맹점이 일반 등급일 때 적용되는 수수료 차이가 발생합니다. 차액정산 서비스는 이 수수료 차액을 정확하게 계산하여 대표 가맹점에게 차액분을 환급하는 서비스입니다.
서비스 이용 절차
정산관리팀에서 제공하는 양식에 따라 각 하위몰의 사업자 정보(사업자명, 사업자번호, 대표자명 등)를 작성하여 파일을 준비합니다.
시스템에 하위몰을 등록하고 정상 응답을 확인합니다. 이후 정산관리팀에 해당 하위몰 사업자의 거래 차액 정산을 요청합니다.
정산관리팀 양식에 맞게 차액 정산 요청서를 작성합니다. 한 거래건에 여러 하위몰이 있을 경우, 모든 하위몰의 합계 금액이 원래 승인 금액과 일치하는지 반드시 확인해야 합니다.
SFTP 파일 송수신
파일명 형식:
파일명.요청일(yyyyMMdd) — 예: batch_settlement.20260406
파일 송수신 시간
※ 송수신 시간은 추후 변경될 수 있습니다.
SFTP 계정 신청 절차
2. 필수 정보 제공: SFTP 서버에 접속할 가맹점 IP 주소
3. SFTP 정보 수령: IP, ID, PASSWORD, 경로, 송수신 파일명
4. 방화벽 설정: 가맹점 IP가 PG SFTP 서버에 접속할 수 있도록 방화벽 개방
5. SFTP 접속 테스트
📄 차액정산 전문 규격
고객사 → PG사 방향으로 송신하는 차액정산 요청 배치 파일 규격입니다.
범례: A(Alphabet), N(숫자), YYYY(연도), MM(월), DD(일) — N(숫자) 단독이면 우측정렬·0패딩, 문자포함 형식이면 좌측정렬·공백패딩
| 항목 | 형식 | 길이 | 설명 | 비고 |
|---|---|---|---|---|
| 레코드구분 | A | 2 | DT로 고정 | |
| 처리요청일자 | YYYYMMDD | 8 | 처리 요청 일자 | |
| 거래일자 | YYYYMMDD | 8 | 실제 거래 발생 일자 | |
| 승인/취소구분 | A | 1 | 승인 및 취소 구분 | 0: 승인 / 1: 취소 |
| 거래번호 (TID) | AN | 15 | PG에서 발행된 거래 고유번호 | |
| 취소거래번호 | AN | 15 | 취소 시 전달받은 거래 고유번호 | 승인 시는 공백 |
| 주문번호 | AN | 65 | 고객사에서 발행하는 주문 고유번호 | |
| 상점ID (MID) | AN | 15 | PG에서 발행된 거래기준 MID | |
| 사업자번호 | A | 10 | 대표 가맹점 사업자번호 | |
| 하위사업자번호 | A | 10 | 실제 물품 판매 하위사업자(최종 셀러) 사업자번호 | |
| 거래금액 | N | 10 | 거래구분에 따른 해당 Transaction 금액 | |
| 하위사업자 매출액 | N | 15 | 하위 사업자의 매출금액 | 하나의 거래(TID) 총금액 ≥ 하위사업자 매출액의 합 |
| 공백 | AN | 76 | 예약 필드 | SPACE |
0으로 채워서 생성합니다.| 항목 | 형식 | 길이 | 설명 | 비고 |
|---|---|---|---|---|
| 레코드구분 | A | 2 | TR로 고정 | |
| 파일 전체 라인수 | N | 8 | 해당 파일 내 전체 라인수 (데이터부 + Trailer부) | |
| 승인거래건수 | N | 8 | 승인/취소구분 0(승인)인 거래 총건수 | |
| 취소거래건수 | N | 8 | 승인/취소구분 1(취소)인 거래 총건수 | |
| 총거래금액 부호 | A | 1 | 총거래금액 부호 | 양수: 0 / 음수: 1 |
| 총거래금액 | N | 15 | 승인거래금액 − 취소거래금액 | |
| 공백 | AN | 208 | 예약 필드 | SPACE |
| 항목 | 형식 | 길이 | 설명 | 비고 |
|---|---|---|---|---|
| 레코드구분 | A | 2 | DT로 고정 | |
| 처리요청일자 | YYYYMMDD | 8 | 처리 요청 일자 | |
| 거래일자 | YYYYMMDD | 8 | 실제 거래 발생 일자 | |
| 승인/취소구분 | A | 1 | 승인 및 취소 구분 | 0: 정상 / 1: 취소 (취소 시 차감 수수료) |
| 거래번호 (TID) | AN | 15 | PG에서 발행된 거래 고유번호 | |
| 취소거래번호 | AN | 15 | 취소 시 전달받은 거래 고유번호 | 승인 시는 공백 |
| 주문번호 | AN | 65 | 고객사에서 발행하는 주문 고유번호 | |
| 상점ID (MID) | AN | 15 | PG에서 발행된 거래기준 MID | |
| 사업자번호 | A | 10 | 대표 가맹점 사업자번호 | |
| 하위사업자번호 | A | 10 | 최종 셀러(하위사업자) 사업자번호 | |
| 거래금액 | N | 10 | 거래구분에 따른 해당 Transaction 금액 | |
| 하위사업자 매출액 | N | 15 | 하위 사업자의 매출금액 | 하나의 거래(TID) 총금액 ≥ 합계 |
| 결과코드 | A | 4 | 처리 결과 코드 | 0000: 정상. 1xxx: PG사 실패, 2xxx: VAN/카드사 실패 |
| 영중소등급 | A | 2 | 하위 사업자 등급 | 00:영세 / 01:중소1 / 02:중소2 / 03:중소3 / 04:일반 (오류/실패 시 빈값) |
| 차액 수수료율 | AN | 5 | 소수점 둘째자리까지. 일반 등급은 0.00 | |
| 차액정산 금액 | N | 15 | 차액정산율에 따른 금액. 일반 등급은 000000000000000 | |
| 차액정산 예정일 | YYYYMMDD | 8 | 차액정산 입금 예정일. 일반 등급은 99999999 | |
| 공백 | AN | 42 | 예약 필드 | SPACE |
| 항목 | 형식 | 길이 | 설명 | 비고 |
|---|---|---|---|---|
| 레코드구분 | A | 2 | TR로 고정 | |
| 파일전체라인수 | N | 8 | 해당 파일 내 전체 라인수 (데이터부 + Trailer부) | |
| 승인거래건수 | N | 8 | 승인/취소구분 0(정상)인 거래 총건수 | |
| 취소거래건수 | N | 8 | 승인/취소구분 1(취소)인 거래 총건수 | |
| 총 거래금액 부호 | A | 1 | 총거래금액 부호 | 양수: 0 / 음수: 1 |
| 총 거래금액 | N | 15 | 승인거래금액 − 취소거래금액 | |
| 총 차액정산금액 | N | 15 | 데이터부의 차액정산 금액 총 합계 | |
| 공백 | AN | 193 | 예약 필드 | SPACE |
차액정산 반송코드
PG사 반송코드 (1xxx)
VAN/카드사 반송코드 (2xxx)
📄 하위몰 정보 등록 전문 규격
차액정산 서비스 이용 전 하위몰 사업자 정보를 등록하는 배치 파일 규격입니다. 레코드 길이: 500byte
| 항목 | 형식 | 길이 | 필수 | 설명 |
|---|---|---|---|---|
| 레코드구분 | AN | 2 | O | DT로 고정 |
| 등록구분 | A | 2 | O | 00: 신규 / 01: 해지 / 02: 변경 |
| MID | AN | 15 | O | 중간표시자 생략 |
| 사업자등록번호 (하위몰) | N | 10 | O | 최종 하위사업자 사업자등록번호 |
| 업종명 (하위몰) | H | 20 | 선택 | 한글 10자 |
| 회사명 (하위몰) | H | 40 | O | 한글 20자 |
| 주소 (하위몰) | H | 100 | 선택 | TEXT |
| 대표자명 (하위몰) | H | 40 | 선택 | TEXT |
| 전화번호 (하위몰) | N | 11 | O | TEXT |
| 이메일 (하위몰) | ANS | 40 | 선택 | 이메일 주소 |
| 웹사이트 URL (하위몰) | ANS | 80 | O | TEXT |
| 공백 | AN | 140 | 선택 | 예약 필드 (SPACE) |
| 항목 | 형식 | 길이 | 필수 | 설명 |
|---|---|---|---|---|
| 레코드구분 | AN | 2 | O | TR로 고정 |
| 총 건수 합계 | N | 10 | O | DATA부 건수 |
| 공백 | AN | 488 | 선택 | 예약 필드 (SPACE) |
| 항목 | 형식 | 길이 | 설명 |
|---|---|---|---|
| 레코드구분 | A | 2 | DT로 고정 |
| 등록구분 | A | 2 | 00: 신규 / 01: 해지 / 02: 변경 |
| MID | A | 15 | |
| 사업자등록번호 (하위몰) | N | 10 | 최종 하위사업자 |
| 카드사 | N | 10 | 카드사 코드 (코드표 참조) |
| 업종명 (하위몰) | HS | 20 | 한글 10자 (특수기호 가능) |
| 회사명 (하위몰) | H | 40 | 한글 20자 |
| 주소 (하위몰) | H | 100 | TEXT |
| 대표자명 (하위몰) | H | 40 | TEXT |
| 전화번호 (하위몰) | N | 11 | TEXT |
| 이메일 (하위몰) | ANS | 40 | 이메일 주소 |
| 웹사이트 URL (하위몰) | ANS | 80 | TEXT |
| 정보등록일 | YYYYMMDD | 8 | 등록 처리 완료 일자 |
| 반송코드 | A | 2 | 00: 정상처리. 반송코드표 참조 |
| 공백 | AN | 120 | 예약 필드 (SPACE) |
| 항목 | 형식 | 길이 | 설명 |
|---|---|---|---|
| 레코드구분 | A | 2 | TR로 고정 |
| 총 건수 합계 | N | 10 | DATA부 건수 |
| 공백 | AN | 488 | 예약 필드 (SPACE) |
하위몰 등록 반송코드
처리 결과 코드
카드사 코드표
Java 샘플 코드
Java 환경에서 KOVAN PG 결제연동에 필요한 유틸리티 클래스입니다. 보안·안정성을 고려하여 운영 환경에서 바로 사용 가능한 수준으로 작성했습니다.
org.apache.httpcomponents:httpclient:4.5.14 |
commons-codec:commons-codec:1.16 |
com.fasterxml.jackson.core:jackson-databind:2.17
Config.java — 환경 설정
운영/개발 환경 전환을 IS_PROD 플래그 하나로 관리합니다. API KEY는 환경변수에서 읽도록 개선하여 소스코드에 직접 노출되지 않습니다.
KOVAN_API_KEY)나 Vault/Secrets Manager를 통해 주입하세요.
package pay;
public class Config {
// ★ 운영/개발 전환 플래그 (true = 운영, false = 개발)
private static final boolean IS_PROD = false;
// 상점 ID
public static final String MID = IS_PROD
? System.getenv("KOVAN_MID") // 운영: 환경변수
: "M20200203113418"; // 개발: 테스트 MID
// API KEY — 절대 소스에 하드코딩 금지, 환경변수로 주입
public static final String API_KEY = IS_PROD
? System.getenv("KOVAN_API_KEY") // 운영: 환경변수
: "796963983a56e1a28cf62ad564851ef2"; // 개발: 테스트 키
// PG 도메인
public static final String PG_DOMAIN = IS_PROD
? "https://epay.kovanpay.com"
: "https://dev-epay.kovanpay.com";
// API 엔드포인트
public static final String URL_CANCEL = PG_DOMAIN + "/webpay/cancel.pay";
public static final String URL_INQUIRY = PG_DOMAIN + "/webpay/getTransInfo.pay";
public static final String URL_CASHBILL_APPROVE = "https://ema.kovanpay.com/cashbill/v1/approval.out";
public static final String URL_CASHBILL_CANCEL = "https://ema.kovanpay.com/cashbill/v1/cancel.out";
// HTTP 타임아웃 (ms)
public static final int CONNECT_TIMEOUT = 5_000; // 연결 타임아웃: 5초
public static final int SOCKET_TIMEOUT = 30_000; // 읽기 타임아웃: 30초
private Config() {}
}
HmacSha256Enc.java — Hash 생성 & 검증
Hash 생성뿐 아니라 PG 응답의 CHECK_HASH 검증 기능을 추가했습니다. 응답 위변조를 반드시 서버에서 확인해야 합니다.
package pay;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
public class HmacSha256Enc {
private static final String ALGORITHM = "HmacSHA256";
/**
* HMAC-SHA256 Base64 해시 생성
*
* 결제요청: orderno + orderdt + ordertm + buyReqamt
* 결제취소: tid + mid + cancelAmt
* 내역조회: tid + mid + cancelAmt
* 현금영수증: orderno + orderdt + ordertm + approveAmt
*
* @param message 해시 대상 문자열
* @param apiKey 32자리 API KEY
* @return Base64 인코딩된 해시값
*/
public static String getHmac(String message, String apiKey) {
if (message == null || apiKey == null) {
throw new IllegalArgumentException("message와 apiKey는 null일 수 없습니다.");
}
try {
Mac mac = Mac.getInstance(ALGORITHM);
SecretKeySpec keySpec = new SecretKeySpec(
apiKey.getBytes(StandardCharsets.UTF_8), ALGORITHM
);
mac.init(keySpec);
byte[] rawHash = mac.doFinal(message.getBytes(StandardCharsets.UTF_8));
return Base64.encodeBase64String(rawHash);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
throw new RuntimeException("해시 생성 실패: " + e.getMessage(), e);
}
}
/**
* PG 응답의 CHECK_HASH 유효성 검증
*
* 결제 승인 응답 검증: RESULT_CODE + TID + ORDERNO
*
* @param resultCode 응답의 RESULT_CODE
* @param tid 응답의 TID
* @param orderNo 응답의 ORDERNO
* @param receivedHash 응답의 CHECK_HASH
* @param apiKey API KEY
* @return true = 정상, false = 위변조 의심
*/
public static boolean verifyResponseHash(
String resultCode, String tid, String orderNo,
String receivedHash, String apiKey) {
if (receivedHash == null || receivedHash.isEmpty()) return false;
String expected = getHmac(resultCode + tid + orderNo, apiKey);
return expected.equals(receivedHash);
}
}
HttpRestClient.java — REST API 호출
CloseableHttpClient로 교체하고, TLS 1.2 강제·타임아웃·리소스 자동 해제·에러 핸들링을 모두 적용했습니다.
package pay;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.logging.Logger;
public class HttpRestClient {
private static final Logger log = Logger.getLogger(HttpRestClient.class.getName());
/**
* PG 서버에 JSON POST 요청
*
* @param url 요청 URL
* @param jsonBody JSON 형식 요청 본문
* @return 응답 JSON 문자열 (실패 시 null)
*/
public static String post(String url, String jsonBody) {
log.info("[PG Request] URL=" + url + " BODY=" + jsonBody);
// 타임아웃 설정
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(Config.CONNECT_TIMEOUT)
.setSocketTimeout(Config.SOCKET_TIMEOUT)
.build();
try {
// TLS 1.2 강제 설정
SSLContext sslContext = SSLContexts.custom().build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext,
new String[]{"TLSv1.2"}, // TLS 1.2 필수
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier() // 인증서 검증 활성화
);
// try-with-resources: 자동 자원 해제
try (CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.setDefaultRequestConfig(requestConfig)
.build()) {
HttpPost request = new HttpPost(url);
request.setHeader("Accept", "application/json");
request.setHeader("Content-Type", "application/json;charset=UTF-8");
request.setEntity(new StringEntity(jsonBody, StandardCharsets.UTF_8));
try (CloseableHttpResponse response = httpClient.execute(request)) {
int statusCode = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
log.info("[PG Response] status=" + statusCode + " body=" + responseBody);
if (statusCode != 200) {
log.warning("[PG Error] HTTP " + statusCode + " - " + responseBody);
return null;
}
return responseBody;
}
}
} catch (IOException e) {
log.severe("[PG IO Error] " + e.getMessage());
return null;
} catch (Exception e) {
log.severe("[PG Unexpected Error] " + e.getMessage());
return null;
}
}
}
ResponseValidator.java — 응답 검증 & 결제취소 예시
실제 쇼핑몰에서 필요한 입력값 검증, 이중결제 방지, 응답 Hash 검증을 통합한 클래스입니다.
package pay;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.logging.Logger;
public class ResponseValidator {
private static final Logger log = Logger.getLogger(ResponseValidator.class.getName());
private static final ObjectMapper mapper = new ObjectMapper();
private static final String SUCCESS_CODE = "EC0000";
// ── 결제취소 요청 예시 ────────────────────────────────────────
public static void cancelPayment(String tid, String cancelAmt, String cancelReason) throws Exception {
String mid = Config.MID;
// 1. 입력값 검증
validateCancelInput(tid, cancelAmt, mid);
// 2. checkHash 생성: tid + mid + cancelAmt
String message = tid + mid + cancelAmt;
String checkHash = HmacSha256Enc.getHmac(message, Config.API_KEY);
// 3. 요청 JSON 구성
String jsonBody = String.format(
"{\"mid\":\"%s\",\"payGroup\":\"GEP\",\"payType\":\"CC\"," +
"\"tid\":\"%s\",\"cancelAmt\":\"%s\"," +
"\"cancelReason\":\"%s\",\"cancelRequester\":\"2\"," +
"\"checkHash\":\"%s\"}",
mid, tid, cancelAmt, cancelReason, checkHash
);
// 4. PG 서버 호출
String responseJson = HttpRestClient.post(Config.URL_CANCEL, jsonBody);
// 5. 응답 처리
if (responseJson == null) {
throw new RuntimeException("PG 서버 응답 없음 (타임아웃 또는 통신 오류)");
}
processResponse(responseJson, tid);
}
// ── 입력값 검증 ───────────────────────────────────────────────
private static void validateCancelInput(String tid, String cancelAmt, String mid) {
if (tid == null || tid.trim().isEmpty()) {
throw new IllegalArgumentException("TID는 필수입니다.");
}
if (cancelAmt == null || !cancelAmt.matches("^[0-9]+$")) {
throw new IllegalArgumentException("취소금액은 숫자만 입력 가능합니다.");
}
if (Integer.parseInt(cancelAmt) <= 0) {
throw new IllegalArgumentException("취소금액은 0보다 커야 합니다.");
}
if (mid == null || mid.trim().isEmpty()) {
throw new IllegalArgumentException("MID는 필수입니다.");
}
}
// ── 응답 처리 & 위변조 검증 ───────────────────────────────────
private static void processResponse(String responseJson, String originalTid) throws Exception {
JsonNode root = mapper.readTree(responseJson);
String resultCode = root.path("RESULT_CODE").asText();
String resultMsg = root.path("RESULT_MSG").asText();
String tid = root.path("TID").asText();
String orderNo = root.path("ORDERNO").asText();
String checkHash = root.path("CHECK_HASH").asText();
// ★ 응답 Hash 검증 (위변조 탐지)
if (!checkHash.isEmpty()) {
boolean isValid = HmacSha256Enc.verifyResponseHash(
resultCode, tid, orderNo, checkHash, Config.API_KEY
);
if (!isValid) {
log.severe("[Security] 응답 Hash 불일치! 위변조 의심 TID=" + tid);
throw new SecurityException("PG 응답 무결성 검증 실패 - 위변조 의심");
}
}
// ★ TID 일치 여부 확인
if (!originalTid.equals(tid)) {
throw new SecurityException("요청 TID와 응답 TID 불일치");
}
if (SUCCESS_CODE.equals(resultCode)) {
log.info("[Cancel OK] TID=" + tid + " cancelAmt=" + root.path("CANCEL_AMT").asText());
// TODO: DB 취소 상태 업데이트
} else {
log.warning("[Cancel FAIL] code=" + resultCode + " msg=" + resultMsg);
throw new RuntimeException("취소 실패: [" + resultCode + "] " + resultMsg);
}
}
public static void main(String[] args) throws Exception {
cancelPayment("210728130414390", "5000", "고객 변심");
}
}
PHP 샘플 코드
보안·안정성을 보완하여 운영 환경에서 바로 사용 가능한 수준으로 개선했습니다. API KEY 서버사이드 처리, 응답 Hash 검증, 이중결제 방지, cURL 타임아웃 등을 모두 적용했습니다.
① API KEY 클라이언트 노출 제거 → 서버 상수로 관리
② 응답 CHECK_HASH 재검증 추가 (위변조 탐지)
③ 이중결제 방지 로직 추가 (orderno 중복 체크)
④ 입력값 서버사이드 검증 추가
⑤ file_get_contents → cURL (타임아웃·에러 처리)
⑥ SSL verify_peer true (운영 환경 인증서 검증)
⑦ 결제 요청/응답 로깅 추가
config.php — 환경 설정
환경변수에서 API KEY를 읽고, 운영/개발 전환을 상수 하나로 관리합니다. 모든 PHP 파일에서 require_once로 포함하세요.
<?php
// ★ 운영/개발 전환 (true = 운영, false = 개발)
define('IS_PROD', false);
// 상점 ID (운영 시 환경변수로 주입)
define('PG_MID', IS_PROD ? getenv('KOVAN_MID') : 'M20200203113418');
// API KEY — 절대 클라이언트에 노출하거나 소스에 하드코딩 금지
define('PG_API_KEY', IS_PROD ? getenv('KOVAN_API_KEY') : '796963983a56e1a28cf62ad564851ef2');
// PG 도메인
define('PG_DOMAIN', IS_PROD
? 'https://epay.kovanpay.com'
: 'https://dev-epay.kovanpay.com');
// API 엔드포인트
define('URL_PAY_PC', PG_DOMAIN . '/paypage/common/mainFrame.pay');
define('URL_PAY_MOBILE', PG_DOMAIN . '/mobilepage/common/mainFrame.pay');
define('URL_CANCEL', PG_DOMAIN . '/webpay/cancel.pay');
define('URL_INQUIRY', PG_DOMAIN . '/webpay/getTransInfo.pay');
// Return URL (가맹점 서버 주소로 변경)
define('RETURN_URL', IS_PROD
? 'https://your-shop.com/pg/simplepay_return.php'
: 'http://localhost/sample_pg_php/simplepay/simplepay_return.php');
// 로그 경로
define('LOG_PATH', __DIR__ . '/logs/pg_' . date('Ymd') . '.log');
// cURL 타임아웃 (초)
define('CURL_CONNECT_TIMEOUT', 5);
define('CURL_TIMEOUT', 30);
PgHelper.php — 공통 유틸리티
Hash 생성/검증, cURL POST, 로깅, 입력값 검증을 한 곳에 모았습니다. 모든 파일에서 재사용합니다.
<?php
require_once __DIR__ . '/config.php';
class PgHelper {
/**
* HMAC-SHA256 Base64 해시 생성
* 결제요청: orderno + orderdt + ordertm + buyReqamt
* 결제취소: tid + mid + cancelAmt
* 현금영수증: orderno + orderdt + ordertm + approveAmt
*/
public static function getHash(string $message): string {
$rawHash = hash_hmac('sha256', $message, PG_API_KEY, true);
return base64_encode($rawHash);
}
/**
* PG 응답의 CHECK_HASH 검증 (위변조 탐지)
* 검증 message: RESULT_CODE + TID + ORDERNO
*/
public static function verifyResponseHash(
string $resultCode,
string $tid,
string $orderNo,
string $receivedHash
): bool {
if (empty($receivedHash)) return false;
$expected = self::getHash($resultCode . $tid . $orderNo);
return hash_equals($expected, $receivedHash); // 타이밍 공격 방지
}
/**
* cURL JSON POST 요청 (타임아웃·SSL 검증 포함)
*/
public static function curlPost(string $url, array $data): ?array {
$jsonBody = json_encode($data, JSON_UNESCAPED_UNICODE);
self::writeLog('REQUEST', $url, $jsonBody);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $jsonBody,
CURLOPT_HTTPHEADER => [
'Accept: application/json',
'Content-Type: application/json;charset=UTF-8',
],
CURLOPT_CONNECTTIMEOUT => CURL_CONNECT_TIMEOUT,
CURLOPT_TIMEOUT => CURL_TIMEOUT,
// ★ 운영: true / 개발: false
CURLOPT_SSL_VERIFYPEER => IS_PROD,
CURLOPT_SSL_VERIFYHOST => IS_PROD ? 2 : 0,
CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2, // TLS 1.2 강제
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
self::writeLog('CURL_ERROR', $url, $error);
return null;
}
if ($httpCode !== 200) {
self::writeLog('HTTP_ERROR', $url, "HTTP {$httpCode}: {$response}");
return null;
}
$decoded = json_decode($response, true);
self::writeLog('RESPONSE', $url, $response);
return $decoded;
}
/**
* 입력값 검증
*/
public static function validateAmount(string $amount, string $fieldName = '금액'): void {
if (!preg_match('/^\d+$/', $amount) || (int)$amount <= 0) {
throw new InvalidArgumentException("{$fieldName}은 양의 정수만 입력 가능합니다.");
}
}
public static function validateRequired(array $params, array $requiredKeys): void {
foreach ($requiredKeys as $key) {
if (empty($params[$key])) {
throw new InvalidArgumentException("필수 항목 누락: {$key}");
}
}
}
/**
* 로그 기록
*/
public static function writeLog(string $type, string $url, string $body): void {
$dir = dirname(LOG_PATH);
if (!is_dir($dir)) mkdir($dir, 0755, true);
$line = sprintf("[%s] [%s] URL=%s BODY=%s\n",
date('Y-m-d H:i:s'), $type, $url, $body);
file_put_contents(LOG_PATH, $line, FILE_APPEND | LOCK_EX);
}
}
simplepay_req.php — 결제요청
API KEY를 클라이언트에 노출하지 않고 서버에서만 Hash를 생성합니다. 페이지 로드 시 서버에서 checkHash를 미리 계산하여 hidden 필드에 삽입합니다.
<?php
require_once __DIR__ . '/config.php';
require_once __DIR__ . '/PgHelper.php';
// ── 주문 정보 생성 (실제로는 DB에서 조회) ─────────────────────
$orderdt = date('Ymd');
$ordertm = date('His');
$orderno = $orderdt . $ordertm . rand(1000, 9999); // 유니크 주문번호
$buyReqamt = '5000'; // 실제: DB에서 가져온 주문금액
// ★ Hash는 서버에서 계산 — API KEY 클라이언트 노출 없음
$checkHash = PgHelper::getHash($orderno . $orderdt . $ordertm . $buyReqamt);
?>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>결제 요청</title>
<script>
var PG_URL_PC = '<?= URL_PAY_PC ?>';
var PG_URL_MOBILE = '<?= URL_PAY_MOBILE ?>';
function goPc() {
openPayWindow(PG_URL_PC, 'pcPop', 815, 600);
}
function goMobile() {
openPayWindow(PG_URL_MOBILE, 'mobilePop', 550, 653);
}
function openPayWindow(url, name, w, h) {
window.name = 'myOpener';
var left = (screen.width - w) / 2;
var top = (screen.height - h) / 2;
var opts = 'menubar=no,toolbar=no,status=no,resizable=no,'
+ 'scrollbars=no,location=no'
+ ',left=' + left + ',top=' + top
+ ',width=' + w + ',height=' + h;
window.open('', name, opts).focus();
var form = document.getElementById('form_payment');
form.action = url;
form.target = name;
form.submit();
}
// 결제그룹별 결제수단 동적 갱신
var PAY_TYPES = {
GEP: [{v:'CC',t:'신용카드'},{v:'BA',t:'계좌이체'},{v:'VA',t:'가상계좌'}],
NVP: [{v:'CC',t:'네이버신용카드'},{v:'VO',t:'네이버포인트'}],
KKP: [{v:'CC',t:'카카오신용카드'},{v:'VO',t:'카카오머니'}]
};
function categoryChange(sel) {
var target = document.getElementById('payType');
target.options.length = 0;
(PAY_TYPES[sel.value] || []).forEach(function(d) {
target.options.add(new Option(d.t, d.v));
});
}
</script>
</head>
<body>
<form id="form_payment" name="form_payment" method="post">
<!-- 상점 정보 -->
<input type="hidden" name="mid" value="<?= htmlspecialchars(PG_MID) ?>" />
<input type="hidden" name="rUrl" value="<?= htmlspecialchars(RETURN_URL) ?>" />
<input type="hidden" name="rMethod" value="POST" />
<!-- 결제수단 -->
<select name="payGroup" onchange="categoryChange(this)">
<option value="GEP">일반결제(GEP)</option>
<option value="NVP">네이버페이(NVP)</option>
<option value="KKP">카카오페이(KKP)</option>
<option value="TOT">통합결제(TOT)</option>
</select>
<select name="payType" id="payType">
<option value="CC">신용카드</option>
</select>
<!-- 상품 정보 -->
<input type="hidden" name="buyItemnm" value="오이비누" />
<input type="hidden" name="buyReqamt" value="<?= htmlspecialchars($buyReqamt) ?>" />
<input type="hidden" name="buyItemcd" value="oiSoap" />
<!-- 구매자 정보 -->
<input type="hidden" name="buyerid" value="gildonghong" />
<input type="hidden" name="buyernm" value="홍길동" />
<input type="hidden" name="buyerEmail" value="gildong2@naver.com" />
<!-- 주문 정보 -->
<input type="hidden" name="orderno" value="<?= htmlspecialchars($orderno) ?>" />
<input type="hidden" name="orderdt" value="<?= htmlspecialchars($orderdt) ?>" />
<input type="hidden" name="ordertm" value="<?= htmlspecialchars($ordertm) ?>" />
<!-- ★ checkHash 서버에서 계산 완료 — API KEY 미노출 -->
<input type="hidden" name="checkHash" value="<?= htmlspecialchars($checkHash) ?>" />
<!-- 예약 필드 -->
<input type="hidden" name="reserved01" value="" />
<input type="hidden" name="reserved02" value="" />
<!-- 모바일 App Scheme (앱 연동 시 필수, 예: myapp://) -->
<input type="hidden" name="returnAppUrl" value="" />
<button type="button" onclick="goPc()">PC 결제</button>
<button type="button" onclick="goMobile()">Mobile 결제</button>
</form>
</body>
</html>
simplepay_return.php — 결제결과 수신
응답 Hash 검증, 이중결제 방지, 입력값 검증을 모두 적용했습니다. 실제 서비스에서는 DB 저장 로직을 추가하세요.
<?php
require_once __DIR__ . '/config.php';
require_once __DIR__ . '/PgHelper.php';
header('Content-Type: text/html; charset=utf-8');
// ── 1. 응답 파라미터 수신 ─────────────────────────────────────
$RESULT_CODE = $_POST['RESULT_CODE'] ?? '';
$RESULT_MSG = $_POST['RESULT_MSG'] ?? '';
$DRESULT_CODE = $_POST['DRESULT_CODE'] ?? '';
$DRESULT_MSG = $_POST['DRESULT_MSG'] ?? '';
$PAY_METHOD = $_POST['PAY_METHOD'] ?? '';
$TID = $_POST['TID'] ?? '';
$ORDERNO = $_POST['ORDERNO'] ?? '';
$CHECK_HASH = $_POST['CHECK_HASH'] ?? '';
$RESERVED01 = $_POST['RESERVED01'] ?? '';
$RESERVED02 = $_POST['RESERVED02'] ?? '';
PgHelper::writeLog('RETURN_RECEIVE', RETURN_URL, json_encode($_POST));
// ── 2. 필수 파라미터 검증 ─────────────────────────────────────
if (empty($TID) || empty($ORDERNO) || empty($RESULT_CODE)) {
PgHelper::writeLog('RETURN_ERROR', '', '필수 파라미터 누락');
die('잘못된 요청입니다.');
}
// ── 3. 결제 성공 처리 ─────────────────────────────────────────
if ($RESULT_CODE === 'EC0000') {
// ★ 3-1. 응답 Hash 검증 (위변조 탐지)
if (!PgHelper::verifyResponseHash($RESULT_CODE, $TID, $ORDERNO, $CHECK_HASH)) {
PgHelper::writeLog('HASH_FAIL', '', "TID={$TID} ORDERNO={$ORDERNO}");
die('[보안 오류] 응답 무결성 검증 실패. 관리자에게 문의하세요.');
}
// ★ 3-2. 이중결제 방지 (DB에서 ORDERNO 중복 확인)
// 실제 구현 시 아래 주석을 해제하고 DB 연동:
// $db = new PDO(/* DSN */);
// $stmt = $db->prepare('SELECT COUNT(*) FROM orders WHERE orderno = ? AND status = "paid"');
// $stmt->execute([$ORDERNO]);
// if ($stmt->fetchColumn() > 0) {
// PgHelper::writeLog('DUPLICATE', '', "ORDERNO={$ORDERNO} TID={$TID}");
// die('이미 처리된 주문입니다.');
// }
// ── 결제수단별 추가 파라미터 수신 ─────────────────────────
if ($PAY_METHOD === 'CC') {
// 신용카드
$APPROVNO = $_POST['APPROVNO'] ?? '';
$APPRODT = $_POST['APPRODT'] ?? '';
$APPROTM = $_POST['APPROTM'] ?? '';
$APPROAMT = $_POST['APPROAMT'] ?? '';
$CARD_NO = $_POST['CARD_NO'] ?? '';
$ISSUE_CODE = $_POST['ISSUE_CODE'] ?? '';
$ISSUE_NAME = $_POST['ISSUE_NAME'] ?? '';
$PURCHASE_CODE = $_POST['PURCHASE_CODE'] ?? '';
$PURCHASE_NAME = $_POST['PURCHASE_NAME'] ?? '';
$NOINT = $_POST['NOINT'] ?? '';
$QUOTA_MONTHS = $_POST['QUOTA_MONTHS'] ?? '';
$CHECKCD = $_POST['CHECKCD'] ?? '';
} elseif ($PAY_METHOD === 'VA') {
// 가상계좌
$TRBEGIN = $_POST['TRBEGIN'] ?? '';
$TREND = $_POST['TREND'] ?? '';
$BUY_REQAMT = $_POST['BUY_REQAMT'] ?? '';
$BANK_CD = $_POST['BANK_CD'] ?? '';
$BANK_NM = $_POST['BANK_NM'] ?? '';
$ACCT_NO = $_POST['ACCT_NO'] ?? '';
$ESCR_FLAG = $_POST['ESCR_FLAG'] ?? '';
} elseif ($PAY_METHOD === 'BA') {
// 계좌이체
$MID = $_POST['MID'] ?? '';
$BANK_CD = $_POST['BANK_CD'] ?? '';
$BANK_NM = $_POST['BANK_NM'] ?? '';
$ACCT_NO = $_POST['ACCT_NO'] ?? '';
}
// ★ 3-3. DB 저장 (실제 구현 시 해제)
// $stmt = $db->prepare(
// 'INSERT INTO orders (orderno, tid, pay_method, amount, status, created_at)
// VALUES (?, ?, ?, ?, "paid", NOW())'
// );
// $stmt->execute([$ORDERNO, $TID, $PAY_METHOD, $APPROAMT ?? $BUY_REQAMT ?? 0]);
PgHelper::writeLog('PAYMENT_OK', '', "TID={$TID} ORDERNO={$ORDERNO} METHOD={$PAY_METHOD}");
} else {
// 결제 실패
PgHelper::writeLog('PAYMENT_FAIL', '', "CODE={$RESULT_CODE} MSG={$RESULT_MSG} TID={$TID}");
}
// XSS 방지를 위한 출력 이스케이프 함수
function h($str): string {
return htmlspecialchars($str ?? '', ENT_QUOTES, 'UTF-8');
}
?>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<title>결제 결과</title>
<script>
document.addEventListener('DOMContentLoaded', function() {
var pm = '<?= h($PAY_METHOD) ?>';
var rc = '<?= h($RESULT_CODE) ?>';
var show = (rc === 'EC0000') ? pm : 'FAIL';
document.getElementById('creditDiv').style.display = (show === 'CC') ? '' : 'none';
document.getElementById('vaDiv').style.display = (show === 'VA') ? '' : 'none';
document.getElementById('baDiv').style.display = (show === 'BA') ? '' : 'none';
});
</script>
</head>
<body>
<h3>공통 응답</h3>
<table>
<tr><td>결과코드(가맹점)</td><td><?= h($RESULT_CODE) ?></td></tr>
<tr><td>결과메시지(가맹점)</td><td><?= h($RESULT_MSG) ?></td></tr>
<tr><td>결과코드(사용자)</td><td><?= h($DRESULT_CODE) ?></td></tr>
<tr><td>결과메시지(사용자)</td><td><?= h($DRESULT_MSG) ?></td></tr>
<tr><td>결제수단</td><td><?= h($PAY_METHOD) ?></td></tr>
<tr><td>거래번호(TID)</td><td><?= h($TID) ?></td></tr>
<tr><td>주문번호</td><td><?= h($ORDERNO) ?></td></tr>
<tr><td>예약필드1</td><td><?= h($RESERVED01) ?></td></tr>
<tr><td>예약필드2</td><td><?= h($RESERVED02) ?></td></tr>
</table>
<div id="creditDiv">
<h3>신용카드 응답</h3>
<table>
<tr><td>승인번호</td><td><?= h($APPROVNO ?? '') ?></td></tr>
<tr><td>승인일자</td><td><?= h($APPRODT ?? '') ?></td></tr>
<tr><td>승인시각</td><td><?= h($APPROTM ?? '') ?></td></tr>
<tr><td>승인금액</td><td><?= h($APPROAMT ?? '') ?></td></tr>
<tr><td>카드번호(마스킹)</td><td><?= h($CARD_NO ?? '') ?></td></tr>
<tr><td>발급사</td><td><?= h(($ISSUE_CODE ?? '') . ' / ' . ($ISSUE_NAME ?? '')) ?></td></tr>
<tr><td>매입사</td><td><?= h(($PURCHASE_CODE ?? '') . ' / ' . ($PURCHASE_NAME ?? '')) ?></td></tr>
<tr><td>무이자여부</td><td><?= h($NOINT ?? '') ?></td></tr>
<tr><td>할부개월수</td><td><?= h($QUOTA_MONTHS ?? '') ?></td></tr>
<tr><td>카드구분(신용N/체크C)</td><td><?= h($CHECKCD ?? '') ?></td></tr>
</table>
</div>
<div id="vaDiv">
<h3>가상계좌 응답</h3>
<table>
<tr><td>입금시작일</td><td><?= h($TRBEGIN ?? '') ?></td></tr>
<tr><td>입금종료일</td><td><?= h($TREND ?? '') ?></td></tr>
<tr><td>결제금액</td><td><?= h($BUY_REQAMT ?? '') ?></td></tr>
<tr><td>은행코드</td><td><?= h($BANK_CD ?? '') ?></td></tr>
<tr><td>은행명</td><td><?= h($BANK_NM ?? '') ?></td></tr>
<tr><td>계좌번호</td><td><?= h($ACCT_NO ?? '') ?></td></tr>
<tr><td>에스크로여부</td><td><?= h($ESCR_FLAG ?? '') ?></td></tr>
</table>
</div>
<div id="baDiv">
<h3>계좌이체 응답</h3>
<table>
<tr><td>상점 ID</td><td><?= h($MID ?? '') ?></td></tr>
<tr><td>은행코드</td><td><?= h($BANK_CD ?? '') ?></td></tr>
<tr><td>은행명</td><td><?= h($BANK_NM ?? '') ?></td></tr>
<tr><td>계좌번호</td><td><?= h($ACCT_NO ?? '') ?></td></tr>
</table>
</div>
</body>
</html>
card_cancel.php — 결제취소 (서버사이드 통합)
취소 요청과 결과 처리를 하나의 파일로 통합했습니다. 입력값 검증, cURL 호출, 에러 처리를 모두 포함합니다.
<?php
require_once __DIR__ . '/config.php';
require_once __DIR__ . '/PgHelper.php';
header('Content-Type: text/html; charset=utf-8');
$result = null;
$error = null;
// XSS 방지
function h($str): string {
return htmlspecialchars($str ?? '', ENT_QUOTES, 'UTF-8');
}
// ── POST 요청 처리 (취소 실행) ────────────────────────────────
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
// 1. 파라미터 수신
$tid = trim($_POST['tid'] ?? '');
$cancelAmt = trim($_POST['cancelAmt'] ?? '');
$payGroup = trim($_POST['payGroup'] ?? 'GEP');
$payType = trim($_POST['payType'] ?? 'CC');
$cancelReason = trim($_POST['cancelReason'] ?? '');
$cancelRequester = trim($_POST['cancelRequester'] ?? '2');
$reserved01 = trim($_POST['reserved01'] ?? '');
$reserved02 = trim($_POST['reserved02'] ?? '');
// 2. 입력값 검증
PgHelper::validateRequired(
['tid' => $tid, 'cancelAmt' => $cancelAmt],
['tid', 'cancelAmt']
);
PgHelper::validateAmount($cancelAmt, '취소금액');
// 3. checkHash 생성: tid + mid + cancelAmt (서버에서만 처리)
$checkHash = PgHelper::getHash($tid . PG_MID . $cancelAmt);
// 4. 요청 파라미터 구성
$postData = [
'mid' => PG_MID,
'payGroup' => $payGroup,
'payType' => $payType,
'tid' => $tid,
'cancelAmt' => $cancelAmt,
'cancelReason' => $cancelReason,
'cancelRequester' => $cancelRequester,
'reserved01' => $reserved01,
'reserved02' => $reserved02,
'checkHash' => $checkHash,
];
// 5. PG 서버 호출
$result = PgHelper::curlPost(URL_CANCEL, $postData);
if ($result === null) {
throw new RuntimeException('PG 서버와 통신에 실패했습니다. 잠시 후 다시 시도해주세요.');
}
// 6. 결과 로깅
$code = $result['RESULT_CODE'] ?? '';
PgHelper::writeLog(
$code === 'EC0000' ? 'CANCEL_OK' : 'CANCEL_FAIL',
URL_CANCEL,
"TID={$tid} CODE={$code}"
);
} catch (InvalidArgumentException $e) {
$error = '입력 오류: ' . $e->getMessage();
} catch (RuntimeException $e) {
$error = $e->getMessage();
}
}
// 결제그룹별 결제수단 목록
$payTypes = [
'GEP' => [['CC','신용카드'],['BA','계좌이체'],['VA','가상계좌']],
'NVP' => [['CC','네이버신용카드'],['VO','네이버포인트']],
'KKP' => [['CC','카카오신용카드'],['VO','카카오머니']],
];
?>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<title>결제취소</title>
<script>
var PAY_TYPES = <?= json_encode($payTypes, JSON_UNESCAPED_UNICODE) ?>;
function categoryChange(sel) {
var target = document.getElementById('payType');
target.options.length = 0;
(PAY_TYPES[sel.value] || []).forEach(function(d) {
target.options.add(new Option(d[1], d[0]));
});
}
</script>
</head>
<body>
<!-- 취소 요청 폼 -->
<?php if (!$result): ?>
<h3>결제취소 요청</h3>
<?php if ($error): ?>
<p style="color:red;"><?= h($error) ?></p>
<?php endif; ?>
<form method="post">
<table>
<tr>
<td>결제수단</td>
<td>
<select name="payGroup" onchange="categoryChange(this)">
<option value="GEP">일반(GEP)</option>
<option value="NVP">네이버페이(NVP)</option>
<option value="KKP">카카오페이(KKP)</option>
</select>
<select name="payType" id="payType">
<option value="CC">신용카드</option>
</select>
</td>
</tr>
<tr>
<td>거래ID (TID)</td>
<td><input type="text" name="tid" required placeholder="승인 시 받은 TID" /></td>
</tr>
<tr>
<td>취소금액 (숫자만)</td>
<td><input type="number" name="cancelAmt" min="1" required /></td>
</tr>
<tr>
<td>취소사유</td>
<td><input type="text" name="cancelReason" /></td>
</tr>
<tr>
<td>취소요청자</td>
<td>
<select name="cancelRequester">
<option value="1">1 - 구매자</option>
<option value="2" selected>2 - 가맹점 관리자</option>
</select>
</td>
</tr>
<tr>
<td>예약필드1</td>
<td><input type="text" name="reserved01" /></td>
</tr>
<tr>
<td>예약필드2</td>
<td><input type="text" name="reserved02" /></td>
</tr>
</table>
<button type="submit">결제취소 요청</button>
</form>
<!-- 취소 결과 표시 -->
<?php else: ?>
<h3>취소 결과</h3>
<?php
$isOk = ($result['RESULT_CODE'] ?? '') === 'EC0000';
?>
<p style="color:<?= $isOk ? 'green' : 'red' ?>; font-weight:bold;">
<?= $isOk ? '✅ 취소 성공' : '❌ 취소 실패' ?>
</p>
<table>
<tr><td>결과코드</td><td><?= h($result['RESULT_CODE'] ?? '') ?></td></tr>
<tr><td>결과메시지</td><td><?= h($result['RESULT_MSG'] ?? '') ?></td></tr>
<tr><td>결제그룹</td><td><?= h($result['PAY_GROUP'] ?? '') ?></td></tr>
<tr><td>결제수단</td><td><?= h($result['PAY_METHOD'] ?? '') ?></td></tr>
<tr><td>거래번호(TID)</td><td><?= h($result['TID'] ?? '') ?></td></tr>
<tr><td>취소금액</td><td><?= h($result['CANCEL_AMT'] ?? '') ?></td></tr>
<tr><td>예약필드1</td><td><?= h($result['RESERVED01'] ?? '') ?></td></tr>
<tr><td>예약필드2</td><td><?= h($result['RESERVED02'] ?? '') ?></td></tr>
</table>
<a href="card_cancel.php">← 다시 취소 요청</a>
<?php endif; ?>
</body>
</html>
연동 데모
KOVAN PG 개발 서버(dev-epay.kovanpay.com)에 실제로 연동하는 데모입니다. 테스트 MID와 API KEY가 미리 설정되어 있으며, 결제창 호출부터 취소·조회까지 전체 플로우를 확인할 수 있습니다.
MID:
M20200203113418 |
API KEY: 796963983a56e1a28cf62ad564851ef2 |
서버: https://dev-epay.kovanpay.com
결제 결과는 이 페이지가 동작 중인 Spring Boot 서버(
)가 직접 수신합니다.
PG 콜백 엔드포인트: /demo/return/{transId}
결제창 호출
아래 파라미터를 설정하고 PC결제창 열기 또는 모바일결제창 열기를 클릭하면 실제 KOVAN 개발 서버의 결제창이 팝업됩니다.
요청 파라미터
Return URL은 서버에서 자동 설정됩니다 (/demo/return/{transId})
생성된 요청 전문
파라미터를 입력하면 전문이 표시됩니다.
📋 결제 결과
@PostMapping("/auth/response.action")
public String pgResponse(HttpServletRequest req) {
String resultCode = req.getParameter("RESULT_CODE");
String tid = req.getParameter("TID");
String orderno = req.getParameter("ORDERNO");
String approAmt = req.getParameter("APPROAMT");
if ("EC0000".equals(resultCode)) {
// 결제 성공 → DB 저장, 주문 처리
}
return "pg/response";
}
<?php
$RESULT_CODE = $_POST['RESULT_CODE'] ?? '';
$TID = $_POST['TID'] ?? '';
$ORDERNO = $_POST['ORDERNO'] ?? '';
$APPROAMT = $_POST['APPROAMT'] ?? '';
if ($RESULT_CODE === 'EC0000') {
// 결제 성공 → DB 저장
}
?>
결제취소
결제창 호출 후 승인된 거래를 취소합니다. 결제 성공 후 TID가 자동으로 입력됩니다.
요청 파라미터
응답 결과
요청 전문
결제내역 조회
TID로 결제내역을 조회합니다. 결제 성공 후 TID가 자동으로 입력됩니다.
요청 파라미터
응답 결과
Hash 생성기
HMAC-SHA256 + Base64 방식으로 checkHash를 직접 생성해볼 수 있습니다.