결제 시작
배송지와 결제 옵션(`option`: PG·결제수단·간편결제사)으로 결제를 시작하고 결제 서비스 주소(`payUrl`)를 돌려준다. `option`은 주문서의 `paymentOptions` 항목을 그대로 보내거나 직접 쓴다. 스토어프론트는 `payUrl`을 팝업(쿼리 `mode=popup`)이나 전체 페이지로 열고, 결제 서비스가 PG 결제창을 띄워 승인까지 마친다(`@sayren/storefront-sdk/payments`). 결제가 끝나면 구매자는 `returnUrl`로 돌아오고, 결과는 결제 상태 조회로 확정한다. `returnUrl`은 https여야 한다(테스트 결제는 localhost 허용). 상점 결제 도메인(상점 플랫폼 설정 › 결제)을 등록했다면 그 안이어야 한다. PG 시크릿은 물론 결제창 호출 값도 이 응답에 담기지 않는다. 비회원은 `guest`가 필수다. `testPayment`가 true면 상점이 테스트 결제(샌드박스) 중이라 실제로 돈이 나가지 않는다. **보낸 배송지로 배송비를 다시 계산해 결제 금액을 확정한다** — 제주·도서산간 추가 배송비 때문에 주문서 조회 시점의 `amounts`와 다를 수 있다. 확정 금액은 이 응답의 `amounts`이고, 미리 보려면 배송비 미리보기를 쓴다. 계좌이체·가상계좌 옵션은 `cashReceipt`로 현금영수증을 신청할 수 있다. 결제가 승인되면 결제한 PG로 발급하고 환불하면 그만큼 취소한다. 회원은 `pointAmount`로 적립금을 쓴다. 계산은 금액 미리보기와 같고, 결제 시작이 그 금액을 예약한다. 결제가 실패하거나 만료되면 예약을 풀어 잔액으로 돌린다. **적립금이 결제 금액 전체를 덮으면(0원 결제) 결제창 없이 이 요청에서 주문을 만든다** — `option`을 생략할 수 있고, 응답은 `status: "completed"`·`orderId`이며 `payUrl`·`attemptId`·`option`이 null이다. 이 결제는 재시도할 수 없다(409 `ALREADY_PROCESSED`). 헤더 `Idempotency-Key`를 보내면 같은 키의 재요청에 처음 결과를 돌려주고, 같은 키의 동시 요청은 409 `IDEMPOTENCY_KEY_IN_USE`다.
배송지와 결제 옵션(option: PG·결제수단·간편결제사)으로 결제를 시작하고 결제 서비스 주소(payUrl)를 돌려준다. option은 주문서의 paymentOptions 항목을 그대로 보내거나 직접 쓴다. 스토어프론트는 payUrl을 팝업(쿼리 mode=popup)이나 전체 페이지로 열고, 결제 서비스가 PG 결제창을 띄워 승인까지 마친다(@sayren/storefront-sdk/payments). 결제가 끝나면 구매자는 returnUrl로 돌아오고, 결과는 결제 상태 조회로 확정한다. returnUrl은 https여야 한다(테스트 결제는 localhost 허용). 상점 결제 도메인(상점 플랫폼 설정 › 결제)을 등록했다면 그 안이어야 한다. PG 시크릿은 물론 결제창 호출 값도 이 응답에 담기지 않는다. 비회원은 guest가 필수다. testPayment가 true면 상점이 테스트 결제(샌드박스) 중이라 실제로 돈이 나가지 않는다. 보낸 배송지로 배송비를 다시 계산해 결제 금액을 확정한다 — 제주·도서산간 추가 배송비 때문에 주문서 조회 시점의 amounts와 다를 수 있다. 확정 금액은 이 응답의 amounts이고, 미리 보려면 배송비 미리보기를 쓴다. 계좌이체·가상계좌 옵션은 cashReceipt로 현금영수증을 신청할 수 있다. 결제가 승인되면 결제한 PG로 발급하고 환불하면 그만큼 취소한다. 회원은 pointAmount로 적립금을 쓴다. 계산은 금액 미리보기와 같고, 결제 시작이 그 금액을 예약한다. 결제가 실패하거나 만료되면 예약을 풀어 잔액으로 돌린다. 적립금이 결제 금액 전체를 덮으면(0원 결제) 결제창 없이 이 요청에서 주문을 만든다 — option을 생략할 수 있고, 응답은 status: "completed"·orderId이며 payUrl·attemptId·option이 null이다. 이 결제는 재시도할 수 없다(409 ALREADY_PROCESSED). 헤더 Idempotency-Key를 보내면 같은 키의 재요청에 처음 결과를 돌려주고, 같은 키의 동시 요청은 409 IDEMPOTENCY_KEY_IN_USE다.
회원 accessToken
In: header
Path Parameters
Header Parameters
멱등키. 같은 키로 다시 보내면 처음 결과를 돌려주고 한 번만 적용한다. 재시도에는 같은 키를 쓴다
length <= 255Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
결제 옵션. 결제 금액이 남으면 필수이고 없으면 400 VALIDATION_FAILED다. 적립금이 결제 금액 전체를 덮는 주문(0원 결제, #93)은 생략한다
결제를 마치면 돌아올 스토어프론트 주소. 상점 결제 도메인에 등록된 도메인이어야 한다
urilength <= 2048배송지. 주문서의 requiresShipping이 true면 필수이고 없으면 400 SHIPPING_ADDRESS_REQUIRED다. 배송이 필요 없는 주문(배송 없는 상품만)은 보내지 않아도 된다. 보내면 형식을 검사한 뒤 버린다
현금영수증 신청. 계좌이체·가상계좌 옵션에서만 보낼 수 있다(그 밖의 옵션이면 400 CASH_RECEIPT_NOT_AVAILABLE). 결제가 승인되면 발급한다
적용할 쿠폰(이슈 #47). 결제 시작이 쿠폰을 예약하고 할인한 금액으로 결제 금액을 정한다 — 응답의 amounts가 확정 금액이다. 적용하지 못하는 쿠폰이 하나라도 있으면 400 COUPON_NOT_APPLICABLE(details에 사유)이다. 결제가 실패하거나 만료되면 예약이 풀린다. 쿠폰을 바꾸려면 새로 결제를 시작한다(재시도는 같은 쿠폰을 쓴다)
items <= 5쓸 적립금(#93, 회원만). 결제 시작이 예약하고 쿠폰 뒤 금액에서 뺀다 — 응답 amounts.pointAmount가 실제 사용액이다(단위로 내리고, 남는 결제 금액이 1~99원이면 100원을 남긴다). 적립금이 결제 금액 전체를 덮으면 결제창 없이 이 요청에서 주문이 만들어진다(응답 status: "completed"·orderId, payUrl·attemptId·option은 null). 적립금 사용이 꺼져 있으면 409 POINTS_UNAVAILABLE, 쓸 수 없으면 400 POINT_NOT_APPLICABLE(details.reason), 그 사이 잔액이 줄었으면 409 POINT_BALANCE_CHANGED다. 결제가 실패하거나 만료되면 예약이 풀린다
0 <= valueResponse Body
application/json
curl -X POST "https://example.com/storefront/v1/checkout/string/payment" \ -H "Content-Type: application/json" \ -d '{ "returnUrl": "http://example.com" }'{ "meta": { "status": 200, "code": "OK", "message": "OK", "isSuccess": true }, "data": { "paymentId": "string", "status": "pending", "orderId": null, "attemptId": "string", "option": { "pg": "tosspayments", "method": "CARD" }, "payUrl": "string", "expiresAt": "string", "testPayment": true, "amounts": { "productAmount": 0, "deliveryFee": 0, "totalAmount": 0, "couponDiscountAmount": 0, "deliveryDiscountAmount": 0, "pointAmount": 0 }, "delivery": { "baseFee": 0, "remoteSurcharge": 0, "remoteArea": "NONE", "remoteAreaLabel": "string", "bundleCount": 0, "freeByThreshold": true, "zipCode": "string" } }, "error": null}