망보드(MangBoard) 기반 쇼핑몰에 네이버페이 주문형(SDK v2)을 연동하는 실전 가이드입니다.
실제 검수를 통과하며 발생한 이슈와 해결 방법을 포함합니다.
내 웹사이트에서 네이버페이로 결제할 수 있게 해주는 서비스입니다. 네이버 스토어나 구글 쇼핑과는 별개입니다.
flowchart LR
subgraph 내사이트["내 웹사이트 (내가 관리)"]
A["상품 상세 페이지"]
B["장바구니"]
end
subgraph 네이버페이["네이버페이 (결제 처리)"]
C["결제창"]
D["주문/배송 관리"]
end
A -->|"버튼 클릭"| C
B -->|"버튼 클릭"| C
C --> D
style 네이버페이 fill:#03C75A,color:#fff
| 구분 | 네이버페이 주문형 | 네이버 스토어 | 구글 쇼핑 |
|---|---|---|---|
| 역할 | 내 사이트의 결제 수단 | 네이버 쇼핑 플랫폼 입점 | 구글 검색에 상품 카드 노출 |
| 판매 장소 | 내 웹사이트 | 네이버 플랫폼 | 내 웹사이트 |
| 검색 노출 | 쇼핑 탭 미노출 | 네이버 쇼핑 탭 노출 | 구글 쇼핑 탭 노출 |
| 입점 비용 | 무료 | 수수료 (기본 2.5~3%) | 무료 |
네이버페이 주문형은 결제 수단일 뿐 상품 노출 채널이 아닙니다.
flowchart TD
A["1. 네이버페이센터 가맹점 가입"] --> B["2. 인증키 발급
Button KEY / 상점 ID / 인증키"]
B --> C["3. SDK v2 마이그레이션
PHP + JS 수정"]
C --> D["4. 검수모드 설정
use_naver_pay = 3"]
D --> E["5. 테스트 결제"]
E --> F["6. 검수 신청
테스트 계정 + XML URL 제출"]
F --> G{"검수 피드백"}
G -->|"수정 요청"| C
G -->|"승인"| H["7. 운영 전환
use_naver_pay = 2"]
H --> I["✅ 오픈 완료"]
style A fill:#E8F5E9
style I fill:#C8E6C9
| 항목 | 발급처 | 용도 |
|---|---|---|
| Button KEY | 네이버페이센터 | SDK 초기화 |
| 상점 ID (MID) | 네이버페이센터 | 주문등록 API |
| 인증키 (CERTI_KEY) | 네이버페이센터 | 주문등록 API |
| Account ID | 네이버페이센터 > 내 정보 | WCS 애널리틱스 |
경로: 망보드 관리자 → 상점설정 → 네이버 페이 (주문형)
| 설정 항목 | 검수 시 | 운영 시 |
|---|---|---|
| 네이버페이 모드 | 네이버 검수모드(상품내용+장바구니) | 사용함(상품내용+장바구니) |
| Button KEY | 발급받은 값 | 동일 |
| 상점 ID | 발급받은 값 | 동일 |
| 인증키 | 발급받은 값 | 동일 |
| Account ID | 발급받은 값 | 동일 |
flowchart LR
subgraph v1["SDK v1 (기존)"]
A1["별도 PC/모바일 스크립트"]
A2["naver.NaverPayButton.apply()"]
A3["동기 핸들러"]
A4["직접 페이지 이동"]
end
subgraph v2["SDK v2 (변경)"]
B1["통합 SDK (PC/모바일)"]
B2["Npay.order.create()"]
B3["async 핸들러 + Promise"]
B4["{key, merchantId} 반환"]
end
A1 --> B1
A2 --> B2
A3 --> B3
A4 --> B4
| 항목 | SDK v1 | SDK v2 |
|---|---|---|
| SDK URL | //pay.naver.com/customer/js/naverPayButton.js |
https://npay-order.pstatic.net/assets/button/latest/npay.button.js |
| 모바일 | 별도 URL | 통합 |
| 버튼 API | naver.NaverPayButton.apply({...}) |
Npay.order.create({...}) |
| 핸들러 | BUY_BUTTON_HANDLER: buy_nc (동기) |
onBuyClick: async function() (Promise) |
| 반환값 | 없음 (직접 이동) | { key, merchantId } 객체 |
flowchart TD
A["use_naver_pay 값 확인"] --> B{"== 3 ?"}
B -->|"YES (검수모드)"| C["test-pay.naver.com
샌드박스 SDK 로드"]
B -->|"NO (운영)"| D["npay-order.pstatic.net
프로덕션 SDK 로드"]
C --> E["test- 접두사 계정에게만
버튼 노출"]
D --> F["전체 회원에게 버튼 노출"]
검수모드에서는 일반 사용자에게 버튼이 보이지 않습니다.
// SDK v2 버튼 생성
var container_id = 'npay-btn-' + uniqid();
// 컨테이너 div (최소 200px × 150px)
document.write('<div id="' + container_id + '" style="min-width:200px;height:150px;"></div>');
Npay.order.create({
buttonKey: 'BUTTON_KEY',
containerId: container_id,
orderRegistrationVersion: '1.0', // 기존 백엔드 API와 호환
type: 'template',
colorTheme: 'green',
enable: true,
components: {
wishlist: true, // 찜하기
talkTalk: false, // 톡톡
benefitMessage: true, // 혜택 문구
benefitCoachMark: true
},
onBuyClick: async function() {
// 주문등록 API 호출 → 결과 반환
return { key: 'ORDER_ID', merchantId: 'SHOP_ID' };
},
onWishlistClick: async function() {
return { merchantId: 'SHOP_ID', payProductId: 'ITEM_ID' };
}
});
sequenceDiagram
participant User as 사용자
participant SDK as 네이버페이 SDK
participant JS as buy_nc()
participant WP as WP AJAX
participant NP as 네이버페이 API
User->>SDK: 버튼 클릭
SDK->>JS: onBuyClick() 호출
JS->>JS: 상품 옵션 검증
JS->>WP: AJAX POST (주문등록 데이터)
WP->>NP: 주문등록 API 호출
NP-->>WP: ORDER_ID + SHOP_ID
WP-->>JS: JSON 응답
JS-->>SDK: Promise resolve {key, merchantId}
SDK->>NP: 결제창 이동
핵심: 핸들러는 async function이며, 반드시 { key, merchantId }를 반환해야 합니다.
망보드의 mb_urls["commerce_api"] 값이 상대경로("mb_commerce")인데, jQuery.ajax()에 직접 전달하면 404가 발생합니다. 망보드 내장 sendDataRequest()와 동일하게 변환해야 합니다:
var ajaxUrl = mb_urls["commerce_api"];
if (String(ajaxUrl).indexOf('http') !== 0) {
data = data + "&action=" + ajaxUrl + "&admin_page=" + mb_ajax_object.admin_page
+ "&hybrid_app=" + mb_hybrid_app;
ajaxUrl = mb_ajax_object.ajax_url; // → /wp-admin/admin-ajax.php
}
| 항목 | 내용 |
|---|---|
| 엔드포인트 | POST /customer/api/order.nhn |
| 프로토콜 | 쿼리스트링 (application/x-www-form-urlencoded) |
| 테스트 환경 | test-pay.naver.com (검수모드 시) |
필수 파라미터:
| 파라미터 | 설명 |
|---|---|
| SHOP_ID | 상점 ID |
| CERTI_KEY | 인증키 |
| ITEM_ID | 상품 번호 |
| ITEM_NAME | 상품명 |
| ITEM_COUNT | 수량 |
| ITEM_TPRICE | 총금액 (수량 × 단가) |
| ITEM_UPRICE | 단가 |
| SHIPPING_TYPE | PAYED 또는 FREE |
| SHIPPING_PRICE | 배송비 |
| TOTAL_PRICE | 결제 총액 (상품 + 배송비) |
flowchart TD
A["상품 개별 배송비 조회"] --> B{"값이 0?"}
B -->|"YES"| C["전역 배송비 설정 참조
mbw_get_option(shipping_cost)"]
B -->|"NO"| D["상품 개별 배송비 사용"]
C --> E{"주문 금액 ≥ 무료배송 기준?"}
E -->|"YES"| F["SHIPPING_TYPE = FREE
SHIPPING_PRICE = 0"]
E -->|"NO"| G["SHIPPING_TYPE = PAYED
SHIPPING_PRICE = 전역 배송비"]
망보드에서 상품 개별 배송비를 설정하지 않으면 항상 0이 반환됩니다.
0일 때 전역 설정(shipping_cost)으로 fallback하는 로직이 필수입니다.
| 파라미터 | 설명 |
|---|---|
| SHOP_ID | 상점 ID |
| CERTI_KEY | 인증키 |
| ITEM_ID | 상품 번호 |
| ITEM_NAME | 상품명 |
| ITEM_UPRICE | 단가 |
| ITEM_IMAGE | 상품 이미지 URL (https 여야 함) |
| ITEM_THUMB | 썸네일 URL (https 여야 함) |
| ITEM_URL | 상품 페이지 URL |
이미지 URL은 반드시 https를 사용하세요. http로 변환하면 검수에서 반려됩니다.
| 항목 | 내용 |
|---|---|
| URL | https://도메인/?mcp=naver&ITEM_ID=XXX |
| Content-Type | application/xml;charset=UTF-8 |
| 필수 항목 | item@id, name, url, description, image, thumb, price, quantity, category |
flowchart LR
I1["1차
SDK 샌드박스 미사용"] --> I2["2차
AJAX 404 에러"]
I2 --> I3["3차
장바구니 ITEM_ID=0"]
I3 --> I4["4차
장바구니 찜 제거"]
I4 --> I5["5차
이미지 http + NaPm 유실"]
I5 --> I6["✅ 오픈 승인"]
style I6 fill:#C8E6C9
문제: SDK를 프로덕션 URL로만 로드해서 검수모드에서도 실운영 환경으로 호출됨.
해결: use_naver_pay == 3일 때 test-pay.naver.com SDK를 로드하도록 분기.
문제: mb_urls["commerce_api"]가 상대경로("mb_commerce")인데, jQuery.ajax()에 직접 전달하면 /shop/mb_commerce로 해석되어 404.
해결: mb_ajax_object.ajax_url(wp-admin/admin-ajax.php)로 변환하는 로직 추가.
문제: 커스텀 상품(추천 조립 PC)을 장바구니에 추가할 때 product_pid가 0으로 저장됨.
해결:
문제: 네이버페이 검수팀에서 장바구니 내 찜하기 버튼 제거 요청.
해결: mbw_get_naver_pay_button()에 wishlist 파라미터 추가. 장바구니에서는 false 전달.
문제:
해결:
str_replace("https://","http://",...) 제거 → 원본 https 유지문제: 네이버페이 구매 시 배송비가 0원으로 전송됨.
해결: 상품 개별 배송비가 0이면 전역 shipping_cost 설정값으로 fallback.
구매와 찜하기는 반환값이 다릅니다:
flowchart LR
subgraph 구매["onBuyClick (구매)"]
A1["{ key: ORDER_ID }"]
A2["{ merchantId: SHOP_ID }"]
end
subgraph 찜["onWishlistClick (찜)"]
B1["{ merchantId: SHOP_ID }"]
B2["{ payProductId: ITEM_ID }"]
end
A1 -.->|"❌ 공유 안 됨"| B1
A2 -.->|"✅ 공유"| B1
| 핸들러 | 반환값 | 키 이름 |
|---|---|---|
| 구매 | { key, merchantId } |
key = 주문 ID |
| 찜 | { merchantId, payProductId } |
payProductId = 상품 ID |
구매와 동일하게
{ key, merchantId }를 반환하면 SDK가 찜하기를 처리하지 못합니다.
| 항목 | 요구사항 |
|---|---|
| 최소 너비 | 200px |
| 최대 너비 | 1280px |
| 권장 높이 | 150px |
| 색상 테마 | green (기본) 또는 white |
use_naver_pay = 3 (검수모드) 설정Npay.order.create() 적용use_naver_pay = 2 (운영) 변경네이버페이와 별개로, 웹사이트 방문자 유입경로를 분석하는 스크립트입니다:
flowchart TD
A["wp_head"] --> B["wcslog.js 로드"]
B --> C["wcs_add wa = Account ID"]
C --> D["wcs.inflow() 호출
도메인 전달"]
D --> E["wp_footer"]
E --> F["wcs_do() 호출"]
SDK v1/v2와 무관하게 동일하게 동작합니다.
| 항목 | 안내 |
|---|---|
| 동일 계정 사용 가능? | 불가. 별도 신규 가맹점 가입 필요 |
| 기존 인증값 재사용? | 불가. 신규 가입 시 새 인증값 발급 |
| 코드 재사용? | 가능. 동일 마이그레이션 패턴 적용 |
| 망보드가 아닌 경우? | SDK v2 초기화 + async 핸들러 + 주문등록 API만 구현하면 됨 |
| 자료 | URL |
|---|---|
| 네이버페이센터 | https://mkt.naver.com |
| 가맹점 연동 가이드 | 네이버페이센터 > 설정 > 연동 가이드 |
| 네이버 스토어 센터 | https://sell.store.naver.com |
| Google Merchant Center | https://merchants.google.com |
| 이전 | KG 이니시스 관련 기록 | 김재석 | 2026-04-28 |
|---|---|---|---|
| 다음 | 범용 마우스 매크로 프로그램 소개 | 웰컴스 매니저 | 2026-03-25 |