Building e-KYC for Indonesian Fintech: NIK/Dukcapil Verification Done Right

Photo by User:Mattes via Wikimedia Commons (CC BY-SA 3.0)
No. Dukcapil does not expose a public API to private companies. You either sign a direct data-cooperation agreement (typical only for large banks and KSEI) or integrate through an authorized e-KYC provider that already holds the Dukcapil connection. Either way you get a match result, never raw citizen data.
No. It is a verify-not-share model. You submit data the user already gave you (NIK, name, birth date, selfie) and Dukcapil answers whether it matches. It returns booleans and a face-match score, not fields you did not already have. Anyone selling a NIK-to-profile lookup is breaking the law.
Biometric data such as a face template is classified as specific personal data under UU No. 27 Tahun 2022 and needs stricter protection and explicit, separate consent. NIK is personal data as well. You must limit its use to the consented purpose, minimize storage, and honor deletion requests.
Pricing is usually per successful verification. As a public reference, one provider lists around USD 0.30 per verification with a free monthly tier, while incumbents charge several times more. Confirm current rates and volume tiers with the provider directly, since they change often.
UU PDP allows administrative fines up to 2% of a company's annual revenue. Criminal provisions reach up to 6 years imprisonment and fines up to Rp6 billion for serious misuse such as illegally selling personal data. Storing raw biometrics or plaintext NIK in logs is a common way to turn a breach into a penalty.

Photo by User:Mattes via Wikimedia Commons (CC BY-SA 3.0)
Key Takeaway
You cannot query Dukcapil directly. Indonesian fintechs verify a NIK through an authorized provider that holds a data-cooperation agreement with Dukcapil. The provider returns only a match or no-match result plus a face-match score, never raw citizen records. Because NIK and biometrics are sensitive data under UU PDP, explicit consent and strict storage rules are mandatory.
On a recent project I built the onboarding flow for an Indonesian lending app, and the single most misunderstood requirement was identity verification. Founders assume there is a public Dukcapil endpoint you POST a NIK to. There is not. Dukcapil (Direktorat Jenderal Kependudukan dan Pencatatan Sipil) runs the national civil registry behind the e-KTP, and it does not hand raw data to private companies. Instead it signs data-cooperation agreements and lets a small set of authorized providers run match-only checks against the population database.
This article is about the architecture and compliance of that flow, not about scraping. If someone offers you a way to bulk-look-up NIK data, walk away: it is illegal, it breaches UU PDP, and it will get your license revoked. The legitimate path is boring, auditable, and exactly what OJK wants to see.
Dukcapil operates a verify-not-share model. An authorized institution sends the data it already collected from the user, and Dukcapil answers whether that combination exists and matches. It never returns fields the caller did not already have. The access tiers you will encounter in practice are:
Dukcapil has repeatedly clarified that the shared e-KYC platform does not give NIK data to anyone. It only confirms verification results. Any provider claiming to sell you a NIK-to-full-profile lookup is either lying or breaking the law. Choose providers that publish their data-cooperation status.
A production e-KYC onboarding for an Indonesian app usually chains five steps. Providers such as Verihubs, Privy, and others expose each as an API call, and a full run typically completes in under 30 seconds.
// POST /v1/identity/verify (via authorized e-KYC provider)
// Request — you only ever send data the user gave you
{
"nik": "3174xxxxxxxxxxxx",
"name": "BUDI SANTOSO",
"birth_date": "1994-03-12",
"selfie_image": "<base64 jpeg>",
"consent_id": "cns_01HXQ..." // proof of user consent, see UU PDP section
}
// Response — match-only, no raw Dukcapil record is returned
{
"nik_valid": true,
"name_match": true,
"birth_date_match": true,
"face_match_score": 0.972, // 0..1 similarity
"liveness_passed": true,
"decision": "approved",
"reference_id": "vrf_01HXQ...", // store THIS, not the biometrics
"verified_at": "2026-07-11T04:12:55Z"
}The face-match score is a probability, not a yes/no. Set two thresholds: an auto-approve floor and a manual-review band below it. A single hard cutoff either lets fraud through or rejects legitimate users whose selfie lighting differs from a years-old KTP photo. Liveness is a separate, non-negotiable gate — a high face-match on a spoofed photo is worthless, so liveness must pass before the match score is even considered.
Start conservative: auto-approve only above a high similarity score, send the middle band to manual review, and hard-decline the rest. Log every decision with its scores so you can move the thresholds later using real data instead of guesses. OJK examiners love that audit trail.
UU No. 27 Tahun 2022 (UU PDP) has been fully enforceable since October 2024. It classifies biometric data as specific personal data (data pribadi spesifik) that demands stricter protection and, critically, explicit and separate consent — not a checkbox buried in your general terms. NIK is personal data too. The practical obligations that shape your architecture are:
// Persist the CONSENT before the verify call, keep it immutable
CREATE TABLE kyc_consent (
id TEXT PRIMARY KEY, -- consent_id sent to provider
user_id TEXT NOT NULL,
purpose TEXT NOT NULL, -- 'identity_verification'
scope TEXT[] NOT NULL, -- ['nik','biometric_face']
policy_version TEXT NOT NULL,
granted_at TIMESTAMPTZ NOT NULL,
ip_address INET,
revoked_at TIMESTAMPTZ
);
// After verification: store the RESULT, discard the biometrics
CREATE TABLE kyc_result (
id TEXT PRIMARY KEY, -- your reference_id
user_id TEXT NOT NULL,
nik_hash TEXT NOT NULL, -- HMAC-SHA256(nik, pepper), never plaintext
decision TEXT NOT NULL, -- approved | review | declined
face_score NUMERIC(4,3),
liveness BOOLEAN,
provider_ref TEXT,
verified_at TIMESTAMPTZ NOT NULL
);
// selfie bytes: process in memory, do NOT write to disk / object storageTwo engineering rules fall out of this. First, hash the NIK with a keyed HMAC and a server-side pepper so you can still de-duplicate users without holding the raw number. Second, treat the raw selfie as radioactive: stream it to the provider, keep it in memory, and never let it touch your logs, object storage, or an APM trace. Store only the score and the decision.
The penalties are real. UU PDP allows administrative fines up to 2% of a company's annual revenue, and criminal provisions reach up to 6 years imprisonment and fines up to Rp6 billion for serious misuse such as illegally selling personal data. Storing raw biometrics or NIK in plaintext logs is exactly the kind of exposure that turns a breach into a fine.
You are really choosing a compliance partner, not just an API. The right questions are about legal standing and data handling, not just uptime. Compare candidates on these axes:
| What to check | Why it matters |
|---|---|
| Dukcapil data-cooperation status | Confirms the provider is authorized, not scraping. |
| OJK / Bank Indonesia registration | Required for regulated financial products. |
| Liveness + face-match bundled | Avoids stitching two vendors and two data flows. |
| Per-verification pricing model | Predictable unit cost as you scale onboarding. |
| Data residency and retention terms | Determines your UU PDP exposure downstream. |
| Audit-log export | Needed to satisfy OJK examinations. |
Pricing is usually per successful verification. As a reference point, one provider (Didit) publicly lists around USD 0.30 per verification with a free monthly tier; incumbents cost several times more. Treat any public number as a starting point and confirm current rates and volume tiers directly, because Indonesian fintech pricing and regulation both change fast.