Verify any data point before it enters your system.
Aptlab validates identity documents, financial instruments, contact details and web data through a single REST call — running real checksums and structural rules, not loose regex. You get a pass/fail, a confidence score, and every sub-check that led to it.
One call in. A full audit trail out.
Send a value and an optional type. Aptlab returns the verdict plus every individual check it ran, so you can log exactly why something was rejected — and defend that decision later.
Send the value
One POST /v1/verify with a value. Pass type to skip
detection, or leave it out and let Aptlab infer it.
Structural and checksum rules run
Format, length, reserved characters, then the real check digit — Verhoeff for Aadhaar, base-36 for GSTIN, MOD 97-10 for IBAN, Luhn for cards.
Optional network checks
Opt into MX resolution for email or DNS for domains. Network checks are bounded and never turn a timeout into a rejection.
Act on the verdict
Branch on valid, gate on confidence, and store
checks as your audit record.
curl -X POST https://api.aptlab.dev/v1/verify/gstin \
-H "Authorization: Bearer $APTLAB_KEY" \
-H "Content-Type: application/json" \
-d '{"value": "29AAECS1234K1Z9"}'
const res = await fetch("https://api.aptlab.dev/v1/verify", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.APTLAB_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({ value: "priya@okhdfcbank" })
});
const { result } = await res.json();
if (!result.valid) {
// result.reasons tells you exactly what failed
throw new Error(result.reasons.join(", "));
}
import os, requests
r = requests.post(
"https://api.aptlab.dev/v1/batch",
headers={"Authorization": f"Bearer {os.environ['APTLAB_KEY']}"},
json={"items": [
{"type": "pan", "value": "ABCPD1234E"},
{"type": "ifsc", "value": "HDFC0000123"},
{"value": "[email protected]"}, # auto-detected
]},
timeout=10,
)
for item in r.json()["results"]:
print(item["result"]["type"], item["result"]["valid"])
29 data types, grouped the way you think about them.
Click any type to open it in the playground with a working example already filled in.
Built for the code path that says no.
Rejecting a customer is the highest-stakes branch in an onboarding flow. It should be explainable, fast, and boring.
Real checksums, not regex theatre
A regex accepts 999999999999 as an Aadhaar. Verhoeff does not.
Aptlab runs the actual algorithm behind every identifier that has one.
Every sub-check is returned
You get checks as a named map — which rule passed, which failed, and
which needed a network call. Store it and your audit trail writes itself.
Sensitive values never persist
Aadhaar numbers, card numbers and passwords are redacted from responses and never written to logs. Verification is stateless by design.
Type detection built in
Don't know what a field holds? Omit type. Aptlab ranks the candidates
and verifies against the best match, returning the alternatives it considered.
Batch heterogeneous records
Send up to 1,000 mixed items in one request — a whole customer record, each field typed independently, one round trip.
Honest about its limits
Structural validity is not existence. Aptlab says so — a valid PAN structure is
marked registryLookup: null, never dressed up as a registry hit.
Metered per verification. No seat fees.
Batch items count individually. Unused quota does not roll over.
For evaluation and local development.
- 1,000 verifications / month
- 30 requests / minute
- 25 items per batch
- All 29 types
- Community support
For products with live onboarding traffic.
- 100,000 verifications / month
- 300 requests / minute
- 250 items per batch
- MX and DNS network checks
- Scoped keys per environment
- Email support, 1 business day
For KYC platforms and high-volume pipelines.
- 5M+ verifications / month
- 2,000 requests / minute
- 1,000 items per batch
- Regional data residency
- Signed audit exports
- Shared incident channel
Questions worth asking first
Does a valid result mean the document actually exists?
No, and this distinction matters. Aptlab tells you an identifier is well-formed — correct structure, correct check digit, plausible embedded fields. That is enough to reject typos and fabricated values at the edge of your system, which is most of what a form needs. Proving that a specific person holds that identifier requires a consent-bound lookup against the issuing authority.
What does the confidence score represent?
How strongly the passing checks constrain the value. A validated IBAN scores 0.95 because MOD 97-10 makes accidental passes very unlikely. A bank account number scores 0.5 because Indian account numbers carry no checksum at all — only length and plausibility could be checked. Use it to decide when to escalate to a heavier check.
How do you handle sensitive inputs?
Aadhaar numbers, card numbers, account numbers and passwords are never echoed back in full and never written to request logs. Responses carry a masked form instead. For password strength, the API returns only the first five characters of the SHA-1 hash so you can run a k-anonymity breach lookup yourself without transmitting the password.
What happens when a DNS or MX lookup times out?
The check is reported as null — not evaluated — and the verdict falls
back to the structural result. A slow resolver never converts a valid address into a
rejection. Network checks are opt-in per request and individually bounded.
Can I restrict a key to specific types?
Yes. Keys can be scoped with an allowedTypes list, so a frontend key
can verify emails and phone numbers while only your backend key can touch Aadhaar or
card data. Requests outside the scope return 403 type_not_permitted.
Is the playground on this site hitting your API?
No — the playground runs the same rule set compiled to JavaScript, entirely in your
browser. Nothing you type there leaves the page. That is why checks needing a resolver
or registry show as server-side: they cannot run client-side.
Verify your first value in under a minute.
No signup for the playground. Paste a value, read every check, then copy the request straight into your codebase.