Skip to main content
Version: 1.520.4

Usage

Basic Example​

import 'package:flutter/material.dart';
import 'package:trustchex_flutter_sdk/trustchex_flutter_sdk.dart';

class VerificationScreen extends StatelessWidget {
final String sessionId;
final String baseUrl;

const VerificationScreen({
super.key,
required this.sessionId,
required this.baseUrl,
});

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Verification')),
body: TrustchexView(
sessionId: sessionId,
baseUrl: baseUrl,
onCompleted: () {
Navigator.of(context).pop();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Verification completed successfully!'),
backgroundColor: Colors.green,
),
);
},
onError: (error) {
Navigator.of(context).pop();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Verification error: $error'),
backgroundColor: Colors.red,
),
);
},
),
);
}
}

Props​

PropTypeRequiredDescription
baseUrlString✅Your API base URL
sessionIdString❌Session identifier
brandingTrustchexBranding❌Colors and logo
localeTrustchexLocale❌Language (en, tr)
onCompletedVoidCallback❌Called when the verification process finishes
onErrorFunction(String)❌Error callback
onDocumentReadFunction(DocumentReadResult)❌Called when document is read (NFC or OCR)
skipNfcResultScreenbool❌Skip the NFC document review screen and proceed automatically after a successful NFC scan. Default: false
skipSuccessScreenbool❌Skip the final success screen and call onCompleted immediately when the process finishes. Default: false

Document Read Event​

The onDocumentRead callback fires as soon as document data is available — immediately after a successful NFC chip read or after a successful camera OCR scan. It receives a unified DocumentReadResult object regardless of source.

import 'package:trustchex_flutter_sdk/trustchex_flutter_sdk.dart';

TrustchexView(
baseUrl: 'https://your-api.com',
sessionId: 'session-123',
onDocumentRead: (result) {
final document = result.document;

print(document.documentType.name); // "passport" | "id"
print(document.issuingCountry); // "DEU"
print(document.nationality); // "DEU"
print(document.documentNumber); // "C01X00T478"
print(document.personalNumber); // "8512310074" | null
print(document.lastName); // "MÜLLER"
print(document.firstName); // "JÜRGEN KARL"
print(document.sex.name); // "male" | "female" | "unspecified" | "unknown"
print(document.dateOfBirth); // "1985-03-10" (ISO 8601)
print(document.dateOfExpiry); // "2030-11-05" (ISO 8601)
},
onCompleted: () => print('Done'),
onError: (error) => print('Error: $error'),
)

DocumentReadResult​

class DocumentReadResult {
final DocumentData document;
final DocumentName name;
final DocumentFaceImage? face;
}

class DocumentData {
final ScannedDocumentType documentType; // .passport | .idCard
final String issuingCountry; // 3-letter ICAO code, e.g. "TUR"
final String nationality;
final String documentNumber;
final String? personalNumber;
final String lastName; // Best available name, e.g. "MÜLLER"
final String firstName; // Best available name, e.g. "JÜRGEN"
final DocumentSex sex; // .male | .female | .unspecified
final String? dateOfBirth; // ISO 8601, e.g. "1990-05-15"
final String? dateOfExpiry; // ISO 8601, e.g. "2028-03-01"
}

class DocumentName {
final String rawLast; // MRZ ASCII surname
final String rawFirst; // MRZ ASCII given name
final String displayLast; // Best Unicode form
final String displayFirst; // Best Unicode form
final DocumentNameSource source; // .dg11 | .reverseTable | .raw
}

class DocumentFaceImage {
final String data; // Base64-encoded image
final String mimeType; // e.g. "image/jpeg"
}

Name Sources​

SourceDescription
dg11Exact printed name read from the NFC chip's DG11 file (UTF-8). Highest accuracy.
reverseTableReconstructed via ICAO 9303 reverse transliteration (e.g. OE→Ö, UE→Ü). Applied for known countries.
rawNo conversion — display equals the raw MRZ ASCII value.

Flow Control​

Skip NFC Result Screen​

By default, after a successful NFC chip read the SDK shows a review screen where the user can verify their document data before proceeding. Set skipNfcResultScreen to bypass this screen entirely — the SDK advances automatically as soon as the NFC scan completes.

TrustchexView(
baseUrl: 'https://your-api.com',
sessionId: 'session-123',
skipNfcResultScreen: true,
onCompleted: () => print('Done'),
onError: (error) => print('Error: $error'),
)

Use onDocumentRead alongside this prop if you need to access the scanned document data without showing the review screen.

Skip Success Screen​

By default, after the verification process completes the SDK shows a success animation for 3 seconds before calling onCompleted. Set skipSuccessScreen to call onCompleted immediately with no animation or delay.

TrustchexView(
baseUrl: 'https://your-api.com',
sessionId: 'session-123',
skipSuccessScreen: true,
onCompleted: () {
// Called immediately when verification is complete
Navigator.of(context).pop();
},
onError: (error) => print('Error: $error'),
)

Both props can be combined:

TrustchexView(
baseUrl: 'https://your-api.com',
sessionId: 'session-123',
skipNfcResultScreen: true,
skipSuccessScreen: true,
onDocumentRead: (result) => print(result.name.displayFirst),
onCompleted: () => Navigator.of(context).pop(),
onError: (error) => print('Error: $error'),
)

With Branding​

TrustchexView(
sessionId: sessionId,
baseUrl: 'https://api.trustchex.com',
locale: TrustchexLocale.en,
branding: const TrustchexBranding(
logoUrl: 'https://trustchex.com/logo.png',
primaryColor: Color(0xFF1E40AF),
secondaryColor: Color(0xFFF8FAFC),
tertiaryColor: Color(0xFFDC2626),
),
onCompleted: () {
Navigator.of(context).pop();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Verification completed successfully!'),
backgroundColor: Colors.green,
),
);
},
onError: (error) {
Navigator.of(context).pop();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Verification error: $error'),
backgroundColor: Colors.red,
),
);
},
)

MASAK Tebliğ 32 (Art. 4/C)​

For remote KYC of non-Turkish nationals via NFC passport, the SDK runs the Article 4/C checks whenever the server-side workflow enables them per step. The relevant step flags are:

FlagEffect
passiveAuthRun Passive Authentication on the eID scan (read EF.SOD, verify DG-hash integrity on-device, send the SOD for server-side signature + CSCA chaining).
enforceChipVizMatchServer terminal-rejects when the chip↔VIZ verdict is not MATCH.
collectGeolocationCapture a coarse device geolocation during the contract step. See below.
addressProofRequiredRequire a proof document in the address-capture step.
blockedNationalitiesServer rejects documents whose nationality is on the list.
requireOperatorRequire a connected operator in the video interview.
enforcePassiveAuthServer terminal-rejects when Passive Auth comes back TAMPERED.

These are driven entirely by the backend — no client code is required to turn them on. The SDK computes the chip↔VIZ verdict and Passive Authentication integrity on-device and sends the artifacts; the server makes the authoritative decision.

Geolocation (Art. 4/C(1)(e))​

Geolocation is captured natively, with no third-party plugin — iOS Core Location, Android LocationManager, through the SDK's own platform channel. When a step has collectGeolocation enabled, the SDK takes a single coarse fix on its own; there is no app-side code to write.

The only setup is declaring the OS permission strings from Installation:

  • iOS NSLocationWhenInUseUsageDescription — Core Location shows the system prompt on first use given this string.
  • Android ACCESS_COARSE_LOCATION — the SDK requests it at runtime.

Everything is fail-soft: if location services are off, permission is denied, or the fix times out, the SDK sends nothing and the flow proceeds — the backend treats a missing fix as "not provided" while still recording that it was expected. The fix is rounded to ~3 decimals (~110 m) before sending.

Deep link functionality is an optional feature if you want to publish a standalone app. To process deep links with the SDK, you need to configure deep links in your app and set up the required hooks to handle incoming URLs.

iOS - Add to Info.plist:

<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>yourapp</string>
</array>
</dict>
</array>

Android - Add to AndroidManifest.xml:

<activity android:name=".MainActivity">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="yourapp" />
</intent-filter>
</activity>

Import and use the DeeplinkUtils class to parse incoming URLs:

import 'package:flutter/material.dart';
import 'package:trustchex_flutter_sdk/trustchex_flutter_sdk.dart';
import 'package:uni_links/uni_links.dart';

class App extends StatefulWidget {
const App({super.key});

@override
State<App> createState() => _AppState();
}

class _AppState extends State<App> {
String? baseUrl;
String? sessionId;

@override
void initState() {
super.initState();
_handleInitialLink();
_handleIncomingLinks();
}

Future<void> _handleInitialLink() async {
try {
final initialLink = await getInitialLink();
if (initialLink != null) {
_processDeepLink(initialLink);
}
} catch (e) {
print('Error handling initial link: $e');
}
}

void _handleIncomingLinks() {
linkStream.listen((String? link) {
if (link != null) {
_processDeepLink(link);
}
});
}

void _processDeepLink(String url) {
final parsed = DeeplinkUtils.parseDeepLink(url);
if (parsed != null && parsed['sessionId'] != null) {
setState(() {
baseUrl = parsed['baseUrl'] ?? 'https://api.trustchex.com';
sessionId = parsed['sessionId'];
});
}
}

@override
Widget build(BuildContext context) {
return TrustchexView(
baseUrl: baseUrl,
sessionId: sessionId,
onCompleted: () => print('Done'),
onError: (error) => print('Error: $error'),
);
}
}

The DeeplinkUtils.parseDeepLink function parses URLs with the format:

scheme://app-url/your-api.com/verification-session/session-123

And returns a map with baseUrl and sessionId keys.

note

You'll need to add the uni_links package to handle deep links:

dependencies:
uni_links: ^0.5.1

Sessions​

Create sessions using the REST API.

Session Access Methods​

The SDK provides multiple ways for users to access their verification session:

Users click a link that opens the app directly with the session:

// Deep link format: yourapp://app-url/your-api.com/verification-session/session-123
TrustchexView(
baseUrl: 'https://your-api.com',
sessionId: 'session-123', // From deep link
onCompleted: () => print('Done'),
)

Benefits:

  • Seamless user experience - one tap to start
  • Direct navigation to verification
  • No manual input required
  • Works great for email and SMS campaigns

Users scan a QR code that contains the session information. The SDK includes a built-in QR scanner accessible from the welcome screen.

Benefits:

  • Quick and contactless
  • No typing required
  • Ideal for in-person verification
  • Built-in scanner included in SDK

3. Session Code Entry (Alternative)​

Users can manually enter an 8-character alphanumeric code:

TrustchexView(
baseUrl: 'https://your-api.com',
// No sessionId prop needed - user enters code manually
onCompleted: () => print('Done'),
)

When no sessionId is provided, the SDK displays a screen where users can:

  • Enter the 8-character session code
  • Scan a QR code

Use Cases:

  • Fallback when QR/deep link unavailable
  • Phone/voice support scenarios
  • Print media without QR capability

Creating Sessions​

When creating a session via the REST API, you'll receive access methods in the response:

final response = await http.post(
Uri.parse('https://your-api.com/api/v1/verification-sessions'),
headers: {'x-api-key': 'YOUR_API_KEY'},
body: jsonEncode({
'workflowId': 'workflow-123',
'email': 'user@example.com'
}),
);

final data = jsonDecode(response.body);
final deepLink = data['deepLink'];
final qrCodeLink = data['qrCodeLink'];
final sessionCode = data['sessionCode'];

// Use deepLink for direct app navigation (recommended)
// Use qrCodeLink to generate QR code (recommended)
// Use sessionCode as alternative access method