이 문서는 등록된 예약결제를 reserve_id로 조회하는 방법을 설명해요.
예약 조회는 실행 전 취소 가능 여부를 확인하거나, 웹훅 처리 실패 후 예약 상태를 보정할 때 사용해요.
핵심 요약
- 예약 조회는
reserve_id기준으로 대기·완료·실패·취소 상태를 확인해요. - 예약 취소 전에는 먼저 조회해서 아직 실행 전인지 확인하는 흐름이 안전해요.
- 이미 결제가 실행된 예약은 예약 취소가 아니라
receipt_id기준 결제 취소 흐름으로 가야 해요. - 내부 DB의 예약 상태와 Bootpay 조회 결과가 다르면 조회 결과를 기준으로 보정해요.
상태 흐름
API 엔드포인트
GET
https://api.bootpay.co.kr/v2/subscribe/payment/reserve/:reserve_idBasic Auth요청 파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
reserve_id |
String | 필수 | 예약 결제 ID (URL 파라미터) |
코드 예제
import { Bootpay } from '@bootpay/backend-js'
Bootpay.setConfiguration({
client_key: '[ Client Key ]',
secret_key: '[ Secret Key ]'
})
try {
const response = await Bootpay.subscribePaymentReserveLookup(
'6261104e1fc19202e6f9420e'
)
console.log(response)
} catch (e) {
console.log(e)
}javascriptfrom bootpay_backend import BootpayBackend
bootpay = BootpayBackend(client_key='CLIENT_KEY', secret_key='SECRET_KEY')
response = bootpay.subscribe_payment_reserve_lookup('6261104e1fc19202e6f9420e')
print(response)pythonuse Bootpay\ServerPhp\BootpayApi;
BootpayApi::setClientKeyConfiguration('CLIENT_KEY', 'SECRET_KEY');
$response = BootpayApi::subscribePaymentReserveLookup('6261104e1fc19202e6f9420e');
print_r($response);phpimport kr.co.bootpay.pg.Bootpay;
Bootpay bootpay = Bootpay.withClientKey("CLIENT_KEY", "SECRET_KEY");
var response = bootpay.reserveSubscribeLookup("6261104e1fc19202e6f9420e");
System.out.println(response);javabootpay = Bootpay::Api.new(client_key: 'CLIENT_KEY', secret_key: 'SECRET_KEY')
response = bootpay.request(
method: :get,
uri: 'subscribe/payment/reserve/6261104e1fc19202e6f9420e'
)
puts response.datarubyimport "github.com/bootpay/backend-go/v2"
api := bootpay.NewAPIWithClientKey("CLIENT_KEY", "SECRET_KEY", nil, "")
response, err := api.ReserveSubscribeLookup("6261104e1fc19202e6f9420e")
if err != nil {
log.Fatal(err)
}
fmt.Println(response)gousing Bootpay;
var bootpay = BootpayApi.WithClientKey("CLIENT_KEY", "SECRET_KEY");
var response = await bootpay.ReserveSubscribeLookup("6261104e1fc19202e6f9420e");
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);csharp응답
예약 조회 결과는 status를 기준으로 내부 예약 상태를 보정해요. 실행이 끝난 예약은 receipt_id로 결제 조회를 한 번 더 호출해 금액과 결제 상태를 확인해야 해요.
응답은 값이 없는 필드를 아예 내려보내지 않아요. 예를 들어 아직 실행 전인 예약에는 reserve_started_at·reserve_finished_at 키 자체가 없어요. null 비교 대신 키 존재 여부로 판단해야 안전해요.
{
"reserve_id": "6261104e1fc19202e6f9420e",
"order_id": "reserve_1705289520000",
"price": 9900,
"tax_free": 0,
"order_name": "예약 잔금 결제",
"user": {
"username": "홍길동",
"phone": "01012345678"
},
"feedback_url": "https://example.com/webhook",
"content_type": "application/json",
"version": 2,
"extra": {},
"metadata": {
"internal_order_no": "A-1024"
},
"reserve_requested_at": "2025-02-01T09:00:00+09:00",
"reserve_execute_at": "2025-02-01T09:00:00+09:00",
"status": 0
}json{
"reserve_id": "6261104e1fc19202e6f9420e",
"receipt_id": "6244f60c1fc19202e42e8c4e",
"order_id": "reserve_1705289520000",
"price": 9900,
"tax_free": 0,
"order_name": "예약 잔금 결제",
"user": {
"username": "홍길동",
"phone": "01012345678"
},
"feedback_url": "https://example.com/webhook",
"content_type": "application/json",
"version": 2,
"extra": {},
"metadata": {
"internal_order_no": "A-1024"
},
"reserve_requested_at": "2025-02-01T09:00:00+09:00",
"reserve_execute_at": "2025-02-01T09:00:00+09:00",
"reserve_started_at": "2025-02-01T09:00:00+09:00",
"reserve_finished_at": "2025-02-01T09:00:03+09:00",
"status": 1
}json{
"reserve_id": "6261104e1fc19202e6f9420e",
"order_id": "reserve_1705289520000",
"price": 9900,
"tax_free": 0,
"order_name": "예약 잔금 결제",
"user": {
"username": "홍길동",
"phone": "01012345678"
},
"feedback_url": "https://example.com/webhook",
"content_type": "application/json",
"version": 2,
"extra": {},
"metadata": {
"internal_order_no": "A-1024"
},
"reserve_requested_at": "2025-02-01T09:00:00+09:00",
"reserve_execute_at": "2025-02-01T09:00:00+09:00",
"reserve_started_at": "2025-02-01T09:00:00+09:00",
"reserve_finished_at": "2025-02-01T09:00:02+09:00",
"status": -1
}json{
"reserve_id": "6261104e1fc19202e6f9420e",
"order_id": "reserve_1705289520000",
"price": 9900,
"tax_free": 0,
"order_name": "예약 잔금 결제",
"user": {
"username": "홍길동",
"phone": "01012345678"
},
"feedback_url": "https://example.com/webhook",
"content_type": "application/json",
"version": 2,
"extra": {},
"metadata": {
"internal_order_no": "A-1024"
},
"reserve_requested_at": "2025-02-01T09:00:00+09:00",
"reserve_execute_at": "2025-02-01T09:00:00+09:00",
"reserve_revoked_at": "2025-01-20T10:10:00+09:00",
"status": 3
}json응답 파라미터
| 파라미터 | 타입 | 설명 |
|---|---|---|
| reserve_id | String | 예약 결제 ID |
| receipt_id | String | 예약 실행으로 만들어진 결제 건 ID. 결제가 성공한 경우에만 내려와요 |
| price | Number | 결제 금액 |
| tax_free | Number | 비과세 금액 |
| order_id | String | 가맹점 주문번호 |
| order_name | String | 주문명 |
| user | Object | 구매자 정보 |
| extra | Object | 예약 등록 시 전달한 부가 옵션 |
| metadata | Object | 예약 등록 시 전달한 커스텀 데이터 |
| reserve_requested_at | Date | 예약 요청 시간. 현재 구현상 reserve_execute_at과 같은 값이 내려와요 |
| reserve_execute_at | Date | 예약 실행 시간 |
| reserve_started_at | Date | 실행 시작 시간 |
| reserve_finished_at | Date | 실행 완료 시간 |
| reserve_revoked_at | Date | 예약 취소 시간 |
| feedback_url | String | 웹훅 수신 URL |
| content_type | String | 웹훅 데이터 타입. 항상 포함되고 application/json 또는 application/x-www-form-urlencoded예요 |
| version | Number | 예약 등록 API 버전. 이 문서의 API로 등록한 예약은 항상 2이고, 1은 v1 레거시 예약이에요 |
| status | Number | 예약 결제 상태 |
status 값
| 값 | 설명 | 서버 처리 |
|---|---|---|
| -1 | 예약 실행 실패 (빌링 결제 실패 포함) | 실패 사유를 확인하고 고객 안내 또는 재청구를 진행해요 |
| 0 | 대기 중 (실행 전) | 필요하면 예약 취소 가능 |
| 1 | 결제 완료 | receipt_id 기준 결제 조회 후 주문 확정 |
| 2 | (v1 레거시) 빌링 결제 실패 | 현재 API로 등록한 예약에는 쓰이지 않아요. 빌링 결제 실패도 -1로 내려와요 |
| 3 | 예약 취소됨 | 내부 예약 상태를 cancelled로 보정 |
상태 보정 기준
내부 DB에는 reserved, cancelled, paid, failed처럼 서비스 운영에 맞는 상태값을 두고, Bootpay 조회 결과를 기준으로 보정해요. 같은 reserve_id로 여러 번 조회해도 같은 결과가 반영되도록 멱등 처리해야 해요.
에러 코드
공통 에러
인증·권한 관련 에러는 에러 코드표를 참고해요.
| 코드 | 메시지 | 대처 방법 |
|---|---|---|
BS_NOT_FOUND (2504) |
예약결제 정보를 찾지 못했다 | reserve_id가 올바른지 확인해요 |
BS_UNAUTHORIZED (2509) |
예약결제 접근 권한 없음 | 해당 예약의 소유자 계정으로 요청해요 |
에러 응답 본문
에러는 error_code, message를 담은 JSON으로 내려와요. error_code는 숫자가 아니라 상수 이름 문자열이고, PG 오류가 함께 있으면 pg_error_code가, 추가 정보가 있으면 payload가 함께 들어와요.
{
"error_code": "BS_NOT_FOUND",
"message": "예약결제 정보를 찾지 못했습니다."
}json