지금 여러분의 앱이 사용자에게 여권이나 신분증 사진을 요청하고 있다면, EU 디지털 신원 지갑(EU Digital Identity Wallet)이 "2026년 말"에 나온다는 이야기를 들어 보셨을 것입니다. 이 날짜는 실제로 존재하며, 정확히 정해져 있습니다. 2026년 12월 24일입니다. 하지만 이것은 여러분이 아니라 회원국에 부과된 마감일이며, 문서 스캔을 없애지도 않습니다.
이 글은 세 가지를 다룹니다. 먼저 이 날짜가 어디서 나오는지 계산과 함께 보여 줍니다. 다음으로 법령의 속성 표를 바탕으로 지갑이 실제로 무엇을 넘겨주는지 정리합니다. 마지막으로 사용자에게 지갑이 있으면 지갑을 받고, 없으면 문서 스캔으로 대체하는 설계를 그려 봅니다. 이 글은 여권·신분증 OCR API인 doc.cheap이 썼으므로, 제품에 관한 부분은 그 점을 감안해서 읽어 주세요. doc.cheap은 문서 이미지를 읽을 뿐, 지갑은 읽지 않습니다.
2026년 12월 24일은 어디서 나왔나
이 의무는 eIDAS 개정법인 Reg. (EU) 2024/1183이 삽입한 Reg. (EU) No 910/2014 제5a조 제1항에 있습니다. 여기서는 각 회원국이 "이 조 제23항 및 제5c조 제6항에 언급된 이행법의 발효일로부터 24개월 이내에 최소 하나의 유럽 디지털 신원 지갑을 제공해야 한다"고 규정합니다.
따라서 시계는 eIDAS 개정법 자체에서 시작되지 않습니다. 시작점은 유럽연합 집행위원회의 이행법입니다. 제5a조 제23항에 따른 이행법은 2024년 11월 28일자 집행위원회 이행법 네 건이며, 그중 하나가 지갑의 무결성과 핵심 기능에 관한 Implementing Reg. (EU) 2024/2979입니다. 이 법은 2024년 12월 4일 관보(OJ L, 2024/2979)에 게재되었습니다. 그 제15조는 이 법이 "유럽연합 관보에 게재된 날의 다음 날부터 20일째 되는 날에 발효한다"고 정합니다.
계산은 다음과 같습니다.
| 단계 | 날짜 |
|---|---|
| 관보 게재 | 2024년 12월 4일 |
| 게재 후 1일째 | 2024년 12월 5일 |
| 게재 후 20일째: 발효 | 2024년 12월 24일 |
| 24개월 추가(제5a조 제1항): 지갑 마감일 | 2026년 12월 24일 |
| 36개월 추가(제5f조 제2항): 일부 민간 신뢰 당사자의 지갑 수용 의무 | 2027년 12월 24일 |
"다음 날부터 20일째"는 게재일 다음 날부터 세므로, 12월 4일에 20일을 더하면 23일이 아니라 24일이 됩니다. 표의 두 번째 날짜도 같은 이행법을 기준으로 계산되며, 대부분의 제품 팀이 실제로 신경 쓰는 날짜는 바로 이것입니다(아래에서 자세히 다룹니다).
지갑이 넘겨주는 것
지갑은 여권 사진을 보내지 않습니다. 서명된 데이터를 제시합니다. 자연인에 대한 데이터 세트는 Implementing Reg. (EU) 2024/2977의 부속서에 정해진 "개인 식별 데이터"(person identification data, PID)입니다. 부속서에 따르면 PID는 두 가지 형식으로 발급됩니다. ISO/IEC 18013-5:2021과 W3C "Verifiable Credentials Data Model 1.1"입니다.
아래는 속성과, 본문이 각 속성에 부여한 필수 여부입니다(부속서의 표 1, 2, 5, 2024년 12월 4일 게재본 기준). 마지막 열은 doc.cheap 스캔 응답에서 가장 가까운 필드로, 두 세계가 어디서 맞고 어디서 어긋나는지 볼 수 있습니다.
| PID 속성 | 필수 여부 | 문서 스캔에서 가장 가까운 필드 |
|---|---|---|
family_name |
필수 | holder.surname |
given_name |
필수 | holder.given_names |
birth_date |
필수 | holder.birth_date(ISO 8601) |
birth_place |
필수 | 문서에 인쇄되어 있을 때 fields[]의 birth_place 항목 |
nationality |
필수(alpha-2, 하나 이상) | holder.nationality(alpha-3, 하나) |
resident_address, resident_country, resident_state, resident_city, resident_postal_code, resident_street, resident_house_number |
선택 | 여권 신원 정보면에는 없음 |
personal_administrative_number |
선택 | 같은 것이 아님. fields[]에 문서에 인쇄된 personal_number가 있을 수 있음 |
portrait |
선택 | images.main_photo |
family_name_birth, given_name_birth |
선택 | 정제된 필드 없음 |
sex |
선택(코드 0, 1, 2, 3, 4, 5, 6, 9) | holder.sex(M, F, X) |
email_address, mobile_phone_number |
선택 | 문서에는 없음 |
expiry_date(메타데이터) |
필수 | document.expiry_date. 단, PID가 아니라 문서의 만료일 |
issuing_authority(메타데이터) |
필수 | 인쇄되어 있을 때 fields[]의 authority 항목 |
issuing_country(메타데이터) |
필수(alpha-2) | document.issuing_state(alpha-3) |
document_number(메타데이터) |
선택 | 같은 것이 아님. PID 번호는 PID 제공자가 부여하고, document.number는 여권 번호 |
issuing_jurisdiction, location_status(메타데이터) |
선택 | 없음 |
매핑 코드를 작성할 때 이 표에서 중요한 점이 세 가지 있습니다.
- 국가 코드가 다릅니다. PID는 ISO 3166-1 alpha-2(
DE)를 사용합니다. 여권과 기계 판독 영역(MRZ)은 alpha-3(DEU)을 사용합니다. 내부 형식은 하나로 정하고 경계에서 변환하세요. - "필수"가 "항상 알려져 있음"을 뜻하지는 않습니다. 표 1 아래에서 본문은 이렇게 덧붙입니다. "어떤 속성 값이 해당 개인에 대해 알려져 있지 않거나 그 밖의 이유로 개인 식별 데이터 세트의 일부로 발급될 수 없는 경우, 회원국은 대신 상황에 맞는 속성 값을 사용해야 한다." 키가 빠지는 것이 아니라 자리표시자 값이 올 것으로 예상하세요.
- 개인에 관한 필수 속성은 다섯 개뿐입니다. 주소, 얼굴 사진, 성별, 출생 시 성명은 모두 선택입니다. 흐름에서 이 중 하나가 필요하다면, 사용자에 따라 지갑에 그 값이 아예 없을 수도 있습니다.
그래도 문서를 들고 오는 사람들
마감일은 각 회원국에 지갑을 제공할 의무를 지웁니다. 누구에게도 지갑을 사용할 의무를 지우지 않습니다. 제5a조 제15항은 단호합니다. "유럽 디지털 신원 지갑의 사용은 자발적이다." 이어서 "기존의 다른 식별 및 인증 수단으로 공공 및 민간 서비스에 접근하는 것은 계속 가능해야 한다."
따라서 2026년 12월 24일 이후에도 다음과 같은 경우를 계속 보게 됩니다.
- EU 밖에서 온 여행자와 고객. 전문(recitals)은 지갑을 "연합 시민, 연합 내 거주자 또는 법인의 법적 신원"과 연결합니다. 다른 지역의 여권을 가진 방문자에게는 제시할 EU 지갑이 없습니다.
- 지갑을 설치하지 않은 사람, 설치할 수 없는 사람, 또는 설치하고 싶지 않은 사람. 본문은 그 선택을 보호합니다.
- 문서 자체가 필요한 흐름. 어떤 절차는 개인에 대한 증명이 아니라 실물 문서의 이미지, 문서 번호 또는 기계 판독 영역을 원합니다. 지갑의 PID에는 PID 제공자가 부여한 자체
document_number가 있으며, 이는 여권 번호가 아닙니다. - 특정 국가의 지갑이 가동되기 전의 기간. 2026년 12월 24일은 법적 마감일입니다. 각국 지갑이 실제로 언제 사용자에게 도달하는지는 별개의 문제이며, 어느 한 나라에 대해 믿을 수 있는 유일한 답은 그 나라의 발표나 집행위원회의 발표입니다.
둘 다 받는 설계
이 모든 조건에서도 살아남는 구조는 단순합니다. 사용자에게 지갑이 있으면 지갑 제시를 요청하고, 없으면 문서 스캔으로 대체합니다. 두 경로 모두 같은 내부 레코드로 끝납니다.
user starts verification
|
v
offers a wallet? --yes--> wallet presentation --> verify signature --> map PID
| |
no v
| internal identity
v record
document photo --> POST /v1/scans --> map scan fields ----------------^
두 경로를 서로 바꿔 쓸 수 있게 해 주는 규칙이 몇 가지 있습니다.
- 둘 다 하나의 레코드로 매핑하세요. 필드 이름은 여러분의 것을 사용합니다. 위의 표를 매핑 표로 쓰세요.
- 출처를 보관하세요. 레코드가 지갑에서 왔는지 스캔에서 왔는지 저장합니다. 두 경로는 서로 다른 증거를 담고 있고, 검토자는 어느 쪽인지 알고 싶어 할 것입니다.
- null을 정직한 값으로 다루세요. doc.cheap 응답에서는 모든 키가 항상 존재하고, 알 수 없는 값은
null입니다. 지갑은 그 대신 자리표시자를 보낼 수 있습니다. 둘 다 하나의 규칙으로 정규화하세요. - 흐름에 필요한 만큼만 저장하세요. 스캔은 API 쪽에 아무것도 기록되지 않도록 실행할 수 있습니다(아래 참고).
다음은 기본 fetch로 작성한 대체 호출입니다. 공개 샌드박스 키 sk_sandbox_public은 문서에 공개되어 있고 가입이 필요 없으며, 클라이언트 주소별로 요청 속도가 제한됩니다.
import { readFileSync } from "node:fs";
import { randomUUID } from "node:crypto";
async function scanDocument(path, apiKey = "sk_sandbox_public") {
const response = await fetch("https://api.doc.cheap/v1/scans", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
"Idempotency-Key": randomUUID(), // 재시도하면 첫 번째 결과가 반환됨
},
body: JSON.stringify({
image: readFileSync(path).toString("base64"),
options: { retain_hours: 0, return_portrait: false }, // 아무것도 저장하지 않음
}),
});
if (!response.ok) throw new Error(`scan failed: HTTP ${response.status}`);
return response.json();
}
// 스캔 결과를 지갑 제시가 채울 것과 같은 레코드로 매핑합니다.
function fromScan(scan) {
if (scan.meta.status !== "recognized") return null;
const field = (name) => scan.fields.find((f) => f.id === `${name}@0`)?.value ?? null;
return {
source: "document_scan",
family_name: scan.holder?.surname ?? null,
given_name: scan.holder?.given_names ?? null,
birth_date: scan.holder?.birth_date ?? null,
birth_place: field("birth_place"),
nationality_alpha3: scan.holder?.nationality ?? null,
issuing_country_alpha3: scan.document?.issuing_state ?? null,
document_number: scan.document?.number ?? null,
mrz_status: scan.mrz.status, // "passed", "failed" 또는 "absent"
};
}
meta.status는 다섯 가지 문자열 중 하나입니다. recognized, no_document_found, unreadable, unsupported_document, rejected. 레코드를 채워야 하는 것은 첫 번째뿐이고, 나머지는 사용자에게 사진을 다시 찍도록 안내해야 합니다. 유료 키에서는 과금 대상 스캔일 때만 잔액이 차감됩니다.
저희는 2026년 9월 24일 21:17 UTC에 제품 자체의 테스트 문서인 여권으로 sk_sandbox_public에 이런 호출을 한 번 실행했습니다. 응답은 HTTP 200으로 돌아왔습니다. 아래의 문서 값은 모두 가렸고, fields, images, mrz.lines는 줄였습니다.
{
"meta": {
"schema_version": "1.0",
"id": "<SCAN_ID>",
"status": "recognized",
"billed": true,
"confidence": "medium",
"timing": { "upload_ms": 255, "processing_ms": 409, "total_ms": 678 },
"created_at": "<RUN_TIMESTAMP>",
"reference": null
},
"document": {
"kind": "passport", "country": "<ISO3>", "country_name": "<COUNTRY>",
"issuing_state": "<ISO3>", "number": "<DOCUMENT_NUMBER>", "series": null,
"issue_date": "<DATE>", "expiry_date": "<DATE>", "is_expired": false, "days_remaining": "<N>"
},
"holder": {
"given_names": "<GIVEN_NAMES>", "surname": "<SURNAME>", "full_name": "<FULL_NAME>",
"birth_date": "<DATE>", "sex": "<SEX>", "nationality": "<ISO3>"
},
"mrz": { "status": "passed", "reason": null, "lines": ["<LINE_1>", "<LINE_2>"], "text": "<MRZ>" },
"quality": { "overall": "pass" },
"authenticity": { "overall": "not_checked", "checks": [] }
}
여기서 billed: true는 스캔이 과금 대상이어서 샌드박스의 무료 한도에서 차감되었다는 뜻입니다. 샌드박스 키 자체에는 절대 요금이 부과되지 않습니다. 이 실행의 fields 배열에는 birth_place, authority, personal_number 항목이 들어 있었고, 위의 표가 해당 PID 속성에 대응하는 곳으로 가리킨 것이 바로 이 항목들입니다. 여권 신원 정보면에는 TD3 레이아웃의 두 줄짜리 MRZ가 있습니다. TD1, TD2, TD3 형식 페이지에서 각 레이아웃을 나란히 볼 수 있습니다.
authenticity.overall: "not_checked"에 주목하세요. 이런 스캔은 인식입니다. 인쇄된 내용을 읽고 MRZ 검증 숫자(check digit)를 확인합니다. 위조 탐지가 아니며, 서명된 지갑 제시와 같은 수준의 보증도 아닙니다. 스캔 경로에서 더 높은 보증 수준이 필요한 절차라면, 그 보증은 흐름의 다른 부분에서 확보해야 합니다. 대체 수단을 위한 제공자를 고르고 있다면, 저희의 여권 OCR API 비교에서 인식 이상을 해 주는 선택지까지 포함해 정리해 두었습니다.
앞으로 지켜볼 것
- 2026년 12월 24일 – 지갑 마감일. 제5a조 제1항, Reg. (EU) 2024/1183. 위에서 보인 대로 이행법의 발효일부터 계산합니다.
- 2027년 12월 24일 – 민간 신뢰 당사자. 제5f조 제2항은 법률이나 계약에 따라 온라인 식별에 강력한 사용자 인증을 사용해야 하는 민간 신뢰 당사자가 "제5a조 제23항 및 제5c조 제6항에 언급된 이행법의 발효일로부터 늦어도 36개월 이내에, 그리고 사용자의 자발적 요청이 있는 경우에만, 유럽 디지털 신원 지갑도 수용해야 한다"고 규정합니다. 본문은 운송, 에너지, 은행, 금융 서비스, 사회 보장, 보건, 식수, 우편 서비스, 디지털 인프라, 교육, 전기통신을 명시하며, 소기업과 영세기업은 제외합니다.
- 초대형 온라인 플랫폼. 제5f조 제3항은 이들 플랫폼이 사용자 인증에 지갑을 수용하도록 합니다. 역시 사용자의 자발적 요청이 있을 때만, 필요한 최소한의 데이터에 대해서입니다.
- 이행법의 변경. Implementing Reg. (EU) 2024/2979의 전문 제4항은 집행위원회가 필요한 경우 이를 "검토하고 갱신해야 한다"고 말합니다. 매핑을 확정하기 전에 2024/2977의 속성 표를 확인하세요.
실무적인 결론은 이렇습니다. 사용자의 국가가 지갑을 내놓으면 지갑 경로를 만들고, 문서 경로는 유지하며, 첫날부터 둘 다 하나의 레코드로 매핑하세요. 스캔 쪽은 여권·신분증 OCR API 문서에서 모두 다룹니다.
이 글은 엔지니어링 관점의 요약이며, 법률 자문이 아닙니다.