navbar
javascript

개요

CHAI는 사용자의 브라우저상에서 실행되는 결제용 Javascript와 결제 승인/취소용 RESTful API로 구성되어 있습니다. 간단한 몇가지 절차를 통해 CHAI를 연동하실 수 있습니다.

키 발급

CHAI를 이용하려면 API 키를 발급받아야 합니다. 현재는 CHAI와 계약을 통해서만 발급받으실 수 있습니다.
가맹점 등록 후 공개키(public key)와 비밀키(private key) 두 가지의 키가 발급됩니다.

공개키(public key)

공개키는 클라이언트 CHAI SDK 초기화에 사용합니다. 호출할 수 있는 API가 제한되어있습니다.

비밀키(private key)

비밀키로는 모든 API 호출이 가능합니다. 서버 사이드에서만 사용해야하며, 키가 유출되지 않도록 보안에 각별한 주의가 필요합니다.

결제 연동하기

Chai Payment Flow 차이의 결제는 다음과 같은 플로우로 이루어져 있습니다.

1) 가맹점 서버에서 CHAI API를 호출하여 결제 생성(Create)
2) 가맹점 웹페이지에서 CHAI Javascript를 통해 CHAI 결제페이지를 호출
2-1) CHAI 결제페이지에서 결제내역 확인(Prepare) 및 결제 비밀번호 입력(Approve)
3) 가맹점 결제완료 웹페이지(returnUrl)에서 CHAI API를 호출하여 결제승인(Confirm)

1. 결제 생성

생성 API의 정의를 참고해 서버 사이드에서 생성하세요. 응답값에 있는 paymentId와 publicAPIKey, paymentId, returnUrl 총 네개의 값을 CHAI 결제 페이지로 전달해야 합니다.

2. CHAI 결제 페이지 호출

  1. 결제가 필요한 웹 페이지에 CHAI용 script 태그를 추가합니다.
  2. ChaiPayment.checkout 함수를 호출하여 CHAI 결제 페이지로 이동하면 CHAI 앱에서 결제가 진행됩니다.

Import CHAI javascript

<script
  type="text/javascript"
  src="https://chai.finance/js/v1/payment.min.js">
</script>

Create instance and call ChaiPayment.checkout()

<script type="text/javascript">
  ChaiPayment.checkout({
    // mode: 'production' // default: staging
    publicAPIKey: '<발급 받은 Public API Key>',
    paymentId: '<생성 결과에서 전달된 값>',
    returnUrl: '<결제 후 돌아올 가맹점 결제 페이지 url>',
    idempotencyKey: '<가맹점 주문 번호>',
  });
</script>

ChaiPayment.checkout Parameters

KeyTypeDescriptionRequiredMax Length
publicAPIKeyString발급 받은 Public API KeyY100
paymentIdString서버에서 결제 생성 결과에 있는 paymentIdY100
returnUrlString결제 후 돌아올 가맹점 결제 페이지 urlY500
idempotencyKeyString가맹점 주문 번호 (고유번호, 중복 결제 방지 등)Y100
modeString개발용: 'staging', 실서버: 'prod'N100

3. 결제 승인

app.get('/payment/complete', async (req, res) => {
  res.writeHead(200, {
    'content-type': 'application/json; charset=utf-8'
  });

  const { paymentId, idempotencyKey, status, code } = req.query;
  let payment;

  // Payment를 만들지 못하면 paymentId, idempotencyKey가 전달되지 않는다.
  if (!paymentId || !idempotencyKey) {
    res.end(JSON.stringify({ status, code }));
    return;
  }

  if (status === 'approved') {
    // 승인 API 호출
    const result = await got({
      method: 'POST',
      url: `https://api.chai.finance/v1/payment/${paymentId}/confirm`,
      headers: {
        'Private-API-Key': PRIVATE_API_KEY,
        'Idempotency-Key': idempotencyKey
      }
    });

    payment = result.body;
  } else {
    // 조회 API 호출
    const result = await got({
      method: 'GET',
      url: `https://api.chai.finance/v1/payment/${paymentId}`,
      headers: {
        'Private-API-Key': PRIVATE_API_KEY,
        'Idempotency-Key': idempotencyKey
      }
    });

    payment = result.body;
  }

  if (payment.status === 'confirmed') {
    // TODO: 가맹점 측 주문 완료 처리
  } else {
    // TODO: 가맹점 측 주문 실패 처리
  }

  res.end(payment);
})

CHAI 결제 페이지에서 결제가 완료되면 ChaiPayment.checkout 함수 호출시 입력한 returnUrl로 리다이렉트 됩니다. 이 때 paymentId, idempotencyKey, status 값이 query parameter로 함께 리다이렉트 됩니다.
(e.g. * https://example.io/returnUrl?paymentId=xx&idempotencyKey=yy&status=approved)
해당 페이지의 서버 핸들러에서 CHAI RESTFul API 호출을 통해 결제 결과를 조회하거나 승인 또는 취소할 수 있습니다.

리다이렉트 시 결제 상태 (status)

앱 연동 가이드

차이 앱 결제는 가맹점의 웹뷰에서 브릿지 페이지를 노출하고, 사용자가 브릿지 페이지의 결제 버튼을 클릭하여 차이 앱으로 이동해 결제 승인 후 다시 돌아와 해당 페이지에서 결제를 완료하는 구조로 되어있습니다.

차이 앱이 동작 가능한 버전은 Android 5.1(LOLLIPOP_MR1, API Level 22) 이상, iOS 9 이상입니다.

Android

webview.webViewClient = object : WebViewClient() {
    // API level 24 이상에서 사용
    override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
        if (request?.url != null) {
            return shouldOverrideUrlLoading(request.url)
        }
        return false
    }

    // API level 24 미만에서 사용
    override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
        if (url != null) {
            val uri = Uri.parse(url)
            return shouldOverrideUrlLoading(uri)
        }
        return false
    }

    fun shouldOverrideUrlLoading(uri: Uri): Boolean {
        // 차이 앱에서 사용하는 chaipayment:// market:// 이 여기에서 처리됩니다.
        // 다른 PG나 특정 앱 URL이 들어온다면 조건을 더 추가해서 처리해주세요
        if (!listOf("http", "https").contains(uri.scheme)) {
            return try {
                val intent = Intent.parseUri(uri.toString(), Intent.URI_INTENT_SCHEME)
                startActivity(intent)
                // 액티비티가 시작 되었으므로 true를 리턴하여
                // 웹뷰에서 해당 페이지로 이동하지 않습니다.
                true
            } catch (e: URISyntaxException) {
                e.printStackTrace()
                false
            } catch (e: ActivityNotFoundException) {
                e.printStackTrace()
                // chaipayment:// 호출 시 차이 앱이 없다면 이곳이 실행되지만
                // 숨겨진 iframe 내부에서 에러 페이지가 뜨기 때문에(화면에 노출되지 않음)
                // 따로 핸들링 하지 않아도 무관합니다.
                // if (uri.scheme != null && uri.scheme == "chaipayment") true
                false
            }
        }
        return false
    }
}
  1. 안드로이드 어플리케이션에서 WebView를 만들어 전달해드린 브릿지 페이지 링크로 이동합니다.

  2. WebViewClient를 상속받는 클래스를 구현하고 클래스 내 아래 두 함수를 오버라이드합니다.

구현 목적은 웹뷰 내에서 이동하려는 URI의 scheme이 chaipayment:// 또는 market:// 일 경우 웹뷰에서 노출하는 대신 각각의 액티비티를 생성해 이동하는 것입니다. 구현하지 않을 경우 차이 앱, 마켓으로 연결되지 않으며 웹뷰에 오류페이지가 노출될 수 있습니다.

상세한 내용은 코드에서 설명하니, 코드를 참고해 알맞게 구현해주면 됩니다.

  1. 결제 후 차이 액티비티가 닫히면 웹뷰로 돌아와 나머지 처리가 진행되므로, 차이 앱 또는 마켓 앱이 뜬 뒤에도 해당 웹뷰를 닫지 않고 유지해야합니다.

iOS

func webView(_ webView: WKWebView,
              decidePolicyFor navigationAction: WKNavigationAction,
              decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
  guard let url = navigationAction.request.url else {
    decisionHandler(.cancel)
    return
  }

  if url.absoluteString.range(of: "//itunes.apple.com/") != nil {
    UIApplication.shared.openURL(url)
    // 웹뷰에서 직접 URL을 열지 않도록 네비게이션을 취소합니다.
    decisionHandler(.cancel)
    return
  }
  // 다른 PG나 특정 앱 URL이 들어온다면 조건을 더 추가해서 처리해주세요
  // else if !url.absoluteString.hasPrefix("http://") && !url.absoluteString.hasPrefix("https://") {
  //   if UIApplication.shared.canOpenURL(url) {
  //     UIApplication.shared.openURL(url)
  //     decisionHandler(.cancel)
  //     return
  //   }
  // }
}
  1. 아이폰 어플리케이션에서 WKWebView를 만들고, 전달드린 브릿지 페이지 링크로 차이 결제 페이지로 이동합니다.
  1. WKWebView에서는 앱스토어 링크가 더 이상 동작하지 않기 때문에 해당 링크를 직접 앱스토어로 보내주는 구현이 필요합니다. WKNavigationDelegate를 구현하는 클래스를 구현하고, 아래 메소드를 오버라이드합니다.

상세한 내용은 코드에서 설명하니, 코드를 참조해 알맞게 구현해주면 됩니다.

  1. 결제 후 차이 액티비티가 닫히면 웹뷰로 돌아와 나머지 처리가 진행되므로, 차이 앱 또는 마켓 앱이 뜬 뒤에도 해당 웹뷰를 닫지 않고 유지해야합니다.

API 정의

결제 상태

결제 상태에는 status와 displayStatus가 있습니다.

Status

StatusDescription
waiting결제 생성 완료, 사용자가 CHAI 결제 페이지에 오기를 기다리는 중
prepared사용자가 CHAI 결제 페이지에 도달, 결제 정보 확인
approved사용자가 결제 완료(결제 비밀번호 입력)
confirmed가맹점 측 결제 승인 완료 (결제 성공)
user_canceled사용자가 결제 진행 중에 취소
canceled취소된 결제
failed특정 이유로 결제 실패
timeout일정 시간 동안 다음 단계로 넘어가지 않고 있는 결제건 자동 취소

Display Status

Display StatusDescription
partial_confirmed부분 취소된 결제

생성

curl -X POST https://api.chai.finance/v1/payment \
-H 'Private-API-Key: 97d1de70-189b-4c64-a4dd-8d7af44ba8a4' \
-H 'Idempotency-Key: af9a88a8-109f-4513-989b-12f2fb20a301' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'merchantUserId=chai_tester&checkoutAmount=20000&description=%5B%EB%8C%80%EC%9A%A9%EB%9F%89%5D%EB%86%8D%EC%8B%AC%20%EC%95%88%EC%84%B1%ED%83%95%EB%A9%B4%20125g%20X%2040%EA%B0%9C%20X%201%EB%B0%95%EC%8A%A4&returnUrl=%2Fresult'

The above command returns JSON structured like this:

{
  "paymentId": "d22e1f5eab6fe7791725b0da921f665345c08e29",
  "type": "payment",
  "status": "waiting",
  "displayStatus": "waiting",
  "idempotencyKey": "af9a88a8-109f-4513-989b-12f2fb20a301",
  "currency": "KRW",
  "checkoutAmount": 20000,
  "discountAmount": 2000,
  "billingAmount": 18000,
  "chargingAmount": 18000,
  "canceledAmount": 0,
  "canceledBillingAmount": 0,
  "canceledDiscountAmount": 0,
  "returnUrl": "/result",
  "description": "[대용량]농심 안성탕면 125g X 40개 X 1박스",
  "createdAt": "2018-12-18T05:14:22.337Z",
  "updatedAt": "2018-12-18T05:14:22.337Z"
}

HTTP Request

POST api.chai.finance/v1/payment

Headers

Body

KeyTypeDescriptionRequiredMax Length
descriptionString결제 상세 정보 (상품명 등)Y500
checkoutAmountNumber결제 금액Y
returnUrlString결제 후 이동될 가맹점 측 페이지 urlY500
merchantUserIdString가맹점 측 유저 아이디 (CS 등에 사용)100
currencyString사용할 화폐 (현재 KRW만 지원)3
localeString사용할 언어
auto(default), en, ko, zh
4
appSchemeString차이앱 결제후 앱복귀를 위한 URL scheme
(기본값 null)
cashReceiptBoolean현금영수증 발급 가능 여부
(기본값 true)
taxFreeAmountNumber복합과세: 결제 금액 중 비과세 금액
(기본값 0)
serviceFeeAmountNumber복합과세: 결제 금액 중 봉사료
bookShowAmountNumber복합과세: 결제 금액 중 도서공연비
metadataObject{
  address: '서울시 강남구 ...',
  pid: 'promotion_id'
}

현금영수증 발급 가능 여부 (cashReceipt)

현금영수증 발급 가능 여부를 설정할 수 있습니다.
(문화상품권이나 백화점상품권, 모바일 쿠폰 등 과세 대상에서 제외되는 유가증권 등의 상품은 현금영수증 발행 대상에서 제외됩니다)

복합과세 처리

결제 금액 중 비과세/봉사료/도서공연비 처리가 필요할 경우 '복합과세' 파라미터를 설정해야 합니다.

3개의 파라미터 중 하나라도 0이 아닌 값으로 설정하면 해당 결제 건은 '복합과세' 결제로 처리되며, '과세 금액'과 '부가세'는 자동으로 계산됩니다.
위 파라미터를 통해 설정한 값은 현금영수증 발행에도 반영됩니다.

복합과세가 아닌 경우, 아래와 같이 처리됩니다.

복합과세의 경우 아래와 같이 처리됩니다. 도서공연비가 있는 경우 따로 현금영수증이 발급됩니다.

단, 현금영수증 발행 불가 결제(cashReceipt = false)인 경우, 아래와 같이 처리됩니다.

Response

KeyTypeDescriptionMax Length
paymentIdString결제 고유 번호100
typeString결제 타입 (payment, charge)50
statusString결제 상태50
displayStatusString결제 상태 (상세)50
idempotencyKeyString가맹점 측 결제 고유 식별자 (중복 결제 방지용)100
currencyString사용할 화폐 (현재 KRW만 지원)3
checkoutAmountNumber결제 요청 금액
billingAmountNumber실결제 금액
descriptionString결제 상세 정보 (상품명 등)500
returnUrlString결제 완료 후 돌아갈 페이지500
createdAtDate결제 생성일
updatedAtDate결제 최종 갱신일

조회

curl -X GET https://api.chai.finance/v1/payment/d22e1f5eab6fe7791725b0da921f665345c08e29 \
-H 'Public-API-Key: 885738d9-78ed-483d-a923-e8db56aa393b' \
-H 'Idempotency-Key: af9a88a8-109f-4513-989b-12f2fb20a301'

The above command returns JSON structured like this:

{
  "paymentId": "d22e1f5eab6fe7791725b0da921f665345c08e29",
  "type": "payment",
  "status": "confirmed",
  "displayStatus": "confirmed",
  "idempotencyKey": "af9a88a8-109f-4513-989b-12f2fb20a301",
  "currency": "KRW",
  "checkoutAmount": 20000,
  "discountAmount": 2000,
  "billingAmount": 18000,
  "chargingAmount": 18000,
  "canceledAmount": 0,
  "canceledBillingAmount": 0,
  "canceledDiscountAmount": 0,
  "returnUrl": "/result",
  "description": "[대용량]농심 안성탕면 125g X 40개 X 1박스",
  "merchantUserId": "xxxyyyzzz",
  "createdAt": "2018-12-18T05:14:22.337Z",
  "updatedAt": "2018-12-18T05:14:22.337Z"
}

HTTP Request

GET api.chai.finance/v1/payment/:paymentId

Parameters

Headers

Response

KeyTypeDescriptionMax Length
paymentIdString결제 고유 번호100
typeString결제 타입 (payment, charge)50
statusString결제 상태50
displayStatusString결제 상태 (상세)50
idempotencyKeyString가맹점 측 결제 고유 식별자 (중복 결제 방지용)100
currencyString사용할 화폐 (현재 KRW만 지원)3
checkoutAmountNumber결제 요청 금액
discountAmountNumber할인 금액
billingAmountNumber실결제 금액
chargingAmountNumber충전 금액 (잔여 포인트 부족시)
canceledAmountNumber취소된 금액 (누적)
canceledBillingAmountNumber취소된 실결제 금액 (누적)
canceledDiscountAmountNumber취소된 할인 금액 (누적)
descriptionString결제 상세 정보 (상품명 등)500
returnUrlString결제 완료 후 돌아갈 페이지500
createdAtDate결제 생성일
updatedAtDate결제 최종 갱신일

승인

curl -X POST https://api.chai.finance/v1/payment/d22e1f5eab6fe7791725b0da921f665345c08e29/confirm \
-H 'Private-API-Key: 97d1de70-189b-4c64-a4dd-8d7af44ba8a4' \
-H 'Idempotency-Key: af9a88a8-109f-4513-989b-12f2fb20a301' \

The above command returns JSON structured like this:

{
  "paymentId": "d22e1f5eab6fe7791725b0da921f665345c08e29",
  "type": "payment",
  "status": "confirmed",
  "displayStatus": "confirmed",
  "idempotencyKey": "af9a88a8-109f-4513-989b-12f2fb20a301",
  "currency": "KRW",
  "checkoutAmount": 20000,
  "discountAmount": 2000,
  "billingAmount": 18000,
  "chargingAmount": 18000,
  "canceledAmount": 0,
  "canceledBillingAmount": 0,
  "canceledDiscountAmount": 0,
  "returnUrl": "/result",
  "description": "[대용량]농심 안성탕면 125g X 40개 X 1박스",
  "merchantUserId": "xxxyyyzzz",
  "createdAt": "2018-12-18T05:14:22.337Z",
  "updatedAt": "2018-12-18T05:14:22.337Z",
  "charge": {
    "bankCode": "004",
    "bankName": "국민은행",
    "accountNumber": "123456789012"
  }
}

HTTP Request

POST api.chai.finance/v1/payment/:paymentId/confirm

Timeout

Parameters

Headers

Response

KeyTypeDescriptionMax Length
paymentIdString결제 고유 번호100
typeString결제 타입 (payment, charge)50
statusString결제 상태50
displayStatusString결제 상태 (상세)50
idempotencyKeyString가맹점 측 결제 고유 식별자 (중복 결제 방지용)100
currencyString사용할 화폐 (현재 KRW만 지원)3
checkoutAmountNumber결제 요청 금액
discountAmountNumber할인 금액
billingAmountNumber실결제 금액
chargingAmountNumber충전 금액 (잔여 포인트 부족시)
descriptionString결제 상세 정보 (상품명 등)500
returnUrlString결제 완료 후 돌아갈 페이지500
createdAtDate결제 생성일
updatedAtDate결제 최종 갱신일
chargeObject결제 계좌 정보

charge Object

KeyTypeDescriptionMax Length
bankCodeString은행 코드3
bankNameString은행명100
accountNumberString마스킹된 계좌번호100

취소

curl -X POST https://api.chai.finance/v1/payment/d22e1f5eab6fe7791725b0da921f665345c08e29/cancel \
-H 'Private-API-Key: 97d1de70-189b-4c64-a4dd-8d7af44ba8a4' \
-H 'Idempotency-Key: af9a88a8-109f-4513-989b-12f2fb20a301' \
-d '{
  "cancelAmount":10000, # 취소 금액 (필수)
}'

The above command returns JSON structured like this:

{
  "paymentId": "d22e1f5eab6fe7791725b0da921f665345c08e29",
  "type": "payment",
  "status": "canceled",
  "displayStatus": "canceled",
  "idempotencyKey": "af9a88a8-109f-4513-989b-12f2fb20a301",
  "currency": "KRW",
  "checkoutAmount": 20000,
  "discountAmount": 2000,
  "billingAmount": 18000,
  "chargingAmount": 18000,
  "canceledAmount": 20000,
  "canceledBillingAmount": 18000,
  "canceledDiscountAmount": 2000,
  "returnUrl": "/result",
  "description": "[대용량]농심 안성탕면 125g X 40개 X 1박스",
  "merchantUserId": "xxxyyyzzz",
  "createdAt": "2018-12-18T05:14:22.337Z",
  "updatedAt": "2018-12-18T05:14:22.337Z",
  "transactionResult": {
    "canceledAmount": 20000,
    "canceledBillingAmount": 18000,
    "canceledDiscountAmount": 2000
  }
}

HTTP Request

POST api.chai.finance/v1/payment/:paymentId/cancel

Timeout

Parameters

Headers

Parameters

KeyTypeDescriptionRequired
cancelAmountNumber취소 금액Y
checkoutAmountNumber취소요청시의 결제잔액(중복취소 방지용)
taxFreeAmountNumber복합과세: 취소 금액 중 비과세 금액
(기본값 0)
serviceFeeAmountNumber복합과세: 취소 금액 중 봉사료
bookShowAmountNumber복합과세: 취소 금액 중 도서공연비

중복 취소 방지

cancel api가 두 번 호출되어 부분 취소가 두 번 일어나는 일을 방지하려면, checkoutAmount(남은 결제잔액)을 넣어주세요.

복합과세 결제 취소 처리

결제 생성 시 복합과세 파라미터(비과세금액/봉사료/도서공연비)를 지정했다면, 취소 요청 시에도 반드시 어떤 부분에서 취소 처리할지 지정해야 합니다.

취소 요청하는 금액은 '남은 결제 금액'보다 작거나 같아야 하고, '과세 금액'과 '부가세'는 자동으로 계산됩니다.

Response

KeyTypeDescriptionMax Length
paymentIdString결제 고유 번호100
typeString결제 타입 (payment, charge)50
statusString결제 상태50
displayStatusString결제 상태 (상세)50
idempotencyKeyString가맹점 측 결제 고유 식별자 (중복 결제 방지용)100
currencyString사용할 화폐 (현재 KRW만 지원)3
checkoutAmountNumber취소 후 남은 결제 금액
discountAmountNumber취소 후 재계산 된 할인 금액
billingAmountNumber취소 후 남은 실결제 금액
chargingAmountNumber취소 후 남은 충전 금액
canceledAmountNumber취소된 금액 (누적)
canceledBillingAmountNumber취소된 실결제 금액 (누적)
canceledDiscountAmountNumber취소된 할인 금액 (누적)
descriptionString결제 상세 정보 (상품명 등)500
returnUrlString결제 완료 후 돌아갈 페이지500
createdAtDate결제 생성일
updatedAtDate결제 최종 갱신일
transactionResultObject트랜잭션 결과 값

transactionResult Object

KeyTypeDescriptionMax Length
canceledAmountNumber해당 트랜잭션에서 취소된 금액
canceledBillingAmountNumber해당 트랜잭션에서 취소된 실결제 금액
canceledDiscountAmountNumber해당 트랜잭션에서 취소된 할인 금액

영수증 조회

curl -X GET https://api.chai.finance/v1/payment/receipt \
-H 'Public-API-Key: 885738d9-78ed-483d-a923-e8db56aa393b' \
-H 'Idempotency-Key: af9a88a8-109f-4513-989b-12f2fb20a301'

The above command returns JSON structured like this:

{
  "paymentId": "d22e1f5eab6fe7791725b0da921f665345c08e29",
  "type": "payment",
  "status": "confirmed",
  "displayStatus": "confirmed",
  "idempotencyKey": "af9a88a8-109f-4513-989b-12f2fb20a301",
  "currency": "KRW",
  "checkoutAmount": 20000,
  "discountAmount": 2000,
  "billingAmount": 18000,
  "chargingAmount": 18000,
  "promotionAmount": 0,
  "canceledAmount": 0,
  "canceledBillingAmount": 0,
  "canceledDiscountAmount": 0,
  "returnUrl": "/result",
  "description": "[대용량]농심 안성탕면 125g X 40개 X 1박스",
  "merchantUserId": "xxxyyyzzz",
  "createdAt": "2018-12-18T05:14:22.337Z",
  "updatedAt": "2018-12-18T05:14:22.337Z",
  "merchant": {
    "name": "Test Merchant",
    "businessNumber": "123-45-67890",
    "address": "Seoul",
    "representativeName": "김차이",
    "customerServicePhone": "02-000-0000"
  },
  "initial": {
    "checkoutAmount": 20000,
    "discountAmount": 2000,
    "billingAmount": 18000,
    "chargingAmount": 18000,
  },
  "charge": {
    "bankCode": "000",
    "bankName": "XX은행",
    "accountNumber": "0000"
  },
  "cashReceipt": {
    "approve": [
      {
        "confirmCode": "F99999999",
        "isBookShow": false,
        "totalAmount": 18000,
        "supplyAmount": 16363,
        "vatAmount": 1637,
        "cashReceiptType": "consumer_number",
        "cashReceiptTypeName": "개인 소득공제",
        "cashReceiptNumber": "01012341234"
      }
    ],
    "taxFreeAmount": 0,
    "bookShowAmount": 0,
    "serviceFeeAmount": 0
  }
}

HTTP Request

GET api.chai.finance/v1/payment/receipt

Headers

Response

KeyTypeDescriptionMax Length
paymentIdString결제 고유 번호100
typeString결제 타입 (payment, charge)50
statusString결제 상태50
displayStatusString결제 상태 (상세)50
idempotencyKeyString가맹점 측 결제 고유 식별자 (중복 결제 방지용)100
currencyString사용할 화폐 (현재 KRW만 지원)3
checkoutAmountNumber결제 금액
discountAmountNumber할인 금액
billingAmountNumber실결제 금액
chargingAmountNumber충전 금액
canceledAmountNumber취소된 금액 (누적)
canceledBillingAmountNumber취소된 실결제 금액 (누적)
canceledDiscountAmountNumber취소된 할인 금액 (누적)
descriptionString결제 상세 정보 (상품명 등)500
returnUrlString결제 완료 후 돌아갈 페이지500
createdAtDate결제 생성일
updatedAtDate결제 최종 갱신일
merchantObject가맹점 정보
initialObject최초 결제 정보
chargeObject결제 계좌 정보
cashReceiptObject현금영수증 정보

merchant Object

KeyTypeDescriptionMax Length
nameString서비스명100
businessNumberString사업자번호100
addressString주소500
representativeNameString대표자명100
customerServicePhoneString고객센터100

initial Object

KeyTypeDescriptionMax Length
checkoutAmountNumber최초 결제 금액
discountAmountNumber최초 할인 금액
billingAmountNumber최초 실결제 금액
chargingAmountNumber최초 충전 금액

charge Object

KeyTypeDescriptionMax Length
bankCodeString은행 코드3
bankNameString은행명100
accountNumberString계좌번호100

cashReceipt Object

KeyTypeDescriptionMax Length
approveObject[]발급 내역
taxFreeAmountNumber비과세 금액
serviceFeeAmountNumber봉사료 금액
bookShowAmountNumber도서공연비 금액

approve Object

KeyTypeDescriptionMax Length
confirmCodeString승인번호100
cashReceiptTypeString현금영수증 발급 타입50
cashReceiptTypeNameString현금영수증 발급 타입 텍스트50
cashReceiptNumberString마스킹 처리 된 현금영수증 발급 번호50
isBookShowBoolean도서공연비 여부
totalAmountNumber총 금액
vatAmountNumber부가세
supplyAmountNumber공급가액

은행코드

CodeBankCodeBank
002산업은행003기업은행
004국민은행007수협
011농협020우리은행
023SC 은행031대구은행
032부산은행034광주은행
035제주은행037전북은행
039경남은행045새마을금고
048신협은행071우체국
088신한은행089K뱅크

Error 정의

에러 핸들링

400 Bad Request

{
  "type": "INVALID_REQUEST_ERROR",
}

403 Forbidden

{
  "type": "PAYMENT_ERROR",
  "message": "잔액이 부족합니다. 계좌를 확인해주세요",
  "code": "P004"
}

555 Server Error

{
  "type": "API_ERROR",
  "code": "S201"
}

HTTP(S) status code 200은 성공, 4XX는 실패, 5XX는 서버 또는 네트워크 관련 에러로 처리합니다.

CodeNameDescription
200OK정상적으로 요청이 완료됨
400Bad Request요청을 처리할 수 없음. 보통 필수 파라미터를 입력하지 않았을 때 발생
401Unauthorized유효한 API key가 제공되지 않았거나 권한이 부족함
402Request Failed파라미터는 제대로 입력됐으나 요청을 처리할 수 없음
403Forbidden요청 거부. 권한 없음
404Not Found요청한 주소에 리소스 존재하지 않음 (없는 페이지)
409Conflict요청이 다른 요청과 충돌함 (idempotency key가 중복된 경우)
429Too Many RequestsAPI를 너무 빠른 빈도로 요청했을 때 발생
500, 502, 503, 504Server ErrorsCHAI API 서버에 오류 발생

에러 종류

Error TypeDescription
API_CONNECTION_ERRORCHAI API 서버에 접속할 수 없을 때 발생하는 오류
API_ERROR다른 오류 외의 경우에 발생하는 오류 (예: 일시적인 오류 발생)
AUTHENTICATION_ERROR인증 실패
PAYMENT_ERROR결제 오류 (유저 취소, 잔액 부족 등)
IDEMPOTENCY_ERRORIdempotency Key는 같은데 다른 결제 정보가 들어올 경우 발생
INVALID_REQUEST_ERROR잘못된 파라미터를 입력하면 발생
RATE_LIMIT_ERRORAPI를 너무 빠르게 호출할 때 발생
VALIDATION_ERROR사용자가 잘못되거나 부족한 정보를 입력했을 때 발생
APP_VERSION_IS_TOO_OLD앱 버전이 최소 지원 버전보다 낮을 때 발생

에러 코드

5XX Server Error

TypeCodeMessageDescription
API_ERRORS001결제 데이터 생성 중 문제가 발생했습니다Transaction 실패
API_ERRORS002토큰을 가져오지 못했습니다token을 가져오지 못함
API_ERRORS003핀번호 검증 중 문제가 발생했습니다핀번호 체크 실패
API_ERRORS005ARS 인증에 실패했습니다ARS 인증 요청(승인) 실패
API_ERRORS101가맹점을 찾을 수 없습니다Merchant를 찾을 수 없음
API_ERRORS102계좌를 찾을 수 없습니다계좌를 찾을 수 없음
API_ERRORS103원장을 찾을 수 없습니다Ledger를 찾을 수 없음
API_ERRORS104충전 금액을 찾을 수 없습니다최초 결제시 충전금액을 찾을 수 없음
API_ERRORS105PG사 식별자를 찾을 수 없습니다PG사의 취소 번호를 찾을 수 없음
API_ERRORS106쿠폰을 찾을 수 없습니다쿠폰을 찾을 수 없음
API_ERRORS107은행 데이터를 찾을 수 없습니다은행 목록을 불러오지 못함
API_ERRORP101할인 금액 계산 중 문제가 발생했습니다할인금액 계산 오류
API_ERRORP102실 취소 금액 계산 중 문제가 발생했습니다취소된 실결제금액 계산 오류
API_ERRORS201오류가 발생했습니다API Call Error
API_ERRORS901데이터베이스 통신 중 문제가 발생했습니다DB Error
API_ERRORS902처리 중 타임아웃이 발생했습니다Timeout
API_ERRORS903모듈에 문제가 생겼습니다Module Error

4XX Client Error

TypeCodeMessageDescription
AUTHENTICATION_ERRORA001권한이 없습니다권한 없음
AUTHENTICATION_ERRORA002사용자를 찾을 수 없습니다User를 찾을 수 없음
AUTHENTICATION_ERRORA003사용이 제한된 상태입니다. 해제 후 다시 시도해주세요Inactive User
AUTHENTICATION_ERRORA004인증번호 확인 후 다시 입력해주세요잘못된 코드 번호
AUTHENTICATION_ERRORA005비밀번호가 맞지 않습니다(N회 틀림) 5회 연속 틀릴 경우 사용이 정지됩니다잘못된 핀번호
AUTHENTICATION_ERRORA006인증에 문제가 생겼습니다. 잠시 후 다시 시도해주세요OTP Error
AUTHENTICATION_ERRORA007입력 시간이 만료되었습니다. 재요청을 눌러 다시 인증해주세요만료됨
AUTHENTICATION_ERRORA008본인 인증에 실패했습니다. 입력하신 정보가 맞는지 확인해주세요인증 실패
AUTHENTICATION_ERRORA009전화번호, 생년월일과 연속된 숫자 또는 이전 비밀번호로 설정할 수 없습니다사용할 수 없는 핀번호
AUTHENTICATION_ERRORA010탈퇴 후 재가입은 12시간 이후에 가능합니다탈퇴 후 재가입 시간 제한
AUTHENTICATION_ERRORA011만 14세 이하 고객은 사용하실 수 없습니다사용자 나이 제한
AUTHENTICATION_ERRORA012결제 가능 시간이 지났습니다. 결제를 다시 시도해주세요결제 상태 오류
AUTHENTICATION_ERRORA013인증 시간이 만료되었습니다. 본인인증부터 다시 시작해주세요인증 시간 만료
AUTHENTICATION_ERRORA014등록된 비밀번호와 다릅니다비밀번호 오류
IDEMPOTENCY_ERRORC001결제 정보를 찾을 수 없습니다결제 정보 오류
IDEMPOTENCY_ERRORC002가맹점 정보에 문제가 있습니다잘못된 가맹점
IDEMPOTENCY_ERRORC003결제 상태에 문제가 있습니다결제 상태 오류
IDEMPOTENCY_ERRORC004이미 승인 완료된 거래입니다승인 완료된 거래
IDEMPOTENCY_ERRORC005이미 취소된 거래입니다취소된 거래
INVALID_REQUEST_ERRORR001요청이 없습니다요청 없음
INVALID_REQUEST_ERRORR003결제 금액에 문제가 있습니다요청 금액 오류
INVALID_REQUEST_ERRORR004화폐 단위에 문제가 있습니다잘못된 화폐
INVALID_REQUEST_ERRORR006쿠폰 적용에 문제가 생겼습니다. 확인 후 다시 시도해주세요쿠폰 오류
INVALID_REQUEST_ERRORR007이미 등록된 계좌입니다이미 등록된 계좌
INVALID_REQUEST_ERRORR008계좌에 문제가 있습니다. 확인 후 다시 시도해주세요계좌 오류
INVALID_REQUEST_ERRORR009본인 명의의 계좌만 등록하실 수 있습니다본인 명의 계좌 아님
INVALID_REQUEST_ERRORR010은행마다 하나의 계좌만 등록 가능합니다이미 존재하는 계좌
INVALID_REQUEST_ERRORR011계좌는 4개까지만 등록하실 수 있습니다. 기존 계좌 삭제 후 등록해주세요등록 가능한 계좌 수 초과
INVALID_REQUEST_ERRORR012최소 1개의 계좌가 등록되어 있어야 합니다최소 1개 이상의 계좌 필요
INVALID_REQUEST_ERRORR013취소 금액은 할인 금액보다 커야합니다취소 요청 금액 오류
INVALID_REQUEST_ERRORR014실결제금액 이상 취소할 수 없습니다실결제금액 이상 취소 불가
INVALID_REQUEST_ERRORR015잘못된 API 접근으로 문제가 생겼습니다API Key 오류
PAYMENT_ERRORP001이용할수 없는 계좌입니다. 은행으로 문의해주세요이용할 수 없는 계좌
PAYMENT_ERRORP002거래정지계좌는 사용할수 없습니다. 은행으로 문의해주세요거래 정지 계좌
PAYMENT_ERRORP003존재하지 않는 계좌입니다. 은행으로 문의해주세요존재하지 않는 계좌
PAYMENT_ERRORP004잔액이 부족합니다. 계좌를 확인해주세요잔액 부족
PAYMENT_ERRORP005이용한도를 초과했습니다. 은행으로 문의해주세요이용 한도 초과
PAYMENT_ERRORP006가상계좌 입금시간이 아닙니다. 확인후 다시 시도해주세요가상 계좌 입금 시간 아님
PAYMENT_ERRORP007은행 업무 시간이 아닙니다은행 업무 시간 아님
PAYMENT_ERRORP008은행 점검 시간입니다. 잠시 후 시도해주세요은행 점검 시간
PAYMENT_ERRORP009거래중 오류가 발생했습니다은행 거래 오류
PAYMENT_ERRORP0111회 최소 결제 금액은 XXX원 입니다최소 결제 금액 오류
PAYMENT_ERRORP0121회 최대 결제 금액은 XXX원 입니다최대 결제 금액 오류
PAYMENT_ERRORP013이미 사용된 쿠폰 입니다쿠폰 중복 적용
RATE_LIMIT_ERRORL001YYYY-MM-DD HH:mm:ss까지 시도하실 수 없습니다요청 제한

영수증 페이지

영수증 페이지에서 구매 정보, 결제 정보, 판매처 정보 및 현금영수증 발행정보를 확인할 수 있습니다.

URL

https://payment.chai.finance/receipt

URL Parameters

KeyDescription
publicAPIKey차이에서 제공한 공개키
idempotencyKey중복 결제 방지 식별자

Sample

https://payment-staging.chai.finance/receipt?publicAPIKey=885738d9-78ed-483d-a923-e8db56aa393b&idempotencyKey=a74fcb7d-2f3e-445a-8594-e7e36a31511d

일대사 정산

정산 파일은 매일 오전 4시에 생성됩니다. 날짜별로 정산 파일을 다운로드 받을 수 있습니다.

URL

https://settlement.chai.finance/prod/:publicAPIKey/:date.txt

KeyDescription
publicAPIKey차이에서 제공한 공개키
date정산 날짜 (YYYYMMDD)

Result

publicAPIKey | 거래발생시간 | 결제방식 | idempotencyKey | paymentId | 결제구분 | 결제금액(절대값) | 결제생성시간 | 결과코드 | 대금 지급일 | 결제금액 | 프로모션 분담금 | 유저 아이디

KeyDescription
publicAPIKey차이에서 제공한 공개키
거래발생시간트랜잭션 발생 시간 (YYYYMMDDHHmmss)
결제방식AT: 펌뱅킹
idempotencyKey결제 생성시 전달한 가맹점의 주문 번호
paymentId결제 생성시 받은 paymentId
결제구분P: 결제, C: 취소
결제금액결제한 금액 (절대값)
원거래발생시간결제 생성 시간 (YYYYMMDDHHmmss)
결과코드0000: 정상
대금 지급일정산대금 지급일
결제금액+,- 로 표기된 결제,취소금액
프로모션 분담금정산금액에서 제외되는 프로모션 비용 분담금
유저 아이디가맹점에서 결제시에 전달해준 유저 아이디

결과코드표

CodeDescription
0000정상
2001상점관리자 수동거래

Sample

Sample Data

6bfe11f5-23ac-4028-a9f0-e1f5ba02f0ff|20190722211801|AT|3d351bd0-1c6c-47c1-9de9-bdd59b2af9c9|69ac94eb50f4ca7aeb7d12748fc3593e22925349|P|33000|20190722211727|0000|20190805|33000|0|merchantUserId001
6bfe11f5-23ac-4028-a9f0-e1f5ba02f0ff|20190722220748|AT|26a0b2dd-6bbd-48a1-b64f-c65a75af9840|6472ee85f61c03d5e113743bbfff94ec815ba4ed|C|29900|20190722220717|0000|20190805|-29900|0|merchantUserId002
6bfe11f5-23ac-4028-a9f0-e1f5ba02f0ff|20190722212147|AT|93b87bd5-b819-42a6-b257-38df7e96c02f|1f23febb92cbae2cae607731433b21b138aa471e|P|56000|20190722212123|0000|20190805|56000|3000|merchantUserId003

https://settlement.chai.finance/staging/6bfe11f5-23ac-4028-a9f0-e1f5ba02f0ff/20190722.txt