마켓플레이스

프로젝트

하위 가맹점에 프로젝트를 더 만들고, 목록과 상세를 읽고, 담당자를 초대합니다. 커머스 연동이 실패했으면 여기서 다시 시도합니다.

API 하는 일
1. 프로젝트 생성 가맹점에 프로젝트 추가
2. 프로젝트 목록 가맹점의 프로젝트 목록
3. 프로젝트 조회 프로젝트 상세(키·커머스 포함)
4. 프로젝트 초대 프로젝트에 멤버 초대(프로젝트·가맹점 권한 함께)
5. 커머스 연동 재시도 커머스 프로젝트 생성 재시도

인증·권한 오류는 각 표에 없어도 공통 오류 가 날 수 있습니다.

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 정보

POSThttps://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 로 결제수단까지 한 번에

resources: [{ "pg": "nicepay", "method": "카드", "sandbox": true, "resource": { "mid": "…", "mkey": "…" } }] 처럼 보냅니다. 결제수단마다 넣을 키는 PG·필수 연동 값 목록 에 있고, 필수는 required: true 인 키만입니다. 연동 값이 아직 없으면 resource 없이 { "pg": "nicepay", "method": "카드", "sandbox": true } 로 테스트 모드로만 붙일 수 있습니다(부트페이 테스트 키로 결제). 요청 본문의 resource 는 원문이므로 요청 로그에 남기지 않습니다.

실물 vs 비실물

물리적 배송이 발생하는 상품(쇼핑몰, 식음료) 은 실물, 디지털 콘텐츠 / 구독 / 충전금은 비실물 로 설정합니다. 일부 PG 가 사용 가능한 결제수단 목록을 이 값으로 분기합니다. 안 보내면 비실물 입니다. 정해진 값(실물·비실물·실물&비실물, 영문 real·digital·both) 밖은 APP_REAL_GOOD_INVALID 로 거부합니다.

1-2. 코드 예제

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

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 를 붙입니다.

resources 저장은 프로젝트를 만든 뒤

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 정보

GEThttps://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. 코드 예제

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

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 정보

GEThttps://api.bootpay.co.kr/v2/reseller/seller/app/:app_idBasic Auth (리셀러 계정 키)

3-1. 요청 파라미터

파라미터 타입 필수 설명
app_id String 필수 조회할 프로젝트의 app_id (URL 경로)

3-2. 코드 예제

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

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 조회 실패

커머스 쪽 조회에 실패하면 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 정보

POSThttps://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. 코드 예제

가맹점 관리자로 초대 (기본값)

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

이 프로젝트만 관리하게 초대

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 정보

PUThttps://api.bootpay.co.kr/v2/reseller/seller/app/commerce/:app_idBasic Auth (리셀러 계정 키)

5-1. 요청 파라미터

파라미터 타입 필수 설명
app_id String 필수 커머스를 연결할 프로젝트의 app_id (URL 경로)

5-2. 코드 예제

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

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 가 본인 리셀러 하위 셀러의 프로젝트인지 확인합니다

함께 보기