메인 콘텐츠로 건너뛰기
Didit SDK를 사용하면 최종 사용자의 기기에서 직접 모니터링 대상 거래를 제출할 수 있으며, Travel Rule 송금과 암호화폐 스크리닝도 포함됩니다. 백엔드에서 수명이 짧은 범위 지정 토큰을 발급하면, 나머지는 SDK가 처리합니다. SDK는 기기 인텔리전스를 자동으로 첨부하며, Travel Rule 송금에 지갑 소유 증명이 필요하면 해당 절차를 즉시 자동으로 실행합니다. 필수 인증 세션은 자동으로 실행되지 않습니다. 응답으로 반환되므로, 앱에서 직접 Didit 인증 연동으로 실행해야 합니다. 아래 필요한 사용자 작업을 참고하십시오.

개요

클라이언트 측 제출은 세 가지 보장을 기반으로 합니다.
  • 스푸핑 방지 주체 바인딩. 토큰은 발급 시점에 하나의 vendor_data(사용자 ID)에 범위가 지정됩니다. 이 토큰으로 제출되는 모든 거래의 주체 신원은 해당 바인딩에 따라 서버 측에서 강제 적용됩니다. 따라서 변조된 클라이언트는 다른 사용자를 대신해 제출할 수 없으며, 페이로드에 자격 증명을 포함할 필요도 없습니다.
  • 자동 기기 인텔리전스. SDK는 기기 핑거프린트를 수집해 제출과 함께 전송하며, Didit은 IP 주소와 사용자 에이전트를 서버 측에서 도출합니다. 결합된 기기 컨텍스트는 추가 라이브러리, 별도의 기기 토큰, 개발자 측 구현 없이 거래의 주체에 첨부됩니다. 이 정보는 기기 기반 규칙과 세션 및 거래 전반에 걸친 기기 기준 연관 분석을 지원합니다.
  • 자동 실행되는 지갑 소유 증명. 생성된 거래에서 최종 사용자가 지갑 소유를 증명해야 하면, 응답에 wallet_ownership 유형의 action_required 블록이 포함되고 SDK는 즉시 해당 절차를 엽니다. 절차가 완료되면 거래를 새로 고칩니다. 폴링 루프나 링크 전달을 직접 구현할 필요가 없습니다. 필수 verification_session 작업은 이와 다릅니다. 이 작업은 자동으로 실행되지 않으며, 같은 블록에 반환되어 앱이 자체 Didit 인증 연동으로 실행하도록 합니다.
최종 사용자가 없는 경우에는 서버 측 POST /v3/transactions/가 여전히 적합한 선택입니다. 예를 들어 백오피스 송금, 일괄 가져오기, 자체 시스템이 보고한 이벤트가 이에 해당합니다. 두 경로 모두 동일한 거래 레코드를 생성하고, 동일한 규칙을 실행하며, 동일한 webhook을 발송합니다.

흐름

1

거래 토큰 발급

백엔드에서 API 키와 사용자의 vendor_data로 POST /v3/transactions/sdk-token/를 호출하고, 반환된 sdk_token을 앱에 전달합니다.
2

기기에서 제출

앱이 SDK의 submitTransaction을 호출하면, SDK는 X-Transaction-Token 헤더와 자동 기기 보강 정보를 포함해 페이로드를 POST /v1/transactions/로 전송합니다.
3

필수 작업 처리

action_required.type이 wallet_ownership이면 SDK가 위젯을 자동으로 실행한 다음, GET /v1/transactions/{transaction_id}/로 거래를 새로 고칩니다. verification_session이면 SDK는 아무것도 실행하지 않습니다. action_required를 읽고, session_token(웹에서는 url)으로 자체 인증 절차를 시작하십시오.

거래 토큰 발급

백엔드에서 POST /v3/transactions/sdk-token/로 토큰을 발급합니다. 이때 /v3/ 거래 엔드포인트의 나머지와 동일한 API 키 인증을 사용합니다.
camelCase 별칭(vendorData, ttlSeconds, maxUses)도 나머지 /v3/ API와 마찬가지로 허용됩니다.
앱에 API 키를 절대 포함하지 마십시오. API 키는 백엔드에 두고 토큰을 발급하는 데만 사용합니다. 기기로 전달되는 것은 수명이 짧은 sdk_token뿐입니다. 사용자 세션마다 새 토큰을 발급하고, 장기간 사용하는 토큰을 재사용하지 마십시오. 예상 제출 횟수를 알고 있다면 max_uses를 엄격하게 설정하십시오.

기기에서 제출하기

SDK는 토큰을 X-Transaction-Token 헤더에 담아 POST /v1/transactions/로 전송합니다. 전송 페이로드는 camelCase입니다. submitTransaction 메서드가 페이로드를 구성하므로, 자체 HTTP 클라이언트에서 엔드포인트를 직접 호출할 때만 이 형식을 직접 다루면 됩니다:
각 최상위 필드는 POST /v3/transactions/의 대응 필드에 매핑됩니다: 응답은 /v3/ 엔드포인트와 동일한 snake_case 거래 상세 정보에 action_required 블록이 더해진 형태입니다:

자체 보관 지갑 선언하기

위 예시는 출금 대상을 사용자 본인의 자체 보관 지갑으로 선언합니다. 즉 카운터파티의 paymentMethod.type이 unhosted_wallet입니다. 이 선언은 Travel Rule 교환의 진행 방식을 바꿉니다:
  • Didit는 카운터파티 VASP 라우팅을 완전히 건너뛰고(자체 보관 지갑 뒤에는 VASP가 없습니다), 전송을 UNCONFIRMED_OWNERSHIP 상태로 바로 생성합니다.
  • Travel Rule 설정에서 auto_wallet_verification이 켜져 있으면(기본값), 위 응답과 똑같이 지갑 소유권 위젯 세션이 자동으로 생성되어 action_required에 반환됩니다.
  • SDK가 위젯을 자동으로 실행합니다. 사용자가 지갑에 대한 통제권을 증명하면 전송은 이름 대조를 수행하고, COMPLETED로 진행합니다. 이름이 지갑 주소록 소유자와 일치하지 않으면 COUNTERPARTY_MISMATCHED_DATA로 진행합니다.
선언이 없으면 Didit는 대신 레일을 순서대로 시도하고, 카운터파티 VASP를 찾을 수 없는 경우에만 소유권 흐름으로 대체합니다. 출금 대상이 사용자 본인의 지갑이라는 것을 제품에서 이미 알고 있다면 언제든 지갑을 선언하십시오. 실패한 라우팅 시도를 생략하고 사용자를 증명 흐름으로 곧바로 안내할 수 있습니다.

주체 기준 적용

다음 세 가지는 항상 페이로드가 아니라 토큰이 결정합니다:
  • 거래가 생성되는 애플리케이션.
  • 주체의 신원: 페이로드의 subject.externalUserId는 무시되고 토큰의 vendor_data로 대체됩니다.
  • 주체의 기기 컨텍스트(아래 참고). 서버에서 도출된 필드는 subject.device로 전달된 값과 충돌할 경우 우선합니다.
이 엔드포인트에서 401이 반환되면 토큰이 거부된 것입니다. 토큰이 없거나, 알 수 없거나, 폐기되었거나, max_uses를 초과했거나, 만료된 경우입니다. 만료된 토큰 응답의 오류 상세에는 항상 expired라는 단어가 포함됩니다. SDK는 이 단어로 expired_token 오류와 invalid_token 오류를 구분합니다.

거래 상세 다시 조회하기

GET /v1/transactions/{transaction_id}/는 동일한 X-Transaction-Token 인증으로 같은 상세 정보를 반환합니다. SDK는 실행된 작업 흐름이 완료되거나 그 창이 닫힌 후 이 엔드포인트를 자동으로 호출하므로, 최종 상태가 단일 이벤트나 알림에 의존하지 않습니다. 토큰이 유효한 동안 언제든 직접 이 엔드포인트를 사용해 status와 action_required를 다시 확인할 수 있습니다. 백엔드에서는 GET /v3/transactions/{transaction_id}/가 같은 레코드를 반환합니다.

자동 기기 인텔리전스

모든 제출에는 별도의 연동 작업 없이 기기 인텔리전스가 포함됩니다:
  • SDK는 개인정보를 보호하는 기기 지문(didit-fp-v2 스키마: 플랫폼 및 내비게이터 신호, 지속적인 기기 ID, 봇 점수, 복합 해시)을 수집하여 요청과 함께 전송합니다.
  • Didit는 연결 자체로부터 서버 측에서 IP 주소, 사용자 에이전트, accept-language 값을 도출하므로, 페이로드로 위조할 수 없습니다.
병합된 결과는 주체 참여자의 기기 컨텍스트로 정규화되어, KYC 세션이 데이터를 공급하는 것과 같은 기기 그래프에 삽입 또는 업데이트됩니다. 이로써 전체 사용자 기반에 걸쳐 거래를 기기 기준으로 상관 분석할 수 있으며(“기기 기준 연관”), 기기 및 네트워크 신호를 규칙과 IP 정보 보강에 반영하고, 콘솔의 거래 상세 정보에도 표시됩니다. 서버에서 제출하는 /v3/ 거래는 참여자별로 명시적인 device_context 객체를 계속 전달할 수 있습니다. SDK 경로에서는 같은 데이터의 더 강력한 버전을 추가 작업 없이 얻을 수 있습니다.

필수 사용자 작업

일부 거래는 정산되기 전에 최종 사용자가 무언가를 해야 합니다. 규칙이 인증 세션을 요구할 수도 있고, Travel Rule 이체가 목적지 지갑이 사용자 본인의 지갑이라는 증명을 요구할 수도 있습니다. 두 경우 모두 같은 위치, 즉 제출 응답(그리고 이후 거래를 조회할 때마다 반환되는 응답)의 action_required 블록에 나타납니다.
한 거래에 두 경우가 모두 해당할 수 있다면 wallet_ownership이 우선합니다. 소유권 증명이 없으면 Travel Rule 교환 자체가 진행되지 않기 때문입니다. 대기 중인 작업이 해결되면 action_required는 null이 됩니다. 기존 remediation 필드는 하위 호환성을 위해 유지됩니다. 정식 블록은 action_required입니다.

자동 실행 계약

autoLaunchAction(기본값 true)은 wallet_ownership 작업만 자동으로 실행합니다.
  • 웹 - SDK 고유의 오버레이 모달에서 열립니다. 완료 여부는 출처를 검증한 메시지 전달과 제한된 횟수의 거래 폴링으로 확인합니다. 단일 이벤트에만 의존하지 않습니다.
  • iOS / Android(그리고 네이티브 SDK에 위임하는 React Native 및 Flutter 래퍼) - useNativeWalletOwnership이 true(기본값)이면 SDK의 네이티브 지갑 소유권 화면(SwiftUI / Jetpack Compose)으로 표시합니다. 이 화면을 사용할 수 없으면 SFSafariViewController 또는 Chrome Custom Tab으로, 그것도 안 되면 기본 브라우저로 대체합니다. 흐름이 닫히거나 앱이 포그라운드로 돌아오면 SDK가 거래를 자동으로 다시 조회합니다.
verification_session 작업은 자동으로 실행되지 않습니다. 항상 action_required로 반환되며, 앱이 자체 Didit 인증 연동으로 시작해야 합니다.
지갑 소유권 위젯은 임베디드 모바일 웹뷰 안에서 절대 렌더링하면 안 됩니다. 지갑 딥링크가 웹뷰를 벗어날 수 없어 증명 흐름이 중단됩니다. SDK는 자동 실행 시 올바른 브라우저 화면을 이미 사용합니다. url을 직접 처리하는 경우에도 이 규칙을 유지하세요. 자세한 내용은 지갑 소유권 위젯 가이드를 참조하세요.
SDK가 자동으로 실행한 지갑 소유권 흐름이 완료되거나 닫히면, SDK는 거래를 다시 조회하고 갱신된 결과를 onActionCompleted 콜백으로 전달합니다. verification_session 작업은 이 주기에 포함되지 않습니다. 앱이 직접 실행하기 때문이며, 자세한 내용은 다음 섹션을 참조하세요.

인증 세션 실행

action_required.type이 verification_session이면 result.actionRequired에서 블록을 읽고, 기존 Didit 인증 연동에 전달합니다.
인증 흐름이 끝나면 GET /v1/transactions/{transaction_id}/를 호출하거나 거래 webhook을 기다려 거래의 갱신된 상태를 확인하세요.

예시: 고액 출금 시 추가 생체 인증

이 흐름이 가장 효과적으로 쓰이는 경우는 위험한 거래, 즉 큰 금액, 새로운 수취인, 새로운 기기에 대해 온보딩 때 인증한 본인을 다시 생체 인증으로 확인하도록 요구하는 상황입니다. 계정 탈취는 바로 이런 모습입니다. 올바른 비밀번호, 올바른 2FA 코드(피싱 또는 SIM 스왑으로 탈취), 그리고 한 번도 본 적 없는 지갑으로의 출금입니다. 이 시점에는 자격 증명 기반의 방어가 모두 뚫린 상태입니다. 하지만 얼굴은 다릅니다. 공격자는 정당한 소유자가 KYC 온보딩 때 캡처한 얼굴과 일치해야 하는 라이브니스 감지를 거친 셀피를 통과할 수 없습니다.
1

콘솔에서 규칙을 한 번만 만드세요

Transactions → Rules → Create Rule에서 조건은 amount gte 5000, 작업은 Change status → AWAITING_USER로 설정하고, 작업에서 생체 인증 워크플로를 선택하세요. 처음 보는 거래 상대방, 새로운 기기 지문, IP 국가 변경 같은 위험 조건은 추가 조건 또는 추가 규칙으로 자유롭게 넣을 수 있습니다.
2

평소처럼 출금을 제출하세요

제출 코드는 바꿀 필요가 없습니다. 규칙이 발동하면 응답에 status: "AWAITING_USER"와 verification_session 유형의 action_required 블록이 포함되어 반환됩니다:
3

재확인을 실행하세요

session_token(또는 url)을 인증 세션 실행에서 설명한 것과 같이 기존 Didit 인증 연동에 전달하세요. 세션은 거래 대상자와 같은 vendor_data로 생성되므로, Didit은 온보딩에서 확인된 사용자의 기준 얼굴 이미지를 이미 보유하고 있습니다. 승인된 라이브니스 셀피, 여권 칩 사진, 또는 문서의 초상 사진이 여기에 해당합니다. 사용자는 라이브 셀피를 한 장 찍기만 하면 됩니다. Didit은 라이브니스 검사와 함께, 저장된 기준 얼굴과의 1:1 얼굴 대조를 수행합니다. 문서를 다시 스캔하거나 온보딩을 다시 할 필요는 없습니다. 위험한 거래에서만 몇 초의 번거로움이 추가됩니다.
4

결과에 따라 거래를 확정하세요

세션이 완료되면 거래가 자동으로 다시 평가됩니다. 재확인을 통과하면 APPROVED, 실패하면 DECLINED가 되며, 두 경우 모두 transaction.status.updated webhook이 전송됩니다(거래 타임라인에는 reason: remediation_completed로 기록됩니다). 앱은 onActionCompleted 방식의 콜백, GET /v1/transactions/{transaction_id}/, 또는 webhook으로 결과를 받을 수 있습니다.
이 설계가 작동하는 이유는 KYC 온보딩, 생체 인증 재확인, 거래 결정이 하나의 플랫폼에서 실행되기 때문입니다. 온보딩 때 촬영한 얼굴이 추가 인증의 기준이 되고, 기기 그래프가 세션과 거래를 연결하며, 규칙 엔진이 이들을 하나로 묶습니다. 별도의 벤더 연동, 얼굴 이미지 내보내기, 별도의 생체 인식 계약이 필요하지 않습니다. 재확인은 실제로 실행될 때에만 표준 생체 인증 기능($0.10)으로 과금됩니다.

웹 SDK

submitTransaction은 현재 웹 SDK 싱글톤에서 사용할 수 있습니다:
결과는 { transactionId, status, travelRuleStatus?, actionRequired? } 형식입니다. SDK 수준의 페이로드에서는 category, details, customProperties를 작성합니다. SDK가 이 값들을 와이어 별칭(type, info, props)에 자동으로 매핑합니다. 오류는 DiditTransactionError를 통해 타입이 지정됩니다:

네이티브 SDK

네이티브 submitTransaction API는 iOS 및 Android SDK 4.1.0에 포함되어 제공됩니다(이 버전을 고정하는 React Native 및 Flutter 릴리스 포함). 웹 SDK와 달리 네이티브 페이로드는 와이어 필드 이름인 type, info, props를 그대로 사용합니다.
모든 SDK는 같은 토큰으로 거래를 다시 읽을 수 있도록 getTransaction(transactionToken, transactionId)도 제공합니다. SDK는 실행된 작업 흐름 이후에 이 함수를 자동으로 호출하며, 필요한 시점에 직접 호출할 수도 있습니다. 모바일에서는 기기 지문 전송 방식이 모든 SDK 네트워크 호출에 이미 적용되어 있으므로, 거래 제출에도 같은 기기 인텔리전스가 자동으로 포함됩니다.

SDK 없이 사용하기

SDK가 하는 모든 일은 일반 HTTPS로 수행할 수 있으며, 여기에 SDK가 필요하지는 않습니다. 동등한 연동 방식은 두 가지입니다. 서버 측 전용(토큰 전혀 사용하지 않음). 백엔드에서 API 키를 사용해 POST /v3/transactions/로 제출합니다. 응답과 이후의 모든 GET /v3/transactions/{transaction_id}/ 응답에는 같은 action_required 블록이 포함됩니다. SDK가 기기 정보를 수집해 주지 않으므로, 참여자별로 명시적인 device 컨텍스트를 전달할 수도 있습니다. 클라이언트 측, 직접 구성한 HTTP 스택 사용. POST /v3/transactions/sdk-token/으로 토큰을 발급받은 다음, 기기에서 X-Transaction-Token 헤더와 함께 POST /v1/transactions/ 및 GET /v1/transactions/{transaction_id}/를 호출합니다. 이때 같은 주체 바인딩과 서버 측 IP/사용자 에이전트 도출이 그대로 적용됩니다. 그다음 action_required는 직접 처리해야 합니다: 클라이언트 콜백 없이 완료 여부를 확인하는 방법은 다음과 같습니다:
  • 웹훅(권장). 대기 중인 작업이 거래 처리를 완료하면 transaction.status.updated가 발생하고, Travel Rule의 모든 상태 전환에서 travel_rule.status.updated가 발생합니다. 두 이벤트 모두 폴링 없이 기록을 업데이트하기에 충분한 정보를 담고 있습니다.
  • 폴링. 거래를 다시 조회합니다(백엔드에서는 /v3/, 토큰이 유효한 동안에는 /v1/을 사용합니다). 해결되면 action_required가 null로 돌아가고, status와 travel_rule.status에 결과가 담깁니다.
이 설계에는 일회성 의존성이 없습니다. 위젯, 인증 세션, 백엔드가 모두 같은 영구적인 거래 상태로 수렴하므로, 닫힌 탭이나 놓친 웹훅이 있더라도 거래를 다시 조회하면 항상 복구할 수 있습니다.

웹훅

백엔드가 결과를 보고받기 위해 앱이 필요한 것은 아닙니다. 제출된 거래에 사용자 작업이 필요하면 거래 웹훅(transaction.created 또는 transaction.status.updated)에 같은 action_required 블록이 포함됩니다. 따라서 흐름이 끝나기 전에 앱을 닫더라도 시스템이 대기 중인 작업을 알 수 있습니다. verification_session 작업에는 AWAITING_USER 상태가 함께 제공되지만, wallet_ownership 작업은 그 자체로 거래 상태를 바꾸지 않습니다. 따라서 상태 대신 action_required를 확인하십시오. Travel Rule 상태가 전환되면 travel_rule.status.updated도 추가로 발생합니다.

다음 단계

거래 제출

서버 측 Create Transaction API와 전체 페이로드 참조 문서입니다.

Travel Rule

관리형 송금인-수취인 정보 교환, 설정 및 수명 주기입니다.

지갑 소유권 위젯

wallet_ownership 작업의 기반이 되는 호스팅 제어 권한 증명 흐름입니다.

웹훅

transaction.created, transaction.status.updated 및 서명 검증입니다.

규칙

규칙 작업, 인증 세션을 생성하는 작업을 포함합니다.

상태

거래 수명 주기에서 AWAITING_USER가 의미하는 바입니다.
마지막 수정일 2026년 11월 7일