본문 바로가기
빌링플러스개발자센터
홈 로그인 도입 상담

연동 가이드

홈페이지 가입 링크

홈페이지 '정기결제 가입' 버튼에 거는 가입 링크와 고객사 회원 ID 서명 규칙.

가입 링크는 홈페이지의 '정기결제 가입' 버튼에 거는 고정 주소입니다. 여러 사람이 같은 주소로 들어와 각자 가입합니다. 방문자는 빌링플러스 화면에서 정보 입력 → 휴대폰 문자 인증 → 카드 등록을 마치고, 그 즉시 계약(또는 수시결제 동의)이 만들어집니다. API 호출 없이 주소만 걸어도 동작하고, 로그인한 회원과 연결하려면 가맹점 서버가 서명을 붙입니다.

링크 만들기

빌링플러스 화면의 회원·결제관리 > 가입 링크에서 가맹점 마스터가 만듭니다. 만든 링크의 주소는 …/signup/k3Jx9Q2mTa1b/ 모양이며, /signup/ 다음 부분(k3Jx9Q2mTa1b)이 서명에 쓰는 링크 식별자입니다.

계약 조건 방식

방식조건은 어디서쓰임
조건 하나 (FIXED)링크에 저장한 조건 하나요금제가 하나뿐인 서비스
회원이 요금제 선택 (CHOICES)링크에 저장한 요금제 2~5개 중 방문자가 고름요금제별 버튼은 주소 끝에 ?choice=2(1부터)를 붙여 미리 골라 둡니다.
고객사 서버가 조건 전달 (SIGNED)가맹점 서버가 가입할 때마다 조건을 서명해 주소에 붙임가격이 회원마다 다르거나 가맹점 시스템에서 정해질 때. 서명 없는 가입은 받지 않습니다.

고객사 회원과 연결

가입한 사람이 가맹점 서비스의 어느 회원인지 알아야 이용권을 붙일 수 있습니다. 두 방법이 있습니다.

  • 로그인 없는 가입 — 링크 설정에서 서비스 아이디를 묻게 하면 방문자가 적은 값이 확인되지 않은 값(external_ref_verified: false)으로 전달됩니다. 방문자가 남의 아이디를 적을 수 있으므로 확인 없이 자기 회원과 연결하지 마세요. 이 값은 빌링플러스 회원 정보에 저장되지 않습니다.
  • 로그인한 회원의 가입(권장) — 가맹점 서버가 회원 ID 에 API 시크릿 키로 서명해 주소에 붙입니다. 서명이 맞으면 확인된 값(external_ref_verified: true)으로 전달되고 빌링플러스 회원의 external_ref 에 저장됩니다.

서명 규칙

서명한 주소는 가맹점 서버가 페이지를 그릴 때 만들어 버튼에 넣습니다. 24시간 동안 유효합니다.

쿼리값
ref가맹점 서비스의 회원 ID(100자 이하)
ts서명한 시각, 유닉스 시간(초)
kid서명에 쓴 API 키(bpk_live_…, 공개값). 이 가맹점의 활성 키여야 합니다.
sig아래 서명 문자열의 HMAC-SHA256, 16진수
서명 문자열 — 조건 하나 · 요금제 선택 링크 (3줄)
{링크 식별자}\n{회원ID}\n{ts}
서명 문자열 — 고객사 서버가 조건 전달 링크 (10줄)
{링크 식별자}\n{회원ID}\n{ts}\n{amount}\n{cycle}\n{day}\n{term}\n{first}\n{plan}\n{item}

조건 전달 링크는 아래 일곱 값을 서명에 이어 붙이고 같은 값을 같은 이름의 쿼리로 주소에 싣습니다. 값이 없으면 빈 줄로 두어 언제나 10줄입니다.

쿼리값
amount회차마다 걷을 금액(원, 1 이상 정수)
cycleMONTHLY · QUARTERLY · HALF_YEARLY · YEARLY
day청구일 1~31, 또는 0(가입한 날)
term약정 개월. 비우면 종료일 없는 계약
firstNOW(가입하자마자 첫 결제) · NEXT(다음 청구일부터). 비우면 NEXT
plan요금제 코드(선택). 영문·숫자·_ . - 40자까지. 웹훅에 그대로 돌아옵니다.
item품목명(필수, 100자까지)
Python — 서명한 가입 주소 만들기
import hashlib
import hmac
import os
import time
from urllib.parse import urlencode

API_KEY = os.environ["BILLINGPLUS_API_KEY"]         # kid — 공개값
API_SECRET = os.environ["BILLINGPLUS_API_SECRET"]   # 서명에만 씁니다. 브라우저로 보내지 않습니다
SIGNUP_LINK = "https://…/signup/k3Jx9Q2mTa1b/"      # 가입 링크 화면에서 복사한 주소
LINK_ID = "k3Jx9Q2mTa1b"                            # /signup/ 다음 부분
TERM_KEYS = ("amount", "cycle", "day", "term", "first", "plan", "item")


def signed_signup_url(member_id: str, terms: dict | None = None) -> str:
    """terms 는 '고객사 서버가 조건 전달' 링크일 때만 넘깁니다."""
    ts = str(int(time.time()))
    lines = [LINK_ID, member_id, ts]
    params = {"ref": member_id, "ts": ts, "kid": API_KEY}
    if terms is not None:
        values = ["" if terms.get(k) is None else str(terms[k]) for k in TERM_KEYS]
        lines += values                                  # 늘 7줄 — 없는 값은 빈 줄
        params.update(zip(TERM_KEYS, values))
    params["sig"] = hmac.new(API_SECRET.encode("utf-8"), "\n".join(lines).encode("utf-8"),
                             hashlib.sha256).hexdigest()
    return SIGNUP_LINK + "?" + urlencode(params)          # 주소에 실을 때만 인코딩합니다


# 로그인한 회원의 가입 버튼
url = signed_signup_url("user-1024")

# '고객사 서버가 조건 전달' 링크
url = signed_signup_url("user-1024", {
    "amount": 29900, "cycle": "MONTHLY", "day": 0, "term": None,
    "first": "NEXT", "plan": "basic-monthly", "item": "월 회비",
})

API 요청 서명과 다른 점: 가입 링크는 인코딩하기 전의 값으로 서명하고, 주소에 실을 때만 URL 인코딩합니다(품목명의 한글·공백 등). 값의 앞뒤 공백은 빌링플러스가 지우고 확인하므로 공백 없이 서명하세요.

API 시크릿 키는 서명 계산에만 쓰고 가맹점 서버 밖으로 내보내지 않습니다. 브라우저 스크립트에서 서명하면 안 됩니다.

  • 서명이 틀렸거나 24시간이 지났으면 방문자에게 "링크가 만료되었습니다" 화면이 나옵니다. 서명 없는 가입으로 바꿔 받지 않습니다.
  • 방문자가 주소의 금액을 바꾸면 서명이 맞지 않아 가입 화면이 열리지 않습니다.
  • 서명은 맞는데 값이 규칙에 어긋나면(금액 0, 모르는 주기 등) "가입 조건이 올바르지 않습니다" 화면이 나옵니다. 가맹점 서버의 연동 오류이니 값을 확인하세요.

결과 받기

가입이 끝나면 웹훅 signup.completed 가 갑니다(빌링플러스 화면의 연동관리 > 웹훅 설정에서 수신 주소를 등록). 주요 필드는 다음과 같습니다. 전체 예시는 웹훅 문서에 있습니다.

필드뜻
external_ref · external_ref_verified회원 ID 와 서명으로 확인됐는지. true 일 때만 자기 회원과 바로 연결합니다.
is_new_customer새로 만든 회원인지(같은 휴대폰 번호의 회원이 있으면 그 회원에 계약을 더합니다)
customer_id · customer_code빌링플러스 회원. GET /api/v1/customers/{customer_id} 로 조회합니다.
terms_mode · plan_code링크의 조건 방식과 고른 요금제 코드(없으면 빈 문자열)
billing_modeRECURRING 이면 contract_no · subscription, ON_DEMAND 면 charge_consent 가 채워집니다.

나중에 회원을 찾을 때는 GET /api/v1/customers?external_ref=user-1024(정확히 일치)를 씁니다. 회원 API 로 external_ref 를 직접 넣을 수도 있습니다 — 가맹점 안에서 한 회원에게만 쓸 수 있고, 다른 회원이 쓰는 값이면 400 입니다.

알아 둘 것

  • 휴대폰 문자 인증을 통과한 뒤에만 같은 번호의 회원을 찾습니다. 인증 전에는 가입 여부를 어떤 화면으로도 알리지 않습니다.
  • 같은 링크·같은 조건의 계약이 살아 있는 회원은 카드 입력 전에 멈춥니다(중복 가입 방지). 다른 요금제, 해지 후 재가입은 막지 않습니다.
  • 회원에게 보내는 문자는 가맹점의 발신번호 승인이 끝나야 나갑니다. 승인 전에는 문자 인증을 할 수 없습니다.