가이드
목차

✅ 브랜드페이 JavaScript SDK로 내 상점만의 자체 간편결제를 만들 수 있어요.

흐름도

샘플 프로젝트브랜드페이 샘플 프로젝트입니다.

준비하기

가입 및 브랜드페이 설정하기

토스페이먼츠에 가입하세요. 사업자 번호가 아직 없더라도 테스트 개발을 시작할 수 있습니다. 브랜드페이 페이지에서 결제수단과 리다이렉트 URL을 설정하세요.

리다이렉트 URL은 브랜드페이 사용자를 인증하는 과정에 필요합니다. http://localhost:3000/callback-auth를 리다이렉트 URL로 등록해주세요.

이미지

테스트 연동을 마친 뒤 라이브 연동은 브랜드페이 소개 페이지의 도입 문의하기로 요청해주세요.

API 키 준비하기

API 키 페이지에서 테스트 클라이언트 키, 테스트 시크릿 키를 확인해주세요.

  • 클라이언트 키는 브라우저에서 결제창을 연동할 때 사용합니다.
  • 시크릿 키는 API 요청을 위해 사용합니다. 각각 프론트엔드, 서버 개발에 사용합니다. 시크릿 키는 브라우저에 노출되면 안 됩니다.

더 자세한 내용은 API 키 가이드를 참고하세요.

샘플 프로젝트 준비하기

브랜드페이 샘플 프로젝트 가이드를 따라 샘플 프로젝트를 준비하세요.

샘플 프로젝트가 성공적으로 준비되었다면 브라우저에서 http://localhost:3000/checkout 페이지로 접속했을 때 아래와 같은 화면을 확인할 수 있습니다.

페이지 예시 이미지

샘플 프로젝트에서 주로 사용할 파일 구조는 다음과 같습니다.

views
ㄴ /checkout.html
ㄴ /fail.html
ㄴ /success.html
index.js

views/checkout.html에는 SDK로 결제창을 열 수 있는 주요 코드가 포함됩니다. 결제 성공 및 실패 결과에 따라 리다이렉트 될 페이지가 각각 success.html, fail.html로 생성되어 있습니다.

최상위의 index.js는 사용자 인증 및 결제 요청 로직을 처리하는 코드가 포함되어있는 서버 코드입니다.

1️. API 키 및 SDK 설정하기

서버와 클라이언트 코드에 있는 시크릿 키와 클라이언트 키를 내 상점의 키 값으로 변경합니다.

index.js
JavaScript
// [NOTE] 시크릿 키는 외부에 노출되어서는 안됩니다.
const SECRET_KEY = 'test_sk_zXLkKEypNArWmo50nX3lmeaxYG5R'
views/checkout.html
HTML
<script> var clientKey = 'test_ck_D5GePWvyJnrK0W0k6q8gLzN97Eoq' </script>

키 설정을 했다면 결제 화면을 보여줄 views/checkout.html에 브랜드페이 SDK script를 추가하고 SDK에서 제공하는 BrandPay() 함수로 객체를 초기화합니다.

views/checkout.html
HTML
<script src="https://js.tosspayments.com/v1/brandpay"></script>
<script> var clientKey = 'test_ck_D5GePWvyJnrK0W0k6q8gLzN97Eoq' // 테스트용 클라이언트 키 var customerKey = '{CUSTOMER_KEY}' // 구매자 ID // ... // BrandPay 객체 초기화 var brandpay = BrandPay(clientKey, customerKey, { redirectUrl: 'http://localhost:3000/callback-auth', }) </script>

Brandpay 객체를 초기화하려면 필수 파라미터로 결제가 이루어질 상점을 특정하는 클라이언트 키, 결제할 고객을 특정하는 구매자 ID, 결제할 고객 인증에 사용할 리다이렉트 URL 세 가지가 필요합니다.

초기화 파라미터

  • clientKey 필수 · string

    클라이언트 키는 브라우저에서 결제창을 연동할 때 사용합니다. 토스페이먼츠에서 상점에 발급합니다. API 키 페이지에서 발급된 키 값을 확인할 수 있습니다.

  • customerKey 필수 · string

    구매자 ID입니다. 다른 사용자가 이 값을 알게 되면 악의적으로 사용될 수 있습니다. 자동 증가하는 숫자 또는 이메일・전화번호・사용자 아이디와 같이 유추가 가능한 값은 안전하지 않습니다. UUID와 같이 충분히 무작위적인 고유 값으로 생성해주세요. 영문 대소문자, 숫자, 특수문자 -, _, =, ., @ 를 최소 1개 이상 포함한 최소 2자 이상 최대 50자 이하의 문자열이어야 합니다.

  • redirectUrl string

    리다이렉트 URL에는 Access Token 발급 과정에 필요한 값이 돌아옵니다. Access Token은 브랜드페이 고객을 식별하고 고객의 결제 권한을 증명합니다. 값을 넣지 않으면 브랜드페이 페이지에 최초로 등록한 리다이렉트 URL이 기본값으로 들어갑니다.

    * 브랜드페이 페이지에 두 개 이상의 리다이렉트 URL을 등록한 상점은 각 도메인에 맞는 redirectUrl 값을 필수로 추가하세요.

customerKey는 고객을 특정하는 값으로 다른 사용자가 이 값을 탈취하면 악의적인 사용을 할 수 있습니다. customerKey의 보안을 강화하기 위해 Access Token을 발급할 때 세션을 통해 customerKey를 비교하여 동일한 고객인지 확인하는 로직을 추가할 수 있습니다.

2️. 결제창 띄우기

SDK 초기화가 완료되면 SDK에서 제공하는 결제창을 띄우는 메서드 requestPayment()를 실행할 수 있습니다.

아래와 같이 views/checkout.html에 버튼을 추가하고, 결제창을 띄울 수 있는 메서드를 연결합니다.

views/checkout.html
HTML
<script> function requestPayment() { brandpay.requestPayment({ amount: 5000, // 결제 금액 orderId: orderId, // 주문에 대한 고유한 ID 값 orderName: '토스 티셔츠 외 2건', // 결제에 대한 구매상품 }) } </script>
<button onclick="requestPayment()">결제하기</button>

requestPayment() 메서드의 필수 파라미터는 결제 금액, 상점에서 만든 주문 건 ID와 구매상품 세 가지 입니다.

필수 파라미터

  • amount 필수 · number

    결제되는 금액입니다.

  • orderId 필수 · string

    주문번호입니다. 주문을 구분하는 ID입니다. 충분히 무작위한 값을 생성해서 각 주문마다 고유한 값을 넣어주세요. 영문 대소문자, 숫자, 특수문자 -, _, =로 이루어진 6자 이상 64자 이하의 문자열이어야 합니다.

  • orderName 필수 · string

    구매상품입니다. 예를 들면 생수 외 1건 같은 형식입니다. 최대 길이는 100자입니다.

* 더 자세한 선택 파라미터 정보는 JavaScript SDK 문서에서 확인해보세요.

3️. 인증하기

결제수단 등록

결제창이 열렸으면 고객이 결제수단을 등록할 수 있습니다.

결제수단 등록 이미지

약관 동의

결제수단 등록은 약관 동의를 받으면 마무리됩니다. 동의하고 다음 버튼을 누르면 인증 단계로 넘어갑니다. 약관 동의 메서드는 자동결제 외에는 따로 필요하지 않습니다.

약관 동의 화면

Access Token 발급

Access Token은 브랜드페이 고객을 식별하는 인증 토큰입니다.

약관 동의가 성공적이었다면 이전 과정에서 설정한 리다이렉트 URL로 아래와 같이 Access Token 발급에 필요한 값들이 돌아옵니다.

https://localhost:3000/callback-auth?code={CODE}&customerKey={CUSTOMER_KEY}
  • code: Access Token 발급에 사용할 수 있는 임시 인증 코드입니다.
  • customerKey: 상점에서 만든 고객의 고유 ID입니다.

Access Token 발급 API에 리다이렉트 URL로 돌아온 codecustomerKey를 파라미터로 포함하세요. 처음으로 Access Token을 발급받는 것이기 때문에 토큰 타입을 나타내는 grantTypeAuthorizationCode로 설정해야 합니다.

index.js
JavaScript
app.get('/callback-auth', async (req, res) => {
await axios.post(
'https://api.tosspayments.com/v1/brandpay/authorizations/access-token',
JSON.stringify({
grantType: 'AuthorizationCode',
// Access Token 발급을 위해 리다이렉트 URL에 포함되어 돌아온 code와 customerKey 전달
code: req.query.code,
customerKey: req.query.customerKey,
}),
{
headers: {
// [TODO] Basic 인증 방식의 사용자명과 비밀번호는 콜론으로 구분해서 `사용자명:비밀번호`로 추가합니다. 상점의 시크릿 키를 사용자명으로, 비밀번호는 공백으로 추가한 뒤 base64로 인코딩하세요.
Authorization: `Basic ${Buffer.from(SECRET_KEY + ':', 'utf8').toString('base64')}`,
'Content-Type': 'application/json',
},
}
)
// 성공(HTTP status 200) 응답
res.sendStatus(200)
})

Access Token은 한 번 발급된 뒤에는 SDK에서 자동으로 관리하기 때문에 추가적인 처리가 필요하지 않습니다. 위 과정이 완료되면 브랜드페이 서버가 SDK를 사용하는 사용자가 인증되고 결제를 진행할 수 있습니다.

더 자세한 인증 과정은 브랜드페이 인증 문서를 참고하세요.

본인 확인

고객이 처음으로 브랜드페이를 사용한다면 최초 1회에 한하여 본인 확인을 진행합니다.

본인 확인 이미지

4. 결제하기

결제 비밀번호 등록

본인 확인이 성공적이면 등록한 결제수단으로 결제할 수 있습니다. 브랜드페이를 이용한 최초 결제라면 결제 비밀번호를 설정한 뒤 결제합니다.

비밀번호 추가 이미지

결제 요청

성공적으로 결제 요청이 진행되었다면 requestPayment()가 반환하는 Promise가 resolve 되고 그 결과로 결제를 특정하는 결제 키, 주문번호, 결제 금액이 돌아옵니다.

views/checkout.html
HTML
<!-- ... -->
<script> // ... brandpay .requestPayment({ amount: 5000, // 결제 금액 orderId: orderId, // 주문에 대한 고유한 ID 값 orderName: '토스 티셔츠 외 2건', // 결제에 대한 구매상품 }) .then(res => { // 결제 승인 요청 res.customerKey = customerKey return axios.post('http://localhost:3000/confirm-payment', res) }) .then(() => { // 결제 성공 페이지(/views/success.html)로 리다이렉트 window.location.href = 'http://localhost:3000/success' }) .catch(err => { if (err.code == 'USER_CANCEL') { console.log('사용자 취소') } else { console.log('기타 에러 상황', err.code, err.message) // 결제 실패 페이지(/views/fail.html)로 리다이렉트 window.location.href = 'http://localhost:3000/fail' } }) </script>
<!-- ... -->

상점 서버에서는 돌아온 값의 유효성을 확인한 뒤 결제 승인 API를 호출합니다. 아래 Java, JavaScript 예제 코드로 전체적인 흐름을 파악해보세요.

Java
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.http.*;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
@Controller
public class PaymentController {
private static final String SECRET_KEY = "test_sk_zXLkKEypNArWmo50nX3lmeaxYG5R";
private static final String customerKey = "{CUSTOMER_KEY}";
private final RestTemplate restTemplate;
@Autowired
public PaymentController(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@RequestMapping(
method = RequestMethod.POST,
value = "/shop/confirm-payment"
)
public String confirmPayment(
@RequestParam("customerKey") String customerKey,
@RequestParam("paymentKey") String paymentKey,
@RequestParam("orderId") String orderId,
@RequestParam("amount") Long amount,
Model model
) {
HttpHeaders headers = new HttpHeaders();
String authorization = Base64.getEncoder().encodeToString((SECRET_KEY + ":").getBytes());
headers.set("Authorization", "Basic " + authorization);
headers.setContentType(MediaType.APPLICATION_JSON);
Map<String, String> payloadMap = new HashMap<>();
payloadMap.put("customerKey", customerKey)
payloadMap.put("paymentKey", paymentKey)
payloadMap.put("orderId", orderId);
payloadMap.put("amount", String.valueOf(amount));
HttpEntity<Map<String, String>> request = new HttpEntity<>(payloadMap, headers);
String confirmRequestUrl = "https://api.tosspayments.com/v1/brandpay/payments/confirm";
ResponseEntity<JsonNode> responseEntity = restTemplate.postForEntity(
confirmRequestUrl,
request,
JsonNode.class
);
if (responseEntity.getStatusCode() == HttpStatus.OK) {
JsonNode successNode = responseEntity.getBody();
// 커스텀 모델에 attribute 추가
model.addAttribute("orderId", successNode.get("orderId").asText());
return "success";
} else {
JsonNode failNode = responseEntity.getBody();
model.addAttribute("message", failNode.get("message").asText());
model.addAttribute("code", failNode.get("code").asText());
return "fail";
}
}
}
index.js
JavaScript
// [TODO] 아래 키는 테스트용 시크릿 키입니다. 내 상점의 키 값으로 변경하세요.
// [NOTE] 시크릿 키는 외부에 노출되어서는 안됩니다.
const SECRET_KEY = 'test_sk_zXLkKEypNArWmo50nX3lmeaxYG5R'
const customerKey = '{CUSTOMER_KEY}'
// ...
// 최종 결제 승인
app.post('/confirm-payment', async (req, res) => {
try {
await axios.post(
`https://api.tosspayments.com/v1/brandpay/payments/confirm`,
{
customerKey: customerKey,
paymentKey: req.body.paymentKey,
orderId: req.body.orderId,
amount: req.body.amount,
},
{
headers: {
// [TODO] Basic 인증 방식의 사용자명과 비밀번호는 콜론으로 구분해서 `사용자명:비밀번호`로 추가합니다. 상점의 시크릿 키를 사용자명으로, 비밀번호는 공백으로 추가한 뒤 base64로 인코딩하세요.
// 문서: https://docs.tosspayments.com/guides/brandpay/auth#2-access-token-발급받기
Authorization: `Basic ${Buffer.from(SECRET_KEY + ':', 'utf8').toString('base64')}`,
'Content-Type': 'application/json',
},
}
)
res.status(200).send('OK')
} catch (error) {
console.error(error.response.data.message)
res.status(500).send(error.response.data.message)
}
})

결제가 성공적으로 승인되었다면 HTTP 상태 코드 200 OK가 돌아옵니다. 고객을 결제 성공 페이지로 이동시켜주세요.

결제 완료 페이지

  • 더 궁금한 내용이 있나요?
  • 코드 샘플을 참고하세요
  • 기술지원이 필요한가요?
    실시간 문의|이메일 보내기