無料
開発、テスト、そして最初のユーザー向け。
- 毎月500件のフルKYC認証
- 本人確認、生体認証、顔照合、デバイス&IP
- 200以上の不正検知シグナル、ブロックリスト、重複チェック
- Diditネットワーク全体でKYCを再利用可能
- ワークフロービルダー、ケース管理、SDK
- AIサポート コンソール内AIエージェント、ドキュメント、コミュニティ。
世界中の2,000以上の組織から信頼されています。
ステータスは、本番環境での利用可否と統合テストを区別します。対応国は設定されたウォレットルートを説明するものであり、すべての国でライブIDチェックが完了したことを意味するものではありません。ローンチ日は保証されません。
統合ステータス
Smart-ID、Mobile-ID、Finnish Trust Network、MitIDをご利用いただけます。国ごとに承認するウォレットを選択し、ユーザーがすでに持っている有効なIDで認証できるようにします。その他の統合は近日公開予定です。
コンソールで、環境内の各国で利用可能なウォレットを選択します。キャンセルまたは失敗したサインインがドキュメントキャプチャにフォールバックするか、拒否するかを選択します。
メソッドカタログから直接
カタログ掲載数
対応国数
eIDAS高
順序制御は一切なし
チェックを入れるだけで設定完了です。ユーザーはあなたが許可したものから選択し、画面上の順序に意味はありません。各ウォレットは、稼働開始までカタログの状態を維持します。
Smart-IDとMobile-IDのフロー
MitID · Danish Agency for Digital Government
管理者画面のみ
エンドユーザーが保証ラベル、ソース名、価格を見ることはありません。これら3つはすべてレビュー担当者のみが確認できます。
少なくとも1つのウォレットがある国
国
EUDIウォレットでカバー
対応範囲は国ごとのカタログに準拠します。ここに国旗があるのは、その国でウォレットがリストされていることを意味し、稼働中であることを示すものではありません。
$ curl -X POST https://verification.didit.me/v3/session/ \
-H "x-api-key: <your-api-key>" \
-H "Content-Type: application/json" \
-d '{
"workflow_id": "wf_wallets",
"vendor_data": "user_42"
}'{ "url": "https://verify.didit.me/..." }// Your endpoint receives a signed 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 } = body;
// One entry per ID Verification node; pick yours by node_id when you run several.
const [idv] = decision?.id_verifications ?? [];
// idv.verification_method: "document" | "id_lookup" | "wallet"
res.sendStatus(200);
});{ "verification_method": "wallet", "assurance": "cryptographic" }# Didit digital ID wallets — integrate in 5 minutes
You are adding digital ID wallet sign-in to my_stack. The user signs in with a
government or bank digital identity and the wallet returns signed attributes.
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).
- Grab the API key for your application from the console.
## 2. Read the methods catalog first
Wallet availability is server-driven per country. Never hard-code a wallet list.
The catalog is not a public REST endpoint. Read it one of two ways:
- Business Console (signed in): your application -> ID Verification ->
Countries tab. https://docs.didit.me/console/id-verification-methods
- Didit MCP server tool didit_workflow_get_id_verification_methods_catalog,
authenticated with the same x-api-key; pass country (ISO 3166-1 alpha-3)
to narrow it to one country. https://docs.didit.me/integration/mcp/tools
- Public mirror of the coverage table (no auth, read-only):
https://docs.didit.me/core-technology/id-verification/verification-methods#coverage
The catalog gives you, per wallet id: the display name, the countries it
covers, the issuing authority, the level of assurance, the availability state,
and the attributes it returns. MitID, Smart-ID, Mobile-ID and Finnish Trust
Network are available. Read the Finnish Trust Network integration guide:
https://docs.didit.me/core-technology/id-verification/finnish-trust-network
iDIN and other wallets remain coming soon until the catalog in
your environment marks them available. Re-read it; do not hard-code a date.
## 3. Create a workflow with the ID Verification (OCR) feature
POST https://verification.didit.me/v3/workflows/
-H "x-api-key: <your-api-key>"
-H "Content-Type: application/json"
The ID Verification feature's enum value is OCR (UPPERCASE — strict enum;
there is no ID_VERIFICATION alias and the API rejects it). Wallets are its
wallet method, accepted per country under config.methods on that same
feature entry, in the same request. Keys are ISO 3166-1 alpha-3.
{
"workflow_label": "Wallet onboarding",
"features": [
{
"feature": "OCR",
"config": {
"methods": {
"DNK": {
"document": { "enabled": true },
"wallet": {
"enabled": true,
"providers": ["mitid"],
"on_failure": "fallback_to_document"
}
},
"FIN": {
"document": { "enabled": true },
"wallet": {
"enabled": true,
"providers": ["ftn"],
"on_failure": "fallback_to_document"
}
}
}
}
}
]
}
Response: the workflow uuid — use it as workflow_id in step 4.
Rules that the API enforces:
- providers is an accept-list, not a ranking. Order carries no meaning and
the end user picks
- on_failure is either fallback_to_document or decline. It covers all three
cases: no wallet, cancelled, sign-in failed
- a wallet id the catalog does not mark available for that country is
rejected, and the rejection fails the whole save — including any lookup
configuration next to it. For unavailable wallets, keep wallet.enabled
false (or omit the wallet block) so the save succeeds
- unknown wallet ids already saved on a workflow are preserved untouched, so
a config written by a newer console version is never silently dropped
- a country with no method enabled is rejected at publish time
## 4. Create a session
POST https://verification.didit.me/v3/session/
-H "x-api-key: <your-api-key>"
-H "Content-Type: application/json"
-d '{ "workflow_id": "<id from step 3>", "vendor_data": "<your user id>" }'
Response: 201 with url (the hosted verification link), session_token and
session_id. Redirect the user to url, or open it in the SDK. The field is
named url — there is no session_url and no verification_url. Didit
shows the accepted wallets for the user's country with their brand marks,
hands off to the wallet, and waits for the signed assertion to come back.
## 5. Webhooks
Register a destination (console -> API & Webhooks, or
POST https://verification.didit.me/v3/webhook/destinations/ with
webhook_version "v3" and subscribed_events ["status.updated"]) and store the
secret_shared_key it returns. Verify every delivery:
Header: X-Signature-V2 (NOT X-Signature, NOT X-Signature-Simple)
Algorithm: HMAC-SHA256, hex digest, over the CANONICAL JSON of the payload
— 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
(read the body with express.text, not express.json(),
registered ABOVE any global app.use(express.json()), and
re-emit integers through BigInt(source) — JSON.parse rounds
1000000000000000129); 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", U+FF21 before U+1F642, which
JavaScript's default .sort() reverses); and the bytes come
straight from the sorted entries, never from a rebuilt object.
Do NOT hash the raw request bytes — that is the v1
X-Signature algorithm and fails for V2 whenever whitespace or
key order differs from the canonical form.
Freshness: the signed body field timestamp is the dispatch time (Unix
seconds, refreshed on every retry). Reject when
abs(now - timestamp) > 300 seconds, and reject when the
X-Timestamp header does not equal it. The header is not
covered by the signature, so it must never be the only replay
check: a captured delivery replays with just that header
refreshed.
Compare: constant-time (crypto.timingSafeEqual)
Reference handler (Express) — use it as written:
// Your endpoint receives a signed 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 } = body;
// One entry per ID Verification node; pick yours by node_id when you run several.
const [idv] = decision?.id_verifications ?? [];
// idv.verification_method: "document" | "id_lookup" | "wallet"
res.sendStatus(200);
});
Body fields you will use: session_id, status, webhook_type, workflow_id,
vendor_data, decision.
Status values: Approved, Declined, In Review, In Progress, Not Started,
Abandoned.
## 6. Reading the result
The decision is the V3 shape: every feature result is a plural array with one
entry per workflow node. ID Verification results live in
decision.id_verifications[] — there is no singular decision.kyc (that is the
V2 shape) and no decision.id_verification. Select your entry by node_id (the
id of your ID Verification node in the workflow graph); with a single ID step,
take index 0. Each entry carries, next to the document fields:
verification_method "document" | "id_lookup" | "wallet"
assurance "documentary" | "data_match" | "cryptographic"
wallet_provider the catalog wallet id the user signed in with; null
on document and id_lookup entries
wallet_verification provider, provider_name, issuing_authority,
issuing_country, credential_type, level_of_assurance
(low | substantial | high), verified_at,
signature_valid, attributes (what the wallet shared),
portrait when the wallet shares one; null otherwise
fallback_from { method, reason, action } when the session fell
back to document capture or was declined; else null
A wallet entry that succeeds is assurance cryptographic — the highest of the
three. Check wallet_verification.signature_valid before you trust attributes.
Field-by-field reference: https://docs.didit.me/reference/data-models#id-verification
## 7. Billing
- published customer prices in USD per completed wallet verification:
- MitID personal: $0.25; production availability: Available
- BankID Sweden: $0.20; production availability: Available
- Finnish Trust Network: $0.25; production availability: Available
- Smart-ID: $0.20; production availability: Available
- Mobile-ID: $0.20; production availability: Available
- BankID Norway High: $0.35; production availability: Coming soon
- Vipps Plus: $0.25; production availability: Coming soon
- Buypass ID: Coming soon; production availability: Coming soon
- itsme: Coming soon; production availability: Coming soon
- iDIN full identification: $0.85; production availability: Coming soon
- Personalausweis Profile 2: $0.45; production availability: Coming soon
- Freja eID: $0.25; production availability: Coming soon
- UAE PASS: Coming soon; production availability: Coming soon
- gov.br: Coming soon; production availability: Coming soon
- OneID: $2.50; production availability: Coming soon
- GOV.UK Wallet: Coming soon; production availability: Coming soon
- Bank iD: Coming soon; production availability: Coming soon
- MojeID: Coming soon; production availability: Coming soon
- Diia: Coming soon; production availability: Coming soon
- FranceConnect: Coming soon; production availability: Coming soon
- Auðkenni: Coming soon; production availability: Coming soon
- ConnectID: Coming soon; production availability: Coming soon
- EUDI Wallet: Coming soon; production availability: Coming soon
- Estonian ID-card: Coming soon; production availability: Coming soon
- eParaksts: Coming soon; production availability: Coming soon
- an announced price does not enable a wallet; check the live workflow catalog
- wallet checks are outside the document free tier; other checks are billed separately
- full pricing: https://docs.didit.me/core-technology/id-verification/digital-id-wallets#pricing
- document capture bills its own price when the user falls back
## 8. Hard rules — do not change
- base URL for v3 endpoints: verification.didit.me
- auth header: x-api-key (lowercase, hyphenated)
- webhook headers: X-Signature-V2 plus X-Timestamp; canonical JSON, never
raw bytes; freshness from the signed body timestamp
- feature enum: OCR (uppercase) — the ID Verification feature; per-country
methods go under its config.methods
- method keys: document, id_lookup, wallet (lowercase, snake_case)
- wallet ids come from the catalog verbatim, lowercase, snake_case
- country keys: ISO 3166-1 alpha-3, uppercase
- result path: decision.id_verifications[] (array), never decision.kyc
## 9. Verify your integration
- run one session per accepted wallet in sandbox
- assert the id_verifications[] entry for your node has verification_method
wallet and wallet_verification.signature_valid true
- cancel a wallet sign-in and assert your on_failure setting actually fires
- assert your webhook accepts a correctly signed payload with reordered
keys, whitespace and integer-like metadata keys ("10" before "2"), and
rejects a wrong X-Signature-V2, a payload whose signed timestamp is older
than 300 seconds, and that same stale payload with only the X-Timestamp
header refreshed
Docs: https://docs.didit.me/integration/integration-prompt
以下の価格は、ウォレット認証が完了するごとの米ドル建て料金です。記載された本人確認製品に適用され、その他のワークフローチェックや書類によるフォールバックは別途請求されます。月間500件の無料書類チェックにはウォレットは含まれません。発表された価格はウォレットが利用可能であることを意味するものではなく、利用状況は別途表示されます。公開レートのない利用可能なウォレットは「要問い合わせ」、公開レートのない計画中のウォレットは「近日公開」と表示されます。本人確認ウォレットは個人を認証するものであり、暗号資産ウォレットのスクリーニングは別の製品です。
「利用可能」は本番環境で有効化済みであることを示します。「近日公開」は、統合テストが開始されていても、まだ本番環境で有効化されていないことを示します。利用可能なウォレットが最初に表示されます。
ConnectID(オーストラリア)はサンドボックス環境で統合済みです。本番環境での利用は近日公開予定です。エストニアIDカード(エストニア)とeParaksts(ラトビア)は、今後統合を予定しています。これらのウォレットには、公開されている価格や本番環境でのリリース日はありません。
詳細なドキュメントを読む| IDウォレット | USD / 認証完了 | 国・地域 | 本番環境での利用可能状況 |
|---|---|---|---|
| MitID personal | $0.25 |
| 利用可能 |
| BankID Sweden | $0.20 |
| 利用可能 |
| Finnish Trust Network | $0.25 |
| 利用可能 |
| Smart-ID | $0.20 |
| 利用可能 |
| Mobile-ID | $0.20 |
| 利用可能 |
| BankID Norway High | $0.35 |
| 近日公開 |
| Vipps Plus | $0.25 |
| 近日公開 |
| Buypass ID | 近日公開 |
| 近日公開 |
| itsme | 近日公開 |
| 近日公開 |
| iDIN full identification | $0.85 |
| 近日公開 |
| Personalausweis Profile 2 | $0.45 |
| 近日公開 |
| Freja eID | $0.25 |
| 近日公開 |
| UAE PASS | 近日公開 |
| 近日公開 |
| gov.br | 近日公開 |
| 近日公開 |
| OneID | $2.50 |
| 近日公開 |
| GOV.UK Wallet | 近日公開 |
| 近日公開 |
| Bank iD | 近日公開 |
| 近日公開 |
| MojeID | 近日公開 |
| 近日公開 |
| Diia | 近日公開 |
| 近日公開 |
| FranceConnect | 近日公開 |
| 近日公開 |
| Auðkenni | 近日公開 |
| 近日公開 |
| ConnectID | 近日公開 |
| 近日公開 |
| EUDI Wallet | 近日公開 |
| 近日公開 |
| Estonian ID-card | 近日公開 |
| 近日公開 |
| eParaksts | 近日公開 |
| 近日公開 |
開発、テスト、そして最初のユーザー向け。
25以上のモジュールを公開価格で提供。自動ボリュームディスカウントあり。
大量利用や規制対象プログラム向け。
利用量の増加に応じて割引が自動適用されます。交渉や営業担当とのやり取りは不要です。
Diditは本人確認と不正対策のためのインフラです。私たちが自社でプロダクトを開発していたときに「こんなプラットフォームがあれば」と願ったものを形にしました。オープンで柔軟、そして開発者に優しい設計なので、ブラックボックスとしてではなく、お客様のスタックの一部として機能します。
単一のAPIで、個人の本人確認(KYC、Know Your Customer)、企業の本人確認(KYB、Know Your Business)、暗号資産ウォレットのスクリーニング(KYT、Know Your Transaction)、リアルタイムのトランザクション監視をカバーします。そのスタックは、以下の特長を備えています。
基盤となるフットプリント:48以上の言語に対応する14,000種類以上の書類タイプ、1,000以上のデータソース、そしてすべてのセッションで200以上の不正シグナルを検出します。Diditのインフラは、すべてのセッションから動的に学習し、日々進化しています。
ユーザーは既存の電子ID(eID)で認証を行い、Diditは署名されたID証拠を確認してから結果をセッションに書き込みます。操作はウォレットによって異なり、Smart-IDは個人コードを要求し、Mobile-IDは電話番号も要求します。どちらも比較コードとユーザーデバイスでの承認を使用します。
ウォレット認証は、ドキュメントキャプチャや非ドキュメント検索と並ぶID検証内の1つの方法です。ワークフローAPIでは、この機能はOCRと名付けられています。利用可能なウォレットは国と環境によって異なります。ウォレットのドキュメントから始めてください。
MitID、Smart-ID、Mobile-ID、Finnish Trust Networkをご利用いただけます。Smart-IDはエストニア、ラトビア、リトアニア、ベルギーで、Mobile-IDはエストニアとリトアニアで、Finnish Trust Networkはフィンランドで利用可能です。MitIDはデンマークで提供されています。iDIN、BankID、Freja eID、ConnectID、EUDI Walletを含むその他のウォレットは近日公開予定です。
コンソールで、国ごとに承認するウォレットを選択してください。ワークフローAPIは、お客様の環境と国に応じたカタログを使用します。統合ガイドを参照して、書類によるフォールバックを設定できます。
ユーザーは承認されたウォレットを選択し、個人コードを入力し、Mobile-IDの場合は電話番号を提供します。Diditは比較コードを表示します。ユーザーは、そのコードが自分の携帯電話に表示されているコードと一致することを確認し、そこで認証リクエストを承認します。PINはユーザーのデバイスにのみ入力され、Diditには決して入力されません。
Diditは署名付き応答を待ち、署名と証明書のステータスを確認し、検証済みの本人確認属性をセッションに返します。完了時間はユーザーとウォレットの応答に依存します。Smart-IDおよびMobile-IDガイドに従ってください。
Diditは、そのセッションのチャレンジに対して認証署名を確認し、信頼できる発行者に対して証明書を検証し、その失効ステータスを確認します。返されたIDは、リクエストに使用された個人コードと国と一致する必要があります。ホストされたフローは、セッショントークンも検証し、繰り返しの完了試行を拒否します。
これらのチェックにより、署名された応答が期待されるユーザーとリクエストに接続されます。これらは、ユーザーがコードを比較し、デバイスを保護する必要性を置き換えるものではありません。セッション結果で検証方法、ウォレットプロバイダー、署名された属性を読み取り、アプリケーションで結果を使用する前にWebhook署名を検証してください。技術ガイドを参照してください。
「ウォレットなし」「キャンセル」「サインイン失敗」の3つのケースすべてを1つのスイッチでカバーします。ドキュメントキャプチャにフォールバックするか、セッションを拒否するかを国ごとに設定できます。
結果にはフォールバック元の方法と理由が記録されるため、ウォレットサインインの失敗を見逃すことはありません。
Smart-IDはエストニア、ラトビア、リトアニア、ベルギーで利用可能です。Mobile-IDはエストニアとリトアニアで利用可能です。Mobile-IDはラトビアではサポートされていません。ユーザーは選択したウォレットに対応する資格情報が必要です。
ワークフローで、対応する国ごとに各ウォレットを有効にしてください。認証手順、検証済み本人確認フィールド、書類によるフォールバックについては、Smart-IDおよびMobile-IDガイドを参照してください。
お客様が選択したリージョンで、SOC 2 Type 1およびType 2、ISO 27001、GDPRに準拠し、転送中および保存時に暗号化されます。
ウォレットはリクエストされた属性のみを共有し、オプションの属性はチェックを外すことで一切保存されないようにできます。必須属性は、監査人が必要とする署名付きアサーション参照とともに常に保存されます。
詳細は/security-complianceをご覧ください。
Diditは、フィンテック、銀行、iGaming、暗号資産、マーケットプレイス、ヘルスケア、政府機関といった規制対象業界の2,000社以上で本番稼働しています。
ウォレットサインインは、3つの方法の中で最も強力な証拠である暗号学的な保証レベルに達しており、その保証レベルはすべてのセッションに記録されます。規制当局が特定の国のeIDを指定している場合、そのウォレットを受け入れることが通常、要件を満たす最もクリーンな方法です。
メモは/security-complianceにあります。
数分で、3つの方法があります。
business.didit.meから始めるか、docs.didit.me/integration/integration-promptをご覧ください。