결제 거래의 처리 과정

판매자가 결제 앱을 통합하는 방법과 Payment Request API를 사용한 결제 거래의 작동 방식을 알아보세요.

Web Payments API는 처음으로 브라우저에 내장된 전용 결제 기능입니다. 웹 결제를 사용하면 판매자가 결제 앱과 통합하는 것이 더 간편해지고 고객 경험이 간소화되고 더 안전해집니다.

웹 결제 사용의 이점에 대해 자세히 알아보려면 웹 결제로 결제 앱 지원을 참고하세요.

이 도움말에서는 판매자 웹사이트의 결제 트랜잭션을 안내하고 결제 앱 통합의 작동 방식을 이해하는 데 도움이 됩니다.

이 프로세스는 6단계로 이루어집니다.

  1. 판매자가 결제 거래를 시작합니다.
  2. 판매자가 결제 버튼을 표시합니다.
  3. 고객이 결제 버튼을 누릅니다.

    BobPay(결제 앱) 버튼이 있는 치즈 가게 웹사이트의 다이어그램

  4. 브라우저가 결제 앱을 실행합니다.

    모달로 출시된 BobPay 앱이 있는 치즈 매장 웹사이트의 다이어그램 이 대화상자에는 배송 옵션과 총 비용이 표시됩니다.

  5. 고객이 세부정보(예: 배송 옵션 또는 주소)를 변경하면 판매자가 변경사항을 반영하여 거래 세부정보를 업데이트합니다.

    BobPay 앱 모달에서 고객이 다른 배송 옵션을 선택하는 모습을 보여주는 다이어그램 판매자가 BobPay에 표시된 총 비용을 업데이트하는 모습을 보여주는 두 번째 다이어그램

  6. 고객이 구매를 확인하면 판매자는 결제를 검증하고 거래를 완료합니다.

    고객이 버튼을 누르고 있는 모습을 보여주는 다이어그램

1단계: 판매자가 결제 거래를 시작합니다.

고객이 구매하기로 결정하면 판매자는 PaymentRequest 객체를 생성하여 결제 거래를 시작합니다. 이 객체에는 거래에 관한 다음과 같은 중요한 정보가 포함됩니다.

  • 허용되는 결제 수단 및 거래를 처리하기 위한 데이터
  • 총 가격(필수사항) 및 상품 정보와 같은 세부정보
  • 판매자가 배송지 주소, 배송 옵션과 같은 배송 정보를 요청할 수 있는 옵션입니다.
  • 판매자는 청구서 수신 주소, 지급인 이름, 이메일, 전화번호를 요청할 수도 있습니다.
  • 판매자는 PaymentRequest에 선택적 배송 유형(shipping, delivery 또는 pickup)을 포함할 수도 있습니다. 결제 앱은 이를 힌트로 사용하여 UI에 올바른 라벨을 표시할 수 있습니다.
const request = new PaymentRequest([{
  supportedMethods: 'https://bobpay.xyz/pay',
  data: {
    transactionId: '****'
  }
}], {
  displayItems: [{
    label: 'Anvil L/S Crew Neck - Grey M x1',
    amount: { currency: 'USD', value: '22.15' }
  }],
  total: {
    label: 'Total due',
    amount: { currency: 'USD', value : '22.15' }
  }
}, {
  requestShipping: true,
  requestBillingAddress: true,
  requestPayerEmail: true,
  requestPayerPhone: true,
  requestPayerName: true,
  shippingType: 'delivery'
});
거래 ID 포함

일부 결제 처리자는 판매자가 거래 정보의 일부로 사전에 발급한 거래 ID를 제공하도록 요구할 수 있습니다. 일반적인 통합에는 총 가격을 예약하기 위해 판매자와 결제 핸들러의 서버 간의 통신이 포함됩니다. 이렇게 하면 악의적인 고객이 거래가 끝날 때 가격을 조작하고 유효성 검사를 통해 판매자를 속이는 것을 방지할 수 있습니다.

판매자는 PaymentMethodData 객체의 data 속성의 일부로 거래 ID를 전달할 수 있습니다.

거래 정보가 제공되면 브라우저는 결제 수단 식별자를 기반으로 PaymentRequest에 지정된 결제 앱의 검색 프로세스를 거칩니다. 이렇게 하면 브라우저에서 판매자가 거래를 진행할 준비가 되는 즉시 실행할 결제 앱을 결정할 수 있습니다.

탐색 프로세스의 작동 방식을 자세히 알아보려면 결제 수단 설정을 참조하세요.

2단계: 판매자에게 결제 버튼 표시

판매자는 여러 결제 수단을 지원할 수 있지만 고객이 실제로 사용할 수 있는 결제 버튼만 표시해야 합니다. 사용할 수 없는 결제 버튼을 표시하면 사용자 환경이 저하됩니다. 판매자가 PaymentRequest 객체에 지정된 결제 수단이 고객에게 작동하지 않을 것으로 예상할 수 있는 경우 대체 솔루션을 제공하거나 해당 버튼을 전혀 표시하지 않을 수 있습니다.

판매자는 PaymentRequest 인스턴스를 사용하여 고객이 결제 앱을 사용할 수 있는지 쿼리할 수 있습니다.

고객이 결제 앱을 사용할 수 있나요?

PaymentRequestcanMakePayment() 메서드는 고객의 기기에서 결제 앱을 사용할 수 있는 경우 true를 반환합니다. '사용 가능'은 결제 수단을 지원하는 결제 앱이 검색되고 플랫폼별 결제 앱이 설치되었거나 웹 기반 결제 앱이 등록될 준비가 되었다는 것을 의미합니다.

const canMakePayment = await request.canMakePayment();
if (!canMakePayment) {
  // Fallback to other means of payment or hide the button.
}

3단계: 고객이 결제 버튼을 누릅니다.

고객이 결제 버튼을 누르면 판매자가 PaymentRequest 인스턴스의 show() 메서드를 호출하여 결제 UI 실행을 즉시 트리거합니다.

최종 총 가격이 동적으로 설정되는 경우(예: 서버에서 가져옴) 판매자는 총액이 확인될 때까지 결제 UI 실행을 연기할 수 있습니다.

결제 UI 실행 지연

최종 총 가격이 결정될 때까지 결제 UI를 연기하는 데모를 확인하세요.

판매자는 결제 UI를 지연시키기 위해 show() 메서드에 프라미스를 전달합니다. 프로미스가 확인되고 트랜잭션을 시작할 준비가 될 때까지 브라우저에 로드 표시기가 표시됩니다.

const getTotalAmount = async () => {
  // Fetch the total amount from the server, etc.
};

try {
  const result = await request.show(getTotalAmount());
  // Process the result…
} catch(e) {
  handleError(e);
}

show()의 인수로 지정된 약속이 없으면 브라우저가 결제 UI를 즉시 실행합니다.

4단계: 브라우저에서 결제 앱이 실행됨

브라우저는 플랫폼별 또는 웹 기반 결제 앱을 실행할 수 있습니다. Chrome에서 실행할 결제 앱을 결정하는 방법을 자세히 알아보세요.

결제 앱 빌드 방법은 대부분의 경우 개발자가 결정하지만 판매자로부터 내보낸 이벤트와 이러한 이벤트와 함께 전달되는 데이터의 구조는 표준화됩니다.

결제 앱이 실행되면 1단계에서 PaymentRequest 객체에 전달된 거래 정보를 수신합니다. 여기에는 다음이 포함됩니다.

  • 결제 수단 데이터
  • 총 가격
  • 결제 옵션

결제 앱이 거래 정보를 사용하여 UI에 라벨을 지정합니다.

5단계: 판매자가 고객의 작업에 따라 거래 세부정보를 업데이트하는 방법

고객은 결제 앱에서 결제 수단, 배송 옵션과 같은 거래 세부정보를 변경할 수 있습니다. 고객이 변경하는 동안 판매자는 변경 이벤트를 수신하고 거래 세부정보를 업데이트합니다.

판매자가 수신할 수 있는 이벤트 유형은 다음과 같이 4가지가 있습니다.

  • 결제 수단 변경 이벤트
  • 배송지 주소 변경 이벤트
  • 배송 옵션 변경 이벤트
  • 판매자 유효성 검사 이벤트

결제 수단 변경 이벤트

결제 앱은 여러 결제 수단을 지원할 수 있으며 판매자는 고객의 선택에 따라 특별 할인을 제공할 수 있습니다. 이 사용 사례를 처리하기 위해 결제 수단 변경 이벤트는 판매자에게 새 결제 수단을 알릴 수 있으므로 판매자는 할인된 총가를 업데이트하고 결제 앱에 다시 반환할 수 있습니다.

request.addEventListener('paymentmethodchange', e => {
  e.updateWith({
    // Add discount etc.
  });
});

배송지 주소 변경 이벤트

결제 앱은 원하는 경우 고객의 배송지 주소를 제공할 수 있습니다. 이 방법은 양식에 세부정보를 수동으로 입력할 필요가 없고 여러 판매자 웹사이트가 아닌 선호하는 결제 앱에 배송지 주소를 저장할 수 있으므로 고객에게 편리합니다.

거래가 시작된 후 고객이 결제 앱에서 배송지 주소를 업데이트하면 'shippingaddresschange' 이벤트가 판매자에게 전송됩니다. 이 이벤트는 판매자가 새 주소를 기반으로 배송비를 확인하고 총가를 업데이트하여 결제 앱에 반환하는 데 도움이 됩니다.

request.addEventListener('shippingaddresschange', e => {
  e.updateWith({
    // Update the details
  });
});

업데이트된 주소로 배송할 수 없는 판매자는 결제 앱에 반환되는 거래 세부정보에 오류 매개변수를 추가하여 오류 메시지를 제공할 수 있습니다.

배송 옵션 변경 이벤트

판매자는 고객에게 여러 배송 옵션을 제공할 수 있으며 이 선택사항을 결제 앱에 위임할 수 있습니다. 배송 옵션은 고객이 선택할 수 있는 가격 및 서비스 이름 목록으로 표시됩니다. 예를 들면 다음과 같습니다.

  • 일반 배송 - 무료
  • 특급 배송 - 미화 5달러

고객이 결제 앱에서 배송 옵션을 업데이트하면 'shippingoptionchange' 이벤트가 판매자에게 전송됩니다. 그러면 판매자가 배송비를 결정하고 총 가격을 업데이트하여 결제 앱에 반환할 수 있습니다.

request.addEventListener('shippingoptionchange', e => {
  e.updateWith({
    // Update the details
  });
});

판매자는 고객의 배송지 주소에 따라 배송 옵션을 동적으로 수정할 수도 있습니다. 이는 판매자가 국내 및 해외 고객에게 서로 다른 배송 옵션을 제공하려는 경우에 유용합니다.

판매자 확인 이벤트

추가 보안을 위해 결제 앱은 결제 흐름을 진행하기 전에 판매자 유효성 검사를 실행할 수 있습니다. 유효성 검사 메커니즘의 설계는 결제 앱에 따라 다르지만 판매자 유효성 검사 이벤트는 판매자가 자체 유효성을 검사하는 데 사용할 수 있는 URL을 판매자에게 알리는 역할을 합니다.

request.addEventListener('merchantvalidation', e => {
  e.updateWith({
    // Use `e.validateURL` to validate
  });
});

6단계: 판매자가 결제를 확인하고 거래를 완료합니다.

고객이 결제를 승인하면 show() 메서드는 PaymentResponse로 확인되는 프로미스를 반환합니다. PaymentResponse 객체에는 다음 정보가 포함됩니다.

  • 결제 결과 세부정보
  • 배송지 주소
  • 배송 옵션
  • 연락처 정보

이 시점에서 브라우저 UI에 아직 거래가 완료되지 않았음을 나타내는 로드 표시기가 계속 표시될 수 있습니다.

결제 실패나 오류로 인해 결제 앱이 종료되면 show()에서 반환된 프로미스가 거부되고 브라우저가 결제 트랜잭션을 종료합니다.

결제 처리 및 확인

PaymentResponsedetails는 결제 앱에서 반환된 결제 사용자 인증 정보 객체입니다. 판매자는 사용자 인증 정보를 사용하여 결제를 처리하거나 검증할 수 있습니다. 이 중요한 프로세스의 작동 방식은 결제 핸들러에 따라 다릅니다.

거래 완료 또는 재시도

판매자가 거래가 성공했는지 실패했는지 확인한 후 다음 중 하나를 수행할 수 있습니다.

  • .complete() 메서드를 호출하여 트랜잭션을 완료하고 로드 표시기를 닫습니다.
  • 고객이 retry() 메서드를 호출하여 다시 시도하도록 허용합니다.
async function doPaymentRequest() {
  try {
    const request = new PaymentRequest(methodData, details, options);
    const response = await request.show();
    await validateResponse(response);
  } catch (err) {
    // AbortError, SecurityError
    console.error(err);
  }
}

async function validateResponse(response) {
  try {
    const errors = await checkAllValuesAreGood(response);
    if (errors.length) {
      await response.retry(errors);
      return validateResponse(response);
    }
    await response.complete("success");
  } catch (err) {
    // Something went wrong…
    await response.complete("fail");
  }
}
// Must be called as a result of a click
// or some explicit user action.
doPaymentRequest();

다음 단계