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

Key Type Description Required Max Length
publicAPIKey String 발급 받은 Public API Key Y 100
paymentId String 서버에서 결제 생성 결과에 있는 paymentId Y 100
returnUrl String 결제 후 돌아올 가맹점 결제 페이지 url Y 500
idempotencyKey String 가맹점 주문 번호 (고유번호, 중복 결제 방지 등) Y 100
mode String 개발용: 'staging', 실서버: 'prod' N 100

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

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

Display Status

Display Status Description
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

Key Type Description Required Max Length
description String 결제 상세 정보 (상품명 등) Y 500
checkoutAmount Number 결제 금액 Y
returnUrl String 결제 후 이동될 가맹점 측 페이지 url Y 500
merchantUserId String 가맹점 측 유저 아이디 (CS 등에 사용) 100
currency String 사용할 화폐 (현재 KRW만 지원) 3
locale String 사용할 언어
auto(default), en, ko, zh
4
appScheme String 차이앱 결제후 앱복귀를 위한 URL scheme
(기본값 null)
cashReceipt Boolean 현금영수증 발급 가능 여부
(기본값 true)
taxFreeAmount Number 복합과세: 결제 금액 중 비과세 금액
(기본값 0)
serviceFeeAmount Number 복합과세: 결제 금액 중 봉사료
bookShowAmount Number 복합과세: 결제 금액 중 도서공연비
metadata Object {
  address: '서울시 강남구 ...',
  pid: 'promotion_id'
}

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

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

복합과세 처리

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

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

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

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

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

Response

Key Type Description Max Length
paymentId String 결제 고유 번호 100
type String 결제 타입 (payment, charge) 50
status String 결제 상태 50
displayStatus String 결제 상태 (상세) 50
idempotencyKey String 가맹점 측 결제 고유 식별자 (중복 결제 방지용) 100
currency String 사용할 화폐 (현재 KRW만 지원) 3
checkoutAmount Number 결제 요청 금액
billingAmount Number 실결제 금액
description String 결제 상세 정보 (상품명 등) 500
returnUrl String 결제 완료 후 돌아갈 페이지 500
createdAt Date 결제 생성일
updatedAt Date 결제 최종 갱신일

조회

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

Key Type Description Max Length
paymentId String 결제 고유 번호 100
type String 결제 타입 (payment, charge) 50
status String 결제 상태 50
displayStatus String 결제 상태 (상세) 50
idempotencyKey String 가맹점 측 결제 고유 식별자 (중복 결제 방지용) 100
currency String 사용할 화폐 (현재 KRW만 지원) 3
checkoutAmount Number 결제 요청 금액
discountAmount Number 할인 금액
billingAmount Number 실결제 금액
chargingAmount Number 충전 금액 (잔여 포인트 부족시)
canceledAmount Number 취소된 금액 (누적)
canceledBillingAmount Number 취소된 실결제 금액 (누적)
canceledDiscountAmount Number 취소된 할인 금액 (누적)
description String 결제 상세 정보 (상품명 등) 500
returnUrl String 결제 완료 후 돌아갈 페이지 500
createdAt Date 결제 생성일
updatedAt Date 결제 최종 갱신일

승인

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

Key Type Description Max Length
paymentId String 결제 고유 번호 100
type String 결제 타입 (payment, charge) 50
status String 결제 상태 50
displayStatus String 결제 상태 (상세) 50
idempotencyKey String 가맹점 측 결제 고유 식별자 (중복 결제 방지용) 100
currency String 사용할 화폐 (현재 KRW만 지원) 3
checkoutAmount Number 결제 요청 금액
discountAmount Number 할인 금액
billingAmount Number 실결제 금액
chargingAmount Number 충전 금액 (잔여 포인트 부족시)
description String 결제 상세 정보 (상품명 등) 500
returnUrl String 결제 완료 후 돌아갈 페이지 500
createdAt Date 결제 생성일
updatedAt Date 결제 최종 갱신일
charge Object 결제 계좌 정보

charge Object

Key Type Description Max Length
bankCode String 은행 코드 3
bankName String 은행명 100
accountNumber String 마스킹된 계좌번호 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

Key Type Description Required
cancelAmount Number 취소 금액 Y
checkoutAmount Number 취소요청시의 결제잔액(중복취소 방지용)
taxFreeAmount Number 복합과세: 취소 금액 중 비과세 금액
(기본값 0)
serviceFeeAmount Number 복합과세: 취소 금액 중 봉사료
bookShowAmount Number 복합과세: 취소 금액 중 도서공연비

중복 취소 방지

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

복합과세 결제 취소 처리

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

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

Response

Key Type Description Max Length
paymentId String 결제 고유 번호 100
type String 결제 타입 (payment, charge) 50
status String 결제 상태 50
displayStatus String 결제 상태 (상세) 50
idempotencyKey String 가맹점 측 결제 고유 식별자 (중복 결제 방지용) 100
currency String 사용할 화폐 (현재 KRW만 지원) 3
checkoutAmount Number 취소 후 남은 결제 금액
discountAmount Number 취소 후 재계산 된 할인 금액
billingAmount Number 취소 후 남은 실결제 금액
chargingAmount Number 취소 후 남은 충전 금액
canceledAmount Number 취소된 금액 (누적)
canceledBillingAmount Number 취소된 실결제 금액 (누적)
canceledDiscountAmount Number 취소된 할인 금액 (누적)
description String 결제 상세 정보 (상품명 등) 500
returnUrl String 결제 완료 후 돌아갈 페이지 500
createdAt Date 결제 생성일
updatedAt Date 결제 최종 갱신일
transactionResult Object 트랜잭션 결과 값

transactionResult Object

Key Type Description Max Length
canceledAmount Number 해당 트랜잭션에서 취소된 금액
canceledBillingAmount Number 해당 트랜잭션에서 취소된 실결제 금액
canceledDiscountAmount Number 해당 트랜잭션에서 취소된 할인 금액

영수증 조회

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

Key Type Description Max Length
paymentId String 결제 고유 번호 100
type String 결제 타입 (payment, charge) 50
status String 결제 상태 50
displayStatus String 결제 상태 (상세) 50
idempotencyKey String 가맹점 측 결제 고유 식별자 (중복 결제 방지용) 100
currency String 사용할 화폐 (현재 KRW만 지원) 3
checkoutAmount Number 결제 금액
discountAmount Number 할인 금액
billingAmount Number 실결제 금액
chargingAmount Number 충전 금액
canceledAmount Number 취소된 금액 (누적)
canceledBillingAmount Number 취소된 실결제 금액 (누적)
canceledDiscountAmount Number 취소된 할인 금액 (누적)
description String 결제 상세 정보 (상품명 등) 500
returnUrl String 결제 완료 후 돌아갈 페이지 500
createdAt Date 결제 생성일
updatedAt Date 결제 최종 갱신일
merchant Object 가맹점 정보
initial Object 최초 결제 정보
charge Object 결제 계좌 정보
cashReceipt Object 현금영수증 정보

merchant Object

Key Type Description Max Length
name String 서비스명 100
businessNumber String 사업자번호 100
address String 주소 500
representativeName String 대표자명 100
customerServicePhone String 고객센터 100

initial Object

Key Type Description Max Length
checkoutAmount Number 최초 결제 금액
discountAmount Number 최초 할인 금액
billingAmount Number 최초 실결제 금액
chargingAmount Number 최초 충전 금액

charge Object

Key Type Description Max Length
bankCode String 은행 코드 3
bankName String 은행명 100
accountNumber String 계좌번호 100

cashReceipt Object

Key Type Description Max Length
approve Object[] 발급 내역
taxFreeAmount Number 비과세 금액
serviceFeeAmount Number 봉사료 금액
bookShowAmount Number 도서공연비 금액

approve Object

Key Type Description Max Length
confirmCode String 승인번호 100
cashReceiptType String 현금영수증 발급 타입 50
cashReceiptTypeName String 현금영수증 발급 타입 텍스트 50
cashReceiptNumber String 마스킹 처리 된 현금영수증 발급 번호 50
isBookShow Boolean 도서공연비 여부
totalAmount Number 총 금액
vatAmount Number 부가세
supplyAmount Number 공급가액

은행코드

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

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는 서버 또는 네트워크 관련 에러로 처리합니다.

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

에러 종류

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

에러 코드

5XX Server Error

Type Code Message Description
API_ERROR S001 결제 데이터 생성 중 문제가 발생했습니다 Transaction 실패
API_ERROR S002 토큰을 가져오지 못했습니다 token을 가져오지 못함
API_ERROR S003 핀번호 검증 중 문제가 발생했습니다 핀번호 체크 실패
API_ERROR S005 ARS 인증에 실패했습니다 ARS 인증 요청(승인) 실패
API_ERROR S101 가맹점을 찾을 수 없습니다 Merchant를 찾을 수 없음
API_ERROR S102 계좌를 찾을 수 없습니다 계좌를 찾을 수 없음
API_ERROR S103 원장을 찾을 수 없습니다 Ledger를 찾을 수 없음
API_ERROR S104 충전 금액을 찾을 수 없습니다 최초 결제시 충전금액을 찾을 수 없음
API_ERROR S105 PG사 식별자를 찾을 수 없습니다 PG사의 취소 번호를 찾을 수 없음
API_ERROR S106 쿠폰을 찾을 수 없습니다 쿠폰을 찾을 수 없음
API_ERROR S107 은행 데이터를 찾을 수 없습니다 은행 목록을 불러오지 못함
API_ERROR P101 할인 금액 계산 중 문제가 발생했습니다 할인금액 계산 오류
API_ERROR P102 실 취소 금액 계산 중 문제가 발생했습니다 취소된 실결제금액 계산 오류
API_ERROR S201 오류가 발생했습니다 API Call Error
API_ERROR S901 데이터베이스 통신 중 문제가 발생했습니다 DB Error
API_ERROR S902 처리 중 타임아웃이 발생했습니다 Timeout
API_ERROR S903 모듈에 문제가 생겼습니다 Module Error

4XX Client Error

Type Code Message Description
AUTHENTICATION_ERROR A001 권한이 없습니다 권한 없음
AUTHENTICATION_ERROR A002 사용자를 찾을 수 없습니다 User를 찾을 수 없음
AUTHENTICATION_ERROR A003 사용이 제한된 상태입니다. 해제 후 다시 시도해주세요 Inactive User
AUTHENTICATION_ERROR A004 인증번호 확인 후 다시 입력해주세요 잘못된 코드 번호
AUTHENTICATION_ERROR A005 비밀번호가 맞지 않습니다(N회 틀림) 5회 연속 틀릴 경우 사용이 정지됩니다 잘못된 핀번호
AUTHENTICATION_ERROR A006 인증에 문제가 생겼습니다. 잠시 후 다시 시도해주세요 OTP Error
AUTHENTICATION_ERROR A007 입력 시간이 만료되었습니다. 재요청을 눌러 다시 인증해주세요 만료됨
AUTHENTICATION_ERROR A008 본인 인증에 실패했습니다. 입력하신 정보가 맞는지 확인해주세요 인증 실패
AUTHENTICATION_ERROR A009 전화번호, 생년월일과 연속된 숫자 또는 이전 비밀번호로 설정할 수 없습니다 사용할 수 없는 핀번호
AUTHENTICATION_ERROR A010 탈퇴 후 재가입은 12시간 이후에 가능합니다 탈퇴 후 재가입 시간 제한
AUTHENTICATION_ERROR A011 만 14세 이하 고객은 사용하실 수 없습니다 사용자 나이 제한
AUTHENTICATION_ERROR A012 결제 가능 시간이 지났습니다. 결제를 다시 시도해주세요 결제 상태 오류
AUTHENTICATION_ERROR A013 인증 시간이 만료되었습니다. 본인인증부터 다시 시작해주세요 인증 시간 만료
AUTHENTICATION_ERROR A014 등록된 비밀번호와 다릅니다 비밀번호 오류
IDEMPOTENCY_ERROR C001 결제 정보를 찾을 수 없습니다 결제 정보 오류
IDEMPOTENCY_ERROR C002 가맹점 정보에 문제가 있습니다 잘못된 가맹점
IDEMPOTENCY_ERROR C003 결제 상태에 문제가 있습니다 결제 상태 오류
IDEMPOTENCY_ERROR C004 이미 승인 완료된 거래입니다 승인 완료된 거래
IDEMPOTENCY_ERROR C005 이미 취소된 거래입니다 취소된 거래
INVALID_REQUEST_ERROR R001 요청이 없습니다 요청 없음
INVALID_REQUEST_ERROR R003 결제 금액에 문제가 있습니다 요청 금액 오류
INVALID_REQUEST_ERROR R004 화폐 단위에 문제가 있습니다 잘못된 화폐
INVALID_REQUEST_ERROR R006 쿠폰 적용에 문제가 생겼습니다. 확인 후 다시 시도해주세요 쿠폰 오류
INVALID_REQUEST_ERROR R007 이미 등록된 계좌입니다 이미 등록된 계좌
INVALID_REQUEST_ERROR R008 계좌에 문제가 있습니다. 확인 후 다시 시도해주세요 계좌 오류
INVALID_REQUEST_ERROR R009 본인 명의의 계좌만 등록하실 수 있습니다 본인 명의 계좌 아님
INVALID_REQUEST_ERROR R010 은행마다 하나의 계좌만 등록 가능합니다 이미 존재하는 계좌
INVALID_REQUEST_ERROR R011 계좌는 4개까지만 등록하실 수 있습니다. 기존 계좌 삭제 후 등록해주세요 등록 가능한 계좌 수 초과
INVALID_REQUEST_ERROR R012 최소 1개의 계좌가 등록되어 있어야 합니다 최소 1개 이상의 계좌 필요
INVALID_REQUEST_ERROR R013 취소 금액은 할인 금액보다 커야합니다 취소 요청 금액 오류
INVALID_REQUEST_ERROR R014 실결제금액 이상 취소할 수 없습니다 실결제금액 이상 취소 불가
INVALID_REQUEST_ERROR R015 잘못된 API 접근으로 문제가 생겼습니다 API Key 오류
PAYMENT_ERROR P001 이용할수 없는 계좌입니다. 은행으로 문의해주세요 이용할 수 없는 계좌
PAYMENT_ERROR P002 거래정지계좌는 사용할수 없습니다. 은행으로 문의해주세요 거래 정지 계좌
PAYMENT_ERROR P003 존재하지 않는 계좌입니다. 은행으로 문의해주세요 존재하지 않는 계좌
PAYMENT_ERROR P004 잔액이 부족합니다. 계좌를 확인해주세요 잔액 부족
PAYMENT_ERROR P005 이용한도를 초과했습니다. 은행으로 문의해주세요 이용 한도 초과
PAYMENT_ERROR P006 가상계좌 입금시간이 아닙니다. 확인후 다시 시도해주세요 가상 계좌 입금 시간 아님
PAYMENT_ERROR P007 은행 업무 시간이 아닙니다 은행 업무 시간 아님
PAYMENT_ERROR P008 은행 점검 시간입니다. 잠시 후 시도해주세요 은행 점검 시간
PAYMENT_ERROR P009 거래중 오류가 발생했습니다 은행 거래 오류
PAYMENT_ERROR P011 1회 최소 결제 금액은 XXX원 입니다 최소 결제 금액 오류
PAYMENT_ERROR P012 1회 최대 결제 금액은 XXX원 입니다 최대 결제 금액 오류
PAYMENT_ERROR P013 이미 사용된 쿠폰 입니다 쿠폰 중복 적용
RATE_LIMIT_ERROR L001 YYYY-MM-DD HH:mm:ss까지 시도하실 수 없습니다 요청 제한

영수증 페이지

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

URL

https://payment.chai.finance/receipt

URL Parameters

Key Description
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

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

Result

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

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

결과코드표

Code Description
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