이 문서는 카카오톡 인증 서비스의 K3500 전자서명 API 사용법을 안내합니다.
K3500 전자서명은 계약 또는 문서에 전자서명하는 서비스입니다. 이름, 생년월일, 전화번호, 사용자 연계정보(CI)를 활용하여 서명할 사용자를 특정합니다.
서명 요청 방식은 사용자가 카카오톡 앱을 실행시키고 서명하는 앱투앱(App to app) 방식, 카카오톡 채널을 통해 전자서명을 요청하는 메시지를 발송하는 채널 메시지 방식 두 가지를 제공합니다.
카카오톡 인증 서비스 API는 서버간 연동(Server to Server)을 원칙으로 합니다.
아래는 카카오톡 인증의 전자서명 과정을 표현한 시퀀스 다이어그램(Sequence Diagram)입니다.
위 과정을 요약하면 다음과 같습니다.
tx_id
를 발급받습니다.tx_id
로 전자서명 요청하기 API를 호출해 사용자의 인증을 요청하면, 카카오톡 앱 실행 또는 카카오톡 메시지로 사용자에게 인증 요청이 전달됩니다.identify_items
파라미터에 CI
를 지정해 전자서명 요청 시 서명자 정보 가져오기 API로 연계정보(CI)가 포함된 개인정보를 전달받아야 합니다.tx_id
로 전자서명 상태 확인하기 API를 호출해 진행 상태를 확인합니다.tx_id
로 전자서명 검증하기 API를 호출해 전자서명 값을 전달받습니다.tx_id
로 서명자 정보 가져오기 API를 호출해 서명자 정보를 전달받습니다.사용자는 다음과 같은 과정을 거쳐 전자서명을 수행합니다.
사용자는 아래와 같이 전자서명할 원문을 확인하고 서명할 수 있습니다. document_type
이 TEXT
인 경우에는 전문을 확인할 수 있는 페이지를 제공합니다.
메서드 | URL | 인증 방식 |
---|---|---|
POST |
https://cert-sign.kakao.com/sign/doc/v1/prepare/${PRODUCT_CODE} |
REST API 키 |
권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
---|---|---|---|
필요 | - | - | - |
전자서명 준비하기 API는 전자서명을 수행할 사용자의 정보를 카카오톡 인증 서비스에 전달하고 접수번호를 발급합니다. 이 API의 요청 결과로 받은 tx_id
를 사용해 다음 단계의 전자서명 요청하기, 상태 확인하기, 검증하기를 요청할 수 있습니다. 다건서명(K3511, K3521)의 경우 document_tx_ids
도 포함해야 합니다.
전자서명 준비하기 API는 요청 URL에 경로 변수(Path variable)로 상품 코드를 포함합니다. 예를 들어 K3511 상품 이용 시, 요청 URL의 마지막 부분에 /K3511
을 반드시 포함해야 합니다.
헤더(Header)에 이용기관 앱 REST API 키와 딜러사 앱 REST API 키를 담아 POST
로 요청합니다. 본문의 type
에 사용자 인증 방식을 입력하고, 하단에 각 인증 방식에 따라 필요한 사용자의 이름, 전화번호, 생년월일, CI를 JSON
형식으로 포함해야 합니다. 개인정보는 반드시 지정된 키로 암호화하여 전달해야 하며, 자세한 사항은 암호화 예제를 참고합니다. 다건서명의 경우 count
에 전자서명을 요청할 원문 갯수를 입력합니다.
요청 성공 시 응답은 tx_id
를 포함합니다. 요청 실패 시 문제 해결에서 에러 코드 정보를 확인합니다.
전자서명 준비하기 요청 시 사용자 개인정보인 이름, 전화번호, 생년월일과 서명할 데이터는 반드시 암호화 및 인코딩하여 전달해야 합니다. 다음 순서로 암호화와 인코딩을 처리합니다.
다음은 개인정보 암호화 및 인코딩 결과를 보여주는 예제입니다.
평문 | AES256 암호화 값 | Base64 인코딩 텍스트 |
---|---|---|
이름:홍길동 전화번호 : 01012345678 생년월일: 19950723 |
이름:[6a 33 59 45 34 35 6a 2b 74 67 2b 43] 전화번호: [55 74 36 35 4f 42 4a 31 61 62 55 74 75 45 59 3d] 생년월일: [4e 38 4d 6a 32 54 6f 3d] |
이름:ajNZRTQ1ait0ZytD 전화번호: VXQ2NU9CSjFhYlV0dUVZPQ== 생년월일: TjhNajJUbz0= |
이름 | 설명 | 필수 |
---|---|---|
Authorization | Authorization: KakaoAK ${DEALER_REST_API_KEY} 인증 방식, 딜러사 앱의 REST API 키로 인증 요청 |
O |
Target-Authorization | Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY} 인증 방식, 이용기관 앱 REST API 키로 인증 요청 |
O |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
PRODUCT_CODE | String |
상품 코드, 상품 상세 종류는 카카오톡 인증 상품 종류 참고 다음 중 이용하는 상품의 코드로 지정하여 요청: - K3510 : 단건서명 채널 메시지- K3520 : 단건서명 앱투앱- K3511 : 다건서명 채널 메시지- K3521 : 다건서명 앱투앱(예: K3511 상품 이용 시 요청 URL은 /sign/doc/v1/prepare/K3511 ) |
O |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
settle_id | String |
정산 ID | O |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
type | String |
사용자 인증 방식 다음 중 하나의 값 선택: PERSONAL_INFO : 전화번호, 성명, 생년월일 사용CI_WITH_PHONE_NO : CI, 전화번호 사용CI : CI 사용(기본값: PERSONAL_INFO )주의: 기본값이 아닌 CI_WITH_PHONE_NO 또는 CI 사용자 인증 방식은 매 요청 시 값을 설정해야 합니다.주의: CI 로 인증하는 경우, 지갑 채널을 통해서 채널 메시지가 발송됩니다. 파트너 채널을 이용할 수 없습니다. |
X |
phone_no | String |
암호화된 01000000000 형식의 사용자 전화번호하이픈(-)을 제외한 숫자로만 구성 주의: type 이 PERSONAL_INFO 또는 CI_WITH_PHONE_NO 인 경우 필수 |
X |
name | String |
암호화된 사용자 성명 주의: type 이 PERSONAL_INFO 인 경우 필수 |
X |
birthday | String |
암호화된 YYYYMMDD 형식의 사용자 생년월일 주의: type 이 PERSONAL_INFO 인 경우 필수 |
X |
ci | String |
연계정보(Connecting Information, CI) 카카오톡 전자서명 K3500 상품 이용 시 이용기관이 가진 권한 및 사용자 동의 여부에 따라, AES256(CTR) 방식으로 암호화된 CI 포함 주의: type 이 CI_WITH_PHONE_NO 또는 CI 인 경우 필수 |
X |
enc_version | Integer |
암호화 및 복호화 키 버전1 로 고정 |
O |
count | Integer |
전자서명을 요청할 원문의 갯수(기본: 1 , 최대: 200 )주의: 다건서명(K3511, K3521) 사용 시 필수 |
X |
이름 | 타입 | 설명 |
---|---|---|
tx_id | String |
전자서명 원문 접수번호 |
document_tx_ids | String |
개별 원문 접수번호 참고: 다건서명(K3511, K3521) 사용 시에만 응답에 포함 |
curl -i -X POST "https://cert-sign.kakao.com/sign/doc/v1/prepare/${PRODUCT_CODE}?settle_id=${SETTLE_ID}" \
-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \
-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \
-H "Content-Type: application/json;charset=UTF-8" \
-d '{
"enc_version": 1,
"type": "CI",
"ci": "WkrAtLgnmEoN2mbDqqZQfAlMagiWyQ4Zn+VjuGxKeg/6F3zIGQueEMkeSqaJHSUpaZycTXSf+gnqL2z44t2mlWiFdEYy8/3UiPSEiHoKSE6fTbhvr5cf1g=="
}'
curl -i -X POST "https://cert-sign.kakao.com/sign/doc/v1/prepare/${PRODUCT_CODE}?settle_id=${SETTLE_ID}" \
-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \
-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \
-H "Content-Type: application/json;charset=UTF-8" \
-d '{
"enc_version": 1,
"type": "CI",
"ci": "WkrAtLgnmEoN2mbDqqZQfAlMagiWyQ4Zn+VjuGxKeg/6F3zIGQueEMkeSqaJHSUpaZycTXSf+gnqL2z44t2mlWiFdEYy8/3UiPSEiHoKSE6fTbhvr5cf1g==",
"count": 20
}'
{
"tx_id": "02a05c5bfe-d89a-448b-a538-d80dc5b038fa"
}
{
"tx_id": "02a05c5bfe-d89a-448b-a538-d80dc5b038fa",
"document_tx_ids": [
"0297e72d72-7e09-4d94-b3f0-1d2eff325ab7",
"02bbe332fd-7f02-4633-991c-0d91037e592e",
"024778616f-3bd1-4201-b0ed-239eab1a86f4",
"02aaeaa7e4-c8d7-46c8-86f2-c4cb7f806c34",
"0228d38333-079e-4b8c-aaca-10445525ac30",
"0230bb3d41-9c13-4bef-9113-c2298e478f89",
"02cbffbc9a-e8b2-4f03-b06f-e8943b776de2",
"029a87e896-d778-4597-b689-e6ff99ed9d86",
"02a8834830-9be9-4dd8-bc75-161d5924654b",
"02216d11cc-f774-437a-b655-92f0b98ff0b7",
"027eeefd7c-2272-480d-9454-c277b28437cd",
"02a9375581-d2f4-40a9-ab7a-894b12e887f5",
"02badeb5e1-c34a-4ff9-a845-5175ac724ec6",
"02a05331fe-bcbc-4798-9980-de60bb5c03d5",
"02d656178a-8825-4aee-9d11-72cd9f16ec3d",
"02b014a10f-6dee-421f-b094-534e62c2f632",
"0271980626-f5cc-4823-922a-131d5b4fb1c1",
"02e9604452-bc82-4d5e-a3c6-38fc91c8fcc7",
"0233c6866c-435c-42a1-8902-3ed1486abfa1",
"02af5a8d26-c51d-48bb-ab58-91907b4cab2d"
]
}
메서드 | URL | 인증 방식 |
---|---|---|
POST |
https://cert-sign.kakao.com/sign/doc/v1/request |
REST API 키 |
권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
---|---|---|---|
필요 | - | - | - |
전자서명 요청하기 API는 전자서명 준비하기 API를 통해 접수된 tx_id
에 해당하는 전자서명 요청을 실행합니다. 이 API의 요청 성공 결과로 사용자의 카카오톡에 전자서명 요청 또는 채널 메시지가 발송됩니다. 앱투앱 방식(K3520, K3521) 상품 이용 시, 이 API의 요청 성공 결과로 받은 scheme
으로 카카오톡의 전자서명 요청 화면을 호출해야 합니다.
헤더(Header)에 이용기관 앱 REST API 키와 딜러사 앱 REST API 키를 담아 POST
로 요청합니다. 본문에 서명 원문을 포함한 전자서명 요청 정보를 JSON
형식으로 전달해야 합니다. 서명 원문은 단건서명(K3510, K3520)의 경우 document
에 JSON
형식으로, 다건서명(K3511, K3521)의 경우 documents
에 JSON
형식의 배열로 입력해야 합니다.
요청 성공 시 사용자에게 전자서명 요청이 보내지며, 응답은 tx_id
와 처리 결과인 result
를 포함합니다.
사용자는 전자서명 요청의 남은 유효시간 이내에 채널 메시지의 [인증하기] 버튼을 눌러 전자서명을 진행할 수 있습니다. 이미 전자서명을 완료했거나 유효시간이 경과한 후에는 사용자가 [인증하기] 버튼을 눌렀을 때 에러 안내가 나타납니다.
다음과 같은 경우에는 전자서명 요청이 실패할 수 있습니다.
ci
에 해당하는 카카오계정 없음ci
에 해당하는 카카오계정이 2개 이상이고, 그 중 유효한 인증서를 발급받은 카카오계정 없음요청 실패 시 문제 해결에서 에러 코드 정보를 확인합니다.
전자서명 요청하기의 파라미터 값은 사용자 인증 요청 안내문에 사용됩니다. 아래 예시와 설명을 참고합니다.
영역 | 파라미터 | 설명 |
---|---|---|
🅐 요청구분 | delegate_info.request_type |
요청구분, 공백 포함 최대 40자 단건서명 시 비노출 예: 거래내역 서명요청 |
🅑 요청기관 | - | 등록된 이용기관 이름 예: 서비스 이용기관 |
🅒 받는이 | delegate_info.receiver_name |
전자서명을 요청할 사용자 이름, 공백 포함 최대 80자 예: 김라연 |
🅓 서명요청 | document.document_title (단건서명)documents.document_title (다건서명) |
전자서명 요청 원문 정보 - 단건서명: 카카오톡 메시지와 인증 정보 화면에 document_title 값 출력- 다건서명: 카카오톡 메시지에는 첫 번째 전자서명 요청 원문의 document_title 값과 건수, 인증 정보 화면에는 document_title 값 목록 출력예: 거래내역 1 |
🅔 유효일시 | - | 전자서명 요청 시각으로부터 5분(300초) 후의 시각 |
🅕 서비스 이용기관 고객센터 | - | 등록된 이용기관 고객센터 이름과 연락처 |
🅖 커스텀 메시지 | extra_message |
이용기관에서 지정 가능한 상세 설명, 공백 포함 최대 500자 |
🅗 개인정보 제3자 제공 동의 | identify_items |
인증을 통해 이용기관에서 제공받을 서명자의 개인정보 동의항목 |
documents
목록은 전자서명 준비하기 API의 요청 성공 결과로 받은 document_tx_ids
와 동일한 순서여야 합니다. 해당 목록의 값 중 하나인 document
의 각 항목은 JSON
내부의 문자열(String)을 올바르게 해석(Parsing)할 수 있도록 역슬래시(\) 문자를 큰따옴표(") 앞에 표기해야 합니다. (예: "document": "{\"txId\": ...
) 파라미터 안내와 요청 예제를 참고합니다.
요청 실패 시 문제 해결에서 에러 코드 정보를 확인합니다.
이름 | 설명 | 필수 |
---|---|---|
Authorization | Authorization: KakaoAK ${DEALER_REST_API_KEY} 인증 방식, 딜러사 앱의 REST API 키로 인증 요청 |
O |
Target-Authorization | Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY} 인증 방식, 이용기관 앱 REST API 키로 인증 요청 |
O |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
settle_id | String |
정산 ID | O |
document_title
, document
documents
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
return_url | String |
전자서명 후 사용자가 복귀할 파트너 서비스 URL 전자서명 요청이 완료됐거나 실패했을 때, 사용자가 파트너 서비스로 이동할 수 있도록 하기 위해 사용 (최대: 255자) 주의: 채널 메시지 방식(K3510, K3511)에서 사용 불가 주의: URL에 스킴(Scheme) 지정 시 카카오톡 종료 스킴 사용 불가, 스킴 이름은 알파벳과 숫자만 사용 가능(예: kakaocert://xxxxx 사용 가능, kakao.cert://xxxxx 사용 불가) |
X |
expires_in | Integer |
처리 마감시간(단위: 초, 기본값: 600 , 최대값: 1200 ) |
X |
tx_id | String |
전자서명 요청 원문 접수번호 | O |
document_title | String |
전자서명 요청 원문 제목, 예제 참고 | O(Optional) |
document | String |
전자서명 요청 원문, 예제 참고 아래 항목 포함: txId : 전자서명 요청 원문 접수번호, tx_id 와 같은 값data : 전자서명 원문(최대 3000자) |
O(Optional) |
documents | Document[] |
전자서명 요청 원문 목록, Document 표, 예제 참고 | O(Optional) |
sign_type | String |
서명 방식 다음 중 하나 MESSAGE : 원문 그대로에 서명 진행SIGNED_ATTRIBUTE : 원문을 다이제스트(Digest)한 후에 SIGNED_ATTRIBUTE 에 서명 진행(기본값: MESSAGE ) |
O(Optional) |
document_type | String |
전자서명 요청 원문 작성 방식, 예제 참고 다음 중 하나 TEXT : 키와 값을 갖는 JSON STRING , 상세 서명정보 화면에 노출HASH : 해시 값, 상세 서명정보 화면에 노출되지 않음PLAIN_HASH : 해시 값으로 tx_id 가 붙지 않으며, 상세 서명정보 화면에 노출되지 않음, 원문 없는 전자서명 생성주의: document_type 이 PLAIN_HASH 인 경우, document 는 BASE64로 인코딩되어야 함 |
O |
hash_type | String |
원문 데이터 해시 알고리즘 다음 중 하나 NONE : 해시하지 않은 원문SHA1 , SHA224 , SHA256 , SHA384 , SHA512 : 원문이 해시된 알고리즘(ECDSA 알고리즘에 속하는 해시 알고리즘)document_type 별 기본값 정보:TEXT , HASH 인 경우, NONE PLAIN_HASH 인 경우, SHA256 |
O(Optional) |
document_encrypted | Boolean |
개별 전자서명 원문 내용의 암호화 여부, 암호화 예제 참고 (기본값: false ) |
X |
delegate_info | JSON |
사용자에게 보여질 인증 요청 안내문 delegate_info: 사용자 인증 요청 안내문과 예제 참고 |
O |
extra_message | String |
커스텀 메시지, 사용자에게 보여질 상세 설명, 사용자 인증 요청 안내문 참고 모든 문자 입력 가능, 공백 포함 최대 500자 주의: 카카오톡을 이용하여 메시지를 발송함에 있어 메시지 집행 가이드 및 발송 유의사항 가이드를 준수해야 하며, 위반 시 운영정책에 따라 서비스 이용이 제한될 수 있음 |
X |
identify_items | String[] |
서명자 정보 가져오기 응답으로 확인할 서명자 정보 목록 다음 중 하나 이상의 값 사용 가능 CI : 연계정보NAME : 이름BIRTHDAY : 생일PHONE_NUMBER : 전화번호GENDER : 성별 |
X |
* sign_type, hash_type 파라미터와 document_type의 PLAIN_HASH 값은 카카오톡 10.4.5 버전 이상에서만 사용 가능
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
document_tx_id | String |
개별 전자서명 접수번호 | O |
document_title | String |
개별 전자서명 제목 | O |
document | String |
개별 전자서명 요청 원문, JSON array 형식의 String으로 구성, 예제 참고 아래 항목 포함: txId : 전자서명 요청 원문 접수번호, document_tx_id 와 같은 값data : 전자서명 원문(최대 3000 자) |
O |
request_type
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
request_type | String |
요청 구분, 공백 포함 최대 40자 | O(Optional) |
receiver_name | String |
전자서명을 요청할 사용자 이름, 공백 포함 최대 80자 주의: 암호화 필수, 예제 참고 전자서명 준비하기 API의 type 이 PERSONAL_INFO 인 경우 필수카카오계정의 이름과 다른 경우 E2002 에러 발생 |
X |
* call_center_number, call_center_name, request_organization: Deprecated, 등록된 이용기관 정보를 사용하도록 변경
이름 | 타입 | 설명 |
---|---|---|
tx_id | String |
전자서명 원문 접수번호 |
result | String |
처리 결과Y : 정상 접수N : 접수 실패 |
scheme | String |
사용자가 카카오톡 앱을 실행해 전자서명을 수행할 수 있도록 하기 위한 커스텀 URL 스킴(Custom URL Scheme) 전자서명 요청하기 API 성공 응답을 통해 전달 받은 scheme 값을 사용해 사용자가 전자서명을 요청할 수 있도록 해야 함참고: 앱투앱 방식(K3520, K3521) 상품 이용 시에만 응답에 포함 |
curl -i -X POST "https://cert-sign.kakao.com/sign/doc/v1/request?settle_id=${SETTLE_ID}" \
-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \
-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \
-H "Content-Type: application/json;charset=UTF-8" \
-d '{
"tx_id": "02a05c5bfe-d89a-448b-a538-d80dc5b038fa",
"return_url": "https://www.sample.com/return_url",
"expires_in": 1200,
"document_type": "TEXT",
"delegate_info": {
"receiver_name": "ajNZRTQ1ait0ZytD" // 암호화 필수
},
"document_title": "카카오뱅크 거래내역",
"document": "{\"txId\": \"0297e72d72-7e09-4d94-b3f0-1d2eff325ab7\",\"data\": \"{\\\"납부자 출금은행\\\":\\\"카카오뱅크\\\",\\\"납부자 출금계좌번호\\\":\\\"111111-11-111111\\\",\\\"출금 계좌주명\\\":\\\"홍길동\\\"}\"}"
}'
curl -i -X POST "https://cert-sign.kakao.com/sign/doc/v1/request?settle_id=${SETTLE_ID}" \
-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \
-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \
-H "Content-Type: application/json;charset=UTF-8" \
-d '{
"tx_id": "02a05c5bfe-d89a-448b-a538-d80dc5b038fa",
"return_url": "https://www.sample.com/return_url",
"expires_in": 1200,
"identify_items": ["CI", "NAME", "BIRTHDAY", "PHONE_NUMBER", "GENDER"],
"document_type": "TEXT",
"delegate_info": {
"request_type": "전자계약",
"receiver_name": "ajNZRTQ1ait0ZytD" // 암호화 필수
},
"documents": [
{
"document_tx_id": "0297e72d72-7e09-4d94-b3f0-1d2eff325ab7",
"document_title": "카카오뱅크 거래내역",
"document": "{\"txId\": \"0297e72d72-7e09-4d94-b3f0-1d2eff325ab7\",\"data\": \"{\\\"납부자 출금은행\\\":\\\"카카오뱅크\\\",\\\"납부자 출금계좌번호\\\":\\\"111111-11-111111\\\",\\\"출금 계좌주명\\\":\\\"홍길동\\\"}\"}"
},
...
]
}'
curl -i -X POST "https://cert-sign.kakao.com/sign/doc/v1/request?settle_id=${SETTLE_ID}" \
-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \
-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \
-H "Content-Type: application/json;charset=UTF-8" \
-d '{
"tx_id": "02a05c5bfe-d89a-448b-a538-d80dc5b038fa",
"return_url": "https://www.sample.com/return_url",
"expires_in": 1200,
"identify_items": ["CI", "NAME", "BIRTHDAY", "PHONE_NUMBER", "GENDER"],
"document_type": "HASH",
"delegate_info": {
"receiver_name": "ajNZRTQ1ait0ZytD" // 암호화 필수
},
"document_title": "카카오뱅크 거래내역",
"document": "{\"txId\": \"0297e72d72-7e09-4d94-b3f0-1d2eff325ab7\",\"data\": \"715cfad410498ece9eea5f9f6d963904cf62341d74379c3dcd76e01e37e6a621\"}"
}'
curl -i -X POST "https://cert-sign.kakao.com/sign/doc/v1/request?settle_id=${SETTLE_ID}" \
-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \
-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \
-H "Content-Type: application/json;charset=UTF-8" \
-d '{
"tx_id": "02a05c5bfe-d89a-448b-a538-d80dc5b038fa",
"return_url": "https://www.sample.com/return_url",
"expires_in": 1200,
"identify_items": ["CI", "NAME", "BIRTHDAY", "PHONE_NUMBER", "GENDER"],
"document_type": "HASH",
"delegate_info": {
"request_type": "전자계약",
"receiver_name": "ajNZRTQ1ait0ZytD" // 암호화 필수
},
"documents": [
{
"document_tx_id": "0297e72d72-7e09-4d94-b3f0-1d2eff325ab7",
"document_title": "카카오뱅크 거래내역",
"document": "{\"txId\": \"0297e72d72-7e09-4d94-b3f0-1d2eff325ab7\",\"data\": \"715cfad410498ece9eea5f9f6d963904cf62341d74379c3dcd76e01e37e6a621\"}"
},
...
]
}'
curl -i -X POST "https://cert-sign.kakao.com/sign/doc/v1/request?settle_id=${SETTLE_ID}" \
-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \
-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \
-H "Content-Type: application/json;charset=UTF-8" \
-d '{
"tx_id": "02a05c5bfe-d89a-448b-a538-d80dc5b038fa",
"return_url": "https://www.sample.com/return_url",
"expires_in": 1200,
"identify_items": ["CI", "NAME", "BIRTHDAY", "PHONE_NUMBER", "GENDER"],
"document_type": "PLAIN_HASH",
"delegate_info": {
"receiver_name": "ajNZRTQ1ait0ZytD" // 암호화 필수
},
"document_title": "카카오뱅크 거래내역",
"document": "715cfad410498ece9eea5f9f6d963904cf62341d74379c3dcd76e01e37e6a621"
}'
curl -i -X POST "https://cert-sign.kakao.com/sign/doc/v1/request?settle_id=${SETTLE_ID}" \
-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \
-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \
-H "Content-Type: application/json;charset=UTF-8" \
-d '{
"tx_id": "02a05c5bfe-d89a-448b-a538-d80dc5b038fa",
"return_url": "https://www.sample.com/return_url",
"expires_in": 1200,
"identify_items": ["CI", "NAME", "BIRTHDAY", "PHONE_NUMBER", "GENDER"],
"document_type": "PLAIN_HASH",
"delegate_info": {
"request_type": "전자계약",
"receiver_name": "ajNZRTQ1ait0ZytD" // 암호화 필수
},
"documents": [
{
"document_tx_id": "0297e72d72-7e09-4d94-b3f0-1d2eff325ab7",
"document_title": "카카오뱅크 거래내역",
"document": "715cfad410498ece9eea5f9f6d963904cf62341d74379c3dcd76e01e37e6a621"
},
...
]
}'
{
"tx_id": "02a05c5bfe-d89a-448b-a538-d80dc5b038fa",
"result": "Y"
}
{
"tx_id": "02a05c5bfe-d89a-448b-a538-d80dc5b038fa",
"result": "Y",
"scheme": "kakaotalk://…"
}
메서드 | URL | 인증 방식 |
---|---|---|
GET |
https://cert-sign.kakao.com/sign/doc/v1/status |
REST API 키 |
권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
---|---|---|---|
필요 | - | - | - |
전자서명 상태 확인하기 API는 카카오톡 전자서명 K3500 상품으로 요청된 전자서명의 진행 상태를 확인합니다. 사용자는 카카오톡을 통해 인증을 수행하므로, 이용기관은 전자서명 상태 확인하기 API를 통해서만 인증 진행 상태를 확인할 수 있습니다.
헤더(Header)에 이용기관 앱 REST API 키와 딜러사 앱 REST API 키를 담아 GET
으로 요청합니다. 본문에 상태를 확인할 전자서명 요청의 tx_id
와 settle_id
를 포함해야 합니다.
요청 성공 시 응답은 전자서명의 상태를 포함합니다. 전자서명의 상태는 요청(REQUESTED
), 완료(COMPLETED
), 만료(EXPIRED
) 세 가지로 각각 다음과 같이 조치합니다.
viewed_at
필드 값으로 확인 가능전자서명이 완료된 경우에는 사용자가 서명한 일시, 전자서명이 만료되는 일시를 비롯한 시간 정보들을 제공합니다. 이미 이용기관이 전자서명 검증하기 API를 통해 전자서명 값을 전달받았다면, 전자서명 값이 전달된 일시 정보를 제공합니다.
사용자의 인증서 상태에 따라 인증서를 발급 또는 재발급하거나 2차 본인인증(은행 계좌 확인)을 해야 할 수 있습니다. 이 경우, 추가 인증까지 모두 완료된 후 전자서명 상태가 완료로 변경됩니다.
요청 실패 시 문제 해결에서 에러 코드 정보를 확인합니다.
이름 | 설명 | 필수 |
---|---|---|
Authorization | Authorization: KakaoAK ${DEALER_REST_API_KEY} 인증 방식, 딜러사 앱의 REST API 키로 인증 요청 |
O |
Target-Authorization | Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY} 인증 방식, 이용기관 앱 REST API 키로 인증 요청 |
O |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
settle_id | String |
정산 ID | O |
tx_id | String |
전자서명 원문 접수번호 | O |
이름 | 타입 | 설명 |
---|---|---|
tx_id | String |
전자서명 원문 접수번호 |
status | String |
전자서명 상태, 다음 중 하나REQUESTED : 사용자에게 전자서명을 요청함, 사용자는 채널 메시지를 통해 전자서명 요청을 받음COMPLETED : 사용자가 전자서명을 완료함EXPIRED : 유효시간 이내에 사용자가 전자서명을 완료하지 않아 요청이 만료됨 |
created_at | String |
전자서명 요청 일시* |
viewed_at | String |
사용자가 전자서명 요청을 확인한 일시* |
completed_at | String |
사용자가 전자서명을 완료한 일시* |
expired_at | String |
전자서명 만료 일시* |
partner_notified_at | String |
이용기관이 전자서명 검증하기 API를 통해 전자서명 값을 전달받은 일시* |
* 시간은 yyyy-MM-dd'T'HH:mm:ss 형식, RFC3339 참고
curl -i -X GET "https://cert-sign.kakao.com/sign/doc/v1/status?settle_id=${SETTLE_ID}&tx_id=${TX_ID}" \
-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \
-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \
-H "Content-Type: application/json;charset=UTF-8"
{
"status": "REQUESTED",
"tx_id": "d3a83f53-239d-4d7a-968d-25ec0969047e",
"created_at": "2021-06-18 13:53:36",
"viewed_at": null,
"completed_at": null,
"expired_at": "2021-06-18 14:03:36",
"partner_notified_at": null
}
메서드 | URL | 인증 방식 |
---|---|---|
GET |
https://cert-sign.kakao.com/sign/doc/v1/verify |
REST API 키 |
권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
---|---|---|---|
필요 | - | - | - |
전자서명 검증하기 API는 완료된 전자서명을 검증하고 이용기관에 전자서명 데이터 전문을 제공합니다. 이 API는 카카오톡 전자서명 K3500에 대한 검증을 지원합니다.
이 API는 완료된 전자서명 요청당 1회만 요청 가능하며, 사용자가 서명을 완료한 후, 일정시간(10분) 동안만 정상 응답합니다. 이후 요청에 대해서는 E2013
에러가 발생합니다.
헤더(Header)에 이용기관 앱 REST API 키와 딜러사 앱 REST API 키를 담아 GET
으로 요청합니다. 본문에 완료된 전자서명 요청의 tx_id
와 정산 ID를 포함해야 합니다.
요청 성공 시 응답은 전자서명의 상태와 전자서명 검증 결과를 포함합니다. 요청 실패 시 문제 해결에서 에러 코드 정보를 확인합니다.
전자서명 검증하기 응답 구성은 다음 표를 참고합니다.
상품 | 기본 검증 값 | Response 필드 구성 |
---|---|---|
K3500 | 전자서명 요청하기 API 요청 시 전달된 data 값에 대한 전자서명 데이터 전문 |
result , ci *, vid **, signed_document (K3510, K3520), signed_documents (K3511, K3521) |
* ci: 계약 시 협의한 경우에만 제공
** vid: CI를 제공받고 있거나 VID만 제공하는 상품 이용 시 제공, 자세한 안내는 VID 참고
이름 | 설명 | 필수 |
---|---|---|
Authorization | Authorization: KakaoAK ${DEALER_REST_API_KEY} 인증 방식, 딜러사 앱의 REST API 키로 인증 요청 |
O |
Target-Authorization | Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY} 인증 방식, 이용기관 앱 REST API 키로 인증 요청 |
O |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
settle_id | String |
정산 ID | O |
tx_id | String |
전자서명 원문 접수번호 | O |
이름 | 타입 | 설명 |
---|---|---|
status | String |
전자서명 상태, 전자서명 검증 시에는 전자서명이 완료된 상태인 COMPLETE 값만 제공되며, 이 외 상태인 경우 에러 응답 |
result | String |
전자서명 검증 결과Y : 검증 성공N : 실패 |
ci | String |
연계정보(Connecting Information, CI) 카카오톡 전자서명 K3500 상품 이용 시 이용기관이 가진 권한 및 사용자 동의 여부에 따라, AES256(CTR) 방식으로 암호화된 CI 포함 비고: 전자서명 요청하기 요청의 identify_items 에 CI 포함 시 응답에 미포함 |
vid | String |
계약 시 ci 제공에 협의한 경우에만 제공사용자의 원본 CI(Base64 decoded CI)와 인증서 일련번호(Serial number byte array)로 구성된 SHA256 해시 값( sha256_hash ) |
signed_document | String |
전자서명 데이터 전문 (참고: CMSSignedData) 참고: 단건서명(K3510, K3520) 사용 시에만 응답에 포함 |
signed_documents | SignedDocument[] |
전자서명이 완료된 문서 목록 다음을 포함: document_tx_id : 전자서명 요청 원문 접수번호signed_document : 전자서명 데이터 전문, 아래 signed_document: 전자서명 데이터 전문 표 참고참고: 다건서명(K3511, K3521) 사용 시에만 응답에 포함 |
이름 | 타입 | 설명 |
---|---|---|
document_tx_id | String |
개별 전자서명 접수번호 |
signed_document | String |
전자서명 데이터 전문 (참고: CMSSignedData) |
curl -i -X GET "https://cert-sign.kakao.com/sign/doc/v1/verify?settle_id=${SETTLE_ID}&tx_id=${TX_ID}" \
-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \
-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \
-H "Content-Type: application/json;charset=UTF-8"
{
"status": "COMPLETED",
"result": "Y",
"signed_document": "${CMSSignedData}" // 상단 설명 및 표 참고
}
{
"status": "COMPLETED",
"result": "Y",
"ci": "${CI}", // 상단 설명 및 표 참고
"vid": "${VID}", // 상단 설명 및 표 참고
"signed_document": "${CMSSignedData}" // 상단 설명 및 표 참고
}
{
"status": "COMPLETED",
"result": "Y",
"signed_documents": [
{
"document_tx_id": "0297e72d72-7e09-4d94-b3f0-1d2eff325ab7", // 상단 설명 및 표 참고
"signed_document": "${CMSSignedData}" // 상단 설명 및 표 참고
}
]
}
{
"status": "COMPLETED",
"result": "Y",
"ci": "${CI}", // 상단 설명 및 표 참고
"vid": "${VID}", // 상단 설명 및 표 참고
"signed_documents": [
{
"document_tx_id": "0297e72d72-7e09-4d94-b3f0-1d2eff325ab7", // 상단 설명 및 표 참고
"signed_document": "${CMSSignedData}" // 상단 설명 및 표 참고
}
]
}
아래는 실제 서비스에서 고려해야 할 여러 요소(성능, 예외 처리, 동시성 등)가 반영되지 않은 참고용 예제입니다.
class VerifySample {
val kakaoClient = HttpClient.newBuilder().build()
val mapper = ObjectMapper()
val settleId = "PARTNER_SETTLE_ID"
private val transformation = "AES/CTR/NoPadding"
private val secretKeySpec = SecretKeySpec("PARTNER_SECRET_KEY".decodeBase64(), "AES")
private val ivSpec = IvParameterSpec("PARTNER_IV".decodeBase64())
private fun decrypt(content: ByteArray): String =
Cipher.getInstance(transformation).run {
init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec)
String(doFinal(content))
}
private fun createHttpRequest(uri: URI): HttpRequest {
return HttpRequest.newBuilder()
.uri(uri)
.setHeader(AUTHORIZATION, DEALER_REST_API_KEY)
.setHeader(TARGET_AUTHORIZATION, PARTNER_REST_API_KEY)
.GET()
.build()
}
// 전자서명 검증하기 API
private fun callVerify(txId: String): VerifyResponse {
val uri = URI.create(createURI(txId))
val response: HttpResponse<String> = kakaoClient.send(createHttpRequest(uri), HttpResponse.BodyHandlers.ofString())
return mapper.readValue<VerifyResponse>(response.body())
}
private fun createURI(txId: String): String {
val sb = StringBuilder()
sb.append("https://cert-sign.kakao.com/sign/doc/v1/verify?settle_id=")
.append(settleId)
.append("&tx_id=")
.append(txId)
return sb.toString()
}
/**
* 이용기관에서 CI를 보유한 경우
* 전자서명 검증하기 API를 호출하여 보유한 CI와 비교
* !!중요!! 전자서명 검증하기 API 호출 및 CI 비교는 반드시 서버에서 수행
*/
// 전자서명 검증하기 API 호출
fun compareCI(txId: String): Boolean {
// 응답에 포함된 CI를 복호화
val encryptedCi = callVerify(txId).ci
// 이용기관에서 보유한 CI와 비교
val decryptedCI = decrypt(encryptedCi.decodeBase64())
return exist(decryptedCI)
}
/**
* 실명인증된 CI가 있는 경우
* 전자서명 검증하기 API의 결과와 실명인증된 CI를 비교
* !!중요!! 전자서명 검증하기 API 호출 및 CI 비교는 반드시 서버에서 수행
*/
// 전자서명 검증하기 API 호출
fun compareCI(txId: String, ci: String): Boolean {
// 응답에 포함된 CI를 복호화
val encryptedCi = callVerify(txId).ci
// 실명인증된 CI와 비교
val decryptedCI = decrypt(encryptedCi.decodeBase64())
return ci == decryptedCI
}
}
class VerifySample {
private final HttpClient kakaoClient = HttpClient.newBuilder().build();
private final SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode("PARTNER_SECRET_KEY"), "AES");
private final IvParameterSpec ivSpec = new IvParameterSpec(Base64.getDecoder().decode("PARTNER_IV"));
private final String settleId = "PARTNER_SETTLE_ID";
private String decrypt(byte[] content) throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeyException {
String transformation = "AES/CTR/NoPadding";
Cipher cipher = Cipher.getInstance(transformation);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);
return new String(cipher.doFinal(content));
}
private HttpRequest createHttpRequest(URI uri) {
return HttpRequest.newBuilder()
.uri(uri)
.setHeader(AUTHORIZATION, DEALER_REST_API_KEY)
.setHeader(TARGET_AUTHORIZATION, PARTNER_REST_API_KEY)
.GET()
.build();
}
private VerifyResponse callVerify(String txId) throws IOException, InterruptedException {
URI uri = URI.create(createURI(txId));
// 전자서명 검증하기 API
HttpResponse<String> response = kakaoClient.send(createHttpRequest(uri), HttpResponse.BodyHandlers.ofString());
return Mapper.getInstance().readValue(response.body(), VerifyResponse.class);
}
private String createURI(String txId) {
StringBuilder sb = new StringBuilder();
sb.append("https://cert-sign.kakao.com/sign/doc/v1/verify?settle_id=")
.append(settleId)
.append("&tx_id=")
.append(txId);
return sb.toString();
}
/**
* 이용기관에서 CI를 보유한 경우
* 전자서명 검증하기 API를 호출하여 보유한 CI와 비교
* !!중요!! 전자서명 검증하기 API 호출 및 CI 비교는 반드시 서버에서 수행
*/
// 전자서명 검증하기 API 호출
boolean compareCI(String txId) throws IOException, InterruptedException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
// 응답에 포함된 CI를 복호화
String encryptedCi = callVerify(txId).getCi();
// 이용기관에서 보유한 CI와 비교
String decryptedCI = decrypt(Base64.getDecoder().decode(encryptedCi));
return exist(decryptedCI);
}
/**
* 실명인증된 CI가 있는 경우
* 전자서명 검증하기 API의 결과와 실명인증된 CI를 비교
* !!중요!! 전자서명 검증하기 API 호출 및 CI 비교는 반드시 서버에서 수행
*/
// 전자서명 검증하기 API 호출
boolean compareCI(String txId, String ci) throws IOException, InterruptedException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
// 응답에 포함된 CI를 복호화
String encryptedCi = callVerify(txId).getCi();
// 실명인증된 CI와 비교
String decryptedCI = decrypt(Base64.getDecoder().decode(encryptedCi));
return ci.equals(decryptedCI);
}
}
class VerifySample {
private:
//카카오의 전자서명 검증하기 API를 호출.
json callVerify(const string& txId) {
string uri = createURI(txId);
auto response = kakaoClient.Get(uri.c_str());
return json::parse(response->body);
}
string createURI(const string& txId) {
return "https://cert-sign.kakao.com/sign/doc/v1/verify?settle_id=" + settleId + "&tx_id=" + txId;
}
public:
/**
* 이용기관에서 CI를 보유한 경우
* 전자서명 검증하기 API를 호출하여 보유한 CI와 비교
* !!중요!! 전자서명 검증하기 API 호출 및 CI 비교는 반드시 서버에서 수행
*/
// 전자서명 검증하기 API 호출
bool compareCI(const string& txId) {
// 응답에 포함된 CI를 복호화
string encryptedCi = callVerify(txId)["ci"];
// 이용기관에서 보유한 CI와 비교
string decryptedCI = decrypt(base64_decode(encryptedCi));
return exist(decryptedCI);
}
/**
* 실명인증된 CI가 있는 경우
* 전자서명 검증하기 API의 결과와 실명인증된 CI를 비교
* !!중요!! 전자서명 검증하기 API 호출 및 CI 비교는 반드시 서버에서 수행
*/
// 전자서명 검증하기 API 호출
bool compareCI(const string& txId, const string& ci) {
// 응답에 포함된 CI를 복호화
string encryptedCi = callVerify(txId)["ci"];
// 실명인증된 CI와 비교
string decryptedCI = decrypt(base64_decode(encryptedCi));
return ci == decryptedCI;
}
};
메서드 | URL | 인증 방식 |
---|---|---|
GET |
https://cert-sign.kakao.com/sign/v2/identify |
REST API 키 |
권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
---|---|---|---|
필요 | - | - | - |
서명자 정보받기 API는 서명을 완료한 서명자 정보를 제공합니다.
이 API는 전자서명 검증하기 호출 후 요청 가능하며, 사용자 서명 완료 후 일정시간(10분)동안 1회만 요청 가능합니다. 이후 요청에 대해서는 E2017
에러가 발생합니다. 서명자의 개인정보 제공 동의 및 서명 완료 후, 개발 설계 오류, 네트워크 오류 등으로 인한 이용기관의 정보 수신 실패에 대해 카카오는 책임을 지지 않습니다.
헤더(Header)에 이용기관 앱 REST API 키와 딜러사 앱 REST API 키를 담아 GET
으로 요청합니다. 본문에 완료된 전자서명 요청의 tx_id
와 정산 ID를 포함해야 합니다.
요청 성공 시 응답은 전자서명 요청하기의 identify_items
파라미터로 지정한 서명자 정보를 포함합니다. 요청 실패 시 문제 해결에서 에러 코드 정보를 확인합니다.
카카오톡 인증 서비스에서 제공하는 연계정보(CI)와 이름, 생년월일, 전화번호는 사용자 비교 및 검증 용도로만 사용할 수 있습니다. 서명자 정보 가져오기 API를 통해 제공받은 CI, 이름, 생년월일, 전화번호를 이용기관의 정보와 비교해 올바른 사용자인지 검증해야 합니다. 비교 및 검증은 반드시 이용기관 서버에서 수행해야 합니다.
이름 | 설명 | 필수 |
---|---|---|
Authorization | Authorization: KakaoAK ${DEALER_REST_API_KEY} 인증 방식, 딜러사 앱의 REST API 키로 인증 요청 |
O |
Target-Authorization | Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY} 인증 방식, 이용기관 앱 REST API 키로 인증 요청 |
O |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
settle_id | String |
정산 ID | O |
tx_id | String |
전자서명 원문 접수번호 | O |
이름 | 타입 | 설명 |
---|---|---|
name | String |
암호화된 서명자의 이름 |
phone_no | String |
암호화된 서명자의 카카오톡 전화번호 |
birthday | String |
암호화된 서명자의 생년월일 |
gender | String |
암호화된 서명자의 성별 |
ci | String |
암호화된 서명자의 CI(연계정보) 비고: 전자서명 검증하기로 CI 수신 시 응답에 미포함 |
vid | String |
암호화된 서명자의 CI 검증값 비고: 전자서명 검증하기로 CI 수신 시 응답에 미포함 |
curl -i -X GET "https://cert-sign.kakao.com/sign/v2/identify?settle_id=${SETTLE_ID}&tx_id=${TX_ID}" \
-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \
-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \
-H "Content-Type: application/json;charset=UTF-8"
{
"name": "${NAME}",
"phone_no": "${PHONE_NO}",
"birthday": "${BIRTHDAY}",
"gender": "${GENDER}",
"ci": "${CI}",
"vid": "${VID}"
}