구독 계약을 다른 사용자에게 이전(승계)해요. 기존 구독자의 계약이 새로운 사용자에게 넘어가요.
API 엔드포인트
알려진 문제 — 승계 요청이 지금 서버 오류로 끝나요
이 API와 관리자 승계(PUT /v1/order_subscriptions/:id/transfer)는 현재 요청 내용과 관계없이 서버 오류(500)를 돌려주고, 승계는 처리되지 않아요. 고쳐지기 전까지 승계가 필요하면 부트페이 담당자와 먼저 확인해요.
사용자 요청 vs 관리자 요청
| 구분 | 사용자 요청 | 관리자 요청 |
|---|---|---|
| API | 이 문서 (POST /v1/order_subscriptions/requests/ing/transfer) |
PUT /v1/order_subscriptions/:id/transfer (supervisor 권한) |
| 호출 주체 | 가맹점 서버(Basic 인증). 고객 JWT 또는 user_id를 함께 보내면 구독 소유자와 대조해요 |
가맹점 서버(Basic 인증, supervisor 권한) |
| 승인 필요 | 예 | 아니요 — 즉시 처리 |
| 인수자 지정 | 필수 | 필수 |
요청 파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
order_subscription_id |
String | 필수 | 구독 계약 ID |
user_id |
String | 선택 | 로그인한 회원 ID 또는 이 몰의 외부 회원 ID. 보내면 구독 소유자와 대조해요. Bootpay-User-JWT 헤더로 보내도 돼요 |
new_user_id |
String | 필수 | 새 구독자의 회원 ID 또는 이 몰의 외부 회원 ID. 이 몰의 유효한 회원이어야 해요 |
new_username |
String | 필수 | 새 구독자 이름 |
new_user_email |
String | 필수 | 새 구독자 이메일 |
new_user_phone |
String | 필수 | 새 구독자 전화번호 |
new_user_address |
String | 선택 | 새 구독자 주소 |
wallet_id |
String | 선택 | 새 구독자의 결제 수단 (지갑 ID) |
reason |
String | 선택 | 이전 사유 |
코드 예제
curl -X POST "https://api.bootapi.com/v1/order_subscriptions/requests/ing/transfer" \
-H "Authorization: Basic {base64(client_key:secret_key)}" \
-H "Content-Type: application/json" \
-d '{
"order_subscription_id": "sub_abc123",
"new_user_id": "user_new_001",
"new_username": "김철수",
"new_user_email": "chulsoo@example.com",
"new_user_phone": "01012345678",
"reason": "구독 승계 요청"
}'bashconst { BootpayCommerce } = require('@bootpay/backend-js');
const commerce = new BootpayCommerce({
client_key: '{client_key}',
secret_key: '{secret_key}'
});
const response = await commerce.orderSubscriptionRequest.transfer({
order_subscription_id: 'sub_abc123',
new_user_id: 'user_new_001',
new_username: '김철수',
new_user_email: 'chulsoo@example.com',
new_user_phone: '01012345678',
reason: '구독 승계 요청'
});
console.log(response);javascriptfrom bootpay_backend.commerce import BootpayCommerce
commerce = BootpayCommerce('{client_key}', '{secret_key}')
response = commerce.order_subscription_request_transfer({
'order_subscription_id': 'sub_abc123',
'new_user_id': 'user_new_001',
'new_username': '김철수',
'new_user_email': 'chulsoo@example.com',
'new_user_phone': '01012345678',
'reason': '구독 승계 요청'
})
print(response)pythonuse Bootpay\ServerPhp\BootpayCommerceApi;
$commerce = new BootpayCommerceApi("{client_key}", "{secret_key}");
$response = $commerce->orderSubscriptionRequestTransfer([
'order_subscription_id' => 'sub_abc123',
'new_user_id' => 'user_new_001',
'new_username' => '김철수',
'new_user_email' => 'chulsoo@example.com',
'new_user_phone' => '01012345678',
'reason' => '구독 승계 요청'
]);
print_r($response);phpimport kr.co.bootpay.store.BootpayStore;
import kr.co.bootpay.store.model.request.TokenPayload;
import kr.co.bootpay.store.model.response.BootpayStoreResponse;
import kr.co.bootpay.store.model.request.orderSubscription.request.ing.OrderSubscriptionTransferParams;
TokenPayload tokenPayload = new TokenPayload("{client_key}", "{secret_key}");
BootpayStore commerce = new BootpayStore(tokenPayload).withToken();
OrderSubscriptionTransferParams params = new OrderSubscriptionTransferParams();
params.orderSubscriptionId = "sub_abc123";
params.newUserId = "user_new_001";
params.newUsername = "김철수";
params.newUserEmail = "chulsoo@example.com";
params.newUserPhone = "01012345678";
params.reason = "구독 승계 요청";
BootpayStoreResponse response = commerce.orderSubscription.requestIng.transfer(params);
System.out.println(response);javarequire 'bootpay'
commerce = BootpayStore::RestClient.new(client_key: '{client_key}', secret_key: '{secret_key}')
response = commerce.order_subscription_requests_ing_transfer(
order_subscription_id: 'sub_abc123',
new_user_id: 'user_new_001',
new_username: '김철수',
new_user_email: 'chulsoo@example.com',
new_user_phone: '01012345678',
reason: '구독 승계 요청'
)
puts responserubycommerce := bootpay.NewCommerceApi("{client_key}", "{secret_key}")
response, err := commerce.OrderSubscriptionRequestTransfer(map[string]interface{}{
"order_subscription_id": "sub_abc123",
"new_user_id": "user_new_001",
"new_username": "김철수",
"new_user_email": "chulsoo@example.com",
"new_user_phone": "01012345678",
"reason": "구독 승계 요청",
})
fmt.Println(response)govar commerce = new BootpayCommerceApi("{client_key}", "{secret_key}");
var response = await commerce.OrderSubscriptionRequestTransfer(new {
order_subscription_id = "sub_abc123",
new_user_id = "user_new_001",
new_username = "김철수",
new_user_email = "chulsoo@example.com",
new_user_phone = "01012345678",
reason = "구독 승계 요청"
});
Console.WriteLine(response);csharp응답
정상 동작 시 예상 응답
현재 이 경로는 구독이 있으면 500 SERVER_ERROR로 끝나요. 아래는 서버 문제가 해결됐을 때의 구독 상세 응답 형태를 보여주는 예시예요.
{
"order_subscription_id": "687a1b2c3d4e5f6789012345",
"order_name": "Professional 플랜 구독",
"status": "subscribing",
"approval_status": "approval_approved_auto",
"user_id": "user_new_001",
"price": 29900,
"current_duration": 6,
"total_subscription_duration": 12
}json응답 파라미터
| 파라미터 | 타입 | 설명 |
|---|---|---|
| order_subscription_id | String | 구독 계약 ID |
| order_name | String | 구독 상품명 |
| status | String | 구독 상태 — 커머스 Enum 참고 |
| approval_status | String | 승인 상태 — 커머스 Enum 참고 |
| user_id | String | 승계가 끝나면 새 구독자 ID, 승인 대기 중이면 기존 구독자 ID |
| price | Number | 회차 결제 금액 |
구독 상태 (status) · 승인 상태 (approval_status)
승계는 구독 상태와 승인 상태를 바꾸지 않아요 — 구독 중이면 subscribing 그대로예요. 승계 요청의 처리 상태는 신청 관리에서 request_status 로 확인해요. 전체 목록은 구독 상태·승인 상태를 봐요.
에러 코드
공통 에러
인증·권한 관련 에러는 에러 코드표를 참고해요.
| 코드 | 메시지 | 대처 방법 |
|---|---|---|
SUBSCRIPTION_TRANSFER_NOT_ALLOWED |
해당 구독 상품은 계약 이전/승계를 지원하지 않아요 | 구독 설정에서 이전/승계를 활성화해요 |
ORDER_SUBSCRIPTION_TRANSFER_REQUEST_DUPLICATE |
이미 대기 중인 이전/승계 요청이 있어요. 관리자가 처리 중이니 잠시만 기다려라. | 기존 요청 처리를 기다려라 |
