API Reference — Flutter
SDK-Only Access
To ensure your integration remains stable and supported, always use the official SDKs. The underlying API endpoints are internal implementation details that may change in purpose, functionality, or be removed at any time without notice. Direct API access is not supported. Learn more →
The SDK methods documented here are your supported interface. Versioning is managed through SDK upgrades.
createVerifierSDK(config)
Creates and returns a VerifierSDK instance.
import 'package:vecu_verifier_flutter_sdk/vecu_verifier_flutter_sdk.dart';
final sdk = createVerifierSDK(VerifierConfig(
stage: DeploymentStage.production,
bearerToken: 'your-token',
));
Configuration
VerifierConfig constructor parameters:
stageDeploymentStagerequired.development, .sandbox, or .production. Determines the backend URL.
bearerTokenStringrequiredVECU API authentication token.
apiBaseUrlString?Override the default endpoint for the selected stage.
pollingIntervalMsintMilliseconds between status checks.
pollingTimeoutMsintMaximum wait time (5 minutes).
pollingMaxRetriesintConsecutive errors before stopping.
logLevelLogLevelLogging verbosity: .debug, .info, .warn, .error, .none.
The SDK automatically resolves the correct endpoint for each stage. The apiBaseUrl property is available for local mock server testing only.
Widgets
VerificationView
Full verification flow widget. Handles loading, QR display, polling, and all result states.
VerificationView(
sdk: sdk,
vin: '1HGBH41JXMN109186',
onApproved: (result) { /* VerificationApproved */ },
onDenied: (result) { /* VerificationDenied */ },
onExpired: (result) { /* VerificationExpired */ },
onError: (error) { /* VerifierError */ },
decoration: BoxDecoration(...),
padding: EdgeInsets.all(24),
)
sdkVerifierSDKrequiredSDK instance from createVerifierSDK().
vinStringrequiredVehicle Identification Number to verify.
onApprovedvoid Function(VerificationApproved)?Called when verification succeeds.
onDeniedvoid Function(VerificationDenied)?Called when verification is denied.
onExpiredvoid Function(VerificationExpired)?Called when the session expires.
onErrorvoid Function(VerifierError)?Called on any error.
decorationBoxDecoration?Custom decoration for the outer container (background, border, etc.).
proximityProximityConfig?Optional GPS proximity verification. Device coordinates are retrieved
automatically via platform location services. If location permission is
denied, result will be unchecked.
paddingEdgeInsetsGeometry?Custom padding for the outer container.
VerificationController
ChangeNotifier-based state manager for building custom verification UI. Manages the full flow (create request, poll, state transitions) and exposes a reactive state for your UI.
final controller = VerificationController(
sdk: sdk,
vin: '1HGBH41JXMN109186',
proximity: const ProximityConfig(thresholdMiles: 5.0),
onApproved: (result) { /* VerificationApproved */ },
onDenied: (result) { /* VerificationDenied */ },
onExpired: (result) { /* VerificationExpired */ },
onError: (error) { /* VerifierError */ },
);
sdkVerifierSDKrequiredSDK instance from createVerifierSDK().
vinStringrequiredVehicle Identification Number to verify.
proximityProximityConfig?Optional GPS proximity configuration.
onApprovedVerificationApprovedCallback?Called when verification succeeds.
onDeniedVerificationDeniedCallback?Called when verification is denied.
onExpiredVerificationExpiredCallback?Called when the session expires.
onErrorVerifierErrorCallback?Called when an error occurs.
Properties
| Property | Type | Description |
|---|---|---|
state | UIState | Current UI state (see below) |
vin | String | The VIN being verified |
Methods
| Method | Description |
|---|---|
restart() | Stop polling and start a new verification flow |
notifyQRExpired() | Transition to QRExpiredState when QR timer expires |
addListener(callback) | Register a state change listener (inherited from ChangeNotifier) |
dispose() | Clean up event subscriptions and stop polling |
UIState (Sealed Class)
Use pattern matching on controller.state:
switch (controller.state) {
LoadingState() => // Creating request...
QRState(:final qrContent, :final expiresAt, :final vin) => // Show QR
QRExpiredState() => // QR timer expired, show restart
ApprovedState(:final result, :final vin) => // Verified
DeniedState(:final result, :final vin) => // Do not release
ExpiredState(:final result) => // Session expired
ErrorState(:final error) => // Show error.userMessage
}
Core SDK Methods
createPresentationRequest(vin, [options])
final result = await sdk.createPresentationRequest(
'1HGBH41JXMN109186',
CreatePresentationOptions(
proximity: ProximityConfig(thresholdMiles: 5.0),
),
);
if (result is ApiSuccess<CreatePresentationResponse>) {
final data = result.data;
// data.requestId, data.qrContent, data.expiresAt
}
ApiResult is a sealed class with two subtypes:
ApiSuccess<T>— containsdata: TApiFailure<T>— containserror: VerifierError
Returns: Future<ApiResult<CreatePresentationResponse>>
CreatePresentationResponse
requestIdStringrequiredUnique identifier for polling and support triage.
qrContentStringrequiredOID4VP URL to render as a QR code for the driver's wallet to scan.
expiresAtStringrequiredISO 8601 timestamp when the QR code/request expires.
startPolling()
Starts polling for verification status. Stops automatically on terminal states.
Returns: void Function() — cleanup function to stop polling.
stopPolling({String reason})
Manually stop polling. Accepts an optional reason parameter (defaults to 'manual').
getStatus() / getRequest()
Get current verification status or full request state.
on<T>(listener) / off<T>(listener)
Subscribe/unsubscribe to typed events.
sdk.on<StatusChangedEvent>((event) {
print(event.currentStatus.status);
});
destroy()
Clean up all resources (timers, listeners).
Events
sdk.on<RequestCreatedEvent>((e) { e.requestId; e.qrContent; e.vin; });
sdk.on<StatusChangedEvent>((e) { e.previousStatus; e.currentStatus; });
sdk.on<PollingStartedEvent>((e) { e.requestId; e.intervalMs; });
sdk.on<PollingStoppedEvent>((e) { e.requestId; e.reason; });
sdk.on<ErrorEvent>((e) { e.error; });
Verification Status Types
Sealed class hierarchy with pattern matching:
All statuses share common fields requestId, createdAt?, and expiresAt?:
switch (status) {
case VerificationPending(:final requestId):
print('Waiting...');
case VerificationApproved(:final requestId, :final proximityCheck):
print('Verified: $requestId');
if (proximityCheck?.status == ProximityCheckStatus.fail) {
print('Warning: device is far from origin');
}
case VerificationDenied(:final requestId, :final error):
print('DO NOT RELEASE: $requestId (${error ?? "no reason"})');
case VerificationExpired(:final requestId):
print('Expired: $requestId');
}
Helper methods: status.isTerminal, status.isApproved, status.isDenied
VerificationApproved includes optional verifiedClaims and proximityCheck:
VerifiedClaims
Credential claims extracted by the backend on approval. Access via result.verifiedClaims:
vinString?Vehicle Identification Number from the verified credential.
originLocationString?Origin location from the credential (e.g. auction site name).
destinationLocationString?Destination location from the credential (e.g. dealer name).
case VerificationApproved(:final verifiedClaims, :final proximityCheck):
final vin = verifiedClaims?.vin ?? 'N/A';
final origin = verifiedClaims?.originLocation;
final destination = verifiedClaims?.destinationLocation;
Proximity Types
ProximityConfig
Device GPS coordinates are retrieved automatically via platform location services. If location permission is not granted, the proximity check result will be unchecked.
const ProximityConfig({
required double thresholdMiles, // Max distance from origin (miles)
})
ProximityCheck
Returned on VerificationApproved.proximityCheck:
statusProximityCheckStatusrequiredpass, fail, or unchecked.
distanceMilesdouble?Actual distance between device and origin in miles. Present on pass and
fail.
thresholdMilesdouble?Threshold that was applied (from your ProximityConfig).
originCoordinatesCoordinates?GPS coordinates from the credential (origin location). Has lat and lng
fields.
deviceCoordinatesCoordinates?GPS coordinates of the verifier's device. Has lat and lng fields.
Status behavior:
| Status | Meaning |
|---|---|
pass | Device is within thresholdMiles of origin |
fail | Device is beyond threshold — distanceMiles shows how far |
unchecked | Location permission denied or proximity not configured |
final proximity = result.proximityCheck;
if (proximity != null && proximity.status == ProximityCheckStatus.fail) {
print('Device is ${proximity.distanceMiles?.toStringAsFixed(1)} mi '
'from origin (threshold: ${proximity.thresholdMiles} mi)');
}
Error Types
All errors extend VerifierError with these common fields:
codeStringrequiredMachine-readable error code (e.g. NETWORK_ERROR, API_ERROR).
messageStringrequiredTechnical error message (may contain internal details — not for UI display).
userMessageStringrequiredUI-safe, human-friendly message. Always use this for display.
timestampDateTimerequiredWhen the error occurred.
displayCodeStringTriage-friendly code. For ApiError, includes HTTP status (e.g.
API_ERROR_401).
Subtypes:
| Type | Extra Fields | userMessage example |
|---|---|---|
NetworkError | cause | "Unable to connect. Please check your internet connection" |
ApiError | statusCode, details | "Access denied" (401), "Service busy, try again" (429) |
ValidationError | field | "Invalid input provided" |
TimeoutError | timeoutMs | "The request timed out. Please try again" |
SessionError | sessionId | "Your verification session has expired" |
ApiError.isRetryable returns true for 5xx and 429 status codes. The top-level isRetryableError() function works on any VerifierError.
onError: (error) {
// Show to user
showSnackBar(error.userMessage);
// Log for support
print('Error ${error.displayCode}: ${error.message}');
}
Individual UI Widgets
For headless integrations that want to reuse specific built-in views, the SDK exports individual widgets:
| Widget | Description |
|---|---|
QRCodeDisplay | QR code with countdown timer |
ApprovedView | Green success card |
DeniedView | Red "DO NOT RELEASE" card |
ExpiredView | Orange session expired card |
ErrorView | Error card with code and retry |
LoadingView | Loading spinner |
QRExpiredView | QR expired with refresh button |