Payvit 개발자 가이드 v1.0

온라인 VAN 결제 시스템 — 카드 단말기 수수료 그대로, 온라인 결제로

도메인: https://api.getpayvit.com

🏪 ONLINE VAN PAYMENT

PG 마진 없는 카드사 직접 가맹등록
법정 우대수수료 그대로 적용

Payvit 가맹점은 PG 의 하위가맹점이 아니라 카드사와 직접 계약된 VAN 가맹점으로 등록됩니다. 결제금은 카드사에서 가맹점 통장으로 직접 정산되며, 여신전문금융업법상 법정 우대수수료가 그대로 적용되어 온라인 결제도 카드 단말기 수수료로 받을 수 있습니다.

카드 종류 (영세가맹점 기준) Payvit 일반 PG (토스 / 이니시스 등) 격차
체크카드 0.15% 3.2 ~ 5.5% 최대 약 32배
신용카드 0.40% 3.2 ~ 5.5% 약 8 ~ 14배
간편결제 (카카오/네이버페이) 0.15%~ 3.9 ~ 6.5% 최대 약 43배
  • 카드사 → 가맹점 통장 직접 정산 (PG 마진 없음, 영업일 D+1~5 카드사별 상이)
  • 사업자등록증 1장으로 기존 카드 가맹번호 자동 연결 (신규 등록·심사 X)
  • 가입비 22만원 (1회), 그 외 월 사용료·이체수수료·API 호출비 0원
  • 월 매출 3천만원 → 연 약 1,341만원 수수료 절약 (체크 50% / 신용 50%, PG 평균 4% 비교)

시작하기

사전 준비

Payvit 은 이미 보유한 카드사 가맹번호를 그대로 온라인 결제에 연결합니다. 신규 가맹등록·신용심사 단계가 없으므로 사업자등록증 1장으로 분 단위 시작 가능합니다.

단계설명담당
1가맹점 신청 폼 작성 (사업자등록증 업로드, 5분)가맹점
2기존 카드사 가맹번호 자동 매칭 + 간편결제 하위가맹점 등록 (1분)Payvit (자동)
3가맹점 ID + API Key 발급Payvit (자동)
4가입비 22만원 (1회, 부가세 별도) 결제가맹점
5API Key 로 연동 개발 시작가맹점 개발자
비용 안내: 가입비 22만원 (1회, 부가세 별도) 외 월 사용료·이체수수료·API 호출비는 발생하지 않습니다. 결제 수수료는 카드사가 가맹점에 직접 적용하는 법정 우대수수료 (영세 체크 0.15% / 신용 0.40%) 그대로.

10분 퀵스타트

Step 1. 결제 생성 API를 호출하여 결제 링크를 받습니다.

cURL
curl -X POST https://api.getpayvit.com/api/payment/create \
  -H "Content-Type: application/json" \
  -H "X-API-Key: {발급받은 API Key}" \
  -d '{
    "merchantId": "{가맹점 ID}",
    "orderId": "ORDER-001",
    "productName": "테스트 상품",
    "price": 1000
  }'

Step 2. 응답의 paymentLink를 고객에게 전달합니다.

Response (JSON)
{
  "resultCode": "00",
  "data": {
    "paymentId": "enc_abc123...",
    "paymentLink": "https://api.getpayvit.com/pay/enc_abc123...",
    "merchantId": "my-store",
    "merchantNm": "내 가게",
    "price": "1000"
  }
}
paymentLink를 문자, 카카오톡, 앱 푸시 등으로 고객에게 전달하세요. 고객이 클릭하면 결제창이 자동으로 표시됩니다.

Step 3. 결제 완료 시 가맹점 webhookUrl로 결과가 자동 전달됩니다.

Webhook Payload (Payvit → 가맹점)
{
  "paymentId": "enc_abc123...",
  "orderId": "ORDER-001",
  "merchantId": "my-store",
  "payStatus": "20",
  "price": 1000,
  "approvalNum": "12345678",
  "approvalTime": "20260410173025",
  "paymentCompCode": "KKP2"
}

AI / 기계 판독 스펙

ChatGPT, Claude, Gemini, Cursor 등 AI 코드 생성 도구에 아래 두 파일을 첨부하면 Payvit 연동 코드를 자동으로 생성할 수 있습니다.

파일용도대상
/openapi.yaml OpenAPI 3.1 스펙 — 모든 endpoint / request / response schema 정의 AI / Postman / Swagger UI / OpenAPI Generator (SDK 자동 생성)
/llms.txt LLM 친화 요약 (llmstxt.org 표준) — 핵심 endpoint + 문서 링크 1페이지 AI 챗봇이 빠르게 컨텍스트 파악할 때 첫 진입점

활용 예시

ChatGPT / Claude 프롬프트 예시
다음 OpenAPI 스펙을 참고해서 Payvit 결제 연동 코드를 Node.js + Express 로 작성해줘:
https://api.getpayvit.com/openapi.yaml

요구사항:
- POST /api/payment/create 호출하여 paymentLink 발급
- /webhook endpoint 에서 결제 완료 수신 (HTTP 200 + {"resultCode":"OK"} 응답)
- extraData 에 내부 주문번호 JSON 으로 넣고 webhook 에서 그대로 매칭
SDK 자동 생성 (OpenAPI Generator)
# TypeScript SDK 자동 생성
npx @openapitools/openapi-generator-cli generate \
  -i https://api.getpayvit.com/openapi.yaml \
  -g typescript-fetch \
  -o ./payvit-sdk

# Python SDK 자동 생성
npx @openapitools/openapi-generator-cli generate \
  -i https://api.getpayvit.com/openapi.yaml \
  -g python \
  -o ./payvit-sdk-python
왜 두 파일을 따로 두나요?
openapi.yaml 은 endpoint 한 줄까지 기계가 정확히 읽어낼 수 있는 스펙이고, llms.txt 는 AI 가 첫 1초에 "이 서비스가 뭐 하는 거고 어디에 뭐가 있다" 를 파악하는 네비게이션입니다. AI 챗봇은 먼저 llms.txt 로 전체 그림을 잡고, 구체 endpoint 가 필요해지면 openapi.yaml 을 fetch 해서 정확한 schema 를 사용합니다.

인증

모든 API 요청에 X-API-Key 헤더가 필수입니다.

Header
X-API-Key: {발급받은 API Key}
인증 모드설명접근 범위
MERCHANT가맹점별 API Key본인 가맹점 데이터만
ADMIN글로벌 관리자 Key전체 가맹점 데이터
API Key 보안: API Key는 서버 사이드에서만 사용하세요. 클라이언트(브라우저/앱)에 노출하면 안 됩니다.

결제 흐름

1
결제 생성
POST /api/payment/create 호출 → paymentLink 반환
가맹점 서버Payvit
2
결제 링크 전달
paymentLink를 고객에게 전달 (문자, 카카오톡, 앱 푸시 등)
가맹점고객
3
결제창 진입 + 결제수단 선택
고객이 링크 클릭 → Payvit 결제창 표시 → 카드/간편결제 선택 + 약관 동의
고객Payvit 결제창
4
결제앱 인증 + 승인
결제앱(카카오/신한 등) 실행 → 인증 → Payvit이 NICE에 자동 승인 요청
고객PayvitNICE
5
웹훅 전달 (결제 결과)
Payvit → 가맹점 webhookUrl로 결제 결과 자동 POST (비동기)
Payvit가맹점 서버
6
결제 완료 + 영수증
고객에게 결제 완료 페이지 표시 (승인번호, 카드사, 금액 등)
Payvit고객

결제 상태 코드

코드상태설명
00대기결제 생성됨, 고객 미진입
10인증완료결제앱 인증 완료, 승인 대기
20승인완료결제 성공 (최종)
30취소결제 취소/환불 완료 (최종)
99실패인증/승인 실패 (최종)

지원 결제수단

분류코드이름
간편결제KKP2카카오페이
간편결제NAVER네이버페이 (등록 즉시 결제 가능. NaverPay 측 완전 반영은 D+2일 권고 — 그 전엔 네이버플레이스 미노출 + 프로모션 미적용)
카드SHINHAN신한카드
카드SAMSUNG삼성카드
카드HYUNDAI현대카드
카드HANA하나카드
카드KBPAYKB국민카드
카드WOORI우리카드
카드BCBC카드

통합 가맹점 등록

프랜차이즈/플랫폼에서 업체 등록 시 1회 호출로 가맹점 + NiceVAN + NaverPay까지 완료합니다. ADMIN Key 필수.

POST /api/merchant/register-full
Content-Type: multipart/form-data
X-API-Key: {ADMIN API Key}

Request (multipart/form-data)

필드타입필수설명
merchantIdString필수가맹점 ID (예: stb-gangnam)
merchantNmString필수업체명
bizNoString필수사업자번호 10자 (하이픈 허용)
bizTypeString선택사업자 유형 (AN=개인, CN=법인). 기본 AN
ownerNmString필수대표자명 (사업자등록증 상 첫 번째 기재 대표자 1명)
ownerBirthString필수대표자 개인 생년월일 YYYYMMDD(8자) 또는 YYMMDD(6자). 법인도 대표이사 생년월일 — 법인번호 X
corpRegNoString법인 필수법인등록번호 13자 (bizType=CN 일 때 필수, 하이픈 허용)
ownerPhoneString필수대표자 연락처 (하이픈 허용)
addrString필수사업장 주소
addrDetailString필수상세주소 (층/호/건물명). 최소 2글자. placeholder 차단
zipnoString선택우편번호
emailString선택이메일
webhookUrlString선택웹훅 URL (미입력 시 그룹 기본값)
merchantGroupIdString선택소속 그룹 ID
contractFileFile필수사업자등록증 (PDF/JPG/PNG)
⚠️ 법인사업자 주의
ownerBirth 는 개인/법인 공통 대표자 개인 생년월일 필드입니다. 법인이어도 대표이사 본인의 생년월일(8자 YYYYMMDD)을 넣어주세요. 법인등록번호(13자리)는 반드시 별도 corpRegNo 필드로 분리 전송해야 합니다. 혼동 시 NICE 측 DB 제약으로 ORA-12899 / CONT_0012 에러가 발생하며, Payvit 서버는 validation error(98)로 즉시 차단합니다.

사업자유형 키 검증 (오등록 방지, register-full·/{id}/register 공통) — 법인이 개인으로 잘못 등록되지 않도록 다음을 98명시적 거부합니다 (조용히 무시 X): ① 사업자유형은 반드시 bizType(AN/CN)로 — 미지원 키 businessType은 거부. ② corpRegNo를 보냈는데 bizTypeCN이 아니면 거부.
👥 공동대표 가맹점
사업자등록증에 공동대표(2인 이상)가 기재되어 있어도 NICE API 의 ownerNm / ownerBirth단일값 필드입니다. 사업자등록증 상 첫 번째 기재 대표자 1명만 입력하면 됩니다. NICE 측에서 사업자등록증 파일과 별도 검증하지 않으므로 심사 통과에 문제 없습니다 (2026-04-16 NICE 정보개발실 안내).

Response (전체 성공)

JSON
{
  "resultCode": "00",
  "data": {
    "merchantId": "stb-gangnam",
    "apiKey": "a1b2c3d4e5f6...",
    "catId": "6126530",
    "mid": "NICE-MID-001",
    "naverMerchantId": "LINKPstbgangnam",
    "nicevanStatus": "2",
    "steps": {
      "merchant":  { "success": true,  "message": "가맹점 등록 완료" },
      "catId":     { "success": true,  "message": "CAT-ID 할당 완료: 6126530" },
      "contract":  { "success": true,  "message": "계약서 등록 완료" },
      "affInfo":   { "success": true,  "message": "가맹점번호 조회 완료" },
      "nicevan":   { "success": true,  "message": "NiceVAN 등록 완료 (MID: NICE-MID-001)" },
      "naverPay":  { "success": true,  "message": "NaverPay 등록 완료: LINKPstbgangnam" }
    }
  }
}

Response (부분 실패 — 계약서 실패 시)

JSON
{
  "resultCode": "00",
  "data": {
    "merchantId": "stb-gangnam",
    "apiKey": "a1b2c3d4e5f6...",
    "catId": "6126530",
    "mid": "",
    "naverMerchantId": "",
    "nicevanStatus": "0",
    "steps": {
      "merchant":  { "success": true,  "message": "가맹점 등록 완료" },
      "catId":     { "success": true,  "message": "CAT-ID 할당 완료: 6126530" },
      "contract":  { "success": false, "message": "CONT_9999: 파일 형식 오류" },
      "affInfo":   { "success": false, "message": "미실행 (계약서 등록 실패)" },
      "nicevan":   { "success": false, "message": "미실행 (계약서 등록 실패)" },
      "naverPay":  { "success": false, "message": "미실행 (계약서 등록 실패)" }
    }
  }
}

steps 항목

단계key설명
1merchant가맹점 DB 등록 + API Key 발급
2catIdNiceVAN용 CAT-ID 자동 할당
3contractNiceVAN 사업자등록증 업로드
4affInfoNiceVAN 카드사 가맹점번호 조회
5nicevanNiceVAN 가맹점 자동 등록 (MID 발급)
6naverPayNaverPay 하위가맹점 등록
부분 실패해도 resultCode: "00"입니다 (가맹점 DB 등록은 성공). stepssuccess 필드로 각 단계를 개별 확인하세요. 실패 시 admin에서 수동 재시도 가능합니다.

nicevanStatus (등록 후 결제 가능 시점)

상태결제 가능
0미등록 (NiceVAN 단계 실패)X
2등록완료 (BIZ_0000 응답으로 자동 전환, 즉시 결제 가능)O

1 값(레거시 "심사대기")은 더 이상 자동 부여되지 않습니다. 카드 가맹등록 성공 응답 = 즉시 결제 가능.

register-full 의 카드 가맹등록(nicevan) 단계가 성공하면 즉시 카드 결제가 가능합니다 (별도 심사·전환 단계 없음, nicevanStatus="2" 자동 전환). 단, NaverPay 는 영업일 기준 익일부터 정상 사용 가능합니다 (반영 전에는 네이버플레이스 미노출·NaverPay 프로모션 미적용 — 카드 결제에는 영향 없음).

부분 실패 시 개별 재시도

register-full에서 NiceVAN이나 NaverPay가 실패해도 가맹점 + API Key는 발급된 상태입니다. 실패한 단계만 별도 API로 재시도할 수 있습니다.

실패 단계재시도 API설명
contract / affInfo / nicevan POST /api/merchant/{id}/register NiceVAN 3단계 전체 재시도 (multipart, 사업자등록증 재첨부)
naverPay만 실패 POST /api/merchant/{id}/register-naver NaverPay만 단독 재시도 (JSON, MID 발급 전제)

/{id}/register 전송 필드 (multipart)

register-full동일한 camelCase 규약을 사용합니다.

필드필수설명
contractFile필수사업자등록증 (PDF/JPG/PNG)
bizNo필수사업자번호 (하이픈 허용)
merchantNm필수업체명
ownerNm필수대표자명
ownerBirth필수대표자 생년월일 (YYYYMMDD 또는 YYMMDD)
ownerPhone필수대표자 연락처
addr필수사업장 주소 (도로명+번지)
addrDetail필수상세주소 (층/호/건물명). 최소 2글자. placeholder 차단
bizType선택사업자 유형 (AN=개인, CN=법인). 기본 AN
corpRegNo법인 필수법인등록번호 13자 (bizType=CN 일 때)

※ 이전 snake_case 규약(biz_no / biz_nm / owner_nm / addr_detail …)은 폐지되었습니다. camelCase 로 전송하세요. (상호명은 biz_nmmerchantNm)

NiceVAN 재시도는 계약서 등록부터 3단계를 처음부터 다시 실행합니다 (중간 이어하기 불가). 이미 할당된 CAT-ID는 재사용됩니다. 모든 재시도 API는 ADMIN Key 필수입니다.

결제 생성

POST /api/payment/create
Content-Type: application/json
X-API-Key: {API Key}

Request Body

필드타입필수설명
merchantIdString필수가맹점 ID
orderIdString필수가맹점 주문번호 (고유값 권장)
productNameString필수결제 품목명
priceInteger필수결제 금액 (원)
extraDataString선택추가 데이터 (JSON 권장)
returnUrlString선택결제 완료 화면 [확인] 버튼이 이동할 주소 (http/https, 500자 이내). 앱 WebView 복귀용
cancelUrlString선택결제 실패 화면 [돌아가기] 버튼이 이동할 주소 (http/https, 500자 이내)

결제 후 앱 복귀 (returnUrl / cancelUrl)

앱(WebView) 안에서 결제창을 열면 완료 화면의 "창 닫기"가 동작하지 않습니다. WebView 에는 브라우저 탭 개념이 없기 때문입니다. 결제 생성 시 복귀 주소를 함께 보내면 완료 화면의 [확인] 버튼(영수증 화면의 [닫기] 포함)이 해당 주소로 이동합니다.

복귀 주소 지정
{
  "merchantId": "biz-gangnam",
  "orderId": "ORD-2026-0412-001",
  "productName": "PT 10회권",
  "price": 500000,
  "returnUrl": "https://example.com/orders",
  "cancelUrl": "https://example.com/orders/failed"
}
설정화면 동작
returnUrl 지정결제 완료 화면 [확인] → returnUrl 로 이동
cancelUrl 지정결제 실패 화면에 [돌아가기] 버튼 추가 → cancelUrl 로 이동
미지정기존 동작 그대로 (완료 화면 유지 + 창 닫기 시도)

자동 이동은 하지 않습니다. 완료 화면의 영수증 확인, 실패 화면의 [다시 결제하기] 동선을 남겨두기 위해 사용자가 버튼을 눌렀을 때만 이동합니다.

이동 시 아래 쿼리 파라미터가 자동으로 붙습니다.

복귀 주소 예시
https://example.com/orders?paymentId=enc_abc123&orderId=ORD-2026-0412-001&status=paid

// status: paid(완료) / cancelled(취소) / failed(실패)
status 쿼리 값은 사용자가 주소창에서 위조할 수 있습니다. 화면 전환 용도로만 사용하고, 결제 확정 판단은 반드시 웹훅 또는 결제 조회 API 로 하세요.

제약: http / https 만 허용됩니다 (앱 커스텀 scheme myapp:// 불가). 500자 이내이며, 위반 시 결제 생성이 resultCode: "98" 로 거부됩니다.

returnUrl 을 쓰지 않고 URL 패턴 감지로 처리해도 됩니다. 결과 화면 주소는 고정입니다 — /pay/{paymentId}/complete, /pay/{paymentId}/failed. 또한 완료 화면은 window.opener.postMessage / window.parent.postMessage / JavascriptChannel Payvit 세 경로로 {"type":"payvit:complete","paymentId":"...","orderId":"...","status":"paid"} 를 발송합니다 (수신자가 없으면 아무 일도 일어나지 않습니다).

extraData 활용 (JSON)

JSON으로 넣으면 결제창에 "상세 정보" 카드로 자동 표시됩니다.

extraData 예시
// 학원
{"수강생":"박시훈","반":"심화반","기간":"2026.03.01~03.31"}

// 쇼핑몰
{"배송지":"서울 강남구","수량":"2개","옵션":"블랙 L"}

Response

JSON
{
  "resultCode": "00",
  "data": {
    "paymentId": "enc_abc123...",
    "paymentLink": "https://api.getpayvit.com/pay/enc_abc123...",
    "price": "250000",
    "merchantId": "biz-gangnam",
    "merchantNm": "솔레아스 강남"
  }
}
paymentLink 하나만으로 결제수단 선택 + 결제 + 결과 화면까지 자동 처리됩니다.

결제 조회

GET /api/payment/{paymentId}
X-API-Key: {API Key}
Response
{
  "resultCode": "00",
  "data": {
    "paymentId": "enc_abc123...",
    "merchantId": "biz-gangnam",
    "orderId": "ORD-2026-001",
    "productName": "3월 학원비",
    "price": 250000,
    "payStatus": "20",
    "paymentCompCode": "KKP2",
    "webhookSent": "1",
    "regTs": "2026-04-10T17:30:00",
    "payTs": "2026-04-10T17:32:15"
  }
}

결제 취소 (환불)

승인완료(payStatus=20) 상태의 결제만 취소 가능합니다.

POST /api/payment/{paymentId}/cancel
Content-Type: application/json
X-API-Key: {API Key}
Response (성공)
{
  "resultCode": "00",
  "data": {
    "paymentId": "enc_abc123...",
    "approvalNum": "87654321",
    "approvalTime": "20260410180500"
  }
}
GET /api/payment/search
X-API-Key: {API Key}

?orderId=ORD-001&payStatus=20&startDate=2026-04-01&endDate=2026-04-10&page=1&size=20
파라미터타입필수설명
orderIdString선택주문번호 (부분 검색)
payStatusString선택결제 상태 (00/20/30/97/99)
startDateString선택시작일 (yyyy-MM-dd)
endDateString선택종료일 (yyyy-MM-dd)
pageInteger선택페이지 (기본 1)
sizeInteger선택페이지 크기 (기본 20)

현금영수증 API

가맹점 카드 가맹등록이 완료 (nicevanStatus = "2") 되면 결제 API 와 동일한 API Key 1개로 국세청 현금영수증을 직접 발급/취소할 수 있습니다. 별도 신청 절차나 인증 키 협상 없이 즉시 사용 가능.

발급 종류 (issueType)

코드용도예시
INCOME소득공제 (개인)휴대폰 / 주민번호 / 자진발급
EXPENSE지출증빙 (사업자)사업자번호

식별번호 종류 (cashNoType)

코드길이설명
PHONE10~11휴대폰 번호 (소득공제 가장 일반적)
BIZ_NO10사업자번호 (지출증빙)
RESIDENT13주민등록번호 (소득공제)
SELF_ISSUE고정자진발급 — 01000001234 정확히 일치해야 함 (무기명 발급)

상태 코드 (status)

코드의미가맹점 대응
20발급완료 ✅정상. 영수증 사용 가능
30취소완료정상 취소됨
97확인필요Payvit 운영팀 수동 확인 중 — 가맹점은 추가 발급 시도 X
99실패결제망/국세청 거절. resultMsg 참조

현금영수증 발급

POST /api/cash-receipt
X-API-Key: {API Key}
Content-Type: application/json

{
  "merchantId": "biz-1",
  "issueType":  "INCOME",
  "cashNoType": "PHONE",
  "cashNo":     "01012345678",
  "amount":     10000
}
필드타입필수설명
merchantIdString필수본인 가맹점 ID (가맹점 키 사용 시 본인만 가능)
issueTypeString필수INCOME 또는 EXPENSE
cashNoTypeString필수PHONE / BIZ_NO / RESIDENT / SELF_ISSUE
cashNoString필수식별번호 (하이픈 허용 — 서버에서 자동 제거)
amountLong필수발급 금액 (원, 0 보다 커야 함)

응답 (성공)

200 OK
{
  "resultCode": "00",
  "data": {
    "cashReceiptId": "enc_abc123...",
    "status":   "20",
    "apprNo":   "12345678",
    "apprDate": "260527",
    "seqNo":    "260527XXXXXX",
    "resultCode": "0000"
  }
}

응답의 cashReceiptId 는 취소 시 키로 사용되므로 가맹점 DB 에 반드시 저장하세요. 결제망에서 영구 발급 기록이 보관되지만, 가맹점 측에서도 자체 추적이 필요합니다.

중복 발급 방지: 같은 merchantId + cashNo + amount30초 이내 발급된 건이 있으면 거절됩니다. 의도된 중복 발급은 30초 이상 간격 또는 금액 변경 필요.

현금영수증 취소

status = "20" (발급완료) 인 건만 취소 가능합니다. 부분 취소는 지원하지 않으며 전액 취소만 가능.

POST /api/cash-receipt/{cashReceiptId}/cancel
X-API-Key: {API Key}
Content-Type: application/json

{
  "reason": "고객 환불 요청"
}

응답 (성공)

200 OK
{
  "resultCode": "00",
  "data": {
    "cashReceiptId": "enc_abc123...",
    "status":       "30",
    "cancelApprNo": "98765432",
    "cancelSeqNo":  "260527XXXXXX"
  }
}

현금영수증 단건 조회

GET /api/cash-receipt/{cashReceiptId}
X-API-Key: {API Key}

응답의 cashNo 는 항상 마스킹되어 반환됩니다 (예: 010****5678). 원본 식별번호가 필요하면 가맹점 자체 DB 에 별도 저장하세요 — Payvit 응답으로는 다시 받을 수 없습니다.

GET /api/cash-receipt/search
X-API-Key: {API Key}

?startDate=2026-05-01&endDate=2026-05-27&status=20&page=1&size=20
파라미터타입필수설명
merchantIdString선택가맹점 ID (ADMIN 전용 — 가맹점 키 호출 시 본인 ID 강제 적용)
startDateString선택시작일 (yyyy-MM-dd)
endDateString선택종료일 (yyyy-MM-dd)
statusString선택20 / 30 / 97 / 99
pageInteger선택페이지 (기본 1)
sizeInteger선택페이지 크기 (기본 20, 최대 100)

검색 결과의 cashNo 도 마스킹됩니다. 자세한 사용 예제와 다국어 코드 (Node.js / Python / Java) 는 현금영수증 통합 가이드 (Markdown) 참조.

웹훅

결제 완료 시 Payvit이 가맹점 webhookUrl로 결과를 자동 POST 합니다.

웹훅 수신 구현 (Java)

Java (Spring Boot)
@PostMapping("/api/payment/webhook")
public ResponseEntity<Map<String, Object>> receiveWebhook(
        @RequestBody Map<String, Object> payload) {

    String paymentId = (String) payload.get("paymentId");
    String orderId   = (String) payload.get("orderId");
    int price        = (int) payload.get("price");
    String payStatus = (String) payload.get("payStatus");

    // 주문 상태 업데이트
    orderService.updatePaymentStatus(orderId, payStatus, price);

    // 응답 (HTTP 200 필수)
    Map<String, Object> response = new HashMap<>();
    response.put("resultCode", "OK");
    return ResponseEntity.ok(response);
}

웹훅 수신 구현 (Node.js)

JavaScript (Express)
app.post('/api/payment/webhook', (req, res) => {
    const { paymentId, orderId, price, payStatus } = req.body;

    // 주문 상태 업데이트
    updateOrder(orderId, payStatus, price);

    // 응답 (HTTP 200 필수)
    res.json({ resultCode: 'OK' });
});

웹훅 재시도 정책

항목
최초 발송결제 승인 직후 (비동기)
자동 재시도5분 후 1회
최대 시도2회 (최초 + 재시도 1회)
수동 재발송Payvit 관리자에게 요청
타임아웃connect 5초 / read 10초
웹훅 URL 미설정: 웹훅 URL이 없어도 결제는 정상 동작합니다. Payload는 Payvit DB에 저장되며, 나중에 URL 설정 후 관리자가 재발송할 수 있습니다.

프랜차이즈 웹훅 분기 패턴

다수의 가맹점을 하나의 서버에서 관리하는 경우, 웹훅 URL 1개로 모든 가맹점의 결제를 수신하고 주요 키값으로 분기합니다.

분기 키용도예시
merchantId어느 가맹점의 결제인지"biz-1" = 1번 업체
orderId어느 주문인지"PAY-1-456" = 1번 업체, 456번 결제
extraData결제 생성 시 넣은 커스텀 데이터{"clubNo":"1","studentNo":"789"}
권장: 결제 생성 시 extraData에 내부 식별자를 JSON으로 넣으면, 웹훅에서 그대로 돌려받아 내부 데이터와 매칭할 수 있습니다.

결제창 (호스팅)

Payvit이 호스팅하는 결제 화면입니다. 가맹점은 paymentLink만 고객에게 전달하면 됩니다.

결제창 브랜딩

필드설명기본값
displayName결제창 표시 이름가맹점명
logoUrl상단 로고 URL없음
brandColor강조 색상#e94560

결제창 상태별 페이지

상태표시 페이지
결제 대기결제수단 선택 화면
결제 진행 중로딩 + 폴링 화면
결제 완료영수증 (승인번호, 카드사 등)
결제 실패실패 안내 + 재시도 버튼
이미 결제됨"이미 결제가 완료되었습니다"
청구서 만료"청구서가 만료되었습니다"
결제 없음"결제 정보를 찾을 수 없습니다"

결제창 템플릿

가맹점별로 결제창 디자인을 선택할 수 있습니다.

템플릿스타일비용
default기본 — 카드형, 브랜드 색상무료
modern모던 — 보라 그라데이션, 글래스모피즘무료
minimal미니멀 — 순백, 텍스트 중심무료
custom-{업체}화이트라벨 — 업체 전용 디자인유료
화이트라벨 서비스: 업체 고유의 결제창 디자인이 필요하면 Payvit 관리자에게 문의하세요. 업체 브랜드에 맞는 전용 결제창을 제작해드립니다. (피그마/이미지 시안 제공 필요)

템플릿 설정

Payvit 관리자가 가맹점 설정에서 템플릿을 지정합니다. 가맹점 API에서 직접 변경은 불가합니다.

에러 코드

resultCode설명대응
00성공
98입력 검증 오류필수 파라미터 확인
99비즈니스 오류message 확인
-1시스템 오류재시도 또는 관리자 문의
401인증 실패API Key 확인

주요 에러 메시지

상황message
중복 결제"이미 승인 완료된 주문입니다"
미등록 가맹점"가맹점 정보를 찾을 수 없습니다"
서버 연결 불가"결제 서버와 연결할 수 없습니다"
OTP 만료"결제 인증 시간이 만료되었습니다"

FAQ

Q. 같은 주문번호로 결제를 다시 만들 수 있나요?

이전 결제가 승인완료(20)이면 불가합니다. 취소(30) 또는 실패(99) 후에는 같은 orderId로 재생성 가능합니다.

Q. 결제 링크의 유효기간이 있나요?

가맹점별 billExpireHours 설정에 따릅니다. 미설정이면 무제한.

Q. extraData에 뭘 넣을 수 있나요?

자유 형식 텍스트입니다. JSON으로 넣으면 결제창에 키-값 형태로 자동 표시됩니다.

Q. MERCHANT 키로 다른 가맹점 결제를 조회할 수 있나요?

불가합니다. MERCHANT 키는 본인 가맹점 데이터만 접근 가능합니다.

가맹점 신청

가맹점 등록은 온라인 신청 → 관리자 승인 방식으로 진행됩니다.

신청 방법

1
신청 페이지 접속
독립 가맹점: https://api.getpayvit.com/apply
그룹 소속: https://api.getpayvit.com/apply/{초대코드}
(초대코드는 본사에서 Payvit 관리자에게 발급받아 지점에 공유)
2
정보 입력 + 사업자등록증 첨부 + 신청
가맹점 ID, 가맹점명, 사업자번호, 대표자명, 연락처 + 사업자등록증(PDF/JPG) 첨부
3
관리자 검토 + 승인
Payvit 관리자가 사업자등록증 확인 → 승인 시 가맹점 등록 + API Key + NiceVAN 계약서 자동 처리
4
연동 시작
발급받은 API Key로 결제 API 연동 시작

신청 시 필요 정보

항목필수설명
가맹점 ID필수영문/숫자/하이픈 (예: stb-gangnam)
가맹점명필수지점명 (예: 스포츠트라이브 강남점)
사업자번호필수10자리 숫자
대표자명필수
연락처필수휴대전화 번호
대표자 생년월일선택YYYYMMDD (NiceVAN 등록 시 필요)
사업장 주소선택
이메일선택
웹훅 URL선택나중에 설정 가능
사업자등록증필수PDF / JPG / PNG (NiceVAN 등록에 사용)
그룹 소속 신청: 본사에서 Payvit 관리자에게 초대코드를 발급받아 지점에 공유하세요. 각 지점이 /apply/{초대코드}로 접속하면 그룹이 자동 매칭되고, 승인 시 그룹 설정(템플릿, 채널 등)이 자동 상속됩니다.
승인 시 자동 처리: 관리자가 [승인] 클릭 한 번으로 아래가 모두 자동 실행됩니다.
  1. 가맹점 등록 + API Key 발급
  2. 기본 결제 채널 초기화
  3. NiceVAN 계약서 등록 (S3에서 사업자등록증 자동 전달)
  4. NiceVAN 가맹점번호 조회 + 자동 등록 (CAT-ID/MID 발급)
  5. NaverPay 하위가맹점 자동 등록
NiceVAN 등록에 실패해도 가맹점 등록은 유지되며, admin에서 수동 재시도 가능합니다.
NiceVAN 심사 프로세스: API 호출 성공 = 즉시 결제 가능이 아닙니다.
상태의미결제
미등록 (0)NiceVAN 미실행 또는 어느 단계에서 실패불가
등록완료 (2)BIZ_0000 응답으로 자동 전환 (즉시 결제 가능)가능

1 값(레거시 "심사대기")은 더 이상 자동 부여되지 않습니다. NaverPay 도 등록 즉시 결제 가능 — NaverPay 측 완전 반영(네이버플레이스 노출 + 프로모션 적용)은 D+2일 권고.

연동 체크리스트

Claude Code 연동: 이 가이드를 Claude Code에게 공유하면 연동 코드를 자동으로 생성할 수 있습니다.
Powered by Payvit (하드앤소프트)