계좌 자동이체를 위한 빌링키를 발급받아요. 카드가 아닌 은행 계좌로 정기 결제를 할 때 사용해요.
핵심 요약
- 계좌 빌링키는 카드 빌링키와 달리 발급 요청과 인증 확정이 분리돼요.
- 1단계 응답이
status === 41이면 아직 확정 대기 상태예요. 2단계 publish 호출까지 끝나야 빌링키를 저장해야 해요. - 계좌 정보는 저장하면 안 되고, 발급된
billing_key와 표시용 정보만 저장해야 해요. - 현재 지원 범위가 제한적이므로 운영 전 PG 지원 여부를 먼저 확인해요.
지원 PG사
나이스페이먼츠만 지원해요.
발급 흐름
카드 빌링키와 달리, 계좌 빌링키는 2단계 과정이 필요해요.
| 순서 | 발신 | 수신 | 내용 |
|---|---|---|---|
| ① | 백엔드 | BOOTPAY API | automatic-transfer / 발급 요청 |
| ② | BOOTPAY API | 고객 | ARS / 본인인증 진행 |
| ③ | 고객 | BOOTPAY API | 인증 완료 |
| ④ | BOOTPAY API | 백엔드 | status === 41 / 확정 대기 |
| ⑤ | 백엔드 | BOOTPAY API | publish 호출 |
| ⑥ | BOOTPAY API | 백엔드 | billing_key 발급 완료 |
| ⑦ | 백엔드 | 서비스 DB | billing_key 저장 |
| status | 의미 | 다음 동작 |
|---|---|---|
41 |
ARS/인증 완료, 확정 대기 | 2단계 publish 호출 |
11 |
빌링키 발급 완료 | billing_key 저장 후 사용 |
1단계: 발급 요청
POST
https://api.bootpay.co.kr/v2/request/subscribe/automatic-transferBasic Auth요청 파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
pg |
String | 필수 | PG사 코드 |
order_name |
String | 필수 | 주문명 |
subscription_id |
String | 필수 | 가맹점 고유 구독 번호 |
auth_type |
String | 선택 | 인증 방식. 미입력 시 ARS로 처리해요 |
username |
String | 필수 | 고객 이름 |
bank_name |
String | 필수 | 은행명 |
bank_account |
String | 필수 | 계좌번호 |
identity_no |
String | 필수 | 생년월일 6자리 또는 사업자등록번호 10자리 |
phone |
String | 필수 | 고객 전화번호 |
cash_receipt_type |
String | 선택 | 현금영수증 발행 유형. 지정하면 이후 이 빌링키로 자동이체 결제가 일어날 때마다 현금영수증을 자동 발행해요 |
cash_receipt_identity_no |
String | 선택 | 현금영수증 발행 식별번호. 미입력 시 phone 값을 사용해요 |
price |
Number | 선택 | 결제 금액 |
import { Bootpay } from '@bootpay/backend-js'
Bootpay.setConfiguration({
client_key: '[ Client Key ]',
secret_key: '[ Secret Key ]'
})
try {
const response = await Bootpay.requestSubscribeAutomaticTransferBillingKey({
pg: 'nicepay',
order_name: '자동이체 등록',
subscription_id: 'transfer_' + Date.now(),
auth_type: 'ARS',
username: '홍길동',
bank_name: '국민은행',
bank_account: '12345678901234',
identity_no: '900101',
phone: '01012345678'
})
// status === 41이면 2단계로 진행
console.log(response)
} catch (e) {
console.log(e)
}javascript# Python 서버 SDK에는 자동이체 빌링키 발급 헬퍼가 없어요.
# 이 API는 REST API로 직접 호출해요.pythonuse Bootpay\ServerPhp\BootpayApi;
BootpayApi::setClientKeyConfiguration('CLIENT_KEY', 'SECRET_KEY');
$response = BootpayApi::requestSubscribeAutomaticTransferBillingKey([
'pg' => 'nicepay',
'order_name' => '자동이체 등록',
'subscription_id' => 'transfer_' . time(),
'auth_type' => 'ARS',
'username' => '홍길동',
'bank_name' => '국민은행',
'bank_account' => '12345678901234',
'identity_no' => '900101',
'phone' => '01012345678',
]);
// status === 41이면 2단계로 진행
print_r($response);phpimport kr.co.bootpay.pg.Bootpay;
import kr.co.bootpay.pg.model.request.Subscribe;
Bootpay bootpay = Bootpay.withClientKey("CLIENT_KEY", "SECRET_KEY");
Subscribe transfer = new Subscribe();
transfer.pg = "nicepay";
transfer.orderName = "자동이체 등록";
transfer.subscriptionId = "transfer_" + System.currentTimeMillis();
transfer.authType = "ARS";
transfer.username = "홍길동";
transfer.bankName = "국민은행";
transfer.bankAccount = "12345678901234";
transfer.identityNo = "900101";
transfer.phone = "01012345678";
var response = bootpay.getBillingKeyTransfer(transfer);
// status === 41이면 2단계로 진행
System.out.println(response);java# Ruby 서버 SDK에는 자동이체 빌링키 발급 헬퍼가 없어요.
# 이 API는 REST API로 직접 호출해요.rubyimport "github.com/bootpay/backend-go/v2"
api := bootpay.NewAPIWithClientKey("CLIENT_KEY", "SECRET_KEY", nil, "")
response, err := api.RequestSubscribeAutomaticTransferBillingKey(bootpay.BillingKeyPayload{
Pg: "nicepay",
OrderName: "자동이체 등록",
SubscriptionID: fmt.Sprintf("transfer_%d", time.Now().Unix()),
AuthType: "ARS",
Username: "홍길동",
BankName: "국민은행",
BankAccount: "12345678901234",
IdentityNo: "900101",
Phone: "01012345678",
})
if err != nil {
log.Fatal(err)
}
// status === 41이면 2단계로 진행
fmt.Println(response)gousing Bootpay;
using Bootpay.models;
var bootpay = BootpayApi.WithClientKey("CLIENT_KEY", "SECRET_KEY");
var response = await bootpay.GetBillingKeyTransfer(new Subscribe
{
pg = "nicepay",
orderName = "자동이체 등록",
subscriptionId = $"transfer_{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}",
authType = "ARS",
username = "홍길동",
bankName = "국민은행",
bankAccount = "12345678901234",
identityNo = "900101",
phone = "01012345678"
});
// status === 41이면 2단계로 진행
Console.WriteLine(response);csharp1단계 응답
1단계 응답에는 billing_key가 아직 들어오지 않아요. 인증 확정 대기 상태(status: 41)를 나타내는 요약 정보만 내려와요.
{
"receipt_id": "6261104e1fc19202e6f9420e",
"subscription_id": "transfer_1705289520",
"pg": "나이스페이먼츠",
"method": "계좌자동이체",
"method_symbol": "automatic_transfer_rest",
"method_origin": "계좌자동이체",
"method_origin_symbol": "automatic_transfer_rest",
"requested_at": "2025-01-15T14:31:52+09:00",
"status_locale": "자동결제빌링키발급이전",
"status": 41
}jsonstatus가 41이면 고객이 ARS 인증을 마친 상태예요. 여기서 받은 receipt_id로 2단계 publish를 호출해야 빌링키가 발급돼요.
2단계: 인증 확정 (Publish)
1단계 응답에서 status === 41(ARS 인증 완료)이면 receipt_id를 사용하여 확정 요청을 보내야 해요.
POST
https://api.bootpay.co.kr/v2/request/subscribe/automatic-transfer/publishBasic Auth요청 파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
receipt_id |
String | 필수 | 1단계에서 받은 영수증 ID |
try {
const result = await Bootpay.publishAutomaticTransferBillingKey(
'[ receipt_id ]'
)
// billing_key를 데이터베이스에 저장
console.log(result)
} catch (e) {
console.log(e)
}javascript# Python 서버 SDK에는 자동이체 빌링키 확정 헬퍼가 없어요.
# 이 API는 REST API로 직접 호출해요.python$result = BootpayApi::publishAutomaticTransferBillingKey('[ receipt_id ]');
// billing_key를 데이터베이스에 저장
print_r($result);phpvar result = bootpay.publishBillingKeyTransfer("[ receipt_id ]");
// billing_key를 데이터베이스에 저장
System.out.println(result);java# Ruby 서버 SDK에는 자동이체 빌링키 확정 헬퍼가 없어요.
# 이 API는 REST API로 직접 호출해요.rubyresult, err := api.PublishAutomaticTransferBillingKey("[ receipt_id ]")
if err != nil {
log.Fatal(err)
}
// billing_key를 데이터베이스에 저장
fmt.Println(result)govar result = await bootpay.PublishBillingKeyTransfer("[ receipt_id ]");
// billing_key를 데이터베이스에 저장
Console.WriteLine(result);csharp2단계 응답
2단계 publish가 성공하면 billing_key와 계좌 표시 정보가 함께 내려와요. status가 11이면 발급 완료예요.
{
"receipt_id": "6261104e1fc19202e6f9420e",
"subscription_id": "transfer_1705289520",
"pg": "나이스페이먼츠",
"method": "계좌자동이체",
"method_symbol": "automatic_transfer_rest",
"published_at": "2025-01-15T14:33:10+09:00",
"requested_at": "2025-01-15T14:31:52+09:00",
"status_locale": "빌링키발급완료",
"status": 11,
"billing_key": "615d00f0197c300036b4fef5",
"billing_data": {
"bank_name": "국민은행",
"bank_code": "004",
"bank_account": "1234******1234",
"username": "홍길동"
},
"billing_expire_at": "2099-12-31T23:59:59+09:00"
}json| 파라미터 | 타입 | 설명 |
|---|---|---|
| receipt_id | String | 발급 요청의 영수증 ID |
| subscription_id | String | 요청 시 넣은 가맹점 고유 구독 번호 |
| status | Number | 발급 상태. 11이면 발급 완료 |
| status_locale | String | 발급 상태 한글 |
| billing_key | String | 발급된 빌링키 — 반드시 데이터베이스에 저장 |
| billing_data.bank_name | String | 은행명 |
| billing_data.bank_code | String | 은행코드 3자리 |
| billing_data.bank_account | String | 마스킹된 계좌번호 |
| billing_data.username | String | 예금주명 |
| billing_expire_at | Date | 빌링키 만료일. 계좌 빌링키는 2099-12-31T23:59:59+09:00로 내려와요 |
에러 코드
공통 에러
인증·권한 관련 에러는 에러 코드표를 참고해요.
| 코드 | 메시지 | 대처 방법 |
|---|---|---|
SUBSCRIBE_AT_BLANK_NOT_FOUND (2350) |
은행 코드/은행명이 올바르지 않다 | bank_name을 올바른 은행명으로 입력해요 |
SUBSCRIBE_AT_USERNAME_BLANK (2351) |
은행 예금주명을 입력한다 | username 값을 입력해요 |
SUBSCRIBE_AT_BANK_ACCOUNT_BLANK (2352) |
은행 계좌번호를 입력한다 | bank_account 값을 입력해요 |
SUBSCRIBE_AT_AUTH_TYPE_INVALID (2353) |
인증 방식(auth_type) 값이 올바르지 않거나, 예금주 생년월일/사업자등록번호가 비어있다 | 아래 주의사항을 참고해요 |
SUBSCRIBE_AT_PHONE_BLANK (2354) |
휴대폰 번호를 입력한다 | phone 값을 입력해요 |
SUBSCRIBE_AT_AUTHENTICATE_NOT_FOUND (2355) |
계좌자동이체 동의 인증이 준비된 PG가 아니다 | 이체 동의 인증을 지원하는 PG로 요청해요 |
SUBSCRIBE_AT_LOOKUP_USER_FAILED (2356) |
계좌자동이체 회원 정보 조회 중 오류가 발생했다 | 잠시 후 재시도해요 |
SUBSCRIBE_AT_PUBLISH_INVALID_PG (2358) |
계좌자동이체 발급 승인이 가능한 PG가 아니다 | 계좌자동이체를 지원하는 PG로 요청해요 |
SUBSCRIBE_AT_BANK_CODE_BLANK (2361) |
은행코드가 올바르지 않거나 비어있다 | 올바른 은행코드를 입력해요 |
SUBSCRIBE_PUBLISH_NOT_READY (2303) |
빌링키 발급 대기 상태가 아니다 | 2단계 publish는 1단계 응답이 status: 41일 때만 호출할 수 있어요 |
SUBSCRIBE_ALREADY_PUBLISHED (2319) |
이미 빌링키를 발급받은 진행건이다 | 같은 receipt_id로 publish를 중복 호출한 경우예요. 발급된 빌링키를 그대로 사용해요 |
RC_NOT_AT_SUBSCRIBE (2092) |
계좌 자동이체 요청 등록 건이 아니다 | publish에 넣은 receipt_id가 계좌 자동이체 발급 건인지 확인해요 |
RC_ONLY_REST_API (2058) |
REST API로 요청 가능한 결제 수단이 아니다 | method를 계좌자동이체로 보내야 해요 (미입력 시 기본값도 계좌자동이체예요) |
2353은 두 가지 상황에서 같은 코드로 내려와요
서버 내부에서 SUBSCRIBE_AT_IDENTITY_NO_BLANK와 SUBSCRIBE_AT_AUTH_TYPE_INVALID가 같은 번호 2353에 할당돼 있어요. 응답의 error_code 문자열은 항상 나중에 정의된 SUBSCRIBE_AT_AUTH_TYPE_INVALID로 내려오므로, 코드로 분기할 때는 이 이름을 기준으로 삼고 실제 원인은 message로 구분해야 해요.
