Verification types
Everything you can ask users to prove. Each credential in a user's wallet supports one or more requirements, and you can combine requirements from different credentials in one session.
Proof pricing across methods#
Verifications are priced identically once issued into the user vault: 0.5ยข (โฌ0.005) per proof reuse (less than a cent), with your first 500 successful proof reuses free. When a user does not yet hold a required credential, LKP passes through the exact wholesale cost of initial issuance (no markup, no more, no less). First-time proofs are always paid to cover wholesale provider costs; your 500 free allowance applies to reuses.
| Proof Method | Supported Checks | Initial Issuance (At Cost) | Proof Reuse |
|---|---|---|---|
| Facial Age Estimation | AGE_OVER (18+, 21+) via 1 to 2s selfie | โฌ0.10 | โฌ0.005 |
| Government ID Document | AGE_OVER, COUNTRY_EQUALS, sybil uniqueness | โฌ0.33 | โฌ0.005 |
| Phone Number OTP | Ownership of phone, carrier country code | โฌ0.06 | โฌ0.005 |
| Email Address OTP | Ownership of email, corporate/school domain | โฌ0.01 | โฌ0.005 |
| Social & Developer Accounts | GitHub org, follower thresholds, X, TikTok, Instagram | โฌ0.00 | โฌ0.005 |
| Open Banking Account | Account holder name, balance threshold | โฌ0.15 | โฌ0.005 |
For age verification, businesses can configure kycWorkflow on session creation to choose age_estimation (โฌ0.10 first check, โฌ0.005 reuse), full_id (โฌ0.33 first check, โฌ0.005 reuse), or either (user picks).
Government ID#
government_idFacts printed on a passport, ID card or residence permit, checked with liveness: age, nationality (citizenship), name, sex, document details, and the address country on the document when it has one. This is verified identity, not current physical location.
The holder is at least this many years old today.
{"kind":"AGE_OVER","minAge":18}The nationality (citizenship) printed on the document, not current physical location. Pass several countries to accept any of them (France or the UK).
{"kind":"COUNTRY_EQUALS","countryIsoNumeric":528}The holder is at most this many years old today. Combine with a minimum age for a range.
{"kind":"AGE_AT_MOST","maxAge":25}The sex printed on the document.
{"kind":"SEX_EQUALS","sex":"F"}The identity document stays valid for at least this many more days.
{"kind":"DOCUMENT_VALID_FOR","minDays":90}The kind of document the holder verified with.
{"kind":"DOCUMENT_TYPE_EQUALS","documentType":"passport"}The country that issued the document.
{"kind":"ISSUING_COUNTRY_EQUALS","countryIsoNumeric":528}The holder's given names and surname as printed on the document. Case and accents are ignored.
{"kind":"FULL_NAME_EQUALS","fullName":"JAN DE VRIES"}The number of the document the holder verified with.
{"kind":"DOCUMENT_NUMBER_EQUALS","documentNumber":"NX1234567"}The country of the address printed on the document, when it has one. This is not proof that the holder currently lives there.
{"kind":"RESIDENCE_COUNTRY_EQUALS","countryIsoNumeric":528}Phone number#
phoneOwnership of a phone number, checked with a one-time code. Each number backs only one wallet.
The holder owns a phone number. Each number backs only one wallet.
{"kind":"PHONE_VERIFIED","lineType":"any"}The country the phone number belongs to.
{"kind":"PHONE_COUNTRY_EQUALS","countryIsoNumeric":528}The holder owns exactly this number, in international format.
{"kind":"PHONE_NUMBER_EQUALS","phoneNumber":"+31612345678"}Work or school email#
emailOwnership of an email address at an organisation's domain, checked with a one-time code.
The holder owns an email address of this kind. Work means an organisation's own domain, not a free mailbox.
{"kind":"EMAIL_VERIFIED","type":"work_or_school"}The address belongs to this organisation. Subdomains count: student.uva.nl matches uva.nl.
{"kind":"EMAIL_DOMAIN_EQUALS","domain":"example.com"}The holder owns exactly this email address.
{"kind":"EMAIL_ADDRESS_EQUALS","email":"jane@example.com"}Instagram#
instagramOwnership of an Instagram account, its username, follower and post counts and verified badge, notarized from Instagram's own servers.
The holder's Instagram account has at least this many followers.
{"kind":"FOLLOWERS_AT_LEAST","minFollowers":1000}The holder owns this Instagram account.
{"kind":"INSTAGRAM_USERNAME_EQUALS","username":"lkp"}The Instagram account has published at least this many posts.
{"kind":"INSTAGRAM_POSTS_AT_LEAST","minPosts":10}The Instagram account has Instagram's verified badge.
{"kind":"INSTAGRAM_VERIFIED"}X#
xOwnership of an X account via X's own login: username, followers, posts, account age and verification.
The holder's X account has at least this many followers.
{"kind":"X_FOLLOWERS_AT_LEAST","minFollowers":1000}The holder owns this X account.
{"kind":"X_USERNAME_EQUALS","username":"lkp"}The X account was created at least this many days ago.
{"kind":"X_ACCOUNT_AGE_AT_LEAST","minDays":365}The X account is verified.
{"kind":"X_VERIFIED"}The X account has published at least this many posts.
{"kind":"X_POSTS_AT_LEAST","minPosts":100}TikTok#
tiktokOwnership of a TikTok account via TikTok's own login: username, followers, likes, videos and verification.
The holder's TikTok account has at least this many followers.
{"kind":"TIKTOK_FOLLOWERS_AT_LEAST","minFollowers":1000}The holder owns this TikTok account.
{"kind":"TIKTOK_USERNAME_EQUALS","username":"lkp"}The TikTok account's videos have at least this many likes in total.
{"kind":"TIKTOK_LIKES_AT_LEAST","minLikes":10000}The TikTok account is verified.
{"kind":"TIKTOK_VERIFIED"}The TikTok account has published at least this many videos.
{"kind":"TIKTOK_VIDEOS_AT_LEAST","minVideos":10}GitHub#
githubOwnership of a GitHub account via GitHub's own login: username, followers, account age, two-factor status, repositories, contributions and organisations.
The holder's GitHub account has at least this many followers.
{"kind":"GITHUB_FOLLOWERS_AT_LEAST","minFollowers":10}The holder owns this GitHub account.
{"kind":"GITHUB_USERNAME_EQUALS","username":"lkp"}The GitHub account was created at least this many days ago.
{"kind":"GITHUB_ACCOUNT_AGE_AT_LEAST","minDays":365}The GitHub account has two-factor authentication turned on.
{"kind":"GITHUB_TWO_FACTOR"}The GitHub account owns at least this many public repositories.
{"kind":"GITHUB_REPOS_AT_LEAST","minRepos":5}The GitHub account made at least this many contributions in the last year.
{"kind":"GITHUB_CONTRIBUTIONS_AT_LEAST","minContributions":100}The holder is a member of this GitHub organisation.
{"kind":"GITHUB_ORG_MEMBER","organisation":"github"}Bank account#
bankA bank account read through open banking: its balance, IBAN and account holder name.
The holder's account balance is at least this amount, in euros.
{"kind":"BALANCE_AT_LEAST","minBalanceCents":100000}The holder controls exactly this bank account.
{"kind":"BANK_ACCOUNT_EQUALS","iban":"NL91ABNA0417164300"}The name the bank has on the account. Case and accents are ignored.
{"kind":"BANK_HOLDER_EQUALS","holderName":"JAN DE VRIES"}Combining requirements#
- Send up to 40 requirements per session (the full catalog). Same-credential checks compile to one proof. The user must prove all of them, in one step, with one anonymous ID.
- Minimums of the same kind merge to the strictest: two minimum ages keep the higher one.
- Exact matches accept several values: nationality can be
{ "kind": "COUNTRY_EQUALS", "countryIsoNumeric": [250, 826] }(France or the UK). Repeating the same requirement with different values unions them. The result confirms that one of the values matched, not which one. - Users only share what you ask for. Requiring a minimum age never reveals the birth date or the nationality.
- Nationality is citizenship printed on the document, not current physical location. Address country is the address on the document when it has one.
- Exact-match requirements (a name, a phone number, an organisation) reveal nothing beyond the match. Users see the exact value you ask about before they share.
The console's integration builder lets you pick requirements visually and generates the request for you.
List them programmatically#
Public, no API key needed. Returns every module and requirement with its parameter limits, status and an example, so you can build your own settings UI or validate configuration in CI.
curl https://lkp-verifier.onrender.com/v1/verification-typesResponse
{
"object": "list",
"maxRequirements": 40,
"maxProofs": 27,
"data": [
{
"id": "government_id",
"title": "Government ID",
"provider": "Didit",
"status": "live",
"requirements": [
{
"kind": "AGE_OVER",
"status": "live",
"combine": "strictest",
"param": { "name": "minAge", "label": "Minimum age", "input": "integer", "default": 18, "min": 1, "max": 150, "unit": "years" },
"example": { "kind": "AGE_OVER", "minAge": 18 }
},
{
"kind": "COUNTRY_EQUALS",
"status": "live",
"combine": "any_of",
"maxValues": 16,
"param": { "name": "countryIsoNumeric", "label": "Country", "input": "country", "default": 528, "min": 1, "max": 999 },
"example": { "kind": "COUNTRY_EQUALS", "countryIsoNumeric": [250, 826] }
},
โฆ
]
},
โฆ
]
}Need something else?#
We add new verification types regularly. If you need a check that isn't listed, such as a different document attribute, another social platform or a professional licence, tell us what you need and how you'd use it.