---
Source: https://docs.microblink.com/blinkcard/migration-v3000
Title: Migrating to v3000
Description: How to migrate to BlinkCard v3000
---

# Migrating to v3000

This guide describes how to upgrade to BlinkCard v3000.

For specific platforms (web, iOS, Android...), additional details may be available in their own API references.

:::note 

BlinkCard v3000 brings new capabilities, other than those listed in this migration guide. 
The migration guide is focused on getting you to successfully migrate to the new version, and so it doesn't talk about the new features. 
Read the release notes for your SDK platform to find out more about what else is new.

:::


## Versioning change

Starting with v3000, BlinkCard will adopt the [epoch versioning scheme](https://antfu.me/posts/epoch-semver#epoch-semantic-versioning).

> ```
> {EPOCH * 1000 + MAJOR}.MINOR.PATCH
> ```
>
> EPOCH: Increment when you make significant or groundbreaking changes.
>
> MAJOR: Increment when you make minor incompatible API changes.
>
> MINOR: Increment when you add functionality in a backwards-compatible manner.
>
> PATCH: Increment when you make backwards-compatible bug fixes.

So, instead of going from v2.x.x to v3.x.x, **BlinkCard will go from v2.x.x to v3000.x.x**.

Subsequent versions will follow the same scheme.

## Architecture changes

BlinkCard v3000, similarly to [BlinkID v7 and above](https://docs.microblink.com/blinkid/sdk/web/transition-guide), will adopt a **session-based** architecture.

This means that you no longer need to configure and string together individual recognizers.

Instead, the whole concept of a recognizer is replaced by the concept of a session.

<Tabs queryString="platform">
  <TabItem value="web" label="Web (JS)" default>

  **v2 (Recognizer-based):**
  
  ```javascript
  import { createBlinkCardRecognizer } from "@microblink/blinkcard-in-browser-sdk";
  
  const recognizer = await createBlinkCardRecognizer(wasmSDK);
  await recognizer.updateSettings({
    extractOwner: false,
    returnFullDocumentImage: true
  });
  const result = await recognizer.getResult();
  ```
  
  **v3000 (Session-based):**
  
  ```javascript
  import { createBlinkCard } from "@microblink/blinkcard";
  
  // Complete solution with UI components
  const blinkCard = await createBlinkCard({
    licenseKey: "your-license-key",
    scanningSettings: {
      extractionSettings: { extractCardholderName: false },
      croppedImageSettings: { returnCardImage: true }
    }
  });
  ```

  </TabItem>
  <TabItem value="android" label="Android (Kotlin)">

  **v2 (Recognizer-based):**
  
  ```kotlin
  val recognizer = BlinkCardRecognizer()
  recognizer.setExtractOwner(false)
  recognizer.setReturnFullDocumentImage(true)
  ```
  
  **v3000 (Session-based):**
  
  ```kotlin
  val sdkSettings = BlinkCardSdkSettings(
      licenseKey = "your-license-key"
  )
  val sdk = BlinkCardSdk.initializeSdk(context, sdkSettings).getOrThrow()
  
  val sessionSettings = BlinkCardSessionSettings(
      inputImageSource = InputImageSource.Video,
      scanningSettings = ScanningSettings(
          extractionSettings = ExtractionSettings(extractCardholderName = false),
          croppedImageSettings = CroppedImageSettings(returnCardImage = true)
      )
  )
  val session = sdk.createScanningSession(sessionSettings)
  ```
  
  </TabItem>
  <TabItem value="ios" label="iOS (Swift)">

  **v2 (Recognizer-based):**
  
  ```swift
  let recognizer = MBCBlinkCardRecognizer()
  recognizer.extractOwner = false
  recognizer.returnFullDocumentImage = true
  ```
  
  **v3000 (Session-based):**
  
  ```swift
  let sdkSettings = BlinkCardSdkSettings(
      licenseKey: "your-license-key",
      downloadResources: true
  )
  let sdk = try await BlinkCardSdk.createBlinkCardSdk(withSettings: sdkSettings)
  
  let sessionSettings = BlinkCardSessionSettings(
      inputImageSource: .video,
      scanningMode: .automatic,
      scanningSettings: ScanningSettings(
          extractionSettings: ExtractionSettings(extractCardholderName: false),
          croppedImageSettings: CroppedImageSettings(returnCardImage: true)
      )
  )
  let session = await sdk.createScanningSession(settings: sessionSettings)
  ```
  
  </TabItem>
  <TabItem value="flutter" label="Flutter (Dart)">

  **v2 (Recognizer-based):**
  
  ```dart
  var recognizer = BlinkCardRecognizer();
  recognizer.extractOwner = false
  recognizer.returnFullDocumentImage = true
  ```
  
  **v3000 (Session-based):**
  
  ```dart
  final sdkSettings = BlinkCardSdkSettings(licenseKey: blinkCardLicenseKey);
  sdkSettings.downloadResources = true;

  final sessionSettings = BlinkCardSessionSettings();

  final scanningSettings = ScanningSettings();
  scanningSettings.skipImagesWithBlur = true;
  scanningSettings.tiltDetectionLevel = DetectionLevel.mid;

  sessionSettings.scanningSettings = scanningSettings;

  final scanningUxSettings = ScanningUxSettings();
  scanningUxSettings.showHelpButton = true;
  scanningUxSettings.showIntroductionAlert = false;
  scanningUxSettings.preferredCameraPosition = CameraPosition.back;
  scanningUxSettings.allowHapticFeedback = true;

  final blinkCardResult = await blinkCardPlugin.performScan(
    blinkCardSdkSettings: sdkSettings,
    blinkCardSessionSettings: sessionSettings,
    scanningUxSettings: scanningUxSettings,
  );
  ```
  
  </TabItem>
  <TabItem value="react-native" label="React Native (TypeScript)">

  **v2 (Recognizer-based):**
  
  ```javascript
  var recognizer = new BlinkCardReactNative.BlinkCardRecognizer();
  recognizer.extractOwner = false
  recognizer.returnFullDocumentImage = true;
  ```
  
  **v3000 (Session-based):**
  
  ```typescript
  const sdkSettings = new BlinkCardSdkSettings({
        licenseKey: blinkCardLicenseKey
      });
  sdkSettings.downloadResources = true;

  const sessionSettings = new BlinkCardSessionSettings();

  const scanningSettings = new ScanningSettings();
  scanningSettings.skipImagesWithBlur = true;
  scanningSettings.tiltDetectionLevel = DetectionLevel.Mid;

  sessionSettings.scanningSettings = scanningSettings;

  const scanningUxSettings = new ScanningUxSettings();
  scanningUxSettings.showHelpButton = true;
  scanningUxSettings.showIntroductionAlert = false;
  scanningUxSettings.preferredCameraPosition = CameraPosition.Back;
  scanningUxSettings.allowHapticFeedback = true;

  const blinkCardResult = await performScan(
        sdkSettings,
        sessionSettings,
        scanningUxSettings,
  );
  ```
  </TabItem>
</Tabs>


## License considerations

Old v2 licenses are **compatible** with v3000.
You don't need to issue new licenses.

## Installation and dependencies

<Tabs queryString="platform">
  <TabItem value="web" label="Web (JS)" default>

  **v2:**
  
  ```bash
  npm install @microblink/blinkcard-in-browser-sdk
  ```
  
  **v3000:**
  
  ```bash
  npm install @microblink/blinkcard
  ```
  
  The `@microblink/blinkcard` package (v3000.0.0) is the main user-facing package that provides a complete solution for card scanning in web applications.
  It combines core scanning functionality, camera management, and UI components.
  
  For advanced usage scenarios where you need more control over individual components, you can also use the constituent packages directly:
  
  - `@microblink/blinkcard-core`: core scanning functionality and WASM management
  - `@microblink/blinkcard-ux-manager`: UI feedback and user experience management
  - `@microblink/camera-manager`: camera management (shared library)

  </TabItem>
  <TabItem value="android" label="Android (Kotlin)">
  
  **v2:**
  
  ```gradle
  repositories {
      maven { url 'https://maven.microblink.com' }
  }
  
  dependencies {
      implementation('com.microblink:blinkcard:2.12.0@aar') {
          transitive = true
      }
  }
  ```
  
  **v3000:**
  
  ```gradle
  repositories {
      mavenCentral()  // Changed from maven.microblink.com
  }
  
  dependencies {
      // Core SDK (required)
      implementation('com.microblink:blinkcard-core:3000.0.0')
      
      // UI components (optional, Jetpack Compose-based)
      implementation('com.microblink:blinkcard-ux:3000.0.0')
  }
  ```

  BlinkCard v3000 introduces significant changes to the Android SDK:
  
  - **Minimum SDK raised**: Android 7.0 (API 24) - drops Android 5.x and 6.x support
  - **Kotlin upgrade**: 1.9.x → 2.1.20
  - **Android Gradle Plugin**: Requires AGP 8.0+
  - **UI framework**: Migrated from Views to Jetpack Compose
  - **Modular architecture**: Split into 2 AARs (core + UX)
  - **Distribution**: Now available on Maven Central (instead of Microblink Maven)
  

  </TabItem>
  <TabItem value="ios" label="iOS (Swift)">

  **v2:**
  
  BlinkCard v2 was available via CocoaPods, Carthage, or Swift Package Manager:
  
  ```ruby
  # CocoaPods
  pod 'PPBlinkCard'
  
  # Carthage
  binary "https://github.com/microblink/blinkcard-ios/blob/master/blinkcard-ios.json"
  ```
  
  **v3000:**
  
  BlinkCard v3000 is available via Swift Package Manager (recommended) or manual integration:
  
  ```swift
  // Swift Package Manager
  dependencies: [
      .package(url: "https://github.com/microblink/blinkcard-ios.git", 
               from: "3000.0.0")
  ]
  ```
  
  </TabItem>

  <TabItem value="flutter" label="Flutter (Dart)">

  **v2:**
    
  ```yaml
  dependencies:
    ...
    blinkcard_flutter:
  ```
  
  **v3000:**
  
  BlinkCard v3000 is available via [pub.dev](https://pub.dev/), and the only significant change for the iOS native packages is that the distribution was switched from CocoaPods to Swift Package Manager.

  Before running the `flutter pub get` command, run the following command to enable Swift Package Manager in your Flutter application:
  ```bash
  flutter config --enable-swift-package-manager
  ```

  ```yaml
  dependencies:
    ...
    blinkcard_flutter:
  ```
  
  ```swift
  // Swift Package Manager
  let package = Package(
      name: "blinkcard_flutter",
      platforms: [
          .iOS("16.0")
      ],
      products: [
          .library(name: "blinkcard-flutter", targets: ["blinkcard_flutter"])
      ],
      dependencies: [
          .package(url: "https://github.com/microblink/blinkcard-ios.git", exact: .init(3000, 0, 0))
      ],
      targets: [
          .target(
              name: "blinkcard_flutter",
              dependencies: [
                  .product(name: "BlinkCardUX", package: "blinkcard-ios")
              ],
              resources: []
          )
      ]
  )
  ```


  BlinkCard v3000 introduces significant changes to both Android and iOS platforms:

  **Android**
  
  - **Minimum SDK raised**: Android 7.0 (API 24) - drops Android 5.x and 6.x support
  - **Kotlin upgrade**: 1.9.x → 2.1.20
  - **Android Gradle Plugin**: Requires AGP 8.0+
  
  **iOS**
  
  - **Minimum iOS version**: 16.0
  - **Swift Package Manager**: must be enabled in Flutter setup as the SDK is no longer distributed via CocoaPods.
  
  </TabItem>

  <TabItem value="react-native" label="React Native (TypeScript)">

  **v2:**
  
  ```bash
  npm install @microblink/blinkcard-react-native
  ```
  
  **v3000:**
  
  BlinkCard v3000 is available via [NPM](https://www.npmjs.com/), and the only significant change for the iOS native packages is that the distribution was switched from CocoaPods to directly packing native Xcframeworks in the project structure.

  ```bash
  npm install @microblink/blinkcard-react-native
  ```

  BlinkCard v3000 introduces significant changes to the React Native SDK, but also to both Android and iOS platforms:
  
  **React Native**

  - BlinkID React Native was built and tested with React Native v0.82.1 and was built with the new (Turbo module) architecture.
    - It is also compatible with React Native applications running on the old architecture as it contains backward compatibility with Native Module implementation.
  - v3000 is fully written in TypeScript for improved type safety and developer experience.
  
  **Android**

  - **Minimum SDK raised**: Android 7.0 (API 24) - drops Android 5.x and 6.x support
  - **Kotlin upgrade**: 1.9.x → 2.1.20
  - **Android Gradle Plugin**: Requires AGP 8.0+
  
  **iOS**

  - **Minimum iOS version**: 16.0
  - **Swift Package Manager**: must be enabled in Flutter setup as the SDK is no longer distributed via CocoaPods.
  
  </TabItem>

</Tabs>

## Import statement changes

<Tabs queryString="platform">
  <TabItem value="web" label="Web (JS)" default>

  **v2:**
  
  ```javascript
  import { createBlinkCardRecognizer } from "@microblink/blinkcard-in-browser-sdk";
  ```
  
  **v3000:**
  
  ```javascript
  // Main package (recommended for most use cases)
  import { createBlinkCard } from "@microblink/blinkcard";
  
  // Or for advanced usage with more control
  import { loadBlinkCardCore } from "@microblink/blinkcard-core";
  ```

  </TabItem>
  <TabItem value="android" label="Android (Kotlin)">

  **v2:**
  
  ```kotlin
  import com.microblink.blinkcard.entities.recognizers.Recognizer
  import com.microblink.blinkcard.entities.recognizers.RecognizerBundle
  import com.microblink.blinkcard.entities.recognizers.blinkcard.BlinkCardRecognizer
  import com.microblink.blinkcard.uisettings.BlinkCardUISettings
  import com.microblink.blinkcard.uisettings.UISettings
  ```
  
  **v3000:**
  
  ```kotlin
  import com.microblink.blinkcard.core.BlinkCardSdk
  import com.microblink.blinkcard.core.session.BlinkCardScanningSession
  import com.microblink.blinkcard.core.session.BlinkCardSessionSettings
  ```

  </TabItem>
  <TabItem value="ios" label="iOS (Swift)">

  **v2:**
  
  ```swift
  import BlinkCard
  ```
  
  **v3000:**
  
  ```swift
  import BlinkCard
  import BlinkCardUX  // If using the UX components
  ```

  </TabItem>

  <TabItem value="flutter" label="Flutter (Dart)">

  **v2:**
  
  ```dart
  import 'package:blinkcard_flutter/microblink_scanner.dart';
  ```
  
  **v3000:**
  
  ```dart
  import 'package:blinkcard_flutter/blinkcard_flutter.dart';
  ```
  </TabItem>
  <TabItem value="react-native" label="React Native (TypeScript)">

  **v2:**
  
  ```typescript
  import * as BlinkCardReactNative from '@microblink/blinkcard-react-native';
  ```
  
  **v3000:**
  
  ```typescript
  import { performScan, perfromDirectApiScan } from "@microblink/blinkcard-react-native";
  ```
  </TabItem>
</Tabs>

## Changes in scanning settings

### Changes in structure

The settings body used to be a flat object, with all items in the root level.

The settings structure is now hierarchical, with sub-structures that group related items:

<Tabs queryString="platform">
  <TabItem value="web" label="Web (JS)" default>
  
  **v2:**

  ```javascript
  await recognizer.updateSettings({
    allowBlurFilter: true,
    tiltDetectionLevel: DetectionLevel.Mid,
    paddingEdge: 0.02,
    extractCvv: true,
    extractIban: true,
    extractOwner: true,
    extractExpiryDate: true,
    allowInvalidCardNumber: false
  });
  ```

  **v3000:**

  ```javascript title="Scanning settings object"
  {
    skipImagesWithBlur: false,
    tiltDetectionLevel: "mid",
    inputImageMargin: 0.02,
    extractionSettings: {
      extractCvv: true,
      extractIban: true,
      extractCardholderName: true,
      extractExpiryDate: true,
      extractInvalidCardNumber: false
    }
  }
  ```

  </TabItem>
  <TabItem value="android" label="Android (Kotlin)">

  **v2:**

  ```kotlin
  recognizer.allowBlurFilter(true)
  recognizer.setTiltDetectionLevel(DetectionLevel.Mid)
  recognizer.setPaddingEdge(0.02f)
  recognizer.setExtractCvv(true)
  recognizer.setExtractIban(true)
  recognizer.setExtractOwner(true)
  recognizer.setExtractExpiryDate(true)
  recognizer.setAllowInvalidCardNumber(false)
  ```

  **v3000:**

  ```kotlin title="Scanning settings object"
  ScanningSettings(
      skipImagesWithBlur = false,
      tiltDetectionLevel = DetectionLevel.Mid,
      inputImageMargin = 0.02f,
      extractionSettings = ExtractionSettings(
          extractCvv = true,
          extractIban = true,
          extractCardholderName = true,
          extractExpiryDate = true,
          extractInvalidCardNumber = false
      )
  )
  ```

  </TabItem>
  <TabItem value="ios" label="iOS (Swift)">

  **v2:**

  ```swift
  recognizer.allowBlurFilter = true
  recognizer.tiltDetectionLevel = MBCDetectionLevel.mid
  recognizer.paddingEdge = 0.02
  recognizer.extractCvv = true
  recognizer.extractIban = true
  recognizer.extractOwner = true
  recognizer.extractExpiryDate = true
  recognizer.allowInvalidCardNumber = false
  ```

  **v3000:**

  ```swift title="Scanning settings object"
  ScanningSettings(
      skipImagesWithBlur: false,
      tiltDetectionLevel: .mid,
      inputImageMargin: 0.02,
      extractionSettings: ExtractionSettings(
          extractCvv: true,
          extractIban: true,
          extractCardholderName: true,
          extractExpiryDate: true,
          extractInvalidCardNumber: false
      )
  )
  ```

  </TabItem>

  <TabItem value="flutter" label="Flutter (Dart)">

  **v2:**

  ```dart
  recognizer.allowBlurFilter = true
  recognizer.tiltDetectionLevel = DetectionLevel.mid
  recognizer.paddingEdge = 0.02
  recognizer.extractCvv = true
  recognizer.extractIban = true
  recognizer.extractOwner = true
  recognizer.extractExpiryDate = true
  recognizer.allowInvalidCardNumber = false
  ```

  **v3000:**

  ```dart title="Scanning settings object"
  final scanningSettings = ScanningSettings(
    skipImagesWithBlur: true,
    tiltDetectionLevel: DetectionLevel.mid,
    inputImageMargin: 0.02,
    livenessSettings: LivenessSettings(),
    anonymizationSettings: AnonymizationSettings(),
    croppedImageSettings: CroppedImageSettings(),
    extractionSettings: ExtractionSettings(
      extractCvv: true,
      extractIban: true,
      extractCardholderName: true,
      extractExpiryDate: true,
      extractInvalidCardNumber: false,
    ),
  );
  ```

  </TabItem>

  <TabItem value="react-native" label="React Native (TypeScript)">

  **v2:**

  ```javascript
  recognizer.allowBlurFilter = true
  recognizer.tiltDetectionLevel = DetectionLevel.mid
  recognizer.paddingEdge = 0.02
  recognizer.extractCvv = true
  recognizer.extractIban = true
  recognizer.extractOwner = true
  recognizer.extractExpiryDate = true
  recognizer.allowInvalidCardNumber = false
  ```

  **v3000:**

  ```typescript title="Scanning settings object"
  const scanningSettings = new ScanningSettings({
    skipImagesWithBlur: true,
    tiltDetectionLevel: DetectionLevel.Mid,
    inputImageMargin: 0.02,
    livenessSettings: new LivenessSettings(),
    extractionSettings: new ExtractionSettings({
      extractIban: true,
      extractExpiryDate: true,
      extractCardholderName: true,
      extractCvv: true,
      extractInvalidCardNumber: false,
    }),
    croppedImageSettings: new CroppedImageSettings(),
    anonymizationSettings: new AnonymizationSettings(),
  });
  ```
  </TabItem>

</Tabs>

### Renamed settings

| v2 | v3000 | Notes |
|----|-------|-------|
| `extractOwner` | `extractCardholderName` | Moved to `extractionSettings` |
| `allowBlurFilter` | `skipImagesWithBlur` | Logic inverted: `true` now means skip blurred frames |
| `paddingEdge` | `inputImageMargin` | Same meaning, default changed from 0.0 to 0.02 |
| `allowInvalidCardNumber` | `extractInvalidCardNumber` | Moved to `extractionSettings` |
| `handScaleThreshold` | `handToCardSizeRatio` | Moved to `livenessSettings` |
| `handDocumentOverlapThreshold` | `handCardOverlapThreshold` | Moved to `livenessSettings` |
| `photocopyAnalysisMatchLevel` | `photocopyCheckStrictnessLevel` | Moved to `livenessSettings` |
| `screenAnalysisMatchLevel` | `screenCheckStrictnessLevel` | Moved to `livenessSettings` |
| `returnFullDocumentImage` | `returnCardImage` | Moved to `croppedImageSettings` |
| `ownerAnonymizationMode` | `cardholderNameAnonymizationMode` | Moved to `anonymizationSettings` |



<!-- interactive component omitted -->


  

<!-- interactive component omitted -->


  

<!-- interactive component omitted -->



  

<!-- interactive component omitted -->



  

<!-- interactive component omitted -->


</Tabs>

### Removed settings

- Setting JPEG encoding is no longer a separate option:
  - Web: removed `returnEncodedFullDocumentImage`
  - Android, iOS: removed `encodeFullDocumentImage`
- Liveness status no longer in settings:
  - Web: removed `documentLivenessCallback`
  - Android: removed `setLivenessStatusCallback()` 
  - iOS: removed `livenessStatusCallback` (the delegate method) 

### Added settings

| Setting | Location | Description |
|---------|----------|-------------|
| `enableCardHeldInHandCheck` | `livenessSettings` | Enables/disables the hand presence check |

### Nested settings details

In v3000, settings are organized into logical groups.
Here's what each group contains:

#### ExtractionSettings

Controls which fields should be extracted from the card:

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `extractIban` | boolean | `true` | Extract IBAN number |
| `extractExpiryDate` | boolean | `true` | Extract card expiry date |
| `extractCardholderName` | boolean | `true` | Extract cardholder name |
| `extractCvv` | boolean | `true` | Extract CVV security code |
| `extractInvalidCardNumber` | boolean | `false` | Accept card numbers that fail Luhn checksum validation |

#### CroppedImageSettings

Controls image cropping and return options:

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `dotsPerInch` | number | `250` | DPI value for cropped images |
| `extensionFactor` | number | `0.0` | Extension factor for cropped card image |
| `returnCardImage` | boolean | `false` | Whether to return the cropped card image |

#### LivenessSettings

Controls liveness detection parameters:

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `handToCardSizeRatio` | number | `0.15` | Minimum hand-to-card size ratio for valid hand detection |
| `handCardOverlapThreshold` | number | `0.05` | Minimum overlap threshold between hand and card |
| `enableCardHeldInHandCheck` | boolean | `true` | Enable/disable hand presence check |
| `screenCheckStrictnessLevel` | StrictnessLevel | `Level5` | Sensitivity for screen detection |
| `photocopyCheckStrictnessLevel` | StrictnessLevel | `Level5` | Sensitivity for photocopy detection |

#### AnonymizationSettings

Controls data anonymization:

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `cardNumberAnonymizationSettings` | object | See below | Card number anonymization configuration |
| `cardNumberPrefixAnonymizationMode` | AnonymizationMode | `None` | Card number prefix anonymization |
| `cvvAnonymizationMode` | AnonymizationMode | `None` | CVV anonymization |
| `ibanAnonymizationMode` | AnonymizationMode | `None` | IBAN anonymization |
| `cardholderNameAnonymizationMode` | AnonymizationMode | `None` | Cardholder name anonymization |

**CardNumberAnonymizationSettings:**

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `mode` | AnonymizationMode | `None` | Anonymization mode |
| `prefixDigitsVisible` | number | `0` | Number of prefix digits to keep visible |
| `suffixDigitsVisible` | number | `0` | Number of suffix digits to keep visible |

**AnonymizationMode values:**

| iOS, Android | Web               | Description                |
| ------------ | ----------------- | -------------------------- | 
| `None`       | `none`            | No anonymization           |
| `ImageOnly`  | `image-only`      | Anonymize in images only   |
| `ResultFieldsOnly` | `result-fields-only` | Anonymize in result fields only |
| `FullResult` | `full-result` | Anonymize in both images and result fields |

### StrictnessLevel changes

The `MatchLevel` enum has been renamed to `StrictnessLevel`:

<Tabs queryString="platform">
  <TabItem value="web" label="Web (JS)" default>

  ```typescript
  // v2
  enum MatchLevel {
    Disabled = 0,
    Level1 = 1,
    Level2 = 2,
    Level3 = 3,
    Level4 = 4,
    Level5 = 5,
    Level6 = 6,
    Level7 = 7,
    Level8 = 8,
    Level9 = 9,
    Level10 = 10
  }
  
  // v3000
  type StrictnessLevel = 
    | "disabled" 
    | "level-1" 
    | "level-2" 
    | "level-3" 
    | "level-4" 
    | "level-5" 
    | "level-6" 
    | "level-7" 
    | "level-8" 
    | "level-9" 
    | "level-10";
  ```

  **Key changes:**
  - Changed from `enum` to type union of string literals
  - Values changed from PascalCase (`Level1`) to kebab-case (`"level-1"`)
  - `Disabled` renamed to `"disabled"` (lowercase)
  
  </TabItem>
  <TabItem value="android" label="Android (Kotlin)">

  ```kotlin
  // v2
  enum class MatchLevel { Disabled, Level1, Level2, ..., Level10 }
  
  // v3000
  enum class StrictnessLevel { Disabled, Level1, Level2, ..., Level10 }
  ```

  </TabItem>
  <TabItem value="ios" label="iOS (Swift)">

  ```swift
  // v2
  enum MBCMatchLevel { disabled, level1, level2, ..., level10 }
  
  // v3000
  enum StrictnessLevel { disabled, level1, level2, ..., level10 }
  ```

  </TabItem>

  <TabItem value="flutter" label="Flutter (Dart)">

  ```dart
  // v2
  enum BlinkCardMatchLevel {
    @JsonValue(0)
    Disabled,
    @JsonValue(1)
    Level1,
    @JsonValue(2)
    Level2,
    @JsonValue(3)
    Level3,
    @JsonValue(4)
    Level4,
    @JsonValue(5)
    Level5,
    @JsonValue(6)
    Level6,
    @JsonValue(7)
    Level7,
    @JsonValue(8)
    Level8,
    @JsonValue(9)
    Level9,
    @JsonValue(10)
    Level10,
  }
  ```

  ```dart
  // v3000
  enum StrictnessLevel {
    @JsonValue("disabled")
    disabled,
    @JsonValue("level1")
    level1,
    @JsonValue("level2")
    level2,
    @JsonValue("level3")
    level3,
    @JsonValue("level4")
    level4,
    @JsonValue("level5")
    level5,
    @JsonValue("level6")
    level6,
    @JsonValue("level7")
    level7,
    @JsonValue("level8")
    level8,
    @JsonValue("level9")
    level9,
    @JsonValue("level10")
    level10,
  }
  ```

  **Key changes:**
  - Changed from `int` to `string` enums
  - All cases renamed from uppercase to lowercase to follow Dart's coding practices.
  
  </TabItem>

  <TabItem value="react-native" label="React-Native (TypeScript)" default>

  ```typescript
  // v2
  export const BlinkCardMatchLevel = Object.freeze(
    {
        Disabled: 0,
        Level1: 1,
        Level2: 2,
        Level3: 3,
        Level4: 4,
        Level5: 5,
        Level6: 6,
        Level7: 7,
        Level8: 8,
        Level9: 9,
        Level10: 10
    }
  );
  ```

  ```typescript
  // v3000
  export enum StrictnessLevel {
    Disabled = 'disabled',
    Level1 = 'level1',
    Level2 = 'level2',
    Level3 = 'level3',
    Level4 = 'level4',
    Level5 = 'level5',
    Level6 = 'level6',
    Level7 = 'level7',
    Level8 = 'level8',
    Level9 = 'level9',
    Level10 = 'level10',
  }
  ```
  **Key changes:**
  - Changed from `number` to `string` enums.
  
  </TabItem>

</Tabs>

## Changes in the result object

### Structural changes

The result structure in v3000 is organized differently:

1. **Per-side results**: Card data and images are now organized by side (`firstSideResult`, `secondSideResult`)
2. **Card accounts array**: The `cardAccounts` field now supports multiple payment accounts on a single card
3. **Liveness results**: Liveness checks are now per-side and include a new overall result

<Tabs queryString="platform">
  <TabItem value="web" label="Web (JS)" default>

  **v2 structure:**
  
  ```typescript
  {
    cardNumber: "1234567890123456",  
    cvv: "123",                      
    expiryDate: { /* ... */ },       
    owner: "John Doe",
    issuer: CardIssuer.Visa,  
    processingStatus: ProcessingStatus.Success, 
    
    firstSideFullDocumentImage: { /* ... */ },
    firstSideBlurred: false,
    
    documentLivenessCheck: {
      front: {
        screenCheck: { result: CheckResult.Pass, matchLevel: MatchLevel.Level5 },
        photocopyCheck: { result: CheckResult.Pass, matchLevel: MatchLevel.Level5 },
        handPresenceCheck: CheckResult.Pass
      },
      back: { /* ... */ }
    }
    // ... other fields
  }
  ```

  **v3000 structure:**

  ```typescript
  {
    issuingNetwork: "Visa",  // String (was enum)
    cardholderName: "John Doe",
    
    // Card account fields now in array (cardNumber, cvv, expiryDate moved here)
    cardAccounts: [
      {
        cardNumber: "1234567890123456",
        cvv: "123",
        expiryDate: { /* ... */ },
        // ...
      }
    ],
    overallCardLivenessResult: "pass",  // New field
    
    firstSideResult: {
      cardImage: { image: { /* ... */ } },
      cardLivenessCheckResult: {
        screenCheckResult: "pass",  // Simplified (no matchLevel)
        photocopyCheckResult: "pass",
        cardHeldInHandCheckResult: "pass"
      }
    },
    secondSideResult: { /* ... */ }
    // ... other fields
  }
  ```

  </TabItem>
  
  <TabItem value="android" label="Android (Kotlin)">

  **v2 structure:**
  
  ```kotlin
  result.cardNumber                   // "1234567890123456"
  result.cvv                          // "123"
  result.expiryDate                   // Date
  result.owner                        // "John Doe"
  result.issuer                       // CardIssuer.Visa (enum)
  result.processingStatus             // ProcessingStatus
  
  result.firstSideFullDocumentImage   // Image
  result.isFirstSideBlurred()         // Boolean
  
  result.documentLivenessCheck.front.screenCheck       // TieredCheck
  result.documentLivenessCheck.front.photocopyCheck    // TieredCheck
  result.documentLivenessCheck.front.handPresenceCheck // CheckResult
  result.documentLivenessCheck.back                    // ...
  // ... other fields
  ```

  **v3000 structure:**

  ```kotlin
  result.issuingNetwork              // String (was enum)
  result.cardholderName              // "John Doe"
  
  // Card account fields now in list
  result.cardAccounts[0].cardNumber  // "1234567890123456"
  result.cardAccounts[0].cvv         // "123"
  result.cardAccounts[0].expiryDate  // DateResult
  
  result.overallCardLivenessResult   // CheckResult (new)
  
  result.firstSideResult?.cardImage                              // CroppedImageResult
  result.firstSideResult?.cardLivenessCheckResult.screenCheckResult       // CheckResult
  result.firstSideResult?.cardLivenessCheckResult.photocopyCheckResult    // CheckResult
  result.firstSideResult?.cardLivenessCheckResult.cardHeldInHandCheckResult  // CheckResult
  result.secondSideResult            // ...
  // ... other fields
  ```

  </TabItem>

  <TabItem value="ios" label="iOS (Swift)">

  **v2 structure:**
  
  ```swift
  result.cardNumber                   // "1234567890123456"
  result.cvv                          // "123"
  result.expiryDate                   // MBCDate
  result.owner                        // "John Doe"
  result.issuer                       // MBCIssuer (enum)
  result.processingStatus             // MBCBlinkCardProcessingStatus
  
  result.firstSideFullDocumentImage   // MBCImage
  result.firstSideBlurred             // Bool
  
  result.documentLivenessCheck.front.screenCheck       // MBCTieredCheck
  result.documentLivenessCheck.front.photocopyCheck    // MBCTieredCheck
  result.documentLivenessCheck.front.handPresenceCheck // MBCCheckResult
  result.documentLivenessCheck.back                    // ...
  // ... other fields
  ```

  **v3000 structure:**

  ```swift
  result.issuingNetwork              // String (was enum)
  result.cardholderName              // "John Doe"
  
  // Card account fields now in array
  result.cardAccounts[0].cardNumber  // "1234567890123456"
  result.cardAccounts[0].cvv         // "123"
  result.cardAccounts[0].expiryDate  // DateResult
  
  result.overallCardLivenessResult   // CheckResult (new)
  
  result.firstSideResult?.cardImage                              // CroppedImageResult
  result.firstSideResult?.cardLivenessCheckResult.screenCheckResult       // CheckResult
  result.firstSideResult?.cardLivenessCheckResult.photocopyCheckResult    // CheckResult
  result.firstSideResult?.cardLivenessCheckResult.cardHeldInHandCheckResult  // CheckResult
  result.secondSideResult            // ...
  // ... other fields
  ```

  </TabItem>

  <TabItem value="flutter" label="Flutter (Dart)">

  **v2 structure:**
  
  ```dart
  result.cardNumber                   // "1234567890123456"
  result.cvv                          // "123"
  result.expiryDate                   // Date
  result.owner                        // "John Doe"
  result.issuer                       // Issuer (enum)
  result.processingStatus             // BlinkCardProcessingStatus
  
  result.firstSideFullDocumentImage   // Base64 String
  result.firstSideBlurred             // Bool
  
  result.documentLivenessCheck.front.screenCheck       // BlinkCardCheckResult
  result.documentLivenessCheck.front.photocopyCheck    // BlinkCardCheckResult
  result.documentLivenessCheck.front.handPresenceCheck // BlinkCardCheckResult
  result.documentLivenessCheck.back                    // ...
  // ... other fields
  ```

  **v3000 structure:**

  ```dart
  result.issuingNetwork              // String (was enum)
  result.cardholderName              // "John Doe"
  
  // Card account fields now in array
  result.cardAccounts[0].cardNumber  // "1234567890123456"
  result.cardAccounts[0].cvv         // "123"
  result.cardAccounts[0].expiryDate  // DateResult<String>
  
  result.overallCardLivenessResult   // CheckResult (new)
  
  result.firstSideResult?.cardImage                              // CroppedImageResult
  result.firstSideResult?.cardLivenessCheckResult.screenCheckResult       // CheckResult
  result.firstSideResult?.cardLivenessCheckResult.photocopyCheckResult    // CheckResult
  result.firstSideResult?.cardLivenessCheckResult.cardHeldInHandCheckResult  // CheckResult
  result.secondSideResult            // BlinkCardSingleSideScanningResult
  // ... other fields
  ```

  </TabItem>

  <TabItem value="react-native" label="React Native (TypeScript)">

  **v2 structure:**
  
  ```javascript
  result.cardNumber                   // "1234567890123456"
  result.cvv                          // "123"
  result.expiryDate                   // Date
  result.owner                        // "John Doe"
  result.issuer                       // Issuer (enum)
  result.processingStatus             // BlinkCardProcessingStatus
  
  result.firstSideFullDocumentImage   // Base64 String
  result.firstSideBlurred             // Bool
  
  result.documentLivenessCheck.front.screenCheck       // BlinkCardCheckResult
  result.documentLivenessCheck.front.photocopyCheck    // BlinkCardCheckResult
  result.documentLivenessCheck.front.handPresenceCheck // BlinkCardCheckResult
  result.documentLivenessCheck.back                    // ...
  // ... other fields
  ```

  **v3000 structure:**

  ```typescript
  result.issuingNetwork              // String (was enum)
  result.cardholderName              // "John Doe"
  
  // Card account fields now in array
  result.cardAccounts[0].cardNumber  // "1234567890123456"
  result.cardAccounts[0].cvv         // "123"
  result.cardAccounts[0].expiryDate  // DateResult<string>
  
  result.overallCardLivenessResult   // CheckResult (new)
  
  result.firstSideResult?.cardImage                              // CroppedImageResult
  result.firstSideResult?.cardLivenessCheckResult.screenCheckResult       // CheckResult
  result.firstSideResult?.cardLivenessCheckResult.photocopyCheckResult    // CheckResult
  result.firstSideResult?.cardLivenessCheckResult.cardHeldInHandCheckResult  // CheckResult
  result.secondSideResult            // BlinkCardSingleSideScanningResult
  // ... other fields
  ```

  </TabItem>

</Tabs>

### Moved fields

Fields that haven't been renamed, but just moved, now live in the objects inside the `cardAccounts` array.
These are:

- `cardNumber`
- `cardNumberPrefix`
- `cardNumberValid`
- `cvv`
- `expiryDate`

### Renamed (and moved) fields

- `owner` -> `cardholderName`
- `issuer` -> `issuingNetwork`
  - Changed from enum to string
- `firstSideFullDocumentImage` -> `firstSideResult.cardImage`
  - Now nested in side result
- `secondSideFullDocumentImage` -> `secondSideResult.cardImage`
  - Now nested in side result
- `firstSideBlurred` -> `inputImageAnalysisResult.blurDetectionStatus`
  - Now in ProcessResult
- `secondSideBlurred` -> `inputImageAnalysisResult.blurDetectionStatus`
  - Now in ProcessResult
- `documentLivenessCheck` -> `cardLivenessCheckResult`
  - Split per-side
- `documentLivenessCheck.front.screenCheck.result` -> `firstSideResult.cardLivenessCheckResult.screenCheckResult`
  - Simplified (no matchLevel)
- `documentLivenessCheck.front.photocopyCheck.result` -> `firstSideResult.cardLivenessCheckResult.photocopyCheckResult`
  - Simplified (no matchLevel)
- `documentLivenessCheck.front.handPresenceCheck` -> `firstSideResult.cardLivenessCheckResult.cardHeldInHandCheckResult`

### Removed fields

- Encoded image has been removed from the result:
  - Web: 
    - `firstSideFullDocumentImage.encodedImage` 
    - `secondSideFullDocumentImage.encodedImage`
  - iOS, Android, Flutter, React Native:
    - `encodedFirstSideFullDocumentImage` 
    - `encodedSecondSideFullDocumentImage`
- `scanningFirstSideDone`
- `firstSideAnonymized`
- `secondSideAnonymized`
- `processingStatus` 
- Match levels no longer exposed in results:
  - Web, Android, Flutter, React Native:
    - `documentLivenessCheck.front.screenCheck.matchLevel` 
    - `documentLivenessCheck.front.photocopyCheck.matchLevel`
  - iOS:
    - `documentLivenessCheck.front.screenCheck.level`
    - `documentLivenessCheck.front.photocopyCheck.level`

### New fields

- `overallCardLivenessResult`
  - Aggregated liveness check across all sides. 
  - Possible values (web): `"not-available"`, `"pass"`, `"fail"`
  - Possible values (iOS, Android): `"NotPerformed"`, `"Pass"`, `"Fail"`
- `cardHeldInHandCheckResult`
  - Result of the hand presence check (per-side). 
  - Possible values (web): `"not-available"`, `"pass"`, `"fail"`
  - Possible values (iOS, Android): `"NotPerformed"`, `"Pass"`, `"Fail"`
- `cardAccounts`
  - Supports multiple payment accounts on a card
- `cardAccounts[].fundingType`
  - Optional: Card funding type (e.g., "DEBIT", "CREDIT", "CHARGE CARD")
- `cardAccounts[].cardCategory`
  - Optional: Card category (e.g., "PERSONAL", "BUSINESS", "PREPAID")
- `cardAccounts[].issuerName`
  - Optional: Name of the issuing financial institution
- `cardAccounts[].issuerCountryCode`
  - Optional: ISO 3166-1 alpha-3 country code (e.g., "USA", "GBR", "HRV")
- `cardAccounts[].issuerCountry`
  - Optional: Name of the issuer's country

#### CardAccountResult structure

The `cardAccounts` field is now an array that can contain multiple payment accounts.
Each `CardAccountResult` contains:

<Tabs queryString="platform">
  <TabItem value="web" label="Web (JS)" default>

  ```typescript
  {
    cardNumber: string;
    cardNumberValid: boolean;
    cardNumberPrefix: string | undefined;
    cvv: string | undefined;
    expiryDate: DateResult;
    fundingType: string | undefined;  // New in v3000
    cardCategory: string | undefined;  // New in v3000
    issuerName: string | undefined;  // New in v3000
    issuerCountryCode: string | undefined;  // New in v3000
    issuerCountry: string | undefined;  // New in v3000
  }
  ```

  </TabItem>
  <TabItem value="android" label="Android (Kotlin)">

  ```kotlin
  data class CardAccountResult(
      val cardNumber: String,
      val cardNumberValid: Boolean,
      val cardNumberPrefix: String?,
      val cvv: String?,
      val expiryDate: DateResult<String>?,
      val fundingType: String?,  // New in v3000
      val cardCategory: String?,  // New in v3000
      val issuerName: String?,  // New in v3000
      val issuerCountryCode: String?,  // New in v3000
      val issuerCountry: String?  // New in v3000
  )
  ```

  </TabItem>
  <TabItem value="ios" label="iOS (Swift)">

  ```swift
  struct CardAccountResult {
      var cardNumber: String
      var cardNumberValid: Bool
      var cardNumberPrefix: String?
      var cvv: String?
      var expiryDate: DateResult?
      var fundingType: String?  // New in v3000
      var cardCategory: String?  // New in v3000
      var issuerName: String?  // New in v3000
      var issuerCountryCode: String?  // New in v3000
      var issuerCountry: String?  // New in v3000
  }
  ```

  </TabItem>

  <TabItem value="flutter" label="Flutter (Dart)">

  ```dart
  final class CardAccountResult {
    final String cardNumber;
    final bool cardNumberValid;
    final String? cardNumberPrefix;
    final String? cvv;
    final DateResult<String>? expiryDate;
    final String? fundingType; // New in v3000
    final String? cardCategory; // New in v3000
    final String? issuerName; // New in v3000
    final String? issuerCountryCode; // New in v3000
    final String? issuerCountry; // New in v3000
  }
  ```

  </TabItem>

  <TabItem value="react-native" label="React Native (TypeScript)">

  ```typescript
  export class CardAccountResult {
    cardNumber: string;
    cardNumberValid: boolean;
    cardNumberPrefix?: string;
    cvv?: string;
    expiryDate: DateResult<string>;
    fundingType?: string; // New in v3000
    cardCategory?: string; // New in v3000
    issuerName?: string; // New in v3000
    issuerCountryCode?: string; // New in v3000
    issuerCountry?: string; // New in v3000
  ```
  </TabItem>

</Tabs>

### Processing status changes

Processing status and other frame-level information is now available in the `ProcessResult` object returned during scanning.
This provides real-time feedback about the scanning process on a per-frame basis.

<Tabs queryString="platform">
  <TabItem value="web" label="Web (JS)" default>

  **Example of what you'll see when logging the ProcessResult:**
  
  ```javascript
  {
    inputImageAnalysisResult: {
      processingStatus: "success",  // or "detection-failed", "image-preprocessing-failed", etc.
      scanningSide: "first",  // or "second"
      detectionStatus: "success",  // or "failed", "camera-too-far", "camera-too-close", etc.
      cardLocation: {
        upperLeft: 123,
        upperRight: 456,
        lowerRight: 789,
        lowerLeft: 012
      },
      blurDetectionStatus: "not-detected",  // or "detected", "not-available"
      cardRotation: "zero"  // or "clockwise-90", "counter-clockwise-90", "upside-down", "not-available"
    },
    resultCompleteness: {
      scanningStatus: "scanning-side-in-progress",  // or "side-scanned", "card-scanned"
      cardNumberExtractionStatus: "extracted",  // or "not-available", "not-requested", "not-present", "not-extracted"
      cardNumberPrefixExtractionStatus: "extracted",
      expiryDateExtractionStatus: "not-present",
      cardholderNameExtractionStatus: "extracted",
      cvvExtractionStatus: "not-requested",
      ibanExtractionStatus: "not-present",
      cardImageExtractionStatus: "extracted"
    }
  }
  ```

  </TabItem>
  <TabItem value="android" label="Android (Kotlin)">

  **Example of what you'll see when logging the ProcessResult:**
  
  ```kotlin
  BlinkCardProcessResult(
      inputImageAnalysisResult = InputImageAnalysisResult(
          processingStatus = ProcessingStatus.Success,  // or DetectionFailed, ImagePreprocessingFailed, etc.
          scanningSide = ScanningSide.First,  // or Second
          detectionStatus = DetectionStatus.Success,  // or Failed, CameraTooFar, CameraTooClose, etc.
          cardLocation = Quadrilateral(
              upperLeft = Point(123, 456),
              upperRight = Point(789, 456),
              lowerRight = Point(789, 012),
              lowerLeft = Point(123, 012)
          ),
          blurDetectionStatus = ImageAnalysisDetectionStatus.NotDetected,  // or Detected, NotAvailable
          cardRotation = CardRotation.Zero  // or Clockwise90, CounterClockwise90, UpsideDown, NotAvailable
      ),
      resultCompleteness = ResultCompleteness(
          scanningStatus = ScanningStatus.ScanningSideInProgress,  // or SideScanned, CardScanned
          cardNumberExtractionStatus = FieldExtractionStatus.Extracted,  // or NotAvailable, NotRequested, NotPresent, NotExtracted
          cardNumberPrefixExtractionStatus = FieldExtractionStatus.Extracted,
          expiryDateExtractionStatus = FieldExtractionStatus.NotPresent,
          cardholderNameExtractionStatus = FieldExtractionStatus.Extracted,
          cvvExtractionStatus = FieldExtractionStatus.NotRequested,
          ibanExtractionStatus = FieldExtractionStatus.NotPresent,
          cardImageExtractionStatus = ImageExtractionStatus.Extracted
      )
  )
  ```

  </TabItem>
  <TabItem value="ios" label="iOS (Swift)">

  **Example of what you'll see when logging the ProcessResult:**
  
  ```swift
  BlinkCardSDK.ProcessResult(
      inputImageAnalysisResult: InputImageAnalysisResult(
          processingStatus: .success,  // or .detectionFailed, .imagePreprocessingFailed, etc.
          scanningSide: .first,  // or .second
          detectionStatus: .success,  // or .failed, .cameraTooFar, .cameraTooClose, etc.
          cardLocation: Quadrilateral(
              upperLeft: Point(x: 123, y: 456),
              upperRight: Point(x: 789, y: 456),
              lowerRight: Point(x: 789, y: 012),
              lowerLeft: Point(x: 123, y: 012)
          ),
          blurDetectionStatus: .notDetected,  // or .detected, .notAvailable
          cardRotation: .zero  // or .clockwise90, .counterClockwise90, .upsideDown, .notAvailable
      ),
      resultCompleteness: ResultCompleteness(
          scanningStatus: .scanningSideInProgress,  // or .sideScanned, .cardScanned
          cardNumberExtractionStatus: .extracted,  // or .notAvailable, .notRequested, .notPresent, .notExtracted
          cardNumberPrefixExtractionStatus: .extracted,
          expiryDateExtractionStatus: .notPresent,
          cardholderNameExtractionStatus: .extracted,
          cvvExtractionStatus: .notRequested,
          ibanExtractionStatus: .notPresent,
          cardImageExtractionStatus: .extracted
      )
  )
  ```

  </TabItem>
</Tabs>

**Key differences from v2:**

- `processingStatus` moved from the final result to per-frame `ProcessResult`
- New `resultCompleteness` provides detailed extraction status for each field
- `scanningStatus` indicates overall progress (`scanning-side-in-progress`, `side-scanned`, `card-scanned`)
- Blur detection status is now in `inputImageAnalysisResult.blurDetectionStatus`

## Resource management

BlinkCard v3000 requires recognition resources (models and configuration files) to perform card scanning.
The SDK supports different approaches for managing these resources depending on the platform.

### Web

Resources are loaded from a specified path (typically hosted on your server or CDN):

```javascript
const blinkCard = await createBlinkCard({
  licenseKey: "your-license-key",
  resourcesLocation: "https://example.com",  // URL for WASM and model files; we append "/resources" to this value
  // ... other settings
});
```

**Best practices:**
- Host resources on the same domain to avoid CORS issues
- Use a CDN for better performance and caching
- Ensure resources are served with appropriate cache headers

### iOS

BlinkCard SDK supports both downloaded and bundled resources:

```swift
let settings = BlinkCardSdkSettings(
    licenseKey: "your-license-key",
    downloadResources: true,  // true = download, false = use bundled
    resourceLocalFolder: "BlinkCard"  // Optional custom storage location
)
```

**Downloaded resources:**
- Smaller app bundle size
- Resources downloaded on first use
- Requires network connection on first launch

**Bundled resources:**
- Larger app bundle size
- No network call for resources
- Immediate availability

### Android

Similar to iOS, Android supports both downloaded and bundled resources:

```kotlin
val settings = BlinkCardSdkSettings(
    licenseKey = "your-license-key",
    downloadResources = true,  // true = download, false = use bundled
    resourceLocalFolder = "BlinkCard"  // Optional custom storage location
)
```

### Flutter

For the Flutter SDK, in `BlinkCardSdkSettings` object, both native platforms need to be configured:

```dart
final sdkSettings = BlinkCardSdkSettings(
  licenseKey: "your-blinkcard-license-key",
  downloadResources: false, // true = download, false = use bundled
  resourceLocalFolder: "BlinkCard", // Optional custom storage location - match the folder names in Android and iOS applications
  bundleIdentifier: "com.myiOSapplication", // iOS-specific - need to provide the applications Bundle Identifier
);
``` 

### React Native

Similar to Flutter, both native platforms need to be configured in `BlinkCardSdkSettings`:
```typescript
  const sdkSettings = new BlinkCardSdkSettings({
    licenseKey: 'your-blinkcard-license-key',
    downloadResources: false, // true = download, false = use bundled
    resourceLocalFolder: 'BlinkCard', // Optional custom storage location - match the folder names in Android and iOS applications
    bundleIdentifier: 'com.myiOSapplication', // iOS-specific - need to provide the applications Bundle Identifier
  });
```

--------

## V2 maintenance

With the v3000 release, v2 goes into maintenance mode.

This means that v2 will stop receiving feature updates, but in case of security issues, it will be patched.

For product improvements, better scanning performance, etc., please use v3000.


Last updated on Aug 11, 2026
