하위 가맹점에 프로젝트를 더 만들고, 목록과 상세를 읽고, 담당자를 초대합니다. 커머스 연동이 실패했으면 여기서 다시 시도합니다.
인증·권한 오류는 각 표에 없어도 공통 오류 가 날 수 있습니다.
1 프로젝트 생성
이미 만들어진 셀러 안에 새 프로젝트(=app)를 추가합니다. 본 서비스와 테스트 환경을 분리하거나, 한 셀러가 운영하는 여러 브랜드를 따로 정산·집계하려고 할 때 사용합니다.
동작 규칙
셀러 생성 시 자동으로 만들어지는 기본 프로젝트 외에 추가가 필요할 때만 호출합니다. 신규 셀러용 첫 프로젝트는 가맹점 생성 한 번으로 만들어집니다.
provider_id 가 리셀러 본인 하위 셀러가 아니면 PROVIDER_NOT_FOUND 가 떨어집니다.
응답에는 프로젝트 기본 정보 7 개 필드(app_id, provider_id, app_name, real, desc, unit, status)와 결제 연동키(application_keys·private_key), 결제수단 목록(payment_apps), 커머스 연동 결과(commerce)가 함께 담깁니다.
resources 를 함께 보내면 가맹점 생성 처럼 PG 결제수단을 같이 붙입니다. 프로젝트를 만들기 전에 PG·결제수단·필수 키를 먼저 검사하므로, 검사에 걸리면 프로젝트도 만들어지지 않습니다. 나중에 붙이거나 바꾸려면 PG 리소스 갱신 을 사용합니다.
provider_id 만 있으면 됩니다. 안 보낸 값은 이름 기본프로젝트 · 통화(unit) KRW · 상품 종류(real) 비실물 · 시간대(timezone) Asia/Seoul 로 만듭니다.
API 정보 POST https://api.bootpay.co.kr/v2/reseller/seller/appBasic Auth (리셀러 계정 키)
1-1. 요청 파라미터
파라미터
타입
필수
설명
provider_id
String
필수
프로젝트를 추가할 셀러의 provider_id
name
String
선택
프로젝트명. 콘솔과 영수증 표시에 사용. 기본 기본프로젝트
desc
String
선택
프로젝트 설명
unit
String
선택
결제 통화. KRW 또는 USD. 기본 KRW. 그 외 값은 APP_UNIT_INVALID
real
String
선택
거래 상품 유형. 비실물(digital) · 실물(real) · 실물&비실물(both). 기본 비실물. 그 외 값은 APP_REAL_GOOD_INVALID
timezone
String
선택
프로젝트 시간대(IANA 이름, 예: Asia/Seoul). 기본 Asia/Seoul. 모르는 이름은 APP_TIMEZONE_INVALID
resources
Array
선택
함께 붙일 PG·결제수단 배열. 원소는 PG 리소스 갱신 의 pg·method·sandbox·resource 와 같고, resource 는 원소마다 필수입니다. status: "off" 는 받지 않습니다
resources: [{ "pg": "nicepay", "method": "카드", "sandbox": true, "resource": { "mid": "…", "mkey": "…" } }] 처럼 보냅니다. 결제수단마다 넣을 키는 PG·필수 연동 값 목록 에 있고, 필수는 required: true 인 키만입니다. 연동 값이 아직 없으면 resource 없이 { "pg": "nicepay", "method": "카드", "sandbox": true } 로 테스트 모드로만 붙일 수 있습니다(부트페이 테스트 키로 결제). 요청 본문의 resource 는 원문이므로 요청 로그에 남기지 않습니다.
물리적 배송이 발생하는 상품(쇼핑몰, 식음료) 은 실물, 디지털 콘텐츠 / 구독 / 충전금은 비실물 로 설정합니다. 일부 PG 가 사용 가능한 결제수단 목록을 이 값으로 분기합니다. 안 보내면 비실물 입니다. 정해진 값(실물·비실물·실물&비실물, 영문 real·digital·both) 밖은 APP_REAL_GOOD_INVALID 로 거부합니다.
1-2. 코드 예제 Node.js Python cURL
import fetch from 'node-fetch'
const RESELLER_AUTH = 'Basic ' + Buffer
. from ( `${ process . env . BOOTPAY_RESELLER_CLIENT_KEY }:${ process . env . BOOTPAY_RESELLER_SECRET_KEY }` )
. toString ( 'base64' )
const res = await fetch ( 'https://api.bootpay.co.kr/v2/reseller/seller/app' , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
'Authorization' : RESELLER_AUTH
},
body: JSON . stringify ({
provider_id: '65a1c0aa8f1b5b00367a0001' ,
name: '한입가게 — 정기구독' ,
desc: '월 정기구독 전용 프로젝트' ,
unit: 'KRW' ,
real: '비실물' ,
timezone: 'Asia/Seoul'
})
})
const data = await res. json ()
// data.app_id 저장
console. log (data) javascript Node.js Python cURL
import base64, os, requests
auth = 'Basic ' + base64.b64encode(
f " { os.environ[ 'BOOTPAY_RESELLER_CLIENT_KEY' ] } : { os.environ[ 'BOOTPAY_RESELLER_SECRET_KEY' ] } " .encode()
).decode()
payload = {
'provider_id' : '65a1c0aa8f1b5b00367a0001' ,
'name' : '한입가게 — 정기구독' ,
'desc' : '월 정기구독 전용 프로젝트' ,
'unit' : 'KRW' ,
'real' : '비실물' ,
'timezone' : 'Asia/Seoul'
}
res = requests.post(
'https://api.bootpay.co.kr/v2/reseller/seller/app' ,
json = payload,
headers = { 'Authorization' : auth}
)
print (res.json()) python Node.js Python cURL
RESELLER_AUTH = $( printf '%s' " $BOOTPAY_RESELLER_CLIENT_KEY : $BOOTPAY_RESELLER_SECRET_KEY " | base64 )
curl -X POST 'https://api.bootpay.co.kr/v2/reseller/seller/app' \
-H "Authorization: Basic $RESELLER_AUTH " \
-H 'Content-Type: application/json' \
-d '{
"provider_id": "65a1c0aa8f1b5b00367a0001",
"name": "한입가게 — 정기구독",
"desc": "월 정기구독 전용 프로젝트",
"unit": "KRW",
"real": "비실물",
"timezone": "Asia/Seoul"
}' bash
1-3. 응답 {
"app_id" : "65a1c0ab8f1b5b00367a0010" ,
"provider_id" : "65a1c0aa8f1b5b00367a0001" ,
"app_name" : "한입가게 — 정기구독" ,
"real" : { "name" : "비실물" , "value" : 0 , "desc" : "" },
"desc" : "월 정기구독 전용 프로젝트" ,
"unit" : "KRW" ,
"status" : 20 ,
"application_keys" : [
{ "type" : 1 , "name" : "WEB" , "key" : "65a1c0ab8f1b5b00367a0011" },
{ "type" : 2 , "name" : "Android" , "key" : "65a1c0ab8f1b5b00367a0012" },
{ "type" : 3 , "name" : "iOS" , "key" : "65a1c0ab8f1b5b00367a0013" },
{ "type" : 4 , "name" : "REST" , "key" : "65a1c0ab8f1b5b00367a0014" }
],
"private_key" : "kQ3f8vB2pN7sXq1wE5rT9yU0iO4aS6dF8gH2jK5lZ0c=" ,
"payment_apps" : [
{
"payment_resource_id" : "65a1c0ab8f1b5b00367a0018" ,
"pg_id" : "6098a1b2c3d4e5f600000101" ,
"pg_name" : "나이스페이먼츠" ,
"pg_alias" : "nicepay" ,
"method_id" : "6098a1b2c3d4e5f600000201" ,
"method_name" : "카드" ,
"method_alias" : "card" ,
"resource_mode" : null ,
"sandbox_mode" : true ,
"easypay" : false ,
"updated_at" : "2026-10-27T10:00:00+09:00" ,
"status" : 1 ,
"resource" : { "mid" : "nicep*****" , "mkey" : "EYzu8*****" },
"cert_expire_at" : null
}
],
"commerce" : {
"status" : "created" ,
"seller_id" : "65a1c0ab8f1b5b00367a0016" ,
"project_id" : "65a1c0ab8f1b5b00367a0017" ,
"client_key" : "example_commerce_client_key" ,
"core_app_id" : "65a1c0ab8f1b5b00367a0002" ,
"key_chain" : {
"project_key_chain_id" : "65a1c0ab8f1b5b00367a0020" ,
"name" : "reseller-default" ,
"client_key" : "example_commerce_server_client_key" ,
"secret_key" : "example_commerce_server_secret_key" ,
"is_supervisor" : true ,
"expires_at" : "2099-12-31T23:59:59+09:00"
}
}
} json 응답 파라미터
파라미터
타입
설명
app_id
String
생성된 프로젝트 식별자
provider_id
String
소속 셀러
app_name
String
프로젝트명
real
Object
거래 상품 유형. { name, value, desc } 구조이고 name 은 실물 / 비실물 / 실물&비실물 중 하나입니다
desc
String
프로젝트 설명
unit
String
결제 통화
status
Number
프로젝트 상태. 기본값 20 (심사통과)
application_keys
Array
플랫폼별 SDK 연동키 묶음. WEB / Android / iOS / REST 4 건이 내려옵니다
application_keys[].type
Number
플랫폼 코드. 1 = WEB, 2 = Android, 3 = iOS, 4 = REST
application_keys[].name
String
플랫폼 이름 (WEB / Android / iOS / REST)
application_keys[].key
String
SDK 초기화에 넣는 application_id. Basic Auth 에 쓰는 client_key 와는 다른 값입니다
private_key
String
프로젝트 단위의 백엔드 키
payment_apps
Array
프로젝트에 붙은 결제수단 목록. 항목은 결제수단 목록 과 같고 resource 는 가린 값입니다. 프로젝트를 만들 때 함께 붙는 부트페이 기본 결제수단(테스트 모드)도 들어 있습니다
commerce
Object
함께 만든 부트페이 커머스 프로젝트 정보
commerce.status
String
created 새로 생성, exists 기존 프로젝트 연결, failed 커머스 생성 실패 (error_code·message 포함)
commerce.project_id
String
커머스 프로젝트 식별자
commerce.client_key
String
커머스 공개키. 프론트 SDK 용이며 서버용 secret 은 키 생성·조회 에서 발급합니다
commerce.core_app_id
String
커머스 프로젝트에 연결된 결제 프로젝트(app_id)
commerce.key_chain
Object
리셀러 전용 커머스 서버 키(이름 reseller-default, 전체 권한·만료 없음). 커머스 프로젝트를 이 호출에서 처음 만든 경우(created)에만 오고, secret_key 원문은 이 응답에서만 보입니다. 모양은 키 생성·조회 의 발급 응답과 같습니다. 잃어버리면 키 재발급
commerce.key_error
String
커머스 프로젝트는 만들었지만 서버 키 발급에 실패한 사유. 키 재발급 의 target: commerce 로 다시 받습니다
commerce.error_code
String
failed 일 때 원인 코드
commerce.status 가 failed 이면 커머스 쪽 생성만 실패한 것입니다. 결제(PG) 가맹점·프로젝트는 정상 생성돼 있으므로 같은 생성 API 를 다시 부르지 않습니다. PUT /v2/reseller/seller/app/commerce/:app_id 로 커머스만 다시 시도합니다. 자세한 내용은 커머스 연동 재시도 를 참고합니다.
커머스 프로젝트 생성까지 기다렸다가 응답하므로 10초 가까이 걸릴 수 있습니다. 호출 쪽 HTTP 타임아웃은 15초 이상으로 둡니다. 중간에 끊겼다면 같은 생성 API 를 다시 부르지 말고 커머스 연동 재시도 로 확인합니다(이미 만들어졌으면 exists).
이 응답에 결제 연동키(application_keys·private_key)가 포함됩니다. resources 를 보내지 않았다면 PG 결제수단은 아직 붙어 있지 않으므로 PG 리소스 갱신 을 이어서 호출해 PG 를 붙입니다.
PG·결제수단·필수 키 검사는 프로젝트를 만들기 전에 끝나지만, 연동 값 저장은 프로젝트를 만든 뒤에 합니다. 드물게 저장 단계에서 거부되면(예: KCP 인증서 형식 오류) 프로젝트는 남아 있으므로 같은 생성 API 를 다시 부르지 말고 PG 리소스 갱신 으로 결제수단만 다시 붙입니다.
1-4. 에러 코드
코드
메시지
대처 방법
API_ONLY_RESELLER
리셀러만 이용이 가능한 API입니다
리셀러 권한 계정 키로 호출합니다
API_NOT_PERMIT_LV (10000)
허가된 API 권한이 아닙니다 (HTTP 401)
계정에 이 API 호출 권한이 열려 있는지 부트페이 관리자에게 문의합니다
API_NOT_PERMIT (10001)
허가된 API 권한이 아닙니다 (HTTP 401)
계정에 이 API 호출 권한이 열려 있는지 부트페이 관리자에게 문의합니다
PROVIDER_NOT_FOUND (300)
본인 하위 셀러가 아닙니다
provider_id 가 본인 리셀러 소속인지 확인합니다
APP_REAL_GOOD_INVALID (221)
판매타입(real) 이 유효하지 않습니다
비실물·실물·실물&비실물(또는 digital·real·both)로 보내거나 빼서 기본 비실물 로 둡니다
APP_UNIT_INVALID (222)
화폐유형(unit) 이 유효하지 않습니다
KRW 또는 USD 로 보냅니다
APP_TIMEZONE_INVALID (223)
모르는 시간대 이름입니다
Asia/Seoul 같은 IANA 이름으로 보내거나 빼서 기본 Asia/Seoul 로 둡니다
PG_RESOURCE_NOT_FOUND (1004)
resources[].pg 심볼을 찾지 못했습니다
PG·필수 연동 값 목록 의 symbols 를 넣습니다
METHOD_RESOURCE_NOT_FOUND (1005)
resources[].method 심볼을 찾지 못했습니다
그 PG 가 지원하는 결제수단 심볼인지 확인합니다
RESOURCE_KEY_BLANK (1006)
resources[].resource 에 필수 키가 빠져 있습니다
PG·필수 연동 값 목록 의 resource_keys 중 required: true 인 키를 채웁니다
PM_NOT_SUPPORT_SANDBOX_MODE (1101)
sandbox: true 로 연동 값 없이 붙이려는 결제수단이 테스트 모드를 지원하지 않습니다 (어느 원소인지 메시지에 나옵니다)
PG·필수 연동 값 목록 에서 sandbox_supported 를 확인하고, 지원하지 않으면 resource 와 함께 보냅니다
PARAMS_INVALID (-33)
resources 원소에 resource 가 없거나(테스트 모드로만이면 sandbox: true 도 없음) status 만 보냈습니다
원소마다 resource 나 sandbox: true 를 넣어 보냅니다
2 프로젝트 목록
리셀러 본인 하위 셀러가 가진 프로젝트(app) 를 나열합니다. 가맹점 상세 화면에서 프로젝트 탭을 그릴 때 사용합니다.
동작 규칙
provider_id 가 필수입니다. 본인 하위 셀러가 아니면 PROVIDER_NOT_FOUND 가 떨어집니다.
목록에는 결제 연동키와 커머스 정보가 없습니다. 키와 commerce 는 프로젝트 조회 를 사용합니다.
count 는 페이지와 무관한 전체 프로젝트 수입니다.
API 정보 GET https://api.bootpay.co.kr/v2/reseller/seller/app?provider_id=...Basic Auth (리셀러 계정 키)
2-1. 요청 파라미터
파라미터
타입
필수
설명
provider_id
String
필수
프로젝트를 조회할 셀러의 provider_id (쿼리)
page
Number
선택
페이지 번호 (쿼리). 기본 1
limit
Number
선택
페이지당 건수 (쿼리). 기본 20, 최대 100
2-2. 코드 예제 Node.js Python cURL
import fetch from 'node-fetch'
const RESELLER_AUTH = 'Basic ' + Buffer
. from ( `${ process . env . BOOTPAY_RESELLER_CLIENT_KEY }:${ process . env . BOOTPAY_RESELLER_SECRET_KEY }` )
. toString ( 'base64' )
const providerId = '65a1c0aa8f1b5b00367a0001'
const res = await fetch ( `https://api.bootpay.co.kr/v2/reseller/seller/app?provider_id=${ providerId }` , {
method: 'GET' ,
headers: {
'Authorization' : RESELLER_AUTH
}
})
const data = await res. json ()
console. log (data.count, data.list) javascript Node.js Python cURL
import base64, os, requests
auth = 'Basic ' + base64.b64encode(
f " { os.environ[ 'BOOTPAY_RESELLER_CLIENT_KEY' ] } : { os.environ[ 'BOOTPAY_RESELLER_SECRET_KEY' ] } " .encode()
).decode()
provider_id = '65a1c0aa8f1b5b00367a0001'
res = requests.get(
'https://api.bootpay.co.kr/v2/reseller/seller/app' ,
params = { 'provider_id' : provider_id},
headers = { 'Authorization' : auth}
)
print (res.json()) python Node.js Python cURL
RESELLER_AUTH = $( printf '%s' " $BOOTPAY_RESELLER_CLIENT_KEY : $BOOTPAY_RESELLER_SECRET_KEY " | base64 )
PROVIDER_ID = '65a1c0aa8f1b5b00367a0001'
curl -X GET "https://api.bootpay.co.kr/v2/reseller/seller/app?provider_id= $PROVIDER_ID " \
-H "Authorization: Basic $RESELLER_AUTH " bash
2-3. 응답 {
"list" : [
{
"app_id" : "65a1c0ab8f1b5b00367a0002" ,
"provider_id" : "65a1c0aa8f1b5b00367a0001" ,
"app_name" : "한입가게" ,
"real" : { "name" : "실물" , "value" : 1 , "desc" : "" },
"desc" : "" ,
"unit" : "KRW" ,
"status" : 20
},
{
"app_id" : "65a1c0ab8f1b5b00367a0010" ,
"provider_id" : "65a1c0aa8f1b5b00367a0001" ,
"app_name" : "한입가게 — 정기구독" ,
"real" : { "name" : "비실물" , "value" : 0 , "desc" : "" },
"desc" : "" ,
"unit" : "KRW" ,
"status" : 20
}
],
"count" : 2
} json 응답 파라미터
파라미터
타입
설명
list
Array
프로젝트 배열
list[].app_id
String
프로젝트 식별자
list[].provider_id
String
소속 셀러
list[].app_name
String
프로젝트명
list[].real
Object
거래 상품 유형. { name, value, desc } 구조이고 name 은 실물 / 비실물 / 실물&비실물 중 하나입니다
list[].desc
String
프로젝트 설명
list[].unit
String
결제 통화
list[].status
Number
프로젝트 상태. 기본값 20 (심사통과)
count
Number
전체 프로젝트 수
2-4. 에러 코드
코드
메시지
대처 방법
API_ONLY_RESELLER
리셀러만 이용이 가능한 API입니다
리셀러 권한 계정 키로 호출합니다
API_SCOPE_INVALID
허용되지 않은 API 권한의 키입니다
키에 이 API 의 리셀러 스코프 를 주거나 전체 권한(supervisor) 키로 호출합니다
PROVIDER_NOT_FOUND
본인 하위에 해당 셀러가 없습니다
provider_id 가 본인 리셀러 소속인지 확인합니다
3 프로젝트 조회
app_id 로 프로젝트 한 건을 조회합니다. 프로젝트 기본정보에 결제 연동키와 커머스 프로젝트 정보가 함께 담깁니다.
동작 규칙
본인 하위 셀러의 프로젝트가 아니면 APP_NOT_PERMIT, 없는 프로젝트면 APP_NOT_FOUND 가 떨어집니다.
응답에는 application_keys, commerce 가 포함됩니다. private_key 는 가맹점 생성 ·프로젝트 생성 응답에서만 내려오고 조회에서는 다시 보여주지 않습니다.
commerce 는 항상 status 가 있는 객체입니다 — exists 연결됨, none 커머스 프로젝트 없음(예전에는 null), failed 조회 실패.
payment_setting_lock 은 결제 설정 잠금 상태입니다 — 가맹점이 켠 잠금(seller_locked)과 리셀러가 켠 잠금(reseller_locked). 리셀러 잠금은 결제 설정 잠금 으로 바꿉니다.
서버용 secret 은 응답에 없습니다. 키 생성·조회 에서 발급합니다.
API 정보 GET https://api.bootpay.co.kr/v2/reseller/seller/app/:app_idBasic Auth (리셀러 계정 키)
3-1. 요청 파라미터
파라미터
타입
필수
설명
app_id
String
필수
조회할 프로젝트의 app_id (URL 경로)
3-2. 코드 예제 Node.js Python cURL
import fetch from 'node-fetch'
const RESELLER_AUTH = 'Basic ' + Buffer
. from ( `${ process . env . BOOTPAY_RESELLER_CLIENT_KEY }:${ process . env . BOOTPAY_RESELLER_SECRET_KEY }` )
. toString ( 'base64' )
const appId = '65a1c0ab8f1b5b00367a0002'
const res = await fetch ( `https://api.bootpay.co.kr/v2/reseller/seller/app/${ appId }` , {
method: 'GET' ,
headers: {
'Authorization' : RESELLER_AUTH
}
})
const data = await res. json ()
console. log (data) javascript Node.js Python cURL
import base64, os, requests
auth = 'Basic ' + base64.b64encode(
f " { os.environ[ 'BOOTPAY_RESELLER_CLIENT_KEY' ] } : { os.environ[ 'BOOTPAY_RESELLER_SECRET_KEY' ] } " .encode()
).decode()
app_id = '65a1c0ab8f1b5b00367a0002'
res = requests.get(
f 'https://api.bootpay.co.kr/v2/reseller/seller/app/ { app_id } ' ,
headers = { 'Authorization' : auth}
)
print (res.json()) python Node.js Python cURL
RESELLER_AUTH = $( printf '%s' " $BOOTPAY_RESELLER_CLIENT_KEY : $BOOTPAY_RESELLER_SECRET_KEY " | base64 )
APP_ID = '65a1c0ab8f1b5b00367a0002'
curl -X GET "https://api.bootpay.co.kr/v2/reseller/seller/app/ $APP_ID " \
-H "Authorization: Basic $RESELLER_AUTH " bash
3-3. 응답 {
"app_id" : "65a1c0ab8f1b5b00367a0002" ,
"provider_id" : "65a1c0aa8f1b5b00367a0001" ,
"app_name" : "한입가게" ,
"real" : { "name" : "실물" , "value" : 1 , "desc" : "" },
"desc" : "" ,
"unit" : "KRW" ,
"status" : 20 ,
"application_keys" : [
{ "type" : 1 , "name" : "WEB" , "key" : "65a1c0ab8f1b5b00367a0011" },
{ "type" : 2 , "name" : "Android" , "key" : "65a1c0ab8f1b5b00367a0012" },
{ "type" : 3 , "name" : "iOS" , "key" : "65a1c0ab8f1b5b00367a0013" },
{ "type" : 4 , "name" : "REST" , "key" : "65a1c0ab8f1b5b00367a0014" }
],
"commerce" : {
"status" : "exists" ,
"project_id" : "65a1c0ab8f1b5b00367a0006" ,
"core_app_id" : "65a1c0ab8f1b5b00367a0008" ,
"seller_id" : "65a1c0ab8f1b5b00367a0005" ,
"name" : "한입가게" ,
"seller_name" : "한입가게" ,
"client_key" : "example_commerce_client_key"
},
"payment_setting_lock" : {
"seller_locked" : false ,
"seller_changed_at" : null ,
"reseller_locked" : false ,
"reseller_changed_at" : null
}
} json 응답 파라미터
파라미터
타입
설명
app_id
String
프로젝트 식별자
provider_id
String
소속 셀러
app_name
String
프로젝트명
real
Object
거래 상품 유형. { name, value, desc } 구조이고 name 은 실물 / 비실물 / 실물&비실물 중 하나입니다
desc
String
프로젝트 설명
unit
String
결제 통화
status
Number
프로젝트 상태. 기본값 20 (심사통과)
application_keys
Array
플랫폼별 SDK 연동키 묶음. WEB / Android / iOS / REST 4 건이 내려옵니다
application_keys[].type
Number
플랫폼 코드. 1 = WEB, 2 = Android, 3 = iOS, 4 = REST
application_keys[].name
String
플랫폼 이름 (WEB / Android / iOS / REST)
application_keys[].key
String
SDK 초기화에 넣는 application_id. Basic Auth 에 쓰는 client_key 와는 다른 값입니다
commerce
Object
부트페이 커머스 프로젝트 정보
commerce.status
String
exists 연결됨, none 커머스 프로젝트 없음(다른 필드 없음), failed 조회 실패(error_code·message)
commerce.project_id
String
커머스 프로젝트 식별자
commerce.core_app_id
String
커머스 프로젝트에 연결된 결제 프로젝트 식별자
commerce.seller_id
String
커머스 셀러 식별자
commerce.name
String
커머스 프로젝트명
commerce.seller_name
String
커머스 셀러명
commerce.client_key
String
커머스 공개키. 프론트 SDK 용
payment_setting_lock
Object
결제 설정 잠금 상태. 바꾸는 법은 결제 설정 잠금
payment_setting_lock.seller_locked
Boolean
가맹점이 자기 화면에서 켠 잠금
payment_setting_lock.seller_changed_at
String
가맹점 잠금을 마지막으로 켜거나 끈 시각. 없으면 null
payment_setting_lock.reseller_locked
Boolean
리셀러 잠금. 켜져 있으면 가맹점이 결제수단·테스트 모드·연동 값을 못 바꿉니다
payment_setting_lock.reseller_changed_at
String
리셀러 잠금을 마지막으로 켜거나 끈 시각. 없으면 null
커머스 쪽 조회에 실패하면 commerce 는 { "status": "failed", "error_code": "...", "message": "..." } 로 옵니다. 프로젝트 기본정보와 결제 연동키는 정상으로 내려옵니다.
3-4. 에러 코드
코드
메시지
대처 방법
API_ONLY_RESELLER
리셀러만 이용이 가능한 API입니다
리셀러 권한 계정 키로 호출합니다
API_SCOPE_INVALID
허용되지 않은 API 권한의 키입니다
키에 이 API 의 리셀러 스코프 를 주거나 전체 권한(supervisor) 키로 호출합니다
APP_NOT_FOUND
프로젝트를 찾지 못했습니다
app_id 가 올바른지 확인합니다
APP_NOT_PERMIT
본인 하위 프로젝트가 아닙니다
app_id 가 본인 리셀러 하위 셀러의 프로젝트인지 확인합니다
4 프로젝트 초대
리셀러가 하위 가맹점(셀러)의 프로젝트에 담당자를 초대합니다. app_id 하나로 그 프로젝트의 권한(level)과 그 프로젝트가 속한 가맹점의 권한(provider_level)을 함께 정합니다. 메일이 발송되고, 받는 사람이 메일 안의 링크로 초대를 수락해야 권한이 생깁니다.
동작 규칙
app_id·email 에 프로젝트 권한 level, 가맹점 권한 provider_level 을 함께 보냅니다. 두 값 모두 안 보내면 관리자(admin) 입니다.
가맹점 권한이 사용자(user)·관리자(admin)이면 그 가맹점의 모든 프로젝트에 관리자 권한 이 생깁니다(부트페이 가맹점 권한 규칙). 이때 level 은 쓰이지 않습니다.
이 프로젝트에만 level 권한을 주려면 provider_level: "none" 을 함께 보냅니다(예: 조회만 하는 담당자 = level: "member" + provider_level: "none").
호출 시점에 권한이 바로 붙지는 않습니다. 수락 대기(READY) 초대가 만들어지고 메일이 나갑니다. 받는 사람이 링크로 수락해야 권한이 생깁니다.
초대 링크는 만든 때부터 24시간 뒤 만료됩니다.
응답으로 만든 초대(invite_id·정해진 두 권한·만료 시각)를 돌려줍니다.
API 정보 POST https://api.bootpay.co.kr/v2/reseller/inviteBasic Auth (리셀러 계정 키)
4-1. 요청 파라미터
파라미터
타입
필수
설명
app_id
String
필수
초대할 하위 프로젝트의 app_id. 본인 하위 가맹점의 프로젝트여야 합니다
email
String
필수
초대받을 사람의 이메일
level
String
선택
프로젝트 권한. admin·manager·batch_manager·member(한국어 이름·숫자도 받음). 기본 admin. 아래 표 참고
provider_level
String
선택
가맹점 권한. admin·user·none(한국어 이름·숫자도 받음). 기본 admin. 아래 표 참고
level — 프로젝트 권한
값
이름
숫자
할 수 있는 일
admin
관리자
선택
프로젝트의 모든 설정을 바꿀 수 있습니다
manager
매니저
선택
결제 조회·취소, 결제 설정, 프로젝트 정보 설정
batch_manager
배치매니저
선택
상품 업로드. 콘솔의 권한 선택 목록에는 없지만 API 로는 줄 수 있습니다
member
팀원
선택
결제 내역 조회만
provider_level — 가맹점 권한
값
이름
숫자
할 수 있는 일
admin
관리자
선택
가맹점 정보·멤버 권한을 관리합니다. 가맹점의 모든 프로젝트에 관리자 권한이 생깁니다
user
사용자
선택
가맹점의 모든 프로젝트에 관리자 권한으로 접속합니다. 가맹점 정보·멤버는 관리하지 않습니다
none
무권한(접속자)
선택
가맹점 권한 없이, 초대받은 이 프로젝트에만 level 권한으로 접속합니다
두 값을 함께 보면
provider_level
level
수락하면
admin(기본)
무엇이든
선택
user
무엇이든
선택
none
admin·manager·batch_manager·member
선택
가맹점 대표·운영자: 아무것도 안 보냄(둘 다 admin)
이 프로젝트만 관리: level: "admin" + provider_level: "none"
조회만 하는 CS 담당자: level: "member" + provider_level: "none"
4-2. 코드 예제 가맹점 관리자로 초대 (기본값) Node.js Python cURL
import fetch from 'node-fetch'
const RESELLER_AUTH = 'Basic ' + Buffer
. from ( `${ process . env . BOOTPAY_RESELLER_CLIENT_KEY }:${ process . env . BOOTPAY_RESELLER_SECRET_KEY }` )
. toString ( 'base64' )
const res = await fetch ( 'https://api.bootpay.co.kr/v2/reseller/invite' , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
'Authorization' : RESELLER_AUTH
},
body: JSON . stringify ({
app_id: '65a1c0ab8f1b5b00367a0010' ,
email: 'owner@hanip.shop' ,
level: 'admin' , // 안 보내도 admin
provider_level: 'admin' // 안 보내도 admin
})
})
console. log ( await res. json ()) javascript Node.js Python cURL
import base64, os, requests
auth = 'Basic ' + base64.b64encode(
f " { os.environ[ 'BOOTPAY_RESELLER_CLIENT_KEY' ] } : { os.environ[ 'BOOTPAY_RESELLER_SECRET_KEY' ] } " .encode()
).decode()
res = requests.post(
'https://api.bootpay.co.kr/v2/reseller/invite' ,
json = { 'app_id' : '65a1c0ab8f1b5b00367a0010' , 'email' : 'owner@hanip.shop' , 'level' : 'admin' , 'provider_level' : 'admin' },
headers = { 'Authorization' : auth}
)
print (res.json()) python Node.js Python cURL
RESELLER_AUTH = $( printf '%s' " $BOOTPAY_RESELLER_CLIENT_KEY : $BOOTPAY_RESELLER_SECRET_KEY " | base64 )
curl -X POST 'https://api.bootpay.co.kr/v2/reseller/invite' \
-H "Authorization: Basic $RESELLER_AUTH " \
-H 'Content-Type: application/json' \
-d '{
"app_id": "65a1c0ab8f1b5b00367a0010",
"email": "owner@hanip.shop",
"level": "admin",
"provider_level": "admin"
}' bash
이 프로젝트만 관리하게 초대 body : JSON . stringify ({
app_id: '65a1c0ab8f1b5b00367a0010' ,
email: 'manager@hanip.shop' ,
level: 'admin' ,
provider_level: 'none' // 가맹점의 다른 프로젝트·정보는 보지 못한다
}) javascript 조회만 하는 CS 담당자 body : JSON . stringify ({
app_id: '65a1c0ab8f1b5b00367a0010' ,
email: 'cs@hanip.shop' ,
level: 'member' ,
provider_level: 'none' // 꼭 none — 안 보내면 admin 이라 모든 프로젝트 관리자가 된다
}) javascript 4-3. 응답 {
"invite_id" : "6b2a1c0ab8f1b5b00367a0f1" ,
"app_id" : "65a1c0ab8f1b5b00367a0010" ,
"provider_id" : "65a1c0aa8f1b5b00367a0001" ,
"email" : "owner@hanip.shop" ,
"level" : 10 ,
"level_name" : "관리자" ,
"provider_level" : 10 ,
"provider_level_name" : "관리자" ,
"status" : "ready" ,
"member_exists" : false ,
"expired_at" : "2026-11-06T11:20:00+09:00"
} json 응답 파라미터
파라미터
타입
설명
invite_id
String
초대 식별자
app_id · provider_id
String
초대한 프로젝트와 그 가맹점
level · level_name
Integer · String
정해진 프로젝트 권한
provider_level · provider_level_name
Integer · String
정해진 가맹점 권한
status
String
ready — 수락 전
member_exists
Boolean
이미 부트페이 계정이 있는 이메일이면 true(콘솔 알림도 함께 갑니다)
expired_at
String
수락 기한(ISO8601)
4-4. 동작 규칙
상황
결과
받는 사람이 부트페이 미가입자
초대가 만들어지고 가입 안내 메일이 나갑니다. 가입 + 수락하면 권한이 생깁니다
이미 가입한 사용자
초대 메일과 콘솔 알림이 갑니다. 수락해야 권한이 생깁니다
이미 그 가맹점에 권한이 있는 사용자를 더 높은 provider_level 로 초대
수락하면 가맹점 권한이 올라갑니다(내려가지는 않습니다)
24시간 안에 수락하지 않음
초대가 만료됩니다. 다시 초대합니다
이미 그 프로젝트 권한이 있는 이메일
INVITE_ALREADY
같은 이메일로 수락하지 않은 초대가 너무 많이 쌓임
INVITE_LIMIT_OVER
4-5. 에러 코드
코드
메시지
대처 방법
API_ONLY_RESELLER
리셀러만 이용이 가능한 API입니다
리셀러 권한 계정 키로 호출합니다
API_NOT_PERMIT_LV (10000)
허가된 API 권한이 아닙니다 (HTTP 401)
계정에 이 API 호출 권한이 열려 있는지 부트페이 관리자에게 문의합니다
API_NOT_PERMIT (10001)
허가된 API 권한이 아닙니다 (HTTP 401)
계정에 이 API 호출 권한이 열려 있는지 부트페이 관리자에게 문의합니다
APP_OWNER_MEMBER_NOT_FOUND
초대 주체가 될 멤버를 찾지 못했습니다
리셀러 기본 프로젝트가 정상인지 확인합니다
APP_NOT_FOUND
본인 하위 가맹점의 프로젝트가 아닙니다
app_id 와 소속 셀러를 확인합니다
INVITE_T_MEMBER_BLANK (477)
초대할 이메일이 비었습니다
email 을 넣습니다
INVITE_PROJECT_LEVEL_INVALID (468)
level 값이 올바르지 않습니다
admin·manager·batch_manager·member 중 하나
INVITE_PROVIDER_LEVEL_INVALID (476)
provider_level 값이 올바르지 않습니다
admin·user·none 중 하나
INVITE_TYPE_INVALID (467)
invite_type 을 보냈는데 프로젝트 초대 값이 아닙니다
invite_type 은 보내지 않아도 됩니다
INVITE_ALREADY
이미 그 프로젝트 권한이 있는 사용자입니다
콘솔에서 멤버 목록을 먼저 확인합니다
INVITE_LIMIT_OVER
같은 이메일로 수락하지 않은 초대가 너무 많이 쌓였습니다
받는 사람이 기존 초대를 수락하도록 안내합니다
5 커머스 연동 재시도
프로젝트에 부트페이 커머스 프로젝트를 생성해 연결합니다. 생성 응답에서 커머스 생성이 실패했을 때, 또는 커머스 연동이 없던 시기에 만든 프로젝트에 커머스를 붙일 때 사용합니다.
동작 규칙
생성 응답의 commerce.status 가 failed 였다면 생성 API 를 다시 부르지 말고 이 API 로 커머스만 다시 시도합니다.
여러 번 불러도 커머스 프로젝트가 중복으로 생기지 않습니다. 이미 있으면 exists 로 응답합니다.
이 호출에서 커머스 프로젝트를 처음 만들었으면(created) 리셀러 전용 커머스 서버 키 commerce.key_chain 이 함께 옵니다. exists 에는 오지 않습니다.
요청 본문은 없습니다. 경로의 app_id 만 보냅니다.
커머스 연동 이전에 만든 하위 가맹점의 프로젝트에도 같은 방법으로 커머스를 붙입니다.
API 정보 PUT https://api.bootpay.co.kr/v2/reseller/seller/app/commerce/:app_idBasic Auth (리셀러 계정 키)
5-1. 요청 파라미터
파라미터
타입
필수
설명
app_id
String
필수
커머스를 연결할 프로젝트의 app_id (URL 경로)
5-2. 코드 예제 Node.js Python cURL
import fetch from 'node-fetch'
const RESELLER_AUTH = 'Basic ' + Buffer
. from ( `${ process . env . BOOTPAY_RESELLER_CLIENT_KEY }:${ process . env . BOOTPAY_RESELLER_SECRET_KEY }` )
. toString ( 'base64' )
const appId = '65a1c0ab8f1b5b00367a0002'
const res = await fetch ( `https://api.bootpay.co.kr/v2/reseller/seller/app/commerce/${ appId }` , {
method: 'PUT' ,
headers: {
'Authorization' : RESELLER_AUTH
}
})
const data = await res. json ()
console. log (data.commerce.status) javascript Node.js Python cURL
import base64, os, requests
auth = 'Basic ' + base64.b64encode(
f " { os.environ[ 'BOOTPAY_RESELLER_CLIENT_KEY' ] } : { os.environ[ 'BOOTPAY_RESELLER_SECRET_KEY' ] } " .encode()
).decode()
app_id = '65a1c0ab8f1b5b00367a0002'
res = requests.put(
f 'https://api.bootpay.co.kr/v2/reseller/seller/app/commerce/ { app_id } ' ,
headers = { 'Authorization' : auth}
)
print (res.json()) python Node.js Python cURL
RESELLER_AUTH = $( printf '%s' " $BOOTPAY_RESELLER_CLIENT_KEY : $BOOTPAY_RESELLER_SECRET_KEY " | base64 )
APP_ID = '65a1c0ab8f1b5b00367a0002'
curl -X PUT "https://api.bootpay.co.kr/v2/reseller/seller/app/commerce/ $APP_ID " \
-H "Authorization: Basic $RESELLER_AUTH " bash
5-3. 응답 {
"app_id" : "65a1c0ab8f1b5b00367a0002" ,
"commerce" : {
"status" : "created" ,
"seller_id" : "65a1c0ab8f1b5b00367a0005" ,
"project_id" : "65a1c0ab8f1b5b00367a0006" ,
"client_key" : "example_commerce_client_key" ,
"core_app_id" : "65a1c0ab8f1b5b00367a0002" ,
"key_chain" : {
"project_key_chain_id" : "65a1c0ab8f1b5b00367a0020" ,
"name" : "reseller-default" ,
"client_key" : "example_commerce_server_client_key" ,
"secret_key" : "example_commerce_server_secret_key" ,
"is_supervisor" : true ,
"expires_at" : "2099-12-31T23:59:59+09:00"
}
}
} json 응답 파라미터
파라미터
타입
설명
app_id
String
프로젝트 식별자
commerce
Object
커머스 프로젝트 정보
commerce.status
String
created 새로 생성, exists 기존 프로젝트 연결, failed 커머스 생성 실패 (error_code·message 포함)
commerce.seller_id
String
커머스 셀러 식별자
commerce.project_id
String
커머스 프로젝트 식별자
commerce.client_key
String
커머스 공개키. 프론트 SDK 용이며 서버용 secret 은 키 생성·조회 에서 발급합니다
commerce.core_app_id
String
커머스 프로젝트에 연결된 결제 프로젝트(app_id)
commerce.key_chain
Object
리셀러 전용 커머스 서버 키(이름 reseller-default, 전체 권한·만료 없음). 커머스 프로젝트를 이 호출에서 처음 만든 경우(created)에만 오고, secret_key 원문은 이 응답에서만 보입니다. 모양은 키 생성·조회 의 발급 응답과 같습니다. 잃어버리면 키 재발급
commerce.key_error
String
커머스 프로젝트는 만들었지만 서버 키 발급에 실패한 사유. 키 재발급 의 target: commerce 로 다시 받습니다
commerce.error_code
String
failed 일 때 원인 코드
5-4. 에러 코드
코드
메시지
대처 방법
API_ONLY_RESELLER
리셀러만 이용이 가능한 API입니다
리셀러 권한 계정 키로 호출합니다
API_SCOPE_INVALID
허용되지 않은 API 권한의 키입니다
키에 이 API 의 리셀러 스코프 를 주거나 전체 권한(supervisor) 키로 호출합니다
APP_NOT_FOUND
프로젝트를 찾지 못했습니다
app_id 가 올바른지 확인합니다
APP_NOT_PERMIT
본인 하위 프로젝트가 아닙니다
app_id 가 본인 리셀러 하위 셀러의 프로젝트인지 확인합니다