無料
開発、テスト、そして最初のユーザー向け。
- 毎月500件のフルKYC認証
- 本人確認、生体認証、顔照合、デバイス&IP
- 200以上の不正検知シグナル、ブロックリスト、重複チェック
- Diditネットワーク全体でKYCを再利用可能
- ワークフロービルダー、ケース管理、SDK
- AIサポート コンソール内AIエージェント、ドキュメント、コミュニティ。
世界中の2,000以上の組織から信頼されています。

グローバル対応
スペインのDNI、日本のマイナンバーカード、英国のパスポートなど、毎月新しい書類に対応しています。1チェックあたり$0.15、同じ判定形式、2秒未満の応答速度は変わりません。
方法01
パスポート、国民ID、運転免許証、在留許可証を撮影します。220以上の国、14,000以上の書類に対応し、2秒以内に結果が出ます。
$0.15 · 月500回まで無料現在地
方法02
ユーザーが国民ID番号を入力すると、Diditが発行元の政府データベースと照合します。登録機関に写真がある場合は、セルフィーと登録写真を顔認証で照合します。
36カ国 · 国ごとに料金設定方法を見る
方法03
ユーザーは政府または銀行のデジタルID(MitID、BankID、itsme、UAE PASS、gov.br、EUDI Walletなど)でサインインし、ウォレットが署名付き属性を返し、Diditがその署名を検証します。
22種類のウォレット · 近日公開方法を見る
本人確認、ライブネス、顔照合、制裁リスト、住所、年齢、電話番号、メールアドレス、カスタム質問など、必要なチェック項目を選択します。ダッシュボードでドラッグ&ドロップしてフローを作成するか、同じフローをAPIにPOSTします。条件分岐やA/Bテストも、コード不要で設定できます。
今月更新
対応国
書類タイプ
対応言語
スクリプト
OCR · MRZ · バーコード
有効期限を自動追跡 · ステータス変更時にWebhook通知
$ curl -X POST https://verification.didit.me/v3/session/ \
-H "x-api-key: $DIDIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"workflow_id": "wf_3daf4c64",
"vendor_data": "user-42"
}'{ "url": "verify.didit.me/..." }$ curl -X POST https://verification.didit.me/v3/id-verification/ \
-H "x-api-key: $DIDIT_API_KEY" \
-F "front_image=@front.jpg" \
-F "back_image=@back.jpg"{ "status": "承認済み", "document_type": "パスポート" }# Didit ID Verification — integrate in 5 minutes
You are integrating Didit's ID Verification module into <my_stack>. Follow
these steps exactly. Every URL, header, and enum value below is canonical —
do not paraphrase or "improve" them.
## 1. Provision an account
- Sign up: https://business.didit.me (no credit card required).
- Or provision programmatically: POST https://apx.didit.me/auth/v2/programmatic/register/
(returns an API key bound to the workspace + application).
## 2. Two integration paths — pick one
### Path A — Workflow Builder (hosted UI)
Best when you want Didit to handle camera, lighting cues, retries,
mobile handoff, and accessibility for you.
1. Create a workflow that contains the ID Verification feature:
POST https://verification.didit.me/v3/workflows/
Authorization header: x-api-key: <your-api-key>
Body: workflow_label, features array with the single entry
{ feature: "OCR" } (UPPERCASE — strict enum; "OCR" is the
workflows-endpoint value for ID Verification, and the only one
POST /v3/workflows/ accepts for it)
2. Create a verification session for an end user:
POST https://verification.didit.me/v3/session/
Body: workflow_id (from step 1), vendor_data (your own user id).
Response: url (the hosted verification link) — redirect the user to it.
3. Listen for webhook callbacks (see "Webhooks" below).
### Path B — Standalone server-to-server API
Best when you already have the document image (mobile SDK capture, native
onboarding app, reseller pipeline).
POST https://verification.didit.me/v3/id-verification/
Content-Type: multipart/form-data
Body fields:
- front_image (required, file)
- back_image (optional, file)
- vendor_data (optional string, your user id)
Response: JSON report with extracted fields, image quality scores,
warnings array, and the verdict.
## 3. Webhooks (Path A only — Path B returns synchronously)
- Register a webhook destination once via
POST https://verification.didit.me/v3/webhook/destinations/
Body: url, subscribed_events: ["session.verified", "session.review_started",
"session.declined", "kyc_expired"]
- Response includes secret_shared_key — store it.
- Every webhook delivery carries an X-Signature-V2 header you MUST verify
before trusting the payload. X-Signature-V2 signs the CANONICAL JSON, not
the raw body bytes — that is what makes it survive a proxy or body parser
that re-encodes the payload. (The legacy X-Signature header is the one
computed over the raw bytes.) The canonical form is the sender's Python
json.dumps(sort_keys=True, separators=(",", ":"), ensure_ascii=False)
after whole-valued floats become ints. Reproduce those bytes EXACTLY —
do NOT "parse, sort keys, JSON.stringify", which fails in four ways:
- Numbers come from the wire text, never from parsed doubles: the sender
signs 1000000000000000129 digit for digit, JSON.parse rounds it. Read
the body as TEXT (express.text, not express.json()) and re-emit
integers through BigInt(source). Register the webhook route ABOVE any
global app.use(express.json()): the first parser to run consumes the
stream, and the digits are gone before the route sees them.
- Floats use Python's repr: 1e-05, not 0.00001; 27.0 becomes 27.
- Keys sort by Unicode CODE POINT, as strings: "10" before "2", and
U+FF21 before U+1F642 (JavaScript's default .sort() reverses the latter
because it compares UTF-16 code units).
- Serialise straight from the sorted entries; never rebuild an object
first, because JavaScript moves integer-like keys to the front.
Then HMAC-SHA256 with secret_shared_key, hex-encode, and compare to the
X-Signature-V2 header in constant time (crypto.timingSafeEqual).
- Freshness comes from the SIGNED body field "timestamp" (Unix seconds):
reject a delivery whose body timestamp is more than 300 seconds from now,
and require the X-Timestamp header to equal it. Never check the header
alone — it is not signed, so a replayed delivery with a rewritten header
would pass. This is the Node 22 + Express handler, paste it verbatim:
// Your endpoint receives a signed ID Verification payload
const crypto = require("node:crypto"); // ESM: import crypto from "node:crypto"
// X-Signature-V2 = HMAC over the canonical JSON, never the raw bytes. Match the sender byte for
// byte: keys sorted by code point, integers digit for digit, floats in Python's repr.
class Num { constructor(src) { this.src = src; } } // a number as written on the wire, not a double
const num = (s) => { if (/^-?\d+$/.test(s)) return BigInt(s).toString(); const n = +s; // ints stay exact
if (Number.isInteger(n)) return BigInt(n).toString(); const [m, e] = n.toExponential().split("e"); // 27.0 -> 27
return +e >= -4 ? String(n) : `${m}e-${String(-e).padStart(2, "0")}`; }; // 1e-05, not 0.00001
const byCodePoint = (a, b) => Buffer.compare(Buffer.from(a), Buffer.from(b)); // UTF-8 order = Python's
const canon = (v) => Array.isArray(v) ? `[${v.map(canon)}]` : v instanceof Num ? num(v.src)
: v && typeof v === "object" ? `{${Object.keys(v).sort(byCodePoint).map((k) => `${JSON.stringify(k)}:${canon(v[k])}`)}}`
: JSON.stringify(v);
// Read the body as text: express.json() would round 1000000000000000129 to a double first.
// Register this route ABOVE any global app.use(express.json()): the first parser to run
// consumes the stream, and a body it already parsed has lost the digits the signature covers.
app.post("/webhooks/didit", express.text({ type: "application/json" }), (req, res) => {
const exact = JSON.parse(req.body, (k, v, c) => typeof v === "number" ? new Num(c.source) : v); // Node 21+
const body = JSON.parse(req.body);
const mac = crypto.createHmac("sha256", SECRET).update(canon(exact), "utf8").digest("hex");
const sig = Buffer.from(String(req.headers["x-signature-v2"] ?? ""));
// Freshness comes from the signed body timestamp; the header alone is unsigned and replayable.
const ts = body.timestamp, fresh = String(ts) === req.headers["x-timestamp"]
&& Math.abs(Date.now() / 1000 - ts) <= 300;
if (!fresh || sig.length !== mac.length
|| !crypto.timingSafeEqual(sig, Buffer.from(mac))) return res.sendStatus(401);
const { status, decision, vendor_data } = body;
// status: Approved | Declined | In Review | Expired | Not Finished
res.sendStatus(200);
});
## 4. Reading the report
Both paths return the same FIELDS, in a different container:
- Path A (session decision + webhook): decision.id_verifications is an ARRAY
— one entry per ID Verification node in the workflow. Select the entry you
want by its node_id, never by index and never as a singular object:
const doc = decision.id_verifications.find(
(v) => v.node_id === "id_verification_1"
);
Every other feature is plural the same way: liveness_checks,
face_matches, aml_screenings, ip_analyses, nfc_verifications,
poa_verifications, database_validations.
- Path B (POST /v3/id-verification/): a single id_verification object on the
response body — this endpoint runs exactly one document.
Each id_verification entry includes:
- status: "Approved" | "Declined" | "In Review" | "Expired" | "Not Finished"
- document_type: "Passport" | "Identity Card" | "Driver's License" | "Residence Permit" | null
- document_number, personal_number
- front_image, back_image, portrait_image (signed URLs, expire in 1 hour)
- date_of_birth (YYYY-MM-DD), age (number)
- expiration_date, date_of_issue (YYYY-MM-DD)
- issuing_state, issuing_state_name (ISO 3166-1 alpha-3 + display name)
- first_name, last_name, full_name
- gender ("M" | "F" | "U"), nationality (ISO 3166-1 alpha-3)
- address, formatted_address, parsed_address (street_1, street_2, city,
region, postal_code, geometry { lat, lng })
- front_image_quality_score / back_image_quality_score (focus, brightness,
resolution, overall, each 0-100)
- warnings: Array<{ risk, log_type, short_description, long_description }>
## 5. Hard rules — do not change
- Base URL for /v3/* endpoints is verification.didit.me (NOT apx.didit.me).
- Feature enum is UPPERCASE: OCR (ID Verification), LIVENESS, FACE_MATCH, AML, IP_ANALYSIS.
- Auth header is x-api-key (lowercase, hyphenated).
- Webhook signature header is X-Signature-V2 (NOT X-Signature), and it signs
the canonical JSON — never HMAC the raw bytes under that header, and never
canonicalise a parsed object: read the body as text and serialise the
sender's bytes (see the handler in section 3).
- Webhook freshness is the signed body "timestamp" (300 s window); the
X-Timestamp header must equal it and is never checked on its own.
- decision.id_verifications is an array; select the node you want by node_id.
- Always verify webhook signatures before trusting payload data.
- Status casing matches exactly: "Approved", "Declined", "In Review",
"Expired", "Not Finished" (title-cased, space-separated).
## 6. Pricing reference (public)
- Path A bundled in a full KYC workflow: $0.33 per session
- Path B standalone /v3/id-verification/ call: $0.15 per call
- 500 free verifications every month, forever, on every account.
## 7. Verify your integration
- Sandbox starts on signup at https://business.didit.me — no separate flag.
- Test docs: deterministic synthetic IDs returned in sandbox.
- Switch to live: flip the application's environment toggle in console.
When in doubt: https://docs.didit.me/core-technology/id-verification/overview
開発、テスト、そして最初のユーザー向け。
25以上のモジュールを公開価格で提供。自動ボリュームディスカウントあり。
大量利用や規制対象プログラム向け。
利用量の増加に応じて割引が自動適用されます。交渉や営業担当とのやり取りは不要です。
Diditは本人確認と不正対策のためのインフラです。私たちが自社でプロダクトを開発していた時に「こんなプラットフォームがあれば」と願った、オープンで柔軟、そして開発者に優しいプラットフォームです。そのため、単なるブラックボックスとしてではなく、お客様のスタックの真の構成要素として機能します。
単一のAPIで、個人の確認(KYC、顧客確認)、企業の確認(KYB、企業確認)、暗号資産ウォレットのスクリーニング(KYT、取引確認)、およびリアルタイムでの取引監視をカバーします。このスタックは、以下の特徴を持つように構築されています。
基盤となるフットプリントは、48以上の言語に対応した14,000以上のドキュメントタイプ、1,000以上のデータソース、そして全セッションで200以上の不正シグナルです。Diditのインフラは、すべてのセッションから動的に学習し、日々改善されています。
docs.didit.me/core-technology/id-verification/supported-documents-id-verificationで閲覧でき、このページ上の検索可能なテーブルにも同じデータが反映されています。id_verification JSONオブジェクトです。トップレベルのstatusは、Approved、Declined、In Review、Expired、またはNot Finishedのいずれかです。このオブジェクトには、document_type、document_number、full_name、first_name、last_name、date_of_birth(YYYY-MM-DD)、age、expiration_date、date_of_issue、issuing_state(ISO 3166-1 alpha-3)、nationality、gender、address、ストリート、都市、地域、郵便番号、ジオメトリ座標を含む構造化されたparsed_address、portrait_image / front_image / back_image / front_video / back_videoの署名付きURL、フォーカス / 明るさ / 解像度 / 全体(それぞれ0~100)の画像品質スコア、およびwarnings配列が含まれます。完全なリファレンスはdocs.didit.me/core-technology/id-verification/report-id-verificationをご覧ください。通常、エンドツーエンドの全フローは30秒未満で完了します。IDを手に取り、書類を撮影し、セルフィーを撮影すれば完了です。これは市場最速です。従来のKYCプロバイダーでは、同じフローに90秒以上かかることが一般的です。
バックエンドでは、ユーザーがセルフィーを完了した瞬間からWebhookが起動するまで、Diditはp99で2秒未満で結果を返します。モバイルキャプチャは、低速なスマートフォンやネットワーク向けに最適化されており、プログレッシブ画像圧縮、遅延SDKロード、ユーザーがWebから開始した場合のQRコードによるデスクトップからスマートフォンへのワンタップ連携が可能です。
DOCUMENT_EXPIRED、MINIMUM_AGE_NOT_MET、DOCUMENT_NOT_SUPPORTED_FOR_APPLICATION、ID_DOCUMENT_IN_BLOCKLIST、PORTRAIT_IMAGE_NOT_DETECTEDなどの自動拒否トリガーは、お客様のリスクポリシーに関わらず適用されます。すべてのセッションは7つの明確なステータスのいずれかに分類されるため、お客様のコードは常に適切な処理を判断できます。
Approved, すべてのチェックに合格しました。ユーザーを次のステップに進めます。Declined, 1つ以上のチェックに失敗しました。ユーザーに特定の失敗したステップ(例:セルフィーの再撮影)を再提出させることができます。その際、フロー全体を再実行する必要はありません。In Review, コンプライアンスレビューのためにフラグが立てられました。コンソールでケースを開き、すべてのシグナルを確認し、承認または拒否を決定します。In Progress, ユーザーはフローの途中にいます。Not Started, リンクは送信されましたが、ユーザーはまだ開いていません。長期間放置されている場合はリマインダーを送信します。Abandoned, ユーザーはリンクを開きましたが、時間内に完了しませんでした。再エンゲージするか、期限切れとします。Expired, セッションリンクの有効期限が切れました。新しいセッションを作成します。すべてのステータス変更時に署名付きWebhookが起動するため、お客様のデータベースは常に同期されます。中断および拒否されたセッションは無料です。
本番データは、デフォルトでAmazon Web Services上の欧州連合内で処理および保存されます。 規制当局が要求する管轄区域については、エンタープライズ契約で代替リージョンをリクエストできます。
あらゆる場所で暗号化。 すべてのデータベース、オブジェクトストレージ、バックアップにおいて、保存時にはAES-256で暗号化されます。すべてのAPIコール、Webhook、ビジネスコンソールセッションにおいて、転送時にはTransport Layer Security 1.3が使用されます。生体認証データは、個別のカスタマーマスターキーで暗号化されます。
データ保持期間はお客様が管理できます。 デフォルトの保持期間は無期限(unlimited)ですが、アプリケーションごとに30日から10年の間で短縮設定が可能です。また、ダッシュボードまたはAPIからいつでも個々のセッションを削除できます。
認証: SOC 2 Type 1 & Type 2、ISO/IEC 27001:2022、iBeta Level 1 PAD、およびスペインのTesoro / SEPBLAC / CNMVによる、Diditのリモート本人確認が対面での本人確認よりも安全であるという公式認定。完全なレポートは/security-complianceでご覧いただけます。
Diditは、本人確認インフラストラクチャにとって重要な規制当局の要件にデフォルトで準拠しています。
詳細なメモ、すべての証明書、すべての規制当局からの書簡は/security-complianceをご覧ください。
3つの統合パスから、お客様のスタックに最適なものをお選びください。
すべてのパスで同じダッシュボード、同じ請求、成功ごとの同じ料金が適用されます。ステップバイステップガイドはdocs.didit.me/integration/integration-promptをご覧ください。