Validating PAN Card Numbers in Flutter: Step-by-Step Guide in 2026

TL;DR:
PAN validation in Flutter involves two steps:
(1) regex validation to check the format (5 letters + 4 digits + 1 letter), and (2) API verification with Setu to confirm the PAN exists in NSDL records. This guide covers both with complete code examples.
In this blog post, we will cover complete PAN card validation in Flutter, from basic PAN regex format checking to real-time verification using the Setu PAN API. Whether you need to validate PAN number format on the client side or verify it against NSDL records, this guide has you covered.
Why PAN Card Verification is Important
PAN card verification in Flutter apps is crucial for fintech applications, especially in banking, insurance, and financial services. Building a KYC verification Flutter app requires reliable PAN validation. Here's why:
- KYC Requirements: As part of the mandatory KYC process, verifying PAN cards ensures that users are authenticated and that financial transactions are legitimate.
- Legal Compliance: The Indian government mandates PAN card verification for transactions exceeding a certain threshold to avoid tax evasion and ensure regulatory compliance.
- Loan Approvals and Investment: In fintech, during the loan application process or when users are making a significant financial investment, PAN card verification is essential to validate the user's identity.
- Form Input Validation: Before making any API call, validating the PAN card format on the client side using PAN regex in Dart saves API costs and provides instant user feedback.
Understanding the PAN Card Format
Before writing any code, you need to understand what makes a PAN number valid. Every PAN follows a specific 10-character structure:
**Format: AAAAA9999A**
| Position | Characters | Meaning |
|----------|------------|---------|
| 1-3 | AAA | Random alphabets (A-Z) |
| 4 | A | Category of PAN holder |
| 5 | A | First letter of surname/name |
| 6-9 | 9999 | Sequential number (0001-9999) |
| 10 | A | Alphabetic check digit |
### PAN Category Codes (4th Character)
| Code | Category |
|------|----------|
| P | Individual / Person |
| C | Company |
| H | Hindu Undivided Family (HUF) |
| A | Association of Persons (AOP) |
| B | Body of Individuals (BOI) |
| G | Government |
| J | Artificial Juridical Person |
| L | Local Authority |
| F | Firm / Partnership |
| T | Trust |
**Example:** In PAN "ABCPK1234A":
- ABC = Random letters
- P = Individual (Person)
- K = First letter of surname (e.g., Kumar)
- 1234 = Sequential number
- A = Check digit
Understanding this structure helps you build accurate validation logic.Step-by-Step: PAN Validation Using Regex in Flutter
Before calling any API, you should validate the PAN format on the client side. This saves API calls and provides instant feedback to users.
### The Regex Pattern
The regex pattern for PAN validation is:
```dart
final panRegex = RegExp(r'^[A-Z]{5}[0-9]{4}[A-Z]{1}$');
```
**Breaking it down:**
- `^` — Start of string
- `[A-Z]{5}` — Exactly 5 uppercase letters
- `[0-9]{4}` — Exactly 4 digits
- `[A-Z]{1}` — Exactly 1 uppercase letter
- `$` — End of string
### Creating a PAN Validator Extension
For cleaner code, create a String extension:
```dart
extension PanCardValidator on String {
bool isValidPanCard() {
if (this.isEmpty) return false;
// Convert to uppercase for case-insensitive matching
final pan = this.toUpperCase().trim();
// Check length first
if (pan.length != 10) return false;
// Apply regex pattern
final panRegex = RegExp(r'^[A-Z]{5}[0-9]{4}[A-Z]{1}$');
return panRegex.hasMatch(pan);
}
// Get PAN holder category
String? getPanCategory() {
if (!this.isValidPanCard()) return null;
final categories = {
'P': 'Individual',
'C': 'Company',
'H': 'Hindu Undivided Family',
'A': 'Association of Persons',
'B': 'Body of Individuals',
'G': 'Government',
'J': 'Artificial Juridical Person',
'L': 'Local Authority',
'F': 'Firm',
'T': 'Trust',
};
final categoryCode = this.toUpperCase()[3];
return categories[categoryCode];
}
}
```
### Using in TextFormField
```dart
TextFormField(
decoration: InputDecoration(
labelText: 'Enter PAN Number',
hintText: 'e.g., ABCPK1234A',
),
textCapitalization: TextCapitalization.characters,
maxLength: 10,
validator: (value) {
if (value == null || value.isEmpty) {
return 'PAN number is required';
}
if (!value.isValidPanCard()) {
return 'Enter a valid PAN number';
}
return null;
},
onChanged: (value) {
// Real-time validation feedback
if (value.length == 10) {
final category = value.getPanCategory();
print('PAN Category: $category');
}
},
)
```
### Why Regex Validation Alone Isn't Enough
Regex only validates the format. It cannot tell you if:
- The PAN actually exists in NSDL records
- The PAN is active or deactivated
- The name matches the PAN holder
- The PAN is linked to Aadhaar
For these checks, you need API verification with Setu PAN API (covered in the next section).Comparing Validation Approaches
## Regex vs API: When to Use What
| Aspect | Regex Validation | Setu API Verification |
|--------|------------------|----------------------|
| **Speed** | Instant (client-side) | 200-500ms (API call) |
| **Cost** | Free | Per-request pricing |
| **Accuracy** | Format only | Full verification |
| **Use Case** | Form validation | KYC compliance |
| **Offline** | Works offline | Requires internet |
### Recommended Approach
For fintech applications, use both:
1. **First: Regex validation** — Catch format errors instantly
2. **Then: API verification** — Confirm PAN exists in NSDL
```dart
Future<PanVerificationResult> verifyPan(String panNumber) async {
// Step 1: Regex validation
if (!panNumber.isValidPanCard()) {
return PanVerificationResult(
success: false,
error: 'Invalid PAN format',
);
}
// Step 2: API verification
try {
final apiResult = await ApiService.verifyPan(panNumber);
return PanVerificationResult(
success: true,
data: apiResult,
);
} catch (e) {
return PanVerificationResult(
success: false,
error: 'API verification failed: $e',
);
}
}
```
This approach:
- Reduces unnecessary API calls (saves cost)
- Provides instant feedback on format errors
- Only hits the API when the format is validWhat is Setu PAN API?(Flutter Integration)
Setu PAN API allows you to use just one API to verify your customer's PAN details in your Flutter application. For developers building fintech apps, this Setu PAN API Flutter integration provides direct connection with NSDL for the best uptimes.We directly connect with NSDL to maintain the best uptimes.
Here’s a quick overview of the PAN API. Additionally, here are the URLs you would need for this API
Headers Contact Setu for providing the credentials required to successfully call Setu APIs. This contains:
- x-client-id
- x-client - secret
- x-product-instance-id
Verify PAN Card NumberVerify PAN Card Number in Flutter
Call this API to verify a PAN provided by your customer. A quick explanation of the request params—
- pan is the PAN value. It may belong to different categories like Person, Company, Trust, Government, Firm, etc.
- Consent indicates whether you have collected consent from your customer. To get a successful verification, it must contain Y or y.
- The reason is the explanation of why you are requesting a PAN from your customer. It should be explained in 20 characters or more.
Note: While the implementation of consent and reason cannot be enforced by Setu, we recommend collecting explicit consent from your customers and also explaining to your customers the reason why you are verifying their PAN.
While testing on Sandbox, you may use the following sample values
- Use ABCDE1234A for a valid PAN
- Use ABCDE1234B for an invalid PAN, i.e, a PAN number has been found but is invalid. A PAN is considered invalid by NSDL for different reasons.
For example, if it is a blacklisted one, or maybe because it is not linked to an Aadhaar card. - If you use any other values for PAN, you will get a 404 PAN not found error.
Request Body
{
"data": {
"aadhaar_seeding_status": "LINKED", // optional
"category": "Individual",
"full_name": "John Doe"
},
"message": "PAN is valid",
"verification": "success",
"traceId": "1-6346a91a-620cf6cc4f68d2e30316881e"
}
Prerequisites
Make sure you have:
- A basic understanding of Flutter and Dart before you start.
- Flutter is installed on your system.
- A Setu account is required in order to use the PAN verification API. Here is where you may register. link
Step 1: Configure Your Flutter Project for PAN Validation
If you don't already have a Flutter project, start by creating one:
flutter create pan_verification_app
cd pan_verification_app
Step 2: Add Dependencies
In your pubspec.YAML file, add the http, and get packages to handle HTTP requests and state management:
dependencies:
flutter:
sdk: flutter
http: ^0.14.0
get: ^4.6.5
Step 3: Create the API Service Class
To manage the API requests, create a new file called lib/services/api_service.dart:
import 'package:http/http.dart' as http;
import 'dart:convert';
class ApiService {
static const String apiUrl = 'https://dg-sandbox.setu.co/api/verify/pan';
static const String clientId = 'YOUR_CLIENT_ID';
static const String clientSecret = 'YOUR_CLIENT_SECRET';
static const String productInstanceId = 'YOUR_PRODUCT_INSTANCE_ID';
static const String bearerToken = 'YOUR_BEARER_TOKEN';
static Future<Map<String, dynamic>> verifyPan(String panNumber) async {
final response = await http.post(
Uri.parse(apiUrl),
headers: {
'x-client-id': clientId,
'x-client-secret': clientSecret,
'x-product-instance-id': productInstanceId,
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $bearerToken',
},
body: json.encode({
'pan': panNumber,
'consent': 'Y',
'reason': 'Reason for verifying PAN set by the developer',
}),
);
if (response.statusCode == 200) {
return json.decode(response.body);
} else {
throw Exception('Failed to verify PAN: ${response.body}');
}
}
}
Step 4: Create the Controller
Create a new file lib/controllers/pan_controller.dart to handle the PAN validation business logic using GetX state management. This controller manages the PAN number verification flow.
import 'package:get/get.dart';
import '../services/api_service.dart';
class PanController extends GetxController {
var panNumber = ''.obs;
var result = ''.obs;
var isLoading = false.obs;
void verifyPan() async {
if (panNumber.value.isEmpty) {
result.value = 'Please enter a PAN number.';
return;
}
isLoading.value = true;
try {
final data = await ApiService.verifyPan(panNumber.value);
result.value = 'PAN Verification Successful: ${data['status']}';
} catch (e) {
result.value = 'PAN Verification Failed: $e';
} finally {
isLoading.value = false;
}
}
}
Step 5: Create the UI
In lib/main.dart, create the PAN card validation UI with GetX for state management. This screen allows users to enter their PAN number and see the verification result.
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'controllers/pan_controller.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetMaterialApp(
home: PanVerificationScreen(),
);
}
}
class PanVerificationScreen extends StatelessWidget {
final PanController _panController = Get.put(PanController());
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('PAN Verification'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
onChanged: (value) => _panController.panNumber.value = value,
decoration: InputDecoration(
labelText: 'Enter PAN Number',
),
),
SizedBox(height: 20),
Obx(() => _panController.isLoading.value
? CircularProgressIndicator()
: ElevatedButton(
onPressed: _panController.verifyPan,
child: Text('Verify PAN'),
)),
SizedBox(height: 20),
Obx(() => Text(_panController.result.value)),
],
),
),
);
}
}
Step 6: Run the App
Use an emulator or connect your smartphone to launch the app, and run the command below:
flutter run.
Enter a valid PAN number in the text field and click the button to see the verification result.
Also Read: Digi-Locker Integration with Flutter: A Comprehensive Guide 2026
Conclusion
In this article, we covered complete PAN card validation in Flutter using the Setu PAN API. We demonstrated Flutter PAN verification with GetX for state management and splitting the API call into a distinct service class. This approach to validate PAN number in Flutter apps is production-ready for any KYC verification use case.
By including error management, input validation, and an improved user interface, you may further improve this application. See the official Setu API documentation for further information. Official documentation
Note: In the blog, we are managing the state with GetX. Any alternative state management system that meets the requirements of your project is acceptable.
FAQs
What is the importance of PAN card verification in fintech applications?
PAN card verification is important in fintech apps for verifying users' identities during processes such as KYC, loan applications, and large financial transactions. It ensures legal compliance and helps prevent tax evasion.
What is the Setu PAN API, and how does it work?
The Setu PAN API allows developers to verify PAN details by connecting with NSDL, the official PAN database. It ensures real-time verification, providing the user's name and the status of their PAN card.
What are the prerequisites for using the Setu PAN verification API?
You need basic Flutter and Dart knowledge, a Setu API account for API credentials (client ID, client secret, product instant ID), and the Flutter SDK installed on your machine to begin integration.
What is the regex pattern for PAN card validation?
The regex pattern for validating Indian PAN card numbers is `^[A-Z]{5}[0-9]{4}[A-Z]{1}$`. This pattern checks for 5 uppercase letters, followed by 4 digits, and ending with 1 uppercase letter. In Flutter/Dart, use `RegExp(r'^[A-Z]{5}[0-9]{4}[A-Z]{1}$')` for validation.
Can I validate a PAN card offline in Flutter?
Yes, you can validate the PAN card format offline using regex. However, offline validation only checks the format structure. To verify if the PAN actually exists in government records or to get the holder's name, you need an online API like Setu PAN verification API that connects to NSDL
What does the 4th character in PAN number mean?
The 4th character in a PAN number indicates the category of the PAN holder. "P" stands for Individual/Person, "C" for Company, "H" for Hindu Undivided Family (HUF), "F" for Firm, "T" for Trust, and "G" for Government. This helps identify whether the PAN belongs to a person or an organization.
How do I validate PAN and Aadhaar together in Flutter?
For KYC compliance, you often need to validate both PAN and Aadhaar. Use regex for format validation of both, then verify through APIs. Setu provides both PAN verification API and Aadhaar OKYC API. You can also check if the PAN is linked to Aadhaar using the aadhaar_seeding_status field in Setu's PAN API response.
What are the test PAN numbers for Setu sandbox?
Setu provides test PAN numbers for sandbox testing: Use "ABCDE1234A" for a valid PAN that returns success. Use "ABCDE1234B" for an invalid PAN (blacklisted or not linked to Aadhaar). Any other PAN format will return a 404 "PAN not found" error in sandbox mode.