PredictRAM Resident eKYC — SDK

Resident eKYC SDK

HTTP API + DigiLocker OAuth integration for Resident DigiLocker (/kyc/) and KFin KRA (/kyc/kfin). No native DigiLocker binary SDK — Flutter and React use REST + browser redirect.

Product docs eKYC hub Health API

1. Overview

CapabilityStatus
Flutter (Android / iOS)Supported — REST + system browser / Custom Tabs
React / Next.js / VueSupported — fetch + redirect
Native DigiLocker packageNot required — MeriPehchaan hosted OAuth
DigiLocker secrets in client appNever — stay on PredictRAM Auth Partner

2. Base URL

https://web.predictram.com

Local: your Flask host (e.g. http://127.0.0.1:5010). Always send Accept: application/json on API calls.

3. DigiLocker resident sequence

POST /api/kyc/v1/sessions          → session_id
GET  .../sessions/{id}/digilocker/start  → 302 DigiLocker
     (user consents on MeriPehchaan)
GET  /api/kyc/v1/digilocker/callback     → digilocker_verified
GET  /api/kyc/v1/sessions/{id}           → poll status / ekyc summary
     → /kyc/session/{id}/onboarding
POST .../aadhaar/otp/send|verify
POST .../ipv
POST .../declarations
POST .../signature
POST .../pack/build                      → PDF + All-KRA ZIP
GET  .../pack/download
GET  .../kra-pack/download
POST .../kra-pack/push                   → KFin SFTP (if configured)

4. DigiLocker API reference

MethodEndpointPurpose
GET/api/kyc/v1/healthDigiLocker config health
POST/api/kyc/v1/sessionsCreate resident session
GET/api/kyc/v1/sessions/{id}Session + ekyc summary
GET/api/kyc/v1/sessions/{id}/digilocker/startStart DigiLocker OAuth
GET/api/kyc/v1/digilocker/callbackOAuth callback (hosted)
POST/api/kyc/v1/sessions/{id}/aadhaar/otp/sendOnboarding Aadhaar OTP
POST/api/kyc/v1/sessions/{id}/aadhaar/otp/verifyVerify OTP
POST/api/kyc/v1/sessions/{id}/ipvIPV selfie (+ optional geo)
POST/api/kyc/v1/sessions/{id}/declarationsRA / FATCA / PEP decls
POST/api/kyc/v1/sessions/{id}/signatureWet / click-wrap signature
POST/api/kyc/v1/sessions/{id}/pack/buildPDF + All-KRA packs
GET/api/kyc/v1/sessions/{id}/pack/downloadDownload merged PDF
GET/api/kyc/v1/sessions/{id}/kra-pack/downloadDownload All-KRA ZIP
POST/api/kyc/v1/sessions/{id}/kra-pack/pushSFTP push KFin batch

Create DigiLocker session

POST /api/kyc/v1/sessions
Content-Type: application/json

{
  "journey_type": "resident",
  "external_client_ref": "your-user-id",
  "tenant_id": "your-firm",
  "pan": "ABCDE1234F",
  "pan_consent": true
}

Typical statuses

created → awaiting_digilocker → digilocker_verified
→ (onboarding) → kyc_pack_ready → kyc_kra_pushed | failed

5. KFin resident sequence

POST /api/kyc/v1/kfin/sessions
POST .../contact/otp/send + verify          (mobile + email)
GET|POST .../digilocker/start               (PANCR + e-Aadhaar)
POST .../aadhaar                            (Offline XML/ZIP fallback)
POST .../details                            (MITC + IPV + signature)
POST .../pack/build                         (KFin ZIP + All-KRA ZIP)
GET  .../pack/download
GET  .../pack/download-all-kra
POST .../push                               (SFTP or demo UNDER_PROCESS)
GET  .../checklist

6. KFin API reference

MethodEndpointPurpose
POST/api/kyc/v1/kfin/sessionsCreate KFin session (PAN)
GET/api/kyc/v1/kfin/sessions/{id}Session + checklist
POST/api/kyc/v1/kfin/sessions/{id}/contact/otp/sendSend mobile/email OTP
POST/api/kyc/v1/kfin/sessions/{id}/contact/otp/verifyVerify contact OTP
GET/POST/api/kyc/v1/kfin/sessions/{id}/digilocker/startBridge DigiLocker into KFin
POST/api/kyc/v1/kfin/sessions/{id}/aadhaarOffline Aadhaar XML/ZIP
POST/api/kyc/v1/kfin/sessions/{id}/detailsMITC + IPV + signature
GET/api/kyc/v1/kfin/sessions/{id}/checklistReady-to-push checklist
POST/api/kyc/v1/kfin/sessions/{id}/pack/buildBuild KFin + All-KRA
GET/api/kyc/v1/kfin/sessions/{id}/pack/downloadKFin official ZIP
GET/api/kyc/v1/kfin/sessions/{id}/pack/download-all-kraAll-KRA ZIP
POST/api/kyc/v1/kfin/sessions/{id}/pushSFTP push ({"demo":true} optional)

Create KFin session

POST /api/kyc/v1/kfin/sessions
Content-Type: application/json

{
  "pan": "ABCDE1234F",
  "name": "OPTIONAL NAME",
  "mobile": "9876543210",
  "email": "client@example.com"
}

7. All-KRA pack contents

ALL_KRA_{PAN}_{YYYYMMDD}.zip
  README.txt
  MANIFEST.json
  01_KFIN/   — official KFin batch ZIP (SFTP-ready)
  02_CVL/    — CVL_KYC_DATA.txt (tilde, no header)
  03_CAMS/   — portable CSV + JSON
  04_NDML/   — portable CSV + JSON
  05_DOTEX/  — portable CSV + JSON
  SHARED/    — DL_Aadh.xml / IPV when available

8. Flutter sample (DigiLocker)

import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:url_launcher/url_launcher.dart';

const base = 'https://web.predictram.com';

Future<String> startResidentDigilocker({String? pan}) async {
  final create = await http.post(
    Uri.parse('$base/api/kyc/v1/sessions'),
    headers: {'Content-Type': 'application/json', 'Accept': 'application/json'},
    body: jsonEncode({
      'journey_type': 'resident',
      'external_client_ref': 'flutter-user-1',
      if (pan != null) 'pan': pan,
      'pan_consent': pan != null,
    }),
  );
  final data = jsonDecode(create.body) as Map<String, dynamic>;
  if (data['success'] != true) {
    throw Exception(data['error'] ?? 'session failed');
  }
  final sessionId = data['session']['id'] as String;
  await launchUrl(
    Uri.parse('$base/api/kyc/v1/sessions/$sessionId/digilocker/start'),
    mode: LaunchMode.externalApplication,
  );
  return sessionId;
}

Future<Map<String, dynamic>> getSession(String id) async {
  final res = await http.get(Uri.parse('$base/api/kyc/v1/sessions/$id'));
  return jsonDecode(res.body) as Map<String, dynamic>;
}
Prefer system browser / Custom Tabs for DigiLocker (not an insecure WebView). After digilocker_verified, open onboarding or call pack APIs from your backend.

9. React / Web sample (DigiLocker + KFin)

const BASE = 'https://web.predictram.com';

export async function startDigilockerResident({ pan, externalClientRef }) {
  const res = await fetch(`${BASE}/api/kyc/v1/sessions`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
    body: JSON.stringify({
      journey_type: 'resident',
      external_client_ref: externalClientRef,
      pan,
      pan_consent: !!pan,
    }),
  });
  const data = await res.json();
  if (!data.success) throw new Error(data.error || 'session failed');
  window.location.href =
    `${BASE}/api/kyc/v1/sessions/${data.session.id}/digilocker/start`;
  return data.session.id;
}

export async function startKfinSession({ pan, mobile, email }) {
  const res = await fetch(`${BASE}/api/kyc/v1/kfin/sessions`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
    body: JSON.stringify({ pan, mobile, email }),
  });
  const data = await res.json();
  if (!data.success) throw new Error(data.error || 'kfin session failed');
  // Continue in PredictRAM UI, or drive steps via KFin APIs:
  window.location.href = data.continue_url || `${BASE}/kyc/kfin/session/${data.session_id}`;
  return data.session_id;
}

export async function buildAndDownloadAllKra(sessionId, { kfin = false } = {}) {
  const buildPath = kfin
    ? `${BASE}/api/kyc/v1/kfin/sessions/${sessionId}/pack/build`
    : `${BASE}/api/kyc/v1/sessions/${sessionId}/pack/build`;
  const built = await fetch(buildPath, { method: 'POST', headers: { Accept: 'application/json' } });
  const data = await built.json();
  if (!data.success) throw new Error(data.error || 'pack build failed');
  const dl = kfin
    ? (data.all_kra_download_url || data.download_url)
    : (data.kra_download_url || data.download_url);
  if (dl) window.location.href = dl.startsWith('http') ? dl : `${BASE}${dl}`;
  return data;
}

10. Errors & tips