토스페이 연동가이드

결제 환불

결제 완료 건의 결제 금액 중 일부 또는 전부를 구매자에게 돌려줍니다.

기 환불처리된 거래는 원복이 불가하오니 환불 전 반드시 가맹점 측의 체크가 필요합니다.

각 API 응답 필드와 에러코드는 사전 공지 없이 추가되거나 변경될 수도 있으니, 추가된 항목으로 인해 오류가 발생하지 않도록 처리에 유의해 주시기 바랍니다.

엔드포인트

POSThttps://pay.toss.im/api/v2/refunds

요청 파라미터

apiKeystring필수

가맹점 API Key. 웹 브라우저 혹은 외부에 노출되지 않도록 유의해 주시기 바랍니다.

payTokenstring필수

토스페이 토큰

refundNostring필수

환불 번호. 환불 번호는 요청 시 가맹점별로 매회 유니크한 값을 입력해야 하며, 중복 입력 시 환불 요청이 실패합니다. 최대 36자 이내의 문자열을 사용해야 하며 빈 문자열("") 또는 null로 전달하면 오류가 발생합니다. 중복된 refundNo가 전달되면 원치 않는 결제 건에 대해 환불 요청이 일어날 수 있으며, 네트워크 오류로 인한 처리 응답 미수신 시 문제가 발생할 수 있습니다. refundNo는 승인 응답에서 전달받은 transactionId와는 서로 다른 값이어야 하며, 동일한 값으로 요청할 경우 환불 요청이 실패합니다.

idempotentboolean

멱등성 적용 여부. true: 사용 (기본값), false: 미사용. 멱등성 적용을 원하시는 경우 true, 미사용의 경우 false로 선언해 주시기 바랍니다. 미입력 시 기본값으로 멱등성이 활성화되어, 동일한 요청을 반복적으로 수행하더라도 동일한 결과인 성공으로 응답("code": 0) 처리됩니다.

reasonstring

환불 사유. 환불 사유는 한글 및 숫자, 영문자, 특수문자를 허용합니다.

amountinteger

환불할 금액. 미입력 시 환불할 결제건의 남은 전액을 환불 처리하며, 부분환불 시 필수로 amount를 활용해주세요. 만일 즉시할인이 적용된 거래의 부분환불이 필요한 경우, 가맹점에서는 환불이 필요한 총 요청 금액만 전달해 주시면 됩니다. 계산은 토스페이 서버에서 자동으로 처리합니다.

amountTaxFreeinteger

환불할 금액 중 비과세금액. 환불할 금액 중 비과세 금액, 없으면 0으로 설정합니다.

amountTaxableinteger

환불할 금액 중 과세금액

amountVatinteger

환불할 금액 중 부가세. 값이 없으면 환불할 과세금액을 11로 나눈 후 소수점 첫째 자리에서 올림으로 계산합니다.

amountServiceFeeinteger

환불할 금액 중 봉사료. 결제 생성 시 봉사료 설정한 경우에만 입력 가능

응답 파라미터

codeinteger

응답코드

가능한 값:
0성공
-1실패 (실패사유는 msg와 errorCode로 제공)
refundNostring

환불 번호. 환불요청 시 가맹점이 전달한 refundNo로 리턴됩니다.

refundableAmountinteger

환불 가능 금액. 환불 성공 후 남은 환불 가능 금액

discountedAmountinteger

할인된 금액. 환불 성공 후 남은 할인적용 금액이 전달되고, 전액 환불이거나 할인 적용이 안되었다면 0을 리턴합니다. 예를 들어, 10% 할인을 받아 10,000원 결제를 9,000원에 결제했고, 4,000원을 부분 환불하면 최종적으로 6,000원 결제의 600원 할인을 받은 것이 되므로 discountedAmount 값은 600원으로 리턴됩니다. 가맹점 측에서는 환불요청 금액만 전달해 주시면 되고, 토스페이 서버에서 자동으로 우선순위를 지정하여 할인금액을 차감합니다.

paidAmountinteger

지불수단 승인금액. 환불 성공 후 남은 지불수단의 승인금액

refundedAmountinteger

환불요청 금액. 가맹점에서 환불 요청 시 전달한 amount 금액

refundedDiscountAmountinteger

환불요청 금액 중 실 차감된 할인 금액. 환불요청 시 전달한 amount 금액 중 토스 서버에서 자동 차감된 할인 금액으로 차감액이 없으면 0으로 리턴됩니다. 할인 금액에는 토스 앱에서 자동 적용되는 즉시할인과 토스 포인트 사용금액이 포함됩니다.

refundedPaidAmountinteger

환불요청 금액 중 실 차감된 지불수단 금액. 환불요청 시 전달한 amount 금액 중 토스 서버에서 자동 차감된 지불수단 금액으로 차감액이 없으면 0으로 리턴됩니다.

approvalTimestring

결제건의 환불 처리 시간 (yyyy-MM-dd HH:mm:ss)

cashReceiptMgtKeystring

현금영수증 관리번호 식별값. 국세청 승인번호는 아니며 토스페이에서 자체적으로 만든 식별 값입니다. 해당 필드 존재로 현금영수증 발급 구분 가능합니다.

payTokenstring

환불된 결제토큰

transactionIdstring

거래 트랜잭션 아이디. 환불된 거래건의 매출전표 확인을 위하여 필요한 옵션 값이므로 가맹점의 관리가 필요합니다.

cardMethodTypestring

카드 타입. 승인된 카드의 타입을 구분할 수 있습니다.

가능한 값:
CREDIT신용카드
CHECK체크카드
PREPAYMENT선불카드
cardNumberstring

마스킹된 카드번호. 카드번호 16자리 중 중간자리는 마스킹됩니다.

cardUserTypestring

카드 사용자 구분

가능한 값:
PERSONAL본인 카드
PERSONAL_FAMILY가족 카드
CORP_PERSONAL법인지정 결제계좌 임직원
CORP_PRIVATE법인 공용
CORP_COMPANY법인지정 결제계좌 회사(하나카드만)
cardBinNumberstring

카드 BIN 넘버. 카드사에서 준 카드 BIN 번호(마스킹되어 있을 수 있습니다). 100% 신뢰는 불가합니다.

cardNum4Printstring

사용자가 선택한 카드의 끝 4자리. 사용자가 선택한 결제수단(payMethod)이 '카드'인 경우 카드번호 끝 4자리를 전달합니다. (카드사에 따라 마스킹이 포함되어 있을 수 있습니다)

salesCheckLinkUrlstring

신용카드 매출전표 호출 URL. 승인된 카드 결제건의 매출전표를 확인할 수 있는 URL

accountBankCodestring

은행 코드. 사용자가 선택한 결제수단(payMethod)이 '토스머니'인 경우 토스가 정의한 은행 코드를 전달합니다.

accountBankNamestring

은행 명. [은행코드 리스트](/guide/bank-code)

accountNumberstring

계좌번호. 계좌번호는 일부 마스킹을 포함하고 있습니다.

msgstring

응답이 성공이 아닌 경우 설명 메세지

errorCodestring

에러 코드

가능한 값:
INACTIVE_USER탈퇴한 사용자입니다. 환불이 불가능합니다.
COMMON_REFUND_ERROR환불이 불가능한 상태입니다.
REFUND_EXCEED_DAILY환불 금액이 상점의 일일 환불 한도보다 클 수 없습니다.
그 외의 에러 코드[에러 코드 목록](/guide/error-code)

예제

Example Request

curl "https://pay.toss.im/api/v2/refunds" \
    -H "Content-Type: application/json" \
    -d '{
        "payToken":"example-payToken",
        "apiKey":"sk_test_w5lNQylNqa5lNQe013Nq",
        "amount": 5000,
        "refundNo": "3243c76e-e9cf-4669-881b-33a3b82ddf49"
    }'
import java.nio.charset.StandardCharsets;

URL url = null;
URLConnection connection = null;
StringBuilder responseBody = new StringBuilder();
try {
    url = new URL("https://pay.toss.im/api/v2/refunds");
    connection = url.openConnection();
    connection.addRequestProperty("Content-Type", "application/json");
    connection.setDoOutput(true);
    connection.setDoInput(true);

    org.json.simple.JSONObject jsonBody = new JSONObject();
    jsonBody.put("payToken", "example-payToken");
    jsonBody.put("amount", "5000");
    jsonBody.put("refundNo", "3243c76e-e9cf-4669-881b-33a3b82ddf49");
    jsonBody.put("apiKey", "sk_test_w5lNQylNqa5lNQe013Nq");

    BufferedOutputStream bos = new BufferedOutputStream(connection.getOutputStream());
    bos.write(jsonBody.toJSONString().getBytes(StandardCharsets.UTF_8));
    bos.flush();
    bos.close();

    BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));
    String line = null;
    while ((line = br.readLine()) != null) {
        responseBody.append(line);
    }
    br.close();
} catch (Exception e) {
    responseBody.append(e);
}
System.out.println(responseBody.toString());
$arrayBody = array();
$arrayBody["payToken"] = "example-payToken";
$arrayBody["amount"] = 5000;
$arrayBody["refundNo"] = "3243c76e-e9cf-4669-881b-33a3b82ddf49";
$arrayBody["apiKey"] = "sk_test_w5lNQylNqa5lNQe013Nq";
$jsonBody = json_encode($arrayBody);

$ch = curl_init('https://pay.toss.im/api/v2/refunds');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonBody);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/json',
    'Content-Length: ' . strlen($jsonBody))
);

$result = curl_exec($ch);
curl_close($ch);

echo "Response: ".$result;
import urllib, urllib2

url = "https://pay.toss.im/api/v2/refunds"
params = {
    "payToken": "example-payToken",
    "amount": 5000,
    "refundNo": "3243c76e-e9cf-4669-881b-33a3b82ddf49",
    "apiKey": "sk_test_w5lNQylNqa5lNQe013Nq"
}

response = urllib.urlopen(url, urllib.urlencode(params))
print(response.read())
require 'net/http'
require 'json'

uri = URI.parse("https://pay.toss.im/api/v2/refunds")

params = {
    "payToken" => "example-payToken",
    "amount"=> 5000,
    "refundNo" => "3243c76e-e9cf-4669-881b-33a3b82ddf49",
    "apiKey" => "sk_test_w5lNQylNqa5lNQe013Nq"
}

http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.path)
request.set_form_data(params)
response = http.request(request)

p JSON.parse(response.body)
Dim data, httpRequest, postResponse

data = "apiKey=sk_test_w5lNQylNqa5lNQe013Nq"
data = data & "&payToken=example-payToken"
data = data & "&amount=1000"

Set httpRequest = Server.CreateObject("MSXML2.ServerXMLHTTP")
httpRequest.Open "POST", "https://pay.toss.im/api/v2/refunds", False
httpRequest.SetRequestHeader "Content-Type", "application/json"
httpRequest.Send data

postResponse = httpRequest.ResponseText

Response.Write postResponse

Example Response

{
  "code": 0,
  "refundNo": "3243c76e-e9cf-4669-881b-33a3b82ddf49",
  "approvalTime": "2020-04-29 11:32:52",
  "cashReceiptMgtKey": "0123456-abcd-9abcd0Df",
  "refundableAmount": 2000,
  "discountedAmount": 0,
  "paidAmount": 1000,
  "refundedAmount": -2000,
  "refundedDiscountAmount": 0,
  "refundedPaidAmount": -2000,
  "payToken": "example-payToken",
  "transactionId": "3243c76e-e9cf-4669-881b-33a3b82ddf49",
  "cardMethodType": "CREDIT",
  "cardNumber": "654321******1234",
  "cardUserType": "PERSONAL",
  "cardNum4Print": "1234",
  "cardBinNumber": "654321"

  // payMethod 가 TOSS_MONEY 일때
  //"cashReceiptMgtKey": "0123456-abcd-9abcd0Df",
  //"accountBankCode" : "88",
  //"accountBankName" : "신한은행",
  //"accountNumber" : "110******676"
}