사이드 메뉴
시작하기
로그인
커뮤니케이션
광고
D31: 전자서명문서
이 문서는 카카오톡 전자문서의 D31 전자서명문서 상품 API 사용법을 안내합니다.
카카오톡 전자문서의 D31, 전자서명문서 상품은 문서를 열람한 사용자가 열람한 문서 원문에 대해 전자서명 할 수 있도록 서명 기능을 제공하는 상품입니다. 전자서명문서는 HTML 형식의 전자문서 원문만 지원하며, 문서 발송 요청이 성공하면 문서를 수신하는 사용자에게 카카오톡 알림톡으로 문서 수신 알림을 발송합니다.
세부 상품에 따라, 문서 열람 시 사용자가 카카오 인증서로 본인 확인 과정을 거치도록 할 수 있습니다. 문서를 열람한 이후 사용자는 카카오 인증서로 전자서명을 수행할 수 있으며, 전자서명을 완료한 경우 이용기관은 서명값 조회 API를 호출하여 전자서명 데이터를 제공받을 수 있습니다. 전자서명문서 중 열람 시 본인확인을 하는 상품의 경우 유통정보의 생성 및 등록을 지원합니다.
아래는 D31 상품의 발송 및 열람 과정을 표현한 시퀀스 다이어그램(Sequence Diagram)입니다.

- 이용기관은 문서 발송 API로 문서를 수신할 사용자 정보와 문서 정보를
envelopeId(문서 고유 ID)를 발급받습니다. - 카카오톡 전자문서 서버는 수신자 정보로 카카오톡 사용자를 식별한 뒤, 해당 사용자에게 문서를 생성하고 문서 수신 알림톡을 발송합니다.
D31_2와D31_3상품의 경우, 사용자가 문서를 열람할 때 카카오 인증서로 본인 확인 과정을 수행합니다. 사용자는 인증에 성공해야 문서를 열람할 수 있습니다.- 카카오톡 전자문서 서버가 유효성 검증 후 전자문서의 원문 HTML 내용을 카카오톡 앱에서 출력합니다.
- 사용자가 전자문서 원문을 정상적으로 조회하면 문서가 열람 처리되고, 문서 열람시간이 등록됩니다.
- 문서 열람시간은 유통증명서상 열람시간에 해당합니다.
- 사용자는 열람한 전자문서 원문에 대해 카카오 인증서로 전자서명을 할 수 있습니다.
- 전자문서 원문에 대한 전자서명은 한 번만 가능합니다.
- 이용기관은 문서 발송 요청 이후 언제든 문서 상태 조회 API를 호출할 수 있습니다.
- 전자서명이 완료된 문서인 경우, 이용기관은 서명 값 조회 API로 전자서명 데이터를 요청할 수 있습니다.
| 메서드 | URL | 인증 방식 |
|---|---|---|
POST | https://edoc-gw.kakao.com/v1/envelopes/${PRODUCT_CODE} | REST API 키 |
| 권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
|---|---|---|---|
| 필요 | REST API 키 | - | - |
문서를 수신할 사용자의 정보와 문서의 정보를 카카오톡 전자문서 서버에 전달하고 문서 생성을 요청합니다.
이 API의 요청 결과로 이용기관은 문서 상태 조회, 서명 값 조회 API 호출 시 필요한 envelopeId를 응답받습니다. 단건 발송으로는 1명의 사용자에게 1건의 문서를 발송할 수 있습니다.
헤더(Header)에 이용기관 앱과 딜러사 앱의 REST API 키, 정산 ID를 담아 POST로 요청합니다. 요청 URL의 ${PRODUCT_CODE} 부분에 상품 코드를 입력해야 합니다. 예를 들어, D31_1 상품 사용 시 요청 URL은 https://edoc-gw.kakao.com/v1/envelopes/D31_1입니다. 본문에는 사용자 식별을 위한 수신인 정보와 원문 정보, 열람 만료 시각 등 문서 정보를 JSON 형식으로 포함해야 합니다.
요청 성공 시 응답은 문서의 envelopeId를 포함하며 사용자에게 문서 수신 알림톡을 발송합니다. 요청 실패 시 에러 코드에서 원인을 확인합니다.
이 API로는 초당 최대 100개의 문서를 발송할 수 있습니다.
| 이름 | 설명 | 필수 |
|---|---|---|
| Authorization | Authorization: KakaoAK ${DEALER_REST_API_KEY}인증 방식, 딜러사 앱의 REST API 키로 인증 요청 | O |
| Target-Authorization | Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}인증 방식, 이용기관 앱 REST API 키로 인증 요청 | O |
| settle-id | settle-id: ${SETTLE_ID}정산 ID | O |
| 이름 | 타입 | 설명 | 필수 |
|---|---|---|---|
${PRODUCT_CODE} | String | 상품 코드, 아래 중 하나
| O |
- 사용자 식별을 위한 수신인 정보는 아래 중 한 가지 조합으로 필수 전달해야 합니다.
ciphoneNumber,name,birthday
| 이름 | 타입 | 설명 | 필수 |
|---|---|---|---|
| title | String | 문서 제목(최대 40자) | O |
| content | Content | 문서 원문 | O |
| guide | String | 문서 정보 안내 화면에 노출할 문구(최대: 500자) | O |
| payload | String | 페이로드(Payload, 최대: 200자) | X |
| readExpiresAt | String | 최초 열람 만료 일시 지정(최대: 요청 일시로부터 6개월 이내)yyyy-MM-dd'T'HH:mm:ss 형식 | O |
| reviewExpiresAt | String | 재열람 만료 일시 지정 최소: readExpiresAt 이후의 시각최대: 값 지정 시 9999-12-31T23:59:59, null로 설정 시 무제한중요: DX0 상품인 경우 최대값은 요청 일시로부터 6개월 이내 | X |
| signExpiresAt | String | 서명 만료 일시(최대: 요청 일시로부터 6개월 이내)yyyy-MM-dd'T'HH:mm:ss 형식 | O |
| useNonPersonalizedNotification | Boolean | 알림톡 내용에 민감정보 제거 여부(기본값: false) | X |
| ci | String | 사용자 식별을 위한 수신인 정보, CI(최대: 88자) | X |
| phoneNumber | String | 사용자 식별을 위한 수신인 정보, 전화번호01012345678 형식 | X |
| name | String | 사용자 식별을 위한 수신인 정보, 이름 | X |
| birthday | String | 사용자 식별을 위한 수신인 정보, 생년월일yyyyMMdd 형식 | X |
| externalId | String | 문서 매핑(Mapping)용 식별자(최대: 40자) | X |
| 이름 | 타입 | 설명 | 필수 |
|---|---|---|---|
| html | String | HTML 전문(최대: 64KB) 주의: 사용자 열람 후에도 반드시 동일한 문자열로 유지 필요 | X |
| 이름 | 타입 | 설명 | 필수 |
|---|---|---|---|
| envelopeId | String | 문서 고유 ID, 34자로 고정 | O |
| externalId | String | 문서 매핑용 식별자 | X |
요청
curl -v -X POST "https://edoc-gw.kakao.com/v1/envelopes/D31_2" \-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \-H "settle-id: ${SETTLE_ID}" \-H "Content-Type: application/json;charset=UTF-8" \-d '{"title": "전자문서","content": {"html": "<!DOCTYPEhtml><html><body><h1>MyFirstHeading</h1><p>Myfirstparagraph.</p></body></html>"},"guide": "국민연금 공단에서 보내는 문서입니다.","readExpiresAt": "2023-12-31T10:00:00","reviewExpiresAt": "2023-12-31T13:00:00","signExpiresAt": "2023-12-31T13:00:00","useNonPersonalizedNotification": true,"ci": "${CI}"}'
응답
// HTTP/1.1 200 OK{"envelopeId": "${ENVELOPE_ID}"}
| 메서드 | URL | 인증 방식 |
|---|---|---|
POST | https://edoc-gw.kakao.com/v1/bulk/envelopes/${PRODUCT_CODE} | REST API 키 |
| 권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
|---|---|---|---|
| 필요 | REST API 키 | - | - |
문서를 수신할 사용자의 정보와 문서의 정보를 카카오톡 전자문서 서버에 전달하고 문서 생성을 요청합니다.
이 API의 요청 결과로 이용기관은 문서 상태 조회, 서명 값 조회 API 호출 시 필요한 envelopeId를 응답받습니다. 다건 발송으로는 최대 100건의 문서를 발송할 수 있습니다.
헤더에 이용기관 앱과 딜러사 앱의 REST API 키, 정산 ID를 담아 POST로 요청합니다. 요청 URL의 ${PRODUCT_CODE} 부분에 상품 코드를 입력해야 합니다. 예를 들어, D31_1 상품 사용 시 요청 URL은 https://edoc-gw.kakao.com/v1/bulk/envelopes/D31_1입니다. 본문에는 사용자 식별을 위한 수신인 정보와 원문 정보, 열람 만료 시각 등 각 문서 정보를 JSON 배열 형식으로 포함해야 합니다.
요청 성공 시 응답은 각 문서의 envelopeId를 포함하며 사용자에게 문서 수신 알림톡을 발송합니다. 요청 실패 시 에러 코드에서 원인을 확인합니다.
이 API로는 초당 최대 200개의 문서를 발송할 수 있습니다.
| 이름 | 설명 | 필수 |
|---|---|---|
| Authorization | Authorization: KakaoAK ${DEALER_REST_API_KEY}인증 방식, 딜러사 앱의 REST API 키로 인증 요청 | O |
| Target-Authorization | Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}인증 방식, 이용기관 앱 REST API 키로 인증 요청 | O |
| settle-id | settle-id: ${SETTLE_ID}정산 ID | O |
| 이름 | 타입 | 설명 | 필수 |
|---|---|---|---|
${PRODUCT_CODE} | String | 상품 코드, 아래 중 하나
| O |
| 이름 | 타입 | 설명 | 필수 |
|---|---|---|---|
| envelopes | Envelope[] | 각 전자문서 정보를 담은 배열(최대: 100건) | O |
- 사용자 식별을 위한 수신인 정보는 아래 중 한 가지 조합으로 필수 전달해야 합니다.
ciphoneNumber,name,birthday
| 이름 | 타입 | 설명 | 필수 |
|---|---|---|---|
| title | String | 문서 제목(최대 40자) | O |
| content | Content | 문서 원문 | O |
| guide | String | 문서 정보 안내 화면에 노출할 문구(최대: 500자) | O |
| payload | String | 페이로드(Payload, 최대: 200자) | X |
| readExpiresAt | String | 최초 열람 만료 일시 지정(최대: 요청 일시로부터 6개월 이내)yyyy-MM-dd'T'HH:mm:ss 형식 | O |
| reviewExpiresAt | String | 재열람 만료 일시 지정 최소: readExpiresAt 이후의 시각최대: 값 지정 시 9999-12-31T23:59:59, null로 설정 시 무제한중요: DX0 상품인 경우 최대값은 요청 일시로부터 6개월 이내 | X |
| signExpiresAt | String | 서명 만료 일시(최대: 요청 일시로부터 6개월 이내)yyyy-MM-dd'T'HH:mm:ss 형식 | O |
| useNonPersonalizedNotification | Boolean | 알림톡 내용에 민감정보 제거 여부(기본값: false) | X |
| ci | String | 사용자 식별을 위한 수신인 정보, CI(최대: 88자) | X |
| phoneNumber | String | 사용자 식별을 위한 수신인 정보, 전화번호01012345678 형식 | X |
| name | String | 사용자 식별을 위한 수신인 정보, 이름 | X |
| birthday | String | 사용자 식별을 위한 수신인 정보, 생년월일yyyyMMdd 형식 | X |
| externalId | String | 문서 매핑(Mapping)용 식별자(최대: 40자) 동일 요청에 포함된 각 문서의 externalId 값은 유일(Unique)해야 함 | O |
| 이름 | 타입 | 설명 | 필수 |
|---|---|---|---|
| html | String | HTML 전문(최대: 64KB) 주의: 사용자 열람 후에도 반드시 동일한 문자열로 유지 필요 | X |
| 이름 | 타입 | 설명 | 필수 |
|---|---|---|---|
| envelopes | Result[] | 발송 요청된 문서 목록 | X |
| 이름 | 타입 | 설명 | 필수 |
|---|---|---|---|
| envelopeId | String | 문서 고유 ID, 34자로 고정 | X |
| externalId | String | 문서 매핑용 식별자 | X |
요청
curl -v -X POST "https://edoc-gw.kakao.com/v1/bulk/envelopes/D31_1" \-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \-H "settle-id: ${SETTLE_ID}" \-H "Content-Type: application/json;charset=UTF-8" \-d '{"envelopes": [{"title": "전자문서","content": {"html": "<!DOCTYPEhtml><html><body><h1>MyFirstHeading</h1><p>Myfirstparagraph.</p></body></html>"},"guide": "국민연금 공단에서 보내는 문서입니다.","payload": "이용기관 페이로드","readExpiresAt": "2024-12-31T10:00:00","reviewExpiresAt": "2025-03-31T13:00:00","signExpiresAt": "2023-12-31T13:00:00","phoneNumber": "01099999999","name": "홍길동","birthday": "20000303","externalId": "external_id1"},{"title": "전자문서","content": {"html": "<!DOCTYPEhtml><html><body><h1>MyFirstHeading</h1><p>Myfirstparagraph.</p></body></html>"},"guide": "국민연금 공단에서 보내는 문서입니다.","payload": "이용기관 페이로드","readExpiresAt": "2024-12-31T10:00:00""reviewExpiresAt": "2025-03-31T13:00:00","signExpiresAt": "2023-12-31T13:00:00","ci": "${CI}","externalId": "external_id2"}]}'
응답
// HTTP/1.1 200 OK{"envelopes": [{"envelopeId": "${ENVELOPE_ID}","externalId": "external_id1"},{"envelopeId": "${ENVELOPE_ID}","externalId": "external_id2"}]}
| 메서드 | URL | 인증 방식 |
|---|---|---|
POST | https://edoc-gw.kakao.com/v1/envelopes/status | REST API 키 |
| 권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
|---|---|---|---|
| 필요 | REST API 키 | - | - |
카카오톡 전자문서로 발송한 문서의 상태를 조회합니다.
한 번에 최대 100건의 문서 상태를 조회할 수 있습니다.
헤더(Header)에 이용기관 앱과 딜러사 앱의 REST API 키, 정산 ID를 담아 POST로 요청합니다. envelopeIds에 상태를 조회할 문서 고유 ID 목록을 전달해야 합니다.
요청 성공 시 응답은 각 문서 상태 정보를 포함합니다. 요청 실패 시 에러 코드에서 원인을 확인합니다.
이 API로는 초당 최대 400개의 문서를 조회할 수 있습니다.
| 이름 | 설명 | 필수 |
|---|---|---|
| Authorization | Authorization: KakaoAK ${DEALER_REST_API_KEY}인증 방식, 딜러사 앱의 REST API 키로 인증 요청 | O |
| Target-Authorization | Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}인증 방식, 이용기관 앱 REST API 키로 인증 요청 | O |
| settle-id | settle-id: ${SETTLE_ID}정산 ID | O |
| 이름 | 타입 | 설명 | 필수 |
|---|---|---|---|
| envelopeIds | String[] | 문서 고유 ID 목록 | O |
| 이름 | 타입 | 설명 | 필수 |
|---|---|---|---|
| envelopeStatus | EnvelopeStatus[] | 각 문서 상태 정보 | O |
| 이름 | 타입 | 설명 | 필수 |
|---|---|---|---|
| envelopeId | String | 문서 고유 ID | O |
| externalId | String | 문서 매핑용 식별자 문서 발송 API 요청 시 지정한 경우에만 응답에 포함 | X |
| status | String | 문서 상태, 아래 중 하나
| X |
| sentAt | String | 문서 송신 일시 | X |
| receivedAt | String | 문서 수신 일시 | X |
| readAt | String | 문서 열람 일시 | X |
| readExpiredAt | String | 문서 열람 만료 일시 | X |
| authenticatedAt | String | 문서 열람 인증 일시 | X |
| isNotificationUnavailable | Boolean | 사용자의 알림톡 수신 가능 여부 | X |
| userNotifiedAt | String | 사용자의 알림톡 수신 일시 | X |
| distributionReceivedAt | String | 유통정보의 수신 시각, 공인전자주소 활성화와 문서 수신이 모두 완료된 시각 | X |
| payload | String | 문서 발송 API 요청 시 전달한 페이로드 | X |
| isDocumentSignComplete | Boolean | 서명 완료 여부 | X |
요청
curl -v -X POST "https://edoc-gw.kakao.com/v1/envelopes/status" \-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \-H "settle-id: ${SETTLE_ID}" \-H "Content-Type: application/json;charset=UTF-8" \-d '{"envelopeIds" : ["${ENVELOPE_ID}","${ENVELOPE_ID}"]}'
응답
// HTTP/1.1 200 OK{"envelopeStatus": [{"envelopeId": "${ENVELOPE_ID}","externalId": "external_id01","status": "READ","sentAt": "2023-09-25T17:45:14","receivedAt": "2023-09-25T17:45:14","readAt": "2023-09-25T17:45:14","readExpiredAt": "2023-12-25T17:45:14","authenticatedAt": "2023-09-25T17:45:14","userNotifiedAt": "2023-09-25T17:45:14","distributionReceivedAt": "2023-09-25T17:45:14","payload": "이용기관 페이로드","isDocumentSignComplete": true},{"envelopeId": "${ENVELOPE_ID}","errorCode": "D400_00","errorMessage": "문서[${ENVELOPE_ID}]를 찾을 수 없습니다"}]}
| 메서드 | URL | 인증 방식 |
|---|---|---|
GET | https://edoc-gw.kakao.com/v1/envelopes/${ENVELOPE_ID}/signed-data | REST API 키 |
| 권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
|---|---|---|---|
| 필요 | REST API 키 | - | - |
전자문서에 대한 서명 값을 가져옵니다.
사용자는 전자문서 열람 후 카카오 인증서로 단 한 차례 전자서명을 할 수 있습니다. 이 API를 호출해 서명 값과 서명 시간 정보 등 전자서명 데이터를 제공받을 수 있습니다. 단, 카카오톡 전자문서는 서명 값을 한 번만 제공하므로 주의합니다.
사용자가 전자서명을 완료하지 않았거나, 이용기관이 이미 해당 문서의 서명 값을 제공받은 경우에는 에러가 발생합니다. 사용자가 카카오톡 전자문서를 탈퇴한 경우, 전자서명 데이터가 파기되어 서명 값이 DELETED로 제공됩니다. 서명 요청 및 서명 완료 시간은 사용자 탈퇴 시에도 제공받을 수 있습니다.
헤더에 이용기관 앱과 딜러사 앱의 REST API 키, 정산 ID를 담아 GET으로 요청합니다. 요청 URL의 ${ENVELOPE_ID} 부분에 문서 고유 ID를 입력해야 합니다.
요청 성공 시 응답은 서명 값과 서명 시간 정보를 포함합니다. 요청 실패 시 에러 코드에서 원인을 확인합니다.
카카오톡 전자문서 서버는 아래 규칙에 따라 서명 원문을 생성합니다. 이용기관이 동일한 서명 원문을 보관해야 할 경우 참고합니다.
${ENVELOPE_ID} || ${HTML} || ${SENT_AT_TIMESTAMP}형식 문자열 생성- 생성한 문자열을 UTF-8 디코딩(Decoding)
- 바이트 배열을 SHA256으로 해시(Hash)
- 해시 값을 Base64 인코딩(Encoding)
| 이름 | 설명 | 필수 |
|---|---|---|
| Authorization | Authorization: KakaoAK ${DEALER_REST_API_KEY}인증 방식, 딜러사 앱의 REST API 키로 인증 요청 | O |
| Target-Authorization | Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}인증 방식, 이용기관 앱 REST API 키로 인증 요청 | O |
| settle-id | settle-id: ${SETTLE_ID}정산 ID | O |
| 이름 | 타입 | 설명 | 필수 |
|---|---|---|---|
${ENVELOPE_ID} | String | 문서 고유 ID | O |
| 이름 | 타입 | 설명 | 필수 |
|---|---|---|---|
| requestedAt | String | 서명 요청 일시 | O |
| completedAt | String | 서명 완료 일시 | O |
| signedDocument | String | 전자서명 데이터 전문(참고: CMSSignedData) | O |
요청
curl -v -G GET "https://edoc-gw.kakao.com/v1/envelopes/${ENVELOPE_ID}/signed-data" \-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \-H "settle-id: ${SETTLE_ID}" \-H "Content-Type: application/json;charset=UTF-8"
응답
// HTTP/1.1 200 OK{"requestedAt": "2024-01-02T15:00:12","completedAt": "2024-01-03T16:04:26","signedDocument": "${CMSSignedData}"}
아래는 실제 서비스에서 고려해야 할 여러 요소(성능, 예외 처리, 동시성 등)가 반영되지 않은 참고용 예제입니다.
// 예제에 사용한 라이브러리 정보: org.bouncycastle:bcpkix-jdk18on:1.78.1fun main() {val html = "<!DOCTYPE html><html><body><h1>My First Heading</h1><p>My first paragraph.</p></body></html>"val envelopeId = "EVLP-01J2TX3CKAPNDZ6EDWQBTZ48C5-01"val sentAt = LocalDateTime.parse("2024-07-15T18:55:37")val signVerifier = SignVerifierKt(html, envelopeId, sentAt)val signedDocument = "${SIGNED_DOCUMENT}";if (signVerifier.verify(signedDocument)) {println("서명이 유효합니다.")} else {println("서명이 유효하지 않습니다.")}}class SignVerifierKt(private val html: String, // 발송한 문서 원문private val envelopeId: String, // 발급받은 envelopeId(예: EVLP-01J2TS4X4FN200XXHET1ZJZC38-01)private val sentAt: LocalDateTime // envelopeId로 문서 상태 조회 API (/v1/envelopes/status)를 요청해 응답받은 sentAt) {/*** @param signedDocument : 서명 값 조회 API (/v1/envelopes/${ENVELOPE_ID}/signed-data)를 요청해 응답받은 signedDocument* @return : 서명이 유효하면 true, 아니면 false*/fun verify(signedDocument: String): Boolean {val originOfSign = generateOriginOfSign(envelopeId, html, sentAt)val cmsSignedData = convertToCMSSignedData(signedDocument)for (signer in cmsSignedData.signerInfos.signers) {if (verifySignature(originOfSign, cmsSignedData, signer).not()) {return false}}// 전체 서명 유효 시 검증 성공 응답return true}// 서명 검증private fun verifySignature(originDocument: String,cmsSignedData: CMSSignedData,signer: SignerInformation): Boolean {val certificate = getCertificate(cmsSignedData, signer)runCatching {val signature = Signature.getInstance(certificate.sigAlgName)signature.initVerify(certificate)signature.update(originDocument.toByteArray(StandardCharsets.UTF_8))return signature.verify(getSignature(signer))}.getOrElse { throw RuntimeException(it) }}// 서명자의 인증서를 추출private fun getCertificate(cmsSignedData: CMSSignedData, signer: SignerInformation): X509Certificate {runCatching {val certificateHolder = cmsSignedData.certificates.getMatches(signer.sid as Selector<X509CertificateHolder>).iterator().next() as X509CertificateHolderreturn JcaX509CertificateConverter().getCertificate(certificateHolder)}.getOrElse { throw RuntimeException(it) }}// 서명자의 서명값 추출private fun getSignature(signer: SignerInformation): ByteArray {return signer.signature}// 전자서명 데이터 전문(cmsSignedData) 생성private fun convertToCMSSignedData(signedDocument: String): CMSSignedData {runCatching {return CMSSignedData(decodeBase64(signedDocument))}.getOrElse { throw RuntimeException(it) }}// 서명 원문 생성private fun generateOriginOfSign(envelopeId: String?, html: String?, sentAt: LocalDateTime?): String {val content = String.format("%s || %s || %s", envelopeId, html, toUnixTimestamp(sentAt))return encodeBase64(sha256(content))}private fun toUnixTimestamp(time: LocalDateTime?): Long {return time!!.toEpochSecond(ZoneOffset.of("+09:00"))}private fun encodeBase64(content: ByteArray): String {return Base64.getEncoder().encodeToString(content)}private fun decodeBase64(content: String): ByteArray {return Base64.getDecoder().decode(content)}private fun sha256(content: String): ByteArray {runCatching {return MessageDigest.getInstance("SHA-256").digest(content.toByteArray(StandardCharsets.UTF_8))}.getOrElse { throw RuntimeException(it) }}}
| 메서드 | URL | 인증 방식 |
|---|---|---|
GET | https://edoc-gw.kakao.com/v1/envelopes/${ENVELOPE_ID}/distributions/cert | REST API 키 |
| 권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
|---|---|---|---|
| 필요 | REST API 키 | - | - |
전담기관 시스템에 등록된 유통정보를 증명하는 유통증명서를 발급합니다.
문서 발송이 정상적으로 완료되었더라도 전담기관 시스템에 유통 정보가 적재되기 전까지는 유통증명서를 발급할 수 없습니다. 유통 정보는 수신자가 공인전자주소를 등록한 경우, 약 1시간 이내에 적재됩니다. 수신자가 공인전자주소를 등록하지 않은 경우, 공인전자주소를 등록하기 전까지 적재되지 않습니다.
헤더(Header)에 이용기관 앱과 딜러사 앱의 REST API 키, 정산 ID를 담아 GET으로 요청합니다. 요청 URL의 ${ENVELOPE_ID} 부분에 유통증명서를 발급할 대상 문서의 고유 ID를 입력하고, 유통증명서 발급 목적을 reason 담아 쿼리 파라미터로 포함해야 합니다.
요청 성공 시 응답은 PDF 포멧의 유통증명서 파일입니다. 요청 실패 시 에러 코드에서 원인을 확인합니다.
유통증명서 발급 목적(reason)는 발급 후 추적 관리를 용이하게 할 수 있도록 명확하게 작성할 것을 권장합니다.
| 이름 | 설명 | 필수 |
|---|---|---|
| Authorization | Authorization: KakaoAK ${DEALER_REST_API_KEY}인증 방식, 딜러사 앱의 REST API 키로 인증 요청 | O |
| Target-Authorization | Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}인증 방식, 이용기관 앱 REST API 키로 인증 요청 | O |
| settle-id | settle-id: ${SETTLE_ID}정산 ID | O |
| 이름 | 타입 | 설명 | 필수 |
|---|---|---|---|
${ENVELOPE_ID} | String | 문서 고유 ID | O |
| 이름 | 타입 | 설명 | 필수 |
|---|---|---|---|
| reason | String | 유통증명서 발급 목적(최대: 200자) | O |
- PDF 포멧의 유통증명서 파일
요청
curl -v -G GET "https://edoc-gw.kakao.com/v1/envelopes/${ENVELOPE_ID}/distributions/cert?reason=${REASON}" \-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \-H "Authorization: KakaoAK 52de30f310daaa2830105609a6efec97" \-H "settle-id: ${SETTLE_ID}" \-H "Content-Type: application/json" \-o cert.pdf
| 메서드 | URL | 인증 방식 |
|---|---|---|
GET | https://edoc-gw.kakao.com/v1/distributions/stats/confirmation | REST API 키 |
| 권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
|---|---|---|---|
| 필요 | REST API 키 | - | - |
전담기관 시스템에 등록된 유통 정보 수치를 증명하는 유통 통계 수치 확인서를 발급합니다.
전담기관은 유통 통계를 아래 두 가지 기준으로 제공합니다.
- 조회 기간 내 발송한 문서 중 수신 및 열람 발생 건 수
- 발송 시점과 상관없이 조회 기간에 수신 및 열람 발생 건 수
전담기관이 제공하는 통계 정보는 실시간으로 반영되지 않습니다. 카카오톡 전자문서 서버가 전담기관 서버에 유통정보를 적재한 익일부터 반영됩니다.
헤더(Header)에 이용기관 앱과 딜러사 앱의 REST API 키, 정산 ID를 담아 GET으로 요청합니다. 요청 시 조회 기간을 period 쿼리 파라미터로 포함해야 합니다. 요청 성공 시 응답은 PDF 포맷의 유통 통계 수치 확인서 파일입니다. 요청 실패 시 에러 코드에서 원인을 확인합니다.
유통 통계 수치는 전담기관 시스템에 적재된 다음날에 반영됩니다. 만약 월말 23:59:59에 사용자가 문서를 열람하고 익월 00:00:01에 KISA에 적재 처리된 경우, 익월 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 | settle-id: ${SETTLE_ID}정산 ID | O |
| 이름 | 타입 | 설명 | 필수 |
|---|---|---|---|
| period | String | 유통 통계를 조회할 대상 월, yyyy-MM 형식 | O |
- PDF 포멧의 유통 통계 수치 확인서 파일
요청
curl -v -X GET "https://edoc-gw.kakao.com/v1/distributions/stats/confirmation?period=${PERIOD}" \-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \-H "settle-id: ${SETTLE_ID}" \-H "Content-Type: application/json" \-o cert.pdf