KTP OCR
Extract NIK, name, and address from a KTP photo.
Base URL
https://use.api.co.id
Send a KTP photo to POST /ocr/ktp-extract as multipart/form-data (field file) with the x-api-co-id header. The response contains NIK, name, place/date of birth, address, RT/RW, kelurahan, kecamatan, city, province, religion, marital status, occupation, citizenship, and validity. OCR fields are always returned in full.
File format & limits
| Requirement | Value |
|---|---|
| Formats | JPG, JPEG, PNG |
| Maximum size | 5 MB per file (file and selfie) |
| Content | Indonesian KTP photo |
OCR only
curl -X POST "https://use.api.co.id/ocr/ktp-extract" \
-H "x-api-co-id: YOUR_API_KEY" \
-F "file=@/absolute/path/to/ktp.jpg"
{
"is_success": true,
"message": "Success",
"data": {
"nik": "3201012345678901",
"nama": "JOHN DOE",
"tempat_lahir": "JAKARTA",
"tanggal_lahir": "01-01-1990",
"jenis_kelamin": "LAKI-LAKI",
"alamat": "JL. MERDEKA NO. 123",
"rt": "001",
"rw": "002",
"kelurahan": "GAMBIR",
"kecamatan": "GAMBIR",
"kota": "JAKARTA PUSAT",
"provinsi": "DKI JAKARTA",
"berlaku_hingga": "SEUMUR HIDUP"
}
}
OCR + KTP Check
Set verify_result to "true" to verify the OCR result through KTP Check (ID Verification). Because the request uses multipart/form-data, send this value as the form-data string "true". The selfie field is optional.
curl -X POST "https://use.api.co.id/ocr/ktp-extract" \
-H "x-api-co-id: YOUR_API_KEY" \
-F "file=@/absolute/path/to/ktp.jpg" \
-F "verify_result=true" \
-F "selfie=@/absolute/path/to/selfie.jpg"
API.CO.ID uses the OCR result as the KTP Check input:
nik,name, anddate_of_birthcome from the OCR result;identityuses the same KTP file;selfieuses the customer's selfie file if sent;reference_number, the account email, and the approved KYC phone are prepared server-side.
If selfie is sent, API.CO.ID forwards it to the provider and the verification response is used as is. If it is not sent, API.CO.ID uses an internal fallback selfie to stay compatible with older requests.
The customer needs id-verification access and approved eKYC. If the KTP Check requirements are not met, OCR still returns the full OCR fields and the verification billing entry is marked not_charged. Verification details are nested under verification_result, billing details under billing.
{
"is_success": true,
"message": "Success",
"data": {
"nik": "3201012345678901",
"nama": "JOHN DOE",
"tempat_lahir": "JAKARTA",
"tanggal_lahir": "01-01-1990",
"jenis_kelamin": "LAKI-LAKI",
"alamat": "JL. MERDEKA NO. 123",
"rt": "001",
"rw": "002",
"kelurahan": "GAMBIR",
"kecamatan": "GAMBIR",
"kota": "JAKARTA PUSAT",
"provinsi": "DKI JAKARTA",
"berlaku_hingga": "SEUMUR HIDUP",
"verification_result": {
"result_verified": true,
"result_verified_message": "verified",
"verification_reference_number": "KTP20260725103000"
},
"billing": {
"charged_products": [
{"product_code": "ktp-ocr", "status": "charged"},
{"product_code": "id-verification", "status": "charged"}
]
}
}
}
If verification is not processed (for example, KYC not yet approved), the OCR fields stay complete and the verification part becomes:
{
"verification_result": {
"result_verified": false,
"result_verified_message": "ID verification was not processed because KYC for id-verification is kyc_required.",
"verification_reference_number": "KTP20260725103000"
},
"billing": {
"charged_products": [
{"product_code": "ktp-ocr", "status": "charged"},
{"product_code": "id-verification", "status": "not_charged", "reason": "kyc_not_approved"}
]
}
}
Billing
- KTP OCR and KTP Check are two separate billing products.
- KTP OCR is charged after OCR succeeds.
id-verificationis charged only if the provider processes the KTP Check.- If KTP Check fails because of KYC, balance, OCR result validation, or a provider error,
id-verificationis not charged.
Common errors
| HTTP | Condition |
|---|---|
| 400Bad Request | File missing, unsupported file type, file too large, invalid selfie, or verify_result is not a boolean |
| 401Unauthorized | API key missing or wrong |
| 402Payment Required | Insufficient KTP OCR balance |
| 429Too Many Requests | Rate limit/quota exceeded |
| 500Server Error | OCR pipeline/internal provider failure |
Extract KTP from Image
Extract structured KTP data from an uploaded image file. Maximum file size: 5 MB. Supported formats: JPG, JPEG, PNG. Returns complete KTP data with all extracted fields. Optionally set verify_result=true to verify the OCR result. When selfie is provided, API.CO.ID forwards the customer selfie to the ID Verification provider and does not override the provider business result. When selfie is omitted, API.CO.ID uses an internal fallback selfie for backward compatibility. API.CO.ID injects the provider reference number, account email, and approved KYC phone number server-side.
| Name | Type | Description |
|---|---|---|
fileRequired | file | KTP image file. Maximum size: 5 MB. Supported formats: JPG, JPEG, PNG |
verify_resultOptional | string | Set to "true" to verify extracted KTP data through ID Verification. Send as multipart form-data string. Values: truefalseExample: true |
selfieOptional | file | Optional selfie image for KTP Check when verify_result=true. Maximum size: 5 MB. Supported formats: JPG, JPEG, PNG |
| Name | Type | Description |
|---|---|---|
is_successOptional | boolean | Example: true |
messageOptional | string | Example: Success |
dataOptional | object | |
data.nikOptional | string | NIK (16-digit ID number) Example: 3201012345678901 |
data.namaOptional | string | Full name Example: JOHN DOE |
data.tempat_lahirOptional | string | Birth place Example: JAKARTA |
data.tanggal_lahirOptional | string | Birth date (DD-MM-YYYY) Example: 01-01-1990 |
data.jenis_kelaminOptional | string | Gender (LAKI-LAKI/PEREMPUAN) Example: LAKI-LAKI |
data.golongan_darahOptional | string | Blood type Example: O |
data.alamatOptional | string | Address Example: JL. MERDEKA NO. 123 |
data.rtOptional | string | RT (neighborhood unit) Example: 001 |
data.rwOptional | string | RW (community unit) Example: 002 |
data.kelurahanOptional | string | Village/Kelurahan Example: GAMBIR |
data.kecamatanOptional | string | Subdistrict/Kecamatan Example: GAMBIR |
data.kotaOptional | string | City Example: JAKARTA PUSAT |
data.provinsiOptional | string | Province Example: DKI JAKARTA |
data.agamaOptional | string | Religion Example: ISLAM |
data.status_perkawinanOptional | string | Marital status Example: BELUM KAWIN |
data.pekerjaanOptional | string | Occupation Example: KARYAWAN SWASTA |
data.kewarganegaraanOptional | string | Nationality Example: WNI |
data.berlaku_hinggaOptional | string | Valid until Example: SEUMUR HIDUP |
data.verification_resultOptional | object | Only present when verify_result=true. Contains verification result, message, and generated reference number. |
data.verification_result.result_verifiedOptional | boolean | Example: true |
data.verification_result.result_verified_messageOptional | string | Example: verified |
data.verification_result.verification_reference_numberOptional | string | Example: KTP20260725103000 |
curl -X POST "https://use.api.co.id/ocr/ktp-extract" \ -H "x-api-co-id: $API_CO_ID_KEY" \ -F "[email protected]" \ -F "verify_result=true" \ -F "[email protected]"{ "is_success": true, "message": "Success", "data": { "nik": "3201012345678901", "nama": "JOHN DOE", "tempat_lahir": "JAKARTA", "tanggal_lahir": "01-01-1990", "jenis_kelamin": "LAKI-LAKI", "golongan_darah": "O", "alamat": "JL. MERDEKA NO. 123", "rt": "001", "rw": "002", "kelurahan": "GAMBIR", "kecamatan": "GAMBIR", "kota": "JAKARTA PUSAT", "provinsi": "DKI JAKARTA", "agama": "ISLAM", "status_perkawinan": "BELUM KAWIN", "pekerjaan": "KARYAWAN SWASTA", "kewarganegaraan": "WNI", "berlaku_hingga": "SEUMUR HIDUP" }}