Updated 9 min readBy Lena Hoffmann

Integrate Photo Payment with Flutter

This guide implements a complete asynchronous Dart flow for native Photo Payment on Android and iOS.

The Flutter plugin opens Docutain's native capture UI, recognizes GiroCode or invoice data locally and returns structured JSON. The app maps that result into its own reviewed and authorized payment process.

Targets
Android and iOS
Plugin
docutain_sdk
Result
Nullable JSON string
Processing
Local in the native SDK
Jump to the Flutter setup

The Flutter-to-native payment workflow

  1. A Flutter button invokes the Docutain plugin.
  2. The plugin presents the native Android or iOS capture and review experience.
  3. Docutain reads a GiroCode when available or extracts payment fields from invoice text.
  4. The awaited Future returns JSON, an empty string or null.
  5. Dart maps the data to an application model before the host app shows and authorizes the payment.

Prepare the Android and iOS targets

AreaRequirement
FlutterCurrent Flutter SDK and the docutain_sdk plugin
AndroidAndroid 5.0+, compileSdk 34+ and Android Gradle Plugin 8.0.2+
iOSiOS 11+ and an NSCameraUsageDescription
LicenseA key matching Android applicationId and iOS bundle identifier
EvaluationRepresentative physical Android and iOS devices

For Android, follow the documented memory configuration for high-resolution images. On iOS, the app can run in the Simulator, but Docutain processing must be evaluated on a physical device.

Install and initialize the Flutter plugin

1. Add the dependency

dependencies:
  docutain_sdk: ^2.1.0
flutter pub get

2. Initialize before displaying the payment action

Future<bool> initializeDocutain() async {
  final initialized = await DocutainSdk.initSDK(
    '<YOUR-LICENSE-KEY>',
  );

  if (!initialized) {
    // Read the SDK error and keep Photo Payment disabled.
    final error = await DocutainSdk.getLastError();
    reportInitializationError(error);
  }

  return initialized;
}

Launch Photo Payment and handle all three outcomes

Future<void> startPhotoPayment() async {
  final config = PhotoPaymentConfiguration();
  final paymentData =
      await DocutainSdkUi.startPhotoPayment(config);

  if (paymentData == null) {
    return; // The user canceled the flow.
  }

  if (paymentData.isEmpty) {
    // No data was found. This is reachable when the
    // Empty Result Screen has been disabled.
    showManualEntry();
    return;
  }

  // Decode the JSON, apply app rules and prefill a draft.
  processPaymentData(paymentData);
}

Guard the UI action while the Future is pending. A second tap should not start another native flow before the first one returns.

Decode the JSON into a typed Dart model

{
  "Address": {
    "Name1": "Sanitär Krause",
    "Zipcode": "56068",
    "City": "Koblenz",
    "Street": "Musterstraße 17",
    "Bank": [{
      "BIC": "MALADE51KOB",
      "IBAN": "DE58570501200094710328"
    }]
  },
  "Date": "2026-04-17",
  "Amount": "359.44",
  "InvoiceId": "2026-0417",
  "Reference": "Invoice 2026-0417",
  "PaymentState": "ToBePaid",
  "SEPACreditor": "Sanitär Krause"
}

SEPACreditor is the payment recipient. Make fields nullable in the Dart model and reject malformed JSON without losing the user's current payment draft. Although Docutain only returns valid IBANs, the app must verify the intended recipient, amount and reference before authorization.

Configure analysis and the no-result path

PhotoPaymentConfiguration also controls capture behavior, page editing, onboarding, Scan Tips, colors and the Empty Result Screen. Use analyzeConfig only for fields your payment model actually needs.

final config = PhotoPaymentConfiguration();

// Add the optional paid/to-be-paid classification.
config.analyzeConfig.readPaymentState = true;

final paymentData =
    await DocutainSdkUi.startPhotoPayment(config);

Disabling BIC changes the returned bank-data shape to an IBAN list, so update the mapper at the same time. Keep the default Empty Result Screen during evaluation: it offers retry and cancel when no IBAN, recipient or amount could be read.

GiroCode and text recognition share the same Photo Payment entry point. This removes the need for a separate barcode choice in the Flutter UI.

Test Flutter state and native camera behavior

  • Start with the Android and iOS Showcase Apps, then use a trial license in the Flutter app.
  • Test the same approved invoice corpus on representative physical devices.
  • Include paper, folded and screen-displayed invoices, files and GiroCodes.
  • Measure field-level correctness and manual corrections—not only whether JSON was returned.
  • Test null, empty result, initialization failure and malformed JSON explicitly.
  • Verify widget disposal, app backgrounding and double-tap prevention while the native UI is open.
  • Run TalkBack and VoiceOver tests for both the native capture flow and Flutter payment form.

Official resources

Technical sources last checked on September 13, 2026.

FREQUENTLY ASKED QUESTIONS

Flutter Photo Payment integration




Contact us and receive your quote

Our pricing is tailored to your use case. Let our colleague Harry Beck know how we can help and receive your quote.




Information about how we process your details is available in our Privacy Policy.