Skip to main content

Overview

StablePay provides a complete KYC solution that verifies user identity and bank account ownership. This guide explains the verification flow.
Prerequisite: Mobile and email verification must be completed before starting KYC. See Verification APIs for details.

Prerequisites

Before starting KYC, users must verify their contact information:
VerificationRequiredDescription
Mobile OTPYesVerify mobile number via SMS OTP
Email OTPIf email providedVerify email address via email OTP
All KYC endpoints will return 400 Verification Required if these are not complete.

KYC Requirements

Before users can receive INR payouts, they must complete both Basic KYC and Extended KYC:

Basic KYC

VerificationRequiredPurpose
Aadhaar (DigiLocker)YesGovernment ID, address proof
PANYesTax identity, name verification
Face LivenessYesAnti-fraud, identity confirmation
Bank AccountYesPayout destination verification
UPINo (Optional)Alternative payout verification

Extended KYC (New Guidelines)

StepRequiredPurpose
Profile (DOB, Address, Nationality)YesPersonal information collection
Document UploadYesIdentity document verification
Declaration (Occupation, Income, PEP)YesRegulatory compliance
Users who declare themselves as Politically Exposed Persons (PEP) will have their KYC automatically rejected.

Verification Flow

Use our KYC APIs to build a custom verification experience in your application.
  1. Profile (Nationality, Address, DOB)
  2. Aadhaar via DigiLocker
  3. PAN Verification
  4. Document Upload
  5. Declaration (Occupation, Income, PEP)
  6. Face Liveness
  7. Bank Account
  8. UPI (Optional)

Step 1: Submit Profile (Required)
curl -X POST https://api.stablepay.global/v2/users/{userId}/kyc/profile \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "dateOfBirth": "1990-05-15",
    "nationality": "Indian",
    "addressLine1": "123 Main Street, Apartment 4B",
    "city": "Mumbai",
    "state": "Maharashtra",
    "pincode": "400001",
    "country": "India",
    "deviceId": "device_abc123"
  }'
Step 2: Aadhaar via DigiLocker (Required)
curl -X POST https://api.stablepay.global/v2/users/{userId}/kyc/digilocker/init \
  -H "Authorization: Bearer YOUR_API_KEY"
{
  "success": true,
  "data": {
    "redirectUrl": "https://digilocker-sdk.surepass.io/...",
    "sessionId": "dgl_abc123",
    "expiresAt": "2025-01-05T10:30:00Z"
  }
}
Then poll the status endpoint until verification completes:
curl https://api.stablepay.global/v2/users/{userId}/kyc/digilocker/status \
  -H "Authorization: Bearer YOUR_API_KEY"
Step 3: PAN Verification (Required)
curl -X POST https://api.stablepay.global/v2/users/{userId}/kyc/pan/verify \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"panNumber": "ABCDE1234F", "deviceId": "device_abc123"}'
Step 4: Document Upload (Required) First, get a presigned upload URL:
curl -X POST https://api.stablepay.global/v2/users/{userId}/kyc/document/upload-url \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "documentType": "passport",
    "fileName": "passport.pdf",
    "mimeType": "application/pdf",
    "fileSize": 2048576,
    "deviceId": "device_abc123"
  }'
Upload the file to the returned URL, then confirm:
curl -X POST https://api.stablepay.global/v2/users/{userId}/kyc/document \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "documentType": "passport",
    "s3Key": "kyc/user_123/passport/abc.pdf",
    "fileName": "passport.pdf",
    "fileSize": 2048576,
    "mimeType": "application/pdf",
    "deviceId": "device_abc123"
  }'
Supported document types: passport, driving_license, aadhaar, voter_id Step 5: Declaration (Required)
curl -X POST https://api.stablepay.global/v2/users/{userId}/kyc/declaration \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "occupation": "salaried",
    "incomeRange": "10l_to_25l",
    "isPep": false,
    "declarationAccepted": true,
    "deviceId": "device_abc123"
  }'
If isPep is true, the KYC will be automatically rejected.
Step 6: Face Liveness (Required)
curl -X POST https://api.stablepay.global/v2/users/{userId}/kyc/face/init \
  -H "Authorization: Bearer YOUR_API_KEY"
{
  "success": true,
  "data": {
    "sessionId": "face_session_123",
    "url": "https://kyc-sdk.surepass.io/face-liveness?token=...",
    "expiresIn": 600
  }
}
After completing face capture, verify the result:
curl -X POST https://api.stablepay.global/v2/users/{userId}/kyc/face/verify \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sessionId": "face_session_123"}'
Step 7: Bank Verification (Required)
curl -X POST https://api.stablepay.global/v2/users/{userId}/kyc/bank/verify \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accountNumber": "1234567890",
    "ifsc": "HDFC0001234",
    "accountHolderName": "Rahul Kumar"
  }'
We perform a penny drop (₹1 transfer) to verify account ownership. Step 8: UPI Verification (Optional)
curl -X POST https://api.stablepay.global/v2/users/{userId}/kyc/upi/verify \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"upiId": "rahul.kumar@upi"}'

KYC Status

Check complete KYC status (Basic + Extended) at any time:
curl https://api.stablepay.global/v2/users/{userId} \
  -H "Authorization: Bearer YOUR_API_KEY"
{
  "success": true,
  "data": {
    "user": {
      "id": "usr_abc123",
      "name": "Rahul Kumar",
      "mobile": "+919876543210",
      "email": "rahul@example.com",
      "status": "active",
      "depositAddresses": {
        "evm": "0x742d35Cc6634C0532925a3b844Bc9e7595f3A123",
        "solana": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU"
      },
      "mobileVerified": true,
      "emailVerified": true,
      "createdAt": "2025-01-05T09:00:00Z"
    },
    "kyc": {
      "level": "basic",
      "status": "verified",
      "digilocker": {
        "verified": true,
        "verifiedAt": "2025-01-05T10:02:00Z"
      },
      "aadhaar": {
        "verified": true,
        "verifiedAt": "2025-01-05T10:02:00Z",
        "maskedNumber": "XXXX XXXX 1234"
      },
      "pan": {
        "verified": true,
        "verifiedAt": "2025-01-05T10:03:00Z",
        "maskedNumber": "XXXXX1234F"
      },
      "face": {
        "verified": true,
        "verifiedAt": "2025-01-05T10:07:00Z",
        "confidence": 0.98
      },
      "upi": {
        "verified": false
      },
      "bank": {
        "verified": true,
        "verifiedAt": "2025-01-05T10:10:00Z",
        "maskedAccount": "XXXXXX7890",
        "ifsc": "HDFC0001234",
        "bankName": "HDFC Bank"
      },
      "extended": {
        "complete": true,
        "missing": [],
        "isPepRejected": false,
        "profile": {
          "submitted": true,
          "dateOfBirth": "1990-05-15",
          "nationality": "Indian",
          "city": "Mumbai",
          "state": "Maharashtra",
          "submittedAt": "2025-01-05T10:00:00Z"
        },
        "document": {
          "submitted": true,
          "documentType": "passport",
          "fileName": "passport.pdf",
          "verified": true,
          "uploadedAt": "2025-01-05T10:04:00Z"
        },
        "declaration": {
          "submitted": true,
          "occupation": "salaried",
          "incomeRange": "10l_to_25l",
          "isPep": false,
          "submittedAt": "2025-01-05T10:05:00Z"
        }
      }
    },
    "bankAccounts": [
      {
        "id": "ba_xyz789",
        "maskedAccountNumber": "XXXXXX7890",
        "ifsc": "HDFC0001234",
        "bankName": "HDFC Bank",
        "isPrimary": true,
        "verified": true
      }
    ]
  }
}

KYC Status Values

StatusMeaning
pendingNo verification started
in_progressAt least one verification completed
verifiedAll required verifications complete
rejectedKYC rejected (PEP declaration or fraud)

KYC Levels

LevelRequirementsCan Transact
noneNo verification completedNo
basicBasic KYC (Aadhaar + PAN + Face + Bank) + Extended KYC (Profile + Document + Declaration)Yes
enhancedReserved for future useYes

Extended KYC Fields

The kyc.extended object contains FIU compliance data:
FieldDescription
completeWhether all extended KYC steps are complete
missingArray of missing steps: ["profile", "document", "declaration"]
isPepRejectedIf user declared as Politically Exposed Person (auto-rejected)
profilePersonal details (DOB, nationality, address)
documentUploaded identity document
declarationOccupation, income range, PEP status

Name Matching

We perform fuzzy name matching across all documents:
  • PAN name vs Aadhaar name
  • Aadhaar name vs Bank account name
  • Minimum 80% match required
Transactions will fail if bank account name doesn’t match KYC name.

Error Handling

Common KYC errors:
Error CodeDescriptionResolution
PAN_INVALIDInvalid PAN formatCheck 10-character alphanumeric format
PAN_NOT_FOUNDPAN not in government DBVerify PAN is active
AADHAAR_OTP_EXPIREDDigiLocker session expiredRestart Aadhaar flow
BANK_PENNY_DROP_FAILEDBank transfer failedCheck account number/IFSC
NAME_MISMATCHNames don’t matchContact support

Webhooks

You’ll receive webhooks for KYC status changes:
{
  "event": "user.kyc_updated",
  "timestamp": "2025-01-05T10:15:00Z",
  "data": {
    "userId": "usr_abc123",
    "kyc": {
      "level": "basic",
      "status": "verified"
    }
  }
}