시작하기
AI 코딩 도구로 연동하기
AI 코딩 도구에 빌링플러스 연동 규격을 정확히 전달하는 설명문·요청 예시와, 만든 코드를 검토할 확인 항목.
새로 추가된 안내
AI 코딩 도구(코드 작성 도우미)에 빌링플러스 규격을 정확히 알려 주면 연동 코드의 초안을 빠르게 만들 수 있습니다. 이 문서는 도구에 붙여 넣을 설명문, 작업별 요청 예시, 그리고 만든 코드를 검토할 확인 항목을 제공합니다.
AI 도구는 구현 초안을 만드는 보조 수단입니다. 결과 코드는 반드시 사람이 읽고 검토하고, 실제로 실행해 확인해야 합니다. 특히 서명 검증·멱등키·미확정 결제 처리는 틀려도 겉으로는 잘 돌아가는 것처럼 보입니다. 아래 확인 항목으로 하나씩 점검하세요.
시크릿 키·웹훅 시크릿·실제 회원 정보는 AI 도구에 넣지 마세요. 설명문에는 비밀 값이 없습니다. 코드에는 환경변수 이름만 쓰게 하세요.
1. 연동 설명문 — 대화 처음에 붙여 넣기
아래 글을 복사해 AI 도구 대화의 처음에 붙여 넣고, 그다음에 할 일을 요청하세요. 이 문서 사이트의 규격을 줄여 담았습니다. 규격이 바뀌면 이 글도 함께 고칩니다.
연동 설명문 (복사해서 붙여 넣기)
[빌링플러스(BillingPlus) 공개 API 연동 규격 — 이 내용에 없는 항목은 추측하지 말고 나에게 물어볼 것]
1. 기준 주소: https://api.billingplus.co.kr/api/v1
- 요청·응답 UTF-8 JSON. 금액은 원 단위 정수. 시간은 ISO-8601 + 오프셋(+09:00).
- 카드번호를 보내는 API 는 없다. 카드 등록은 등록창(팝업)·가입 링크·빌링플러스 화면으로만 한다.
2. 인증 헤더(모든 요청)
X-BillingPlus-Key: API 키(bpk_live_…)
X-BillingPlus-Timestamp: 유닉스 시간(초). 서버 시각과 ±5분 안
X-BillingPlus-Nonce: 요청마다 새 난수(32자 16진수 권장, 16~128자). 재사용 금지
X-BillingPlus-Signature: hex(HMAC-SHA256(시크릿 키, 서명 문자열)), 소문자 64자
서명 문자열 = METHOD + "\n" + 경로와쿼리 + "\n" + timestamp + "\n" + nonce + "\n" + sha256hex(본문 바이트)
- METHOD 는 대문자. 경로는 도메인을 뺀 /api/v1/… 부터, 쿼리스트링이 있으면 보내는 그대로 포함.
- 본문이 없으면 sha256hex("") = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
- 서명한 본문 바이트를 그대로 보낸다(다시 직렬화하지 않는다).
- 시크릿 키는 환경변수에서 읽는다. 코드·로그·브라우저에 넣지 않는다.
- 인증 실패는 이유와 상관없이 401 UNAUTHORIZED. 연동 확인은 GET /api/v1/ping.
3. 멱등키
- 모든 POST 에 Idempotency-Key 헤더 필수(200자 이하). 없으면 400 IDEMPOTENCY_KEY_REQUIRED.
- 업무 한 건마다 키를 한 번 만들어 저장하고, 재시도할 때는 같은 키를 쓴다(서명·nonce·timestamp 는 새로).
- 같은 키 + 같은 요청 → 처음 응답을 그대로 돌려준다(헤더 Idempotent-Replay: true, 24시간 보관).
- 같은 키가 처리 중 → 409 REQUEST_IN_PROGRESS + Retry-After.
- 같은 키로 다른 본문·경로·메서드 → 422 IDEMPOTENCY_KEY_REUSED.
- 5xx 응답은 저장되지 않으므로 같은 키로 다시 보내도 된다.
- 예외: 등록창 생성(POST /api/v1/register-windows) 재요청은 창의 지금 상태를 돌려준다. 안 열린 창이면 새 window_url
(window_url_reissued: true, 앞 주소 무효), 열린·만료·사용된 창이면 window_url 이 null.
4. 에러와 결제 결과
- 에러 본문: {"error": {"code": "...", "message": "...", "detail": {...}, "request_id": "req_..."}}
응답 헤더 X-Request-Id 에도 request_id 가 있다. 분기는 code 로 한다(message 문구는 바뀔 수 있다).
- code: UNAUTHORIZED(401) FORBIDDEN_IP(403) INVALID_REQUEST(400) IDEMPOTENCY_KEY_REQUIRED(400)
IDEMPOTENCY_KEY_REUSED(422) REQUEST_IN_PROGRESS(409) NOT_FOUND(404) RATE_LIMITED(429)
UNPROCESSABLE(422, detail.reason 이 있을 수 있음) INTERNAL_ERROR(500/503)
- 결제 거절은 에러가 아니다. 200 응답의 payment.status 로 판단한다:
APPROVED 승인 / FAILED 거절(failure_reason 은 빌링플러스 표준 사유) /
UNKNOWN 미확정 — 실패로 처리하지 말고 재승인하지 말 것. 결제 조회나 웹훅으로 확정을 기다린다.
- 429 이면 Retry-After 초만큼 기다린다. 목록은 커서 방식(cursor, limit 기본 20·최대 100,
응답 page.next_cursor · page.has_more).
5. 웹훅(빌링플러스 → 우리 서버, POST, JSON)
- 봉투: {"event_id": "...", "event": "payment.approved", "occurred_at": "...", "data": {...}}
- 헤더: X-BillingPlus-Event, X-BillingPlus-Event-Id, X-BillingPlus-Timestamp, X-BillingPlus-Signature
- 검증: hex(HMAC-SHA256(웹훅 시크릿, timestamp + "." + 받은 본문 바이트)) 를 서명 헤더와
상수 시간 비교한다. 본문은 파싱 전 원문 바이트를 쓴다. timestamp 가 ±5분 밖이면 거부해도 된다.
- 2xx 로 10초 안에 응답한다. 오래 걸리는 처리는 큐로 넘기고 먼저 2xx.
- 순서 보장 없음 · 중복 도착 가능. event_id 로 한 번만 처리한다(재발송돼도 event_id 는 같다).
- 실패하면 최대 8회 다시 보낸다. 카드번호·연락처 값은 웹훅에 없다. 상세 값은 API 로 다시 조회한다.엔드포인트별 요청·응답 필드가 필요하면 OpenAPI 스펙(JSON)을 함께 주세요. 스펙에는 모든 엔드포인트의 스키마와 웹훅 이벤트 예시가 들어 있습니다.
2. 작업별 요청 예시
요청은 할 일 하나로 좁히고, "문서에 없는 항목은 추측하지 말라" 를 함께 적으면 지어낸 필드가 줄어듭니다.
웹훅으로 이용권 갱신
요청 예시
결제 성공 웹훅(payment.approved)을 받아 우리 서비스의 이용권을 갱신하는 코드를 작성해 주세요.
서명 검증과 중복 이벤트 처리(event_id)를 포함하고, 처리는 큐로 넘긴 뒤 먼저 200 을 돌려주세요.
웹훅 본문의 customer_code 로 우리 회원을 찾습니다. 문서에 없는 항목은 추측하지 마세요.서명하는 API 클라이언트
요청 예시
위 규격대로 빌링플러스 API 를 호출하는 클라이언트 함수를 Node.js 로 만들어 주세요.
서명 계산, 요청마다 새 nonce, POST 의 Idempotency-Key 를 호출하는 쪽에서 받도록 하고,
429 와 409 는 Retry-After 만큼 기다렸다 같은 멱등키로 다시 보내게 해 주세요.
GET /api/v1/ping 을 부르는 사용 예도 붙여 주세요. 시크릿은 환경변수에서 읽습니다.수시결제 요청
요청 예시
회원이 동의한 수시결제 동의(charge-consents)로 POST /api/v1/charge-consents/{id}/charges 를 불러
결제하는 서버 함수를 Python 으로 만들어 주세요. 주문마다 멱등키를 한 번 만들어 DB 에 저장하고,
응답의 payment.status 가 APPROVED·FAILED·UNKNOWN 일 때 각각 어떻게 처리할지 나눠 주세요.
UNKNOWN 은 실패로 처리하지 말고 확정을 기다리게 하고, 422 의 detail.reason 은 그대로 기록해 주세요.등록창으로 카드 등록
요청 예시
가맹점 서버가 POST /api/v1/register-windows 로 등록창을 만들고, 브라우저가 window_url 을 팝업으로
여는 코드를 만들어 주세요. 팝업 차단을 피하도록 클릭 즉시 빈 창을 먼저 열고, 완료 메시지는
event.origin 을 확인한 뒤 받으세요. 등록 완료는 서버에서 GET /api/v1/register-windows/{id} 로
다시 확인합니다. 시크릿 키가 브라우저 코드에 들어가지 않게 해 주세요.3. 만든 코드 검토 — 확인 항목
AI 도구가 만든 코드를 합치기 전에 하나씩 확인하세요. 하나라도 아니면 고친 뒤 다시 봅니다.
| 확인할 것 | 왜 |
|---|---|
| 시크릿 키·웹훅 시크릿이 코드에 적혀 있지 않고 환경변수에서 읽는다 | 저장소·로그로 새면 누구나 우리 가맹점으로 결제를 요청할 수 있습니다 |
| 시크릿을 쓰는 코드가 서버에만 있다(브라우저·앱 번들에 없다) | 브라우저 코드는 누구나 열어 볼 수 있습니다 |
서명 경로에 /api/v1 과 쿼리스트링이 들어간다 | 빠지면 쿼리가 있는 요청만 401 이 납니다 |
| 서명한 본문 바이트를 그대로 보낸다(다시 직렬화하지 않는다) | 본문 해시가 달라져 POST 만 401 이 납니다 |
| timestamp 가 초 단위이고 nonce 를 요청마다 새로 만든다 | 재시도에서 같은 nonce 를 쓰면 401 입니다 |
| 멱등키를 업무 한 건마다 한 번 만들어 저장하고, 재시도에 같은 키를 쓴다 | 재시도마다 새 키를 만들면 같은 결제가 두 번 승인될 수 있습니다 |
status: UNKNOWN 을 실패로 처리하지 않고, 자동으로 재승인하지 않는다 | 미확정 결제는 실제로 승인됐을 수 있습니다. 다시 승인하면 이중 결제입니다 |
결제 거절(200 + FAILED)을 예외·서버 오류로 다루지 않는다 | 거절은 정상 결과입니다. failure_reason 으로 안내합니다 |
| 웹훅 서명을 받은 원문 바이트로 계산하고 상수 시간 비교를 쓴다 | 파싱한 뒤 다시 만든 JSON 으로는 서명이 맞지 않습니다 |
웹훅을 event_id 로 한 번만 처리한다 | 같은 이벤트가 두 번 올 수 있습니다 |
| 웹훅에 10초 안에 2xx 로 답한다(오래 걸리는 일은 큐로) | 늦으면 실패로 보고 다시 보냅니다 |
에러 분기를 error.code 로 하고, request_id 를 로그에 남긴다 | 문구는 바뀔 수 있고, 문의할 때 request_id 가 필요합니다 |
| 로그에 시크릿·서명 값·회원 연락처를 남기지 않는다 | 로그는 생각보다 넓게 퍼집니다 |
| 문서에 없는 필드·엔드포인트·코드값을 쓰지 않는다 | AI 도구는 그럴듯한 이름을 지어낼 수 있습니다. 스펙과 대조하세요 |
4. 실행해서 확인하기
- 서명 함수는 검증용 값을 넣어 같은 결과가 나오는지 먼저 봅니다.
- 클라이언트는
GET /api/v1/ping과POST /api/v1/ping(같은 멱등키로 두 번)으로 확인합니다 — 빠른 시작 - 웹훅 수신은 빌링플러스 화면의 연동관리 > 웹훅 설정에서 [테스트 발송]으로 확인하고, 같은 요청을 두 번 보냈을 때 한 번만 처리되는지 봅니다.
- 테스트 전용 키나 테스트 서버는 현재 제공하지 않습니다. 결제가 일어나는 요청은 실제 카드에서 돈이 나갈 수 있으니, 시험할 때는 가맹점이 직접 관리하는 회원·카드와 작은 금액으로 하고 바로 취소하세요.
개발자센터