Guide to Valide PAN Card Number in Flutter Applicaiton

October 7, 2024

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

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:
  1. KYC Requirements: As part of the mandatory KYC process, verifying PAN cards ensures that users are authenticated and that financial transactions are legitimate.
  2. Legal Compliance: The Indian government mandates PAN card verification for transactions exceeding a certain threshold to avoid tax evasion and ensure regulatory compliance.
  3. 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.
  4. 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 valid

What 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.
Yashesh Shah

Written by

Lowcode | FlutterFlow | AR | VR | XR | Talks about Apple VisionPro | Experienced Sr. Software Engineer with a demonstrated history of working in the information technology and services industry

Found this blog useful? Don't forget to share it wih your network

Frequently Asked Questions

<p>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. </p>

<p>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. </p>

<p>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. </p>

<p>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. </p>

<p>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 </p>

<p>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. </p>

<p>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. </p>

<p>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. </p>

Featured Insights

Team up with us to enhance and

achieve your business objectives

LET'S WORK

TLogoGETHER