iOS Migration

Upgrade Paths

From 2023.x to 2025.0.0

New

Changed

Platform Compatibility

No change in requirements from 2023.1.2. If upgrading from the earlier 2023.x release, the following significant updates should eb considered:

  • The legacy universal framework distribution is no longer provided. The SDK is now distributed only in .xcframework format.
  • Minimal iOS version is 16.0
  • Xcode 16.2

Please review the latest Supported Platforms for more information.

Common

In this release a more consistent namespacing was introduced for major SDK use cases (SensibillSDK, Capture, CaptureFlow, SMUI and Branding). This caused the need to rename the following components:

Previous NameNew Name
CredentialsSensibillSDK.Credentials
AnalyticsSensibillSDK.Analytics
TrackingEventSensibillSDK.Analytics.TrackingEvent
EventListenerSensibillSDKAnalyticsEventListener
CaptureNavigationControllerCapture.NavigationController
CaptureResultCapture.CompletionResult
CaptureFlowCoordinatorCaptureFlow.Coordinator
CaptureFlowCoordinator.DidFinishCaptureResultCaptureFlow.ProcessingInfo
DocumentMetadataCaptureFlow.DocumentMetadata

Capture

  • Advanced Tips feature customization was moved from UIParts to Capture namespace.

      // Prior to 2025.0, could be accessed as follows:
      let tipsScreenStyle = UIParts.TipsFeature.TipsScreenStyle(...)
    
      // With 2025.0, both elements are accessed in the same way:
      let tipsScreenStyle = Capture.TipsFeature.TipsScreenStyle(...)
  • The elements used for advanced Capture customization via Capture.RuntimeSettings modification, were moved from Capture.RuntimeSettings and UIParts namespaces to Capture.Theme namespace.

    For example:

      // Prior to 2025.0, could be accessed as follows:
      let cropShapeStyle = Capture.RuntimeSettings.CropShape(...)
      let doneButtonStyle = UIParts.MainActionButtonStyle(...)
    
      // With 2025.0, both elements are accessed in the same way:
      let cropShapeStyle = Capture.Theme.CropShape(...)
      let doneButtonStyle = Capture.Theme.MainActionButtonStyle(...)

Capture Flow

  • Document Monitoring. Access to add/remove observer was simplified. Instead of SensibillSDK.shared.documentUploadService these functions can be accessed directly from SensibillSDK, i.e.:
      // Before 2025.0
      SensibillSDK.shared.documentUploadService.addObserver(...)
      SensibillSDK.shared.documentUploadService.removeObserver(...)
    
      // With 2025.0
      SensibillSDK.addObserver(...)
      SensibillSDK.removeObserver(...)

Discontinued

Headless Access

Sensibill SDK no longer provides a direct headless access to Sensibill API client and SDK services. This includes the following changes:

  • Access to SensibillAPIClient, which could be accessed via SensibillSDK.shared.apiClient, and provided a library of Sensibill APi requests and models, is no longer provided. You can implement a custom client which allows the same functionality. This change also made the following classes, protocols and namespaces unavailable:

    AuthenticationEndpointsProvider, DocumentsEndpointsProvider, EmailAccountsEndpointsProvider, EmailsEndpointsProvider, EndpointsProvider, ExportsEndpointsProvider, FoldersEndpointsProvider, HomeEndpointsProvider, InterceptsEndpointsProvider, LookupsEndpointsProvider, MerchantsEndpointsProvider, ReceiptsEndpointsProvider, RemindersEndpointsProvider, SensibillAPIProvider, TaskContextProvider, UserAccessTokenDelegate, UsersEndpointsProvider, EndpointVersion, SensibillAPIModel, SensibillAPIModelDocumentType
  • Access to IdentityService, which could be accessed via SensibillSDK.shared.identityService, and allowed to access client and user identity information, is no longer provided. You can obtain the same information by implementing direct requests to Sensibill API:

    • users/{userID} request to obtain user information
    • clientInfo request to obtain client information
  • Access to DocumentUploadService, which could be accessed via SensibillSDK.shared.documentUploadService is no longer provided.

    • Access to addObserver and removeObserver (used for Capture Flow use case) is now available directly through SensibillSDK. See Migrate > Capture Flow section above.
    • Access to functions that allowed adding and removing documents for uploading is no longer provided. Implement Full SDK or Capture Flow use cases to take the advantage of fascilitated upload, or implement custom request to Sensibill API’s’ POST .../v2/document

Other

  • The following components, which are no longer available publicly, didn’t provide any value to integrators, and shouldn’t have been used:

    ClientIdentity, DetectedReceipt, IdentityBasedService, SensibillSDK.StateProvider, UserIdentity, BrandingMetadataProvider, CredentialsDelegate, UIParts

From 2022.0.6 to 2025.0.0

New

  • In 2023.0 the various branding options in the SDK were unified into a Branding object. The main idea behind the Branding was to allow the integrator override any colors, fonts, images, and strings in any way they like, while providing guaranteed defaults to any parts of branding which were not customized. See iOS Branding Basics for more details on Branding concepts and usage.

Changed

Platform Compatibility

  • The legacy universal framework distribution is no longer provided. The SDK is now distributed only in .xcframework format.
  • Minimal iOS version is 16.0
  • Xcode 16.2

Common

Naming

Between 2023.0 and 2025.0 releases, we introduced namespacing for major SDK use cases (SensibillSDK, Capture, CaptureFlow, SMUI and Branding). This caused the need to rename the following components:

Previous NameNew Name
CredentialsSensibillSDK.Credentials
AnalyticsSensibillSDK.Analytics
TrackingEventSensibillSDK.Analytics.TrackingEvent
EventListenerSensibillSDKAnalyticsEventListener
CaptureFeatureFlagsCapture.FeatureFlags
CaptureResultCapture.CompletionResult
CaptureNavigationControllerCapture.NavigationController
CaptureFlowCoordinatorCaptureFlow.Coordinator
SDKConfiguration

SDKConfiguration, used by all SDK use caases, was replaced with Branding in SDK 2023.0. See iOS Branding Basics for more details on Branding concepts and usage.

Branding object is not a singleton, like SDKConfiguration was. It is provided as part of SensibillSDK.Configuration object on SensibillSDK.start. Also Branding object is created with defaults for all properties, so the integrator can change only items they are interested to customize.

The basic Branding setup is as follows:

// Start from default branding
let branding = Branding()

// Override any aspects of branding (all overrides are optional)
branding.colors = MyCustomColors() // BrandingColorsProvider
branding.fonts = MyCustomFonts() // BrandingFontsProvider
branding.images = MyCustomImages() // BrandingImagesProvider
branding.localization = MyCustomLocalization() // BrandingL10NProvider

// For Full SDK or Capture Flow use cases, 
// create a configuration, and pass it to SensibillSDK.start
let configuration = SensibillSDK.Configuration(
  environment: .beta,
  branding: branding
)
SensibillSDK.start(..., configuration: configuration, ...)

// For Standalone Capture, 
// create Capture.RuntimeSettings, and pass them to Capture.NavigationController
let receiptRuntimeSettings = Capture.RuntimeSettings.receipt(branding: branding) 
let captureNavigationController = Capture.NavigationController(settings: receiptRuntimeSettings) 

The following provides the guidance on migration of every property:

  • Color Customization: SDKConfiguration.colors is replaced with branding.colors. To customize, implement BrandingColorsProvider, and override any colors you wish to customize.

    Example:

      // You can override colors used by all SDK components
      var primary: Color { Color(red: 0.91, green: 0.57, blue: 0.30) }
    
      // You can override Capture-specific colors
      var captureBackground: Color { .indigo }
  • Font Customization: SDKConfiguration.fonts and SDKConfiguration.sensibillUI.webFonts are replaced with branding.fonts. To customize, implement BrandingFontsProvider, and override any fonts you wish to customize.

    Example:

      class MyCustomFonts: BrandingFontsProvider {
          // Override some fonts used for Capture and SDK screens (e.g. Errors)
          // No need to override every font
          var caption: Sensibill.Branding.FontDefinition {
            Branding.FontDefinition(name: Faces.elegant, size: 12, style: .largeTitle)
          }
    
          // Override fonts provided to Sensibill Web UI (replaces sensibillUI.webFonts)
          var forWebUI: (family: String, url: String)? {
              (
                  family: "Lobster, Times, serif",
                  url: "https://fonts.googleapis.com/css2?family=Lobster&display=swap"
              )
          }
      }
  • Image Customization: previously only allowed overriding images by providing imageset with exactly the same name as the one you override. With branding.images, you can store images in any way you want. Implement BrandingImagesProvider, and override any images you like. You can use system images, or custom imagesets stored in any bundle, with any names.

    Example:

      class MyCustomImages: BrandingImagesProvider {
        // Only override images you want to change
        // No need to override every image
    
        // Using system image
        var captureTipsIcon: UIImage {
          UIImage(systemName: Images.info)!
        }
    
        // Or using custom imageset in custom bundle
        var captureCloseIcon: UIImage {
          UIImage(named: "myImage", in: Bundle(identifier: "myCustomBundle"), with: nil)!
        }
      }
      // ...
      branding.images = MyCustomImages()
  • SDKConfiguration.capture provided the ability to specify various aspects of Capture configuration. This property is now replaced by Branding and Capture.FeatureFlags as explained below:

    • Capture feature flags: renamed to Capture.FeatureFlags, Capture feature flags can be provided, much like branding to SensibillSDK.Configuration (Full SDK, Capture Flow use cases), or Capture.RuntimeSettings (Standalone Capture):

        let featureFlags: Capture.FeatureFlags = .default
        featureFlags.attachLocationData = true // An example of modified feature flag
      
        // For Full SDK or Capture Flow use cases, 
        // create a configuration, and pass it to SensibillSDK.start
        let configuration = SensibillSDK.Configuration(
          environment: .beta,
          captureFeatureFlags: featureFlags
        )
        SensibillSDK.start(..., configuration: configuration, ...)
      
        // For Standalone Capture, 
        // create Capture.RuntimeSettings, and pass them to Capture.NavigationController
        let receiptRuntimeSettings = Capture.RuntimeSettings.receipt(featureFlags: featureFlags) 
        let captureNavigationController = Capture.NavigationController(settings: receiptRuntimeSettings)
    • Capture UI Customization: the overall branding of the capture was unified with the rest of the SDK in Branding object (see above). In case an advanced customization of the specific elements is needed (such that doesn’t match the rest of the branding), it can be done in Capture.RuntimeSettings object. See Capture Customization section.

    • Tips Customization: is done through Branding object as well. See Customizeing Tips page.

  • externalBundle provided an ability to specify where to look for images, fonts and strings.

    • With Branding, integrator has a complete freedom on where and how to store images and fonts. See Image Customization section above for an example.
    • Bundle still can be provided for localizations as a static property of Branding (you can initialize it at any point before starting SDK):
      Branding.Resources.localizationBundle = Bundle(...)
      This property is used by a default implementation of BrandingL10NProvider. Alternatively you can implement your own BrandingL10NProvider (to resolve strings and localizations in any way you like) and assign it to branding.localization as shown above.
  • certificatePinningEnabled was removed, no longer supported by Sensibill API.

Full SDK

SensibillSDK.start
  • Sensibill.plist is no longer used and should be removed from the app.

  • SensibillSDK.start have changed:

      class func start(
          userIdentifier: String, // renamed from cacheIdentifier
          tokenProvider: TokenProvider, // moved to 2nd place
          configuration: SensibillSDK.Configuration, // NEW, see explanation below
          completion: @escaping (Result<Void, Error>) -> Void // CHANGED, see explanation below
      )
    • The argument configuration replaces Sensibill.plist and defines Sensibill API environment to be used.

    • The completion signature was changed to return Result<Void, Error> instead of Error?. Note: the function with Error? as a callback result is still provided for usage with Objective-C.

    • The async version of the function was introduced as an alternative for the cases where it’s more convenient than a traditional function with callback.

    • Version for use with Objective-C is also available.

    Please follow the detailed instructions on Starting iOS SDK page.

SensibillSDK.stop

Similarly to start, the SensibillSDK.stop function now returns its result in Result<Void, Error> format, has async version, and a version for use with Objective-C. Please check Stopping iOS SDK page for more information.

SensibillSDK.userDefinedLocale

The localization and strings are now managed by a Branding package. If you wish to override how the localization is applied and handled, please follow the instructions provided in iOS Branding Strings - Advanced Customization section. For instance, selectedLocale of the BrandingL10NProvider allows you to specify how Sensibill SDK should select a locale.

TokenProvider

The signature of provideTokenReplacement function was changed to include userIdentifier (the same identifier as used on SDK start). This is done to allow the integrators ensure that the token SensibilL SDK is requesting is for the currently authenticated user. Please see example on how to implement TokenProvider on iOS Authentication page.

Starting Sensibill UI

The basic way to start Sensibill UI:

// Assuming SDK is already started

// Old way
private var sensibillUICoordinator = SensibillUICoordinator(host: self) // 1
sensibillUICoordinator.delegate = self // 2
sensibillUICoordinator.start() // 3 - default: starts UI modally

// New way
SensibillSDK.shared.smui.delegate = self // same as line 2
SensibillSDK.shared.smui.start( // same as line 3
  modalOver: self, // uses the same value, as host from line 1, and starts UI modally
  animated: true
)

Additional customization:

  • To manage the presentation method, the new way provides different methods (instead of options), each with its own set of properties, suitable for that presentation method.

    To embed:

    // Old way
    let sensibillUICoordinator = SensibillUICoordinator(host: self, presentationMethod: .embed)
    sensibillUICoordinator.start()
    
    // New way
    SensibillSDK.shared.smui.start(embedIn: self)

    To push:

    // Old way
    let sensibillUICoordinator = SensibillUICoordinator(host: self, presentationMethod: .push)
    // The SDK would try to extract UINavigationController from the provided UIViewController
    // If it succeeeds, then
    sensibillUICoordinator.start()
    
    // New way
    // The integrator is in charge of which UINavigationController to use
    // For example we can use the one available from the current UIViewController
    guard let navigationController = self.navigationController else {
    return
    }
    
    SensibillSDK.shared.smui.start(
    pushTo: navigationController
    animated: true
    )
  • The StartOption.animated is now a direct argument of the start function, and is only provided for methods that allow animation (modal and push).

  • The StartOption.navigationIntent is now a direct argument of every start method.

Capture Flow

CaptureFlowCoordinator, which was renamed to CaptureFlow.Coordinator, provides an access to a Capture experience, seamlessly integrated with the reliable and easy to use receipt uploading to Sensibill API. Additionally it allows to link a captured document to a bank transaction, monitor document uploading and processing, and display an Edit Metadata screen, which provides an ability to specify Folder, Category and the Notes for all the uploaded documents.

Initialization

Depending on Sensibill API version you use, you can initialize CaptureFlow.Coordinator as follows:

// With default Sensibill API version (v2)
// Note: Edit Metadata screen cannot be used with API v2
let coordinatorV2 = CaptureFlow.Coordinator(host: self)

// With Sensibill API v1 (can be used with Edit Metadata screen)
let coordinatorV1 = CaptureFlow.Coordinator(apiVersion: .v1, host: self)

Note that to display Edit Metadata screen at the end fo Capture flow, you must specify Sensibill API .v1.

CaptureFlow.Coordinator.start
  • The method start() did not change
  • The methods start(transaction:) and start(expenseType:) were replaced with start(metadata: CaptureFlow.DocumentMetadata), which allows to specify bank account and bank transaction information at once. See Bank Transaction Linking page for more details.
CaptureFlowCoordinatorDelegate

The delegate provides the same events, however in case of coordinatorDidFinishCapture event, the Transaction object was replaced with CaptureFlow.ProcessingInfo. It contains an array of sourceIds, which can then be used to monitor document upload, or provided to Edit Metadata screen. The pages Displaying Metadata Screen provides an example of the delegate that launches Edit Metadata screen.

Discontinued

  • Certificate pinning was removed

  • SensibillSDK no longer provides public access to the following properties and methods. They didn’t provide any value to integrators, and shouldn’t have been used:

      tokenProvider, locale, updateToken(completion:)
  • SDK no longer provides password authentication option, thus PasswordAuthenticator was removed.

  • The ReceiptCaptureManager of Capture Flow is no longer required. Use CaptureFlow.Coordinator directly instead.

  • The following components, which are no longer available publicly, didn’t provide any value to integrators, and shouldn’t have been used:

      User
  • Transaction Linking is now only available as part of Capture Flow use case (see Bank Transaction Linking ), and not on its own.

  • Transaction Matching is no longer available.

  • Web Client is no longer available.