에스크로

에스크로 연동

결제·배송등록·구매확정까지 에스크로 전 과정을 연동해요.

에스크로 연동은 ① 결제창을 에스크로로 띄우고, ② 발송 시 배송정보를 전송하고, ③ 구매확정/거절 통지를 처리하는 세 단계로 이뤄져요. 전체 개념과 상태값은 에스크로 개요를 먼저 확인해요.


1에스크로 결제 요청 (프론트엔드)

일반 결제 요청에 extra.escrow: true만 추가하면 에스크로 결제가 돼요. 배송지가 필요하므로 user에 주소 정보를 함께 보내요.

import { Bootpay } from '@bootpay/client-js'

async function requestEscrowPayment() {
    const response = await Bootpay.requestPayment({
        client_key: '[ Client Key ]',
        pg: '이니시스',
        method: 'card',
        order_name: '원목 식탁',
        order_id: 'order_' + Date.now(),
        price: 150000,
        user: {
            username: '홍길동',
            phone: '01012345678',
            addr: '서울특별시 종로구 ...',   // 에스크로는 배송지 정보가 필요해요
        },
        extra: {
            escrow: true,                    // 에스크로 결제 활성화
        },
    })

    if (response.event === 'done') {
        // 결제 완료 → 서버 검증 후 '배송 준비' 상태로 주문 저장
        await verifyPayment(response.receipt_id)
    }
}javascript
결제 후에도 끝이 아니에요

에스크로는 결제 완료(done) 후 배송정보 전송 → 구매확정​​까지 가야 정산돼요. 결제 검증 단계에서 주문을 done이 아니라 배송 준비 같은 중간 상태로 저장하고, 발송 시 배송정보를 전송하도록 설계해요.

결제 요청 파라미터 전반은 결제창 통합 가이드와 같아요. 서버 검증은 결제 조회를 참고해요.


2배송정보 전송 (서버)

상품을 발송하면 택배사·송장번호·배송지를 등록해요. 이 호출로 에스크로 상태가 배송시작(3)으로 바뀌고, 구매자에게 구매확정 안내가 전달돼요.

PUThttps://api.bootpay.co.kr/v2/escrow/shipping/start/{receipt_id}Basic Auth 또는 Bearer 액세스 토큰
연동키에 에스크로 스코프가 필요해요

Basic Auth 로 호출하려면 해당 연동키에 escrow_shipping_start 스코프가 부여돼 있어야 해요. 없으면 API_SCOPE_INVALID (HTTP 401) 로 거부돼요. 관리자 콘솔의 연동키 권한 설정에서 확인해요. 셀러(판매자) 계정 전용이라 리셀러·파트너 키로는 API_ONLY_SELLER 가 떨어져요.

파라미터 타입 필수 설명
receipt_id Path 필수 에스크로 결제의 영수증 ID
tracking_number String 필수 송장(운송장) 번호
delivery_corp String 필수 택배사명. PG별로 인식하는 이름이 달라요 — 아래 표 참고
shipping_prepayment Boolean 선택 배송비 선결제 여부. 현재 구현에서는 false가 무시돼 항상 선불(SH)로 전송​​돼요
shipping_day Integer 선택 배송 예정일 (일 단위). 생략하면 이니시스 기준 5 로 전송돼요
redirect_url String 선택 구매자가 구매확정/거절을 끝낸 뒤 돌아갈 URL. 여기서 등록한 값이 구매확정 화면에 쓰여요
user.username String 선택 수령인 이름. 생략하면 결제 시 저장된 구매자 정보를 그대로 써요
user.phone String 선택 수령인 전화번호. 생략하면 결제 시 저장된 값을 써요
user.address String 선택 배송지 주소. 생략하면 결제 시 같은 address 키로 저장된 값​​만 폴백돼요
user.zipcode String 선택 배송지 우편번호. 생략하면 결제 시 같은 zipcode 키로 저장된 값​​만 폴백돼요
company.name String 선택 발송처(판매자) 이름. 생략하면 가맹점 등록 상호가 쓰여요
company.phone String 선택 발송처 전화번호. 생략하면 가맹점 등록 번호가 쓰여요
company.zipcode String 선택 발송처 우편번호. 현재 이니시스 전송에서는 반영되지 않고 항상 가맹점 등록 우편번호가 쓰여요
company.addr1 String 선택 발송처 주소. 생략하면 가맹점 등록 주소가 쓰여요
company.addr2 String 선택 발송처 상세주소. 생략하면 가맹점 등록 상세주소가 쓰여요

이니시스가 인식하는 delivery_corp 값​: CJ대한통운 한진 롯데 KGB 우체국 로젠 CJGLS 대신 일양로지스 호남 합동 천일 편의점 경동 기타

KCP가 인식하는 값​: 위 목록에 동부 옐로우캡 사가와 직접배달 퀵서비스 추가 (CJGLS 는 없음)

인식하지 못하는 이름은 조용히 "기타"로 전송돼요

매핑에 없는 택배사명을 보내도 오류가 나지 않고 이니시스는 9999(기타), KCP는 ETC(기타)로 전송돼요. 구매자가 송장 조회를 못 하게 되니 위 목록의 이름을 정확히 써요.

배송비 착불은 지정할 수 없어요 (알려진 제약)

shipping_prepayment: false를 보내도 현재 구현에서는 값이 무시되고 항상 선불(SH)로 이니시스에 전송돼요. 착불 배송은 이 API로 표시할 수 없으니, 필요하면 가맹점 주문 정보에 따로 기록해요.

이니시스는 `user` 네 값이 모두 채워져 있어야 해요

이니시스 에스크로는 배송시작 시 수령인 이름·전화·주소·우편번호가 비어 있으면 RC_USER_NAME_BLANK (2713) / RC_USER_PHONE_BLANK (2714) / RC_USER_ADDRESS_BLANK (2715) / RC_USER_ZIPCODE_BLANK (2716) 으로 거부돼요. 폴백은 결제 요청에서 같은 키 이름(address·zipcode) 으로 보낸 값만 되므로, 결제 때 addr 같은 다른 이름으로 보냈다면 이 요청에서 반드시 user.address·user.zipcode를 채워 보내요.

이니시스는 콘솔의 가맹점 정보도 필요해요

이니시스 배송시작은 요청에 company를 보냈는지와 무관하게 관리자 콘솔에 등록된 가맹점 정보를 먼저 검사해요. 상호·주소1·주소2·우편번호·대표번호​​가 모두 채워져 있어야 하고, 하나라도 비면 아래 오류로 거부돼요.

코드 메시지
RC_PROVIDER_NAME_BLANK (2708) 배송정보에 등록할 회사명이 입력되지 않았습니다. 부트페이 관리자에서 입력해주세요.
RC_PROVIDER_ADDR1_BLANK (2709) 배송정보에 등록한 회사 주소가 입력되지 않았습니다. 부트페이 관리자에서 입력해주세요.
RC_PROVIDER_ADDR2_BLANK (2710) 배송정보에 등록할 회사 나머지 주소가 입력되지 않았습니다. 부트페이 관리자에서 입력해주세요.
RC_PROVIDER_ZIP_BLANK (2711) 배송정보에 등록할 회사 우편번호 정보가 입력되지 않았습니다. 부트페이 관리자에서 입력해주세요.
RC_PROVIDER_PHONE_BLANK (2712) 배송정보에 등록할 회사 대표번호 정보가 입력되지 않았습니다. 부트페이 관리자에서 입력해주세요.
KCP는 송장번호·택배사만 전송돼요

KCP 배송정보 전송은 결제 TID·송장번호·택배사만 보내요. 그래서 company뿐 아니라 shipping_prepayment·shipping_day·user 값도 사용되지 않고, 위의 수령인 정보 검증(RC_USER_*)과 가맹점 정보 검증(RC_PROVIDER_*)도 이니시스에서만 수행돼요.

curl -X PUT "https://api.bootpay.co.kr/v2/escrow/shipping/start/RECEIPT_ID" \
  -H "Authorization: Basic $(printf '%s' 'CLIENT_KEY:SECRET_KEY' | base64)" \
  -H "Content-Type: application/json" \
  -d '{
    "tracking_number": "123456789",
    "delivery_corp": "CJ대한통운",
    "shipping_day": 2,
    "user": {
      "username": "홍길동",
      "phone": "01012345678",
      "address": "서울특별시 종로구 ...",
      "zipcode": "03000"
    },
    "company": {
      "name": "부트가구",
      "phone": "0233334444",
      "addr1": "서울특별시 종로구 ...",
      "addr2": "종로빌딩 3층"
    }
  }'bash

응답 예시

배송정보 전송 응답은 결제 조회와 동일한 영수증 전체 payload 이며, 그 안에 escrow_data 가 포함돼요.

{
  "receipt_id":    "6244f60c1fc19202e42e8c4e",
  "order_id":      "order_1700000000",
  "price":         150000,
  "tax_free":      0,
  "order_name":    "원목 식탁",
  "company_name":  "부트가구",
  "method":        "카드",
  "method_symbol": "card",
  "purchased_at":  "2026-06-13T11:02:00+09:00",
  "requested_at":  "2026-06-13T11:01:41+09:00",
  "status_locale": "결제완료",
  "status":        1,
  "currency":      "KRW",
  "escrow_data": {
    "status":              3,
    "status_locale":       "배송시작",
    "shipping_started_at": "2026-06-14T14:13:43+09:00",
    "escrow_confirm_url":  "https://door.bootpay.co.kr/escrow/..."
  }
}json

escrow_data 필드는 다음과 같아요.

필드 타입 설명
status Number 에스크로 상태값
status_locale String 상태 한글명
shipping_started_at String 배송시작 시각 (ISO8601)
receipt_confirmed_at String 구매확정 시각 (ISO8601)
receipt_revoked_at String 구매거절 시각 (ISO8601)
escrow_confirm_url String 이니시스 + 배송시작 상태일 때만 내려오는 구매확정 페이지 URL
값이 없는 필드는 키 자체가 빠져요

escrow_data 는 값이 없는 항목을 null 로 채우지 않고 키를 제거해서 내려줘요. receipt_confirmed_at 같은 필드는 undefined 체크로 읽어요. 드물게 escrow_data 자체가 없거나 null 로 내려오는 경우도 있으니, 하위 필드를 읽기 전에 escrow_data 존재 여부부터 확인하는 방어적 처리를 해요.


3구매확정 / 거절 통지

배송이 시작되면 구매자가 상품을 받고 구매확정 또는 거절(반품)​​을 선택해요. 상태 변경은 두 경로로 통지돼요.

  • 웹훅​: 에스크로 상태가 바뀌면 등록한 웹훅 URL로 통지돼요. 배송정보 전송·구매확정·구매거절·거절승인 모두 이 웹훅으로 통지돼요. 페이로드는 결제 웹훅과 같은 영수증 전체 payload 에 webhook_type: "ESCROW_STATUS_CHANGED", application_id, escrow_webhook: true, escrow_data 가 더해진 형태이고, 빌링키로 결제한 건이면 billing_key 에 빌링키 ID 가 담겨요. 에스크로 상태값은 escrow_data.status 하나만 보면 돼요 — 최상위에는 상태 필드가 없어요.
  • webhook_type 은 API 버전 2.5 이상에서만 채워져요​: 에스크로 웹훅은 결제 웹훅과 달리 빈 값을 걸러내지 않아서, 2.5 미만 프로젝트에서는 webhook_type 키가 빠지는 대신 null 로 내려와요(billing_key 도 빌링 건이 아니면 null). webhook_type 만 보고 분기하면 에스크로 웹훅을 놓칠 수 있으니 escrow_webhook: true 도 함께 확인해요.
  • 결제 조회​: 언제든 GET /v2/receipt/{receipt_id}로 현재 escrow_data.status를 확인할 수 있어요.
{
  "webhook_type": "ESCROW_STATUS_CHANGED",
  "receipt_id": "6244f60c1fc19202e42e8c4e",
  "order_id": "order_1700000000",
  "price": 150000,
  "order_name": "원목 식탁",
  "status_locale": "결제완료",
  "status": 1,
  "application_id": "65a1c0ab8f1b5b00367a0003",
  "escrow_webhook": true,
  "escrow_data": {
    "status": 1,
    "status_locale": "구매확정",
    "shipping_started_at": "2026-06-14T14:13:43+09:00",
    "receipt_confirmed_at": "2026-06-16T10:02:11+09:00"
  }
}json
웹훅도 결제 조회로 검증해요

에스크로 상태 웹훅 역시 위변조될 수 있어요. receipt_id결제 조회를 다시 호출해 escrow_data.status를 확인한 뒤 정산·환불 흐름을 진행해요.

상태별 처리

escrow status 의미 가맹점이 할 일
3 배송시작 배송 중으로 주문 표시
1 구매확정 정산 확정 처리, 주문 완료
-2 구매거절요청 반품/환불 흐름 진행, 재고 복구
-3 구매거절승인 거절이 승인되어 환불 확정. 주문을 환불 완료로 보정
-1 정산보류 운영팀 확인 (분쟁 등)

에러 코드

공통 에러

인증·권한 관련 에러는 에러 코드표를 참고해요.

코드 메시지 대처 방법
RC_NOT_FOUND (2000) 영수증 정보를 찾지 못했습니다. receipt_id가 올바른지 확인해요
RC_NOT_ESCROW (2703) 에스크로 결제건이 아닙니다. 결제 시 extra.escrow: true로 요청했는지, PG가 에스크로를 지원하는지 확인해요
RC_NOT_CONFIRMED (2069) 결제 완료상태건이 아닙니다. 결제가 완료(status: 1)된 뒤에 호출해요
RC_ESCROW_NOT_READY (2700) 에스크로 대기 상태가 아니면 배송 시작을 할 수 없습니다. escrow_data.status0 일 때만 호출해요. 중복 호출을 막아요
RC_TRACKING_NUMBER_BLANK (2706) tracking_number (운송장 번호) 값을 입력해주세요. tracking_number 를 채워 보내요
RC_DELIVERY_CORP_BLANK (2707) delivery_corp (택배회사) 값을 입력해주세요. delivery_corp 를 채워 보내요
RC_ESCROW_SHIPPING_NO_METHOD (2702) 선택된 결제의 PG는 배송시작 API를 지원하지 않습니다. 에스크로 배송정보 전송은 이니시스·KCP만 지원해요 (HTTP 404)
RC_ESCROW_SHIPPING_START_FAILED (2701) PG가 내려준 실패 메시지 원문 (이니시스 resultMsg / KCP res_msg) HTTP 500 으로 내려와요. pg_error_code 에 PG 응답 코드가, message 에 PG 메시지가 그대로 담기니 이 값으로 원인을 확인하고 택배사명·송장번호·배송지 형식을 점검해요
API_ONLY_SELLER (600) 판매점 계정만 사용할 수 있는 API입니다. 리셀러/파트너 키가 아니라 셀러 프로젝트 키로 호출해요

다음 단계

  • 상태 변경 통지 처리는 웹훅을 확인해요.
  • 거절(구매취소) 시 환불은 결제 취소을 참고해요.
  • 택배사 코드는 택배사 목록을 확인해요.