구독을 일시 중단하여 결제를 멈춰요.
고객이 일시정지 요청
고객이 직접 구독 일시정지를 요청해요. 구독 설정에 따라 관리자 승인이 필요할 수 있어요.
API 엔드포인트
요청 파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
order_subscription_id |
String | 필수 | 구독 계약 고유 번호 |
user_id |
String | 선택 | 로그인한 회원 ID 또는 이 몰의 외부 회원 ID. 보내면 구독 소유자와 대조해요. Bootpay-User-JWT 헤더로 보내도 돼요 |
paused_at |
String | 선택 | 일시정지 시작일 (ISO 8601, 비우면 지금) |
expected_resume_at |
String | 필수 | 재개 예정일 (ISO 8601) |
reason |
String | 필수 | 일시정지 요청 사유 |
코드 예제
const { BootpayCommerce } = require('@bootpay/backend-js')
const commerce = new BootpayCommerce({
client_key: 'your-commerce-client-key',
secret_key: 'your-commerce-secret-key',
mode: 'production'
})
const response = await commerce.orderSubscription.requestPause({
order_subscription_id: '687a1b2c3d4e5f6789012345',
paused_at: '2025-08-01T00:00:00Z',
expected_resume_at: '2025-09-01T00:00:00Z',
reason: '여행으로 인한 일시정지 요청'
})
console.log(response)javascriptfrom bootpay_backend import BootpayCommerce
commerce = BootpayCommerce(
client_key='your-commerce-client-key',
secret_key='your-commerce-secret-key',
mode='production'
)
response = commerce.order_subscription.request_pause(
order_subscription_id='687a1b2c3d4e5f6789012345',
paused_at='2025-08-01T00:00:00Z',
expected_resume_at='2025-09-01T00:00:00Z',
reason='여행으로 인한 일시정지 요청'
)
print(response)pythonuse Bootpay\ServerPhp\BootpayCommerceApi;
$commerce = new BootpayCommerceApi("your-commerce-client-key", "your-commerce-secret-key");
$response = $commerce->orderSubscription->requestPause([
'order_subscription_id' => '687a1b2c3d4e5f6789012345',
'paused_at' => '2025-08-01T00:00:00Z',
'expected_resume_at' => '2025-09-01T00:00:00Z',
'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.OrderSubscriptionPauseParams;
TokenPayload tp = new TokenPayload("your-commerce-client-key", "your-commerce-secret-key");
BootpayStore commerce = new BootpayStore(tp).withToken();
OrderSubscriptionPauseParams params = new OrderSubscriptionPauseParams();
params.orderSubscriptionId = "687a1b2c3d4e5f6789012345";
params.pausedAt = "2025-08-01T00:00:00Z";
params.expectedResumeAt = "2025-09-01T00:00:00Z";
params.reason = "여행으로 인한 일시정지 요청";
BootpayStoreResponse response = commerce.orderSubscription.requestIng.pause(params);
System.out.println(response);javarequire 'bootpay'
commerce = BootpayStore::RestClient.new(client_key: 'your-commerce-client-key', secret_key: 'your-commerce-secret-key')
response = commerce.order_subscription_requests_ing_pause(
order_subscription_id: '687a1b2c3d4e5f6789012345',
paused_at: '2025-08-01T00:00:00Z',
expected_resume_at: '2025-09-01T00:00:00Z',
reason: '여행으로 인한 일시정지 요청'
)
puts responserubycommerce := bootpay.NewCommerceApi("your-commerce-client-key", "your-commerce-secret-key")
response, err := commerce.OrderSubscription.RequestPause(bootpay.OrderSubscriptionRequestPauseParams{
OrderSubscriptionID: "687a1b2c3d4e5f6789012345",
PausedAt: "2025-08-01T00:00:00Z",
ExpectedResumeAt: "2025-09-01T00:00:00Z",
Reason: "여행으로 인한 일시정지 요청",
})
fmt.Println(response)gousing Bootpay.Commerce;
var commerce = new BootpayCommerceApi("your-commerce-client-key", "your-commerce-secret-key");
var response = await commerce.OrderSubscription.RequestPause(new {
order_subscription_id = "687a1b2c3d4e5f6789012345",
paused_at = "2025-08-01T00:00:00Z",
expected_resume_at = "2025-09-01T00:00:00Z",
reason = "여행으로 인한 일시정지 요청"
});
Console.WriteLine(response);csharp응답
성공 응답
요청이 반영된 구독 계약 상세 전체를 돌려줘요. 아래는 일부만 추린 예시예요.
{
"order_subscription_id": "687a1b2c3d4e5f6789012345",
"status": "temporarily_paused",
"paused_at": "2025-08-01T00:00:00+09:00",
"pause_expected_resume_at": "2025-09-01T00:00:00+09:00",
"request_histories": [
{ "request_type": "request_pause", "request_status": "request_approved_auto" }
]
}json응답 필드 설명
| 필드 | 타입 | 설명 |
|---|---|---|
order_subscription_id |
String | 구독 계약 고유 ID |
status |
String | 구독 상태. 자동 승인이면 temporarily_paused(일시정지), 관리자 승인이 필요하면 승인 전까지 그대로예요 |
paused_at |
String | 일시정지 시작일 |
pause_expected_resume_at |
String | 재개 예정일 |
request_histories |
Array | 이 구독의 요청 이력. 일시정지 요청은 request_type 이 request_pause (내부값 11). 요청 유형 전체 |
에러 코드
공통 에러
인증·권한 관련 에러는 에러 코드표를 참고해요.
| 코드 | 메시지 | 대처 방법 |
|---|---|---|
ORDER_SUBSCRIPTION_PAUSE_UNABLE |
해당 구독 상품은 일시정지를 지원하지 않는 정책이에요 | 구독 정책을 확인해요 |
SUBSCRIPTION_PAUSE_NOT_ALLOWED |
해당 구독 상품은 일시정지 기능을 제공하지 않아요 | 구독 설정에서 일시정지를 활성화해요 |
SUBSCRIPTION_PAUSE_COUNT_EXCEEDED |
일시정지 횟수가 초과됐어요. | 최대 일시정지 횟수를 확인해요 |
SUBSCRIPTION_RESUME_REASON_REQUIRED |
사유를 입력해야 해요. | reason 을 보내요 (코드명과 달리 일시정지 사유 누락이에요) |
SUBSCRIPTION_PAUSE_RESUME_DATE_REQUIRED |
일시정지 재개 날짜를 입력해야 해요. | expected_resume_at 을 보내요 |
SUBSCRIPTION_PAUSE_DURATION_TOO_LONG |
일시정지 기간이 너무 길어 최대 일시정지 기간을 초과했어요. | 템플릿의 최대 일시정지 기간을 확인해요 |
SUBSCRIPTION_PAUSE_TOTAL_DAYS_EXCEEDED |
총 일시정지 일수가 최대 허용 일수를 초과했어요. | 누적 일시정지 일수를 확인해요 |
SUBSCRIPTION_PAUSE_STATUS_INVALID |
유효하지 않은 일시정지 상태예요. | 구독 중 상태인지 확인해요 |
ORDER_SUBSCRIPTION_PAUSE_REQUEST_DUPLICATE |
이미 대기 중인 일시정지 요청이 있어요. | 기존 요청 처리를 기다려요 |
일시정지는 구독 상태가 구독 중(1)일 때만 요청 가능해요. 구독 설정에서 use_pause가 활성화되어 있어야 해요.
알려진 문제 — 고객 일시정지에는 subscription.paused 웹훅이 오지 않아요
관리자가 일시정지 처리
관리자가 직접 구독 계약을 일시정지해요. 고객 요청 없이 관리자가 즉시 정지할 수 있어요.
이 API는 관리자(Supervisor) 권한이 필요해요.
고객 요청 vs 관리자 직접 정지
| 구분 | 고객 요청 | 관리자 직접 정지 |
|---|---|---|
| API | 고객 일시정지 요청 | 이 API |
| 승인 과정 | 관리자 승인 필요 (설정에 따라) | 즉시 정지 |
| 재개 예정일 | 고객이 설정 | 관리자가 설정 |
API 엔드포인트
PUT
https://api.bootapi.com/v1/order_subscriptions/:order_subscription_id/pauseBasic Auth (supervisor 권한 필요)요청 파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
order_subscription_id |
String | 필수 | 구독 계약 ID (URL 파라미터) |
paused_at |
String | 필수 | 정지 시작일 (ISO 8601). 즉시 멈추려면 지금 시각을 넣어요 |
expected_resume_at |
String | 필수 | 예상 재개일 (ISO 8601). 지금부터 1년 이내여야 해요 |
reason |
String | 선택 | 정지 사유 |
코드 예제
curl -X PUT "https://api.bootapi.com/v1/order_subscriptions/{order_subscription_id}/pause" \
-H "Authorization: Basic {base64(client_key:secret_key)}" \
-H "Content-Type: application/json" \
-d '{
"reason": "결제 수단 문제로 일시정지",
"paused_at": "2025-07-11T15:00:00+09:00",
"expected_resume_at": "2025-08-01T00:00:00+09:00"
}'bashconst { BootpayCommerce } = require('@bootpay/backend-js');
const commerce = new BootpayCommerce({
client_key: '{client_key}',
secret_key: '{secret_key}'
});
const response = await commerce.orderSubscription.adminPause(
'sub_abc123',
{
reason: '결제 수단 문제로 일시정지',
paused_at: '2025-07-11T15:00:00+09:00',
expected_resume_at: '2025-08-01T00:00:00+09:00'
}
);
console.log(response);javascriptfrom bootpay_backend.commerce import BootpayCommerce
commerce = BootpayCommerce('{client_key}', '{secret_key}')
response = commerce.order_subscription_admin_pause(
'sub_abc123',
{
'reason': '결제 수단 문제로 일시정지',
'paused_at': '2025-07-11T15:00:00+09:00',
'expected_resume_at': '2025-08-01T00:00:00+09:00'
}
)
print(response)pythonuse Bootpay\ServerPhp\BootpayCommerceApi;
$commerce = new BootpayCommerceApi("{client_key}", "{secret_key}");
$response = $commerce->orderSubscriptionAdminPause('sub_abc123', [
'reason' => '결제 수단 문제로 일시정지',
'paused_at' => '2025-07-11T15:00:00+09:00',
'expected_resume_at' => '2025-08-01T00:00:00+09:00'
]);
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.SupervisorPauseParams;
TokenPayload tokenPayload = new TokenPayload("{client_key}", "{secret_key}");
BootpayStore commerce = new BootpayStore(tokenPayload).withToken();
SupervisorPauseParams params = new SupervisorPauseParams();
params.reason = "결제 수단 문제로 일시정지";
params.pausedAt = "2025-07-11T15:00:00+09:00";
params.expectedResumeAt = "2025-08-01T00:00:00+09:00";
BootpayStoreResponse response = commerce.orderSubscription.supervisorPause("sub_abc123", params);
System.out.println(response);javarequire 'bootpay'
commerce = BootpayStore::RestClient.new(client_key: '{client_key}', secret_key: '{secret_key}')
response = commerce.supervisor_request_order_subscription_pause(
order_subscription_id: 'sub_abc123',
paused_at: '2025-08-01T00:00:00Z',
expected_resume_at: '2025-09-01T00:00:00Z',
reason: '결제 수단 문제로 일시정지'
)
puts responserubycommerce := bootpay.NewCommerceApi("{client_key}", "{secret_key}")
response, err := commerce.OrderSubscriptionAdminPause("sub_abc123", map[string]interface{}{
"reason": "결제 수단 문제로 일시정지",
"paused_at": "2025-07-11T15:00:00+09:00",
"expected_resume_at": "2025-08-01T00:00:00+09:00",
})
fmt.Println(response)govar commerce = new BootpayCommerceApi("{client_key}", "{secret_key}");
var response = await commerce.OrderSubscriptionAdminPause("sub_abc123", new {
reason = "결제 수단 문제로 일시정지",
paused_at = "2025-07-11T15:00:00+09:00",
expected_resume_at = "2025-08-01T00:00:00+09:00"
});
Console.WriteLine(response);csharp응답
{
"order_subscription_id": "687a1b2c3d4e5f6789012345",
"status": "temporarily_paused",
"paused_at": "2025-07-11T15:00:00+09:00",
"pause_expected_resume_at": "2025-08-01T00:00:00+09:00"
}json응답 필드 설명
| 파라미터 | 타입 | 설명 |
|---|---|---|
| order_subscription_id | String | 구독 계약 ID |
| status | String | 변경된 상태 (temporarily_paused: 일시정지) |
| paused_at | String | 정지 시작 시각 |
| pause_expected_resume_at | String | 예상 재개 시각 |
정지 사유는 응답에 담기지 않아요. 계약 상세의 pause_reason 으로 확인해요.
에러 코드
공통 에러
인증·권한 관련 에러는 에러 코드표를 참고해요.
| 코드 | 메시지 | 대처 방법 |
|---|---|---|
ORDER_SUBSCRIPTION_NOT_FOUND |
구독결제 건을 찾을 수 없어요. | order_subscription_id를 확인해요 |
ORDER_SUBSCRIPTION_ALREADY_PAUSE |
이미 일시정지가 진행된 구독이에요 | 구독 상태를 확인해요 |
ORDER_SUBSCRIPTION_EXPECTED_RESUME_AT_INVALID |
구독 재개 시간이 현재보다 과거이거나 1년 이후는 설정할 수 없어요. | expected_resume_at 을 지금부터 1년 이내로 보내요 |
TIME_INVALID |
시간 포맷이 잘못되었어요. ISO 8601 표준시 포맷으로 보내요. | paused_at·expected_resume_at 형식을 확인해요 |
