> For the complete documentation index, see [llms.txt](https://docs.payments.thalescloud.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.payments.thalescloud.io/merchant-tokenization/sdk-integration/ios-api/migrate-from-2.x-to-3.0.md).

# Migrate from 2.x to 3.0

Starting with TMG SDK 3.0.0, several public APIs are simplified.

## Initialize the SDK <a href="#initialisation-of-sdk" id="initialisation-of-sdk"></a>

The SDK removes `TMGClientConfiguration.Builder` and moves configuration to the `TMGClientConfiguration` initializer:

* Removed: [`TMGClientConfiguration.Builder`](https://thalesgroup.github.io/d1sdk-docs/tmg-sdk/ios/2.1.0/Classes/TMGClientConfiguration/Builder.html)
* Use instead: [`TMGClientConfiguration`](https://thalesgroup.github.io/d1sdk-docs/tmg-sdk/ios/3.0.0/Classes/TMGClientConfiguration.html)

### What changed

* Deprecated `certificatePins`. The SDK now manages certificate pinning internally.
* Renamed `serverUrl` to `serverURL`.
* Renamed `serverKeyId` to `serverKeyID`.

{% tabs %}
{% tab title="Before 3.0.0" %}

```swift
let serverUrl;
let serverCertificate;
let keyIdentifier;
let configurationBuilder = TMGClientConfiguration.Builder(serverUrl: serverUrl, 
                                                          serverCertificate: Data(serverCertificate.utf8), 
                                                          serverKeyId: keyIdentifier)
let configuration: TMGClientConfiguration = TMGClientConfiguration(builder: configurationBuilder)
```

{% endtab %}

{% tab title="3.0.0" %}

```swift
let serverURL = ""
let serverCertificate = ""
let serverKeyID = ""
let configuration = TMGClientConfiguration(serverURL: serverURL,
                                           serverCertificate: Data(serverCertificate.utf8),
                                           serverKeyID: serverKeyID)
```

{% endtab %}
{% endtabs %}

### Initialize `VisaCTFHelper` <a href="#initialisation-of-visactfhelper" id="initialisation-of-visactfhelper"></a>

In TMG SDK 3.0.0, `createVisaCTFHelper` changes from async to sync. This simplifies error handling and control flow.

{% tabs %}
{% tab title="Before 3.0.0" %}

```swift
let tmgClient = TMGClient.sharedInstance
tmgClient.createVisaCTFHelper(tmgClientConfiguration: configuration,
                              completion: { (visaCTFHelper, error) in
  // Gets the VisaCTFHelper object
  // Checks the error
})
```

{% endtab %}

{% tab title="3.0.0" %}

```swift
do {
    let visaCTFHelper = try TMGClient.sharedInstance.createVisaCTFHelper(withConfiguration: configuration)
} catch let error {
    // Handle the error
}
```

{% endtab %}
{% endtabs %}

### Update device binding flows (green and yellow) <a href="#device-binding-in-green-and-yellow-flow" id="device-binding-in-green-and-yellow-flow"></a>

Device binding covers device authentication, Identification and Verification (ID\&V), and binding completion. In TMG SDK 3.0.0, the flow:

* Standardized the use of `completionHandler`.
* Removed the mix of `delegate` and `completionHandler`.
* Removed the need to handle binding success in multiple places.
* Streamlined control flow.

{% hint style="info" %}
When migrating from earlier SDK versions, note these API renames:

* `PendingBindingSession` is now `VisaCTFHelper.IDVSession`.
* `DeviceAuthenticationDelegate` is now `DeviceAuthentication`.
* `IdvMethod` is now `IDVMethod`.
* `IdvType` is now `IDVType`.
* `OtpActivationStatus` is now `OTPActivationStatus`.
  * `maxOtpRequestsAllowed` is now `maxOTPRequestsAllowed`.
  * `maxOtpVerificationAllowed` is now `maxOTPVerificationAllowed`.
    {% endhint %}

Use the code below to update your device binding integration:

{% tabs %}
{% tab title="Before 3.0.0" %}

```swift
// 1. conform to DeviceAuthenticationDelegate (this is for device authentication)
class DeviceAuthenticationDelegateImplementation: DeviceAuthenticationDelegate {

    let authenticationMessage

    func shouldStartAuthentication(startHandler: (String?, Bool) -> Void) {
        //3. Start user authentication 
        startHandler(authenticationMessage, YES)
    }
}

var pendingBindingSession: PendingBindingSession?
let deviceId
let correlationId
let deviceAuthenticationDelegate = DeviceAuthenticationDelegateImplementation()
// 2. Start create binding
visaCTFHelper.createBinding(vProvisionedTokenId: vProvisionedTokenId,
                            correlationId: correlationId,
                            deviceAuthenticationDelegate: deviceAuthenticationDelegate) { session, error in
    // 4. Success bind [Scenario 1]
    if error == nil && session == nil {

    }
    // 5. Store locally session for yellow flow
    pendingBindingSession = session
}
// MARK: idv flow
// 6. Get list of idv methods (Yellow flow)
pendingBindingSession.idvMethods(completion: { idvMethods, error in
    if error == nil {
        let listOfIdvMethod = idvMethods
    }
})

//7. Submit selected idv method (OTP flow)
let selectedIdvMethod
pendingBindingSession.submitIdvMethod(idvMethod: selectedIdvMethod,
                                      completion: { otpActivationStatus, error in
     // Check no error
    if error == nil {
        let maxOtpVerificationAllowed = otpActivationStatus.maxOtpRequestsAllowed
        let maxOtpRequestsAllowed = otpActivationStatus.maxOtpVerificationAllowed
        let otpExpiration = otpActivationStatus.maxOtpVerificationAllowed
    }
    // 8. retry if error
    
})

//9. Activate binding
let otp
pendingBindingSession.activateBinding(otp: otp, 
                                      completion: { error in
    // 4.1 Success bind [Scenario 2]
    if error == nil {

    }
    // 10. Retry if error
})
```

{% endtab %}

{% tab title="3.0.0" %}

```swift
// The singleton class to hold required properties for the visa flow
class VisaService {
    static var shared = VisaService()
    var idvSession: VisaCTFHelper.IDVSession? = nil
    var completionHandler: ((VisaCTFHelper.IDVSession?, TMGError?) -> Void)? = nil
}

let vProvisionedTokenID: String = ""
let correlationID: String = ""
// 1. Start create binding
visaCTFHelper.createBinding(forVProvisionedTokenID: vProvisionedTokenID,
                            correlationID: correlationID,
    deviceAuthenticationHandler: { auth in
        // 2. Start user authentication
        let customMessage = "" // Pass in the custom message. e.g: "Authenticate with Face ID"
        auth.startAuthentication(withMessage: customMessage)
    }, idvSessionHandler: { session in
        // 3. Store locally session for yellow flow
        VisaService.shared.idvSession = session

    }, completionHandler: { session, error in
        // 4. hold the completion handler locally
        VisaService.shared.completionHandler?(session, error)
    })

// MARK: idv flow
do {
    guard let session = VisaService.shared.idvSession else {
        return
    }
    // 5. Get list of idv methods (Yellow flow)
    let idvMethods = try session.idvMethods
    // 6. Submit selected idv method (OTP flow)
    session.selectIDVMethod(idvMethods[0]) { otp in
        // Check otp activation status
    }
} catch let error {
    // error on list of idv methods
}

// 7. Activate Binding
let otp = ""
VisaService.shared.idvSession?.activateBinding(withValue: otp)

// 8. Handle success of error.
// You can listen to completionHandler for success or error
VisaService.shared.completionHandler = {(session, error) in
    // 9. Success bind
    if error == nil {
        
    } else if let error, let session {
        // 10. Retry if error
        if error.description == TMGError.invalidOTPMessage.description {
            VisaService.shared.idvSession = session
        }
    } else {
        // 11. Handle error
    }
}
```

{% endtab %}
{% endtabs %}

### Resume a binding (`resumeBinding`) <a href="#resumebinding-api" id="resumebinding-api"></a>

The `resumeBinding` flow is unchanged from earlier versions. Only the `IDVSession` (ID\&V) steps change.

{% tabs %}
{% tab title="Before 3.0.0" %}

```swift
var pendingBindingSession: PendingBindingSession?
// 1. Start resume binding
visaCTFHelper.resumeBinding(vProvisionedTokenId: vProvisionedTokenId) { session, error in
    // 2. Store locally session for yellow flow
    if error == nil { 
        pendingBindingSession = session
    }
    // Check error
}

// 3. MARK: idv flow (refer to create binding idv flow in code snippet)
```

{% endtab %}

{% tab title="3.0.0" %}

```swift
// The singleton class to hold required properties for the visa flow
class VisaService {
    static var shared = VisaService()
    var idvSession: VisaCTFHelper.IDVSession? = nil
    var completionHandler: ((VisaCTFHelper.IDVSession?, TMGError?) -> Void)? = nil
}
let vProvisionedTokenID: String = ""
// 1. Start resume binding
visaCTFHelper.resumeBinding(forVProvisionedTokenID: vProvisionedTokenID,
                            idvSessionHandler: { session in
        // 2. Store locally session for yellow flow
        VisaService.shared.idvSession = session        
    }, completionHandler: { session, error in
        // 3. hold the completion handler locally
        VisaService.shared.completionHandler?(session, error)
    })
// 4. MARK: idv flow (refer to create binding idv flow in code snippet)
```

{% endtab %}
{% endtabs %}

### Get the binding state (`bindingState`) <a href="#bindingstate-api" id="bindingstate-api"></a>

In TMG SDK 3.0.0, `bindingState` changes from async to sync. This simplifies error handling and control flow.

{% tabs %}
{% tab title="Before 3.0.0" %}

```swift
let vProvisionedTokenId = ""
visaCTFHelper.bindingState(vProvisionedTokenId: vProvisionedTokenId) { (bindingState, error) in 
}
```

{% endtab %}

{% tab title="3.0.0" %}

```swift
let vProvisionedTokenID = ""
do {
    let state = try visaCTFHelper.bindingState(forVProvisionedTokenID: vProvisionedTokenID)
} catch let error {
    // Handle the error
}
```

{% endtab %}
{% endtabs %}

### Authenticate a transaction <a href="#transaction-flow" id="transaction-flow"></a>

Transaction authentication covers device authentication and returning the Visa payload. In TMG SDK 3.0.0, the flow:

* Standardized the use of `completionHandler`.
* Removed the mix of `delegate` and `completionHandler`.

Use the code below to update your transaction authentication integration:

{% tabs %}
{% tab title="Before 3.0.0" %}

```swift
// 1. conform to DeviceAuthenticationDelegate (this is for device authentication)
class DeviceAuthenticationDelegateImplementation: DeviceAuthenticationDelegate {

    let authenticationMessage

    func shouldStartAuthentication(startHandler: (String?, Bool) -> Void) {
        //3. Start user authentication 
        startHandler(authenticationMessage, YES)
    }
}

let deviceAuthenticationDelegate = DeviceAuthenticationDelegateImplementation()

// 2. Start authenticate transaction
visaCTFHelper.authenticateTransaction(vProvisionedTokenId: vProvisionedTokenID,
                                      deviceAuthenticationDelegate: deviceAuthenticationDelegate,
                                      completion: { visaPayload, error in
    // 4. Successfully generate payload
    if error == nil {
    
    } else {
        // Handle error
    } 
})
```

{% endtab %}

{% tab title="3.0.0" %}

```swift
let vProvisionedTokenID: String = ""
        
// 1. Start authenticate transaction
visaCTFHelper.authenticateTransaction(forVProvisionedTokenID: vProvisionedTokenID,
                                        deviceAuthenticationHandler: { auth in
        // 2. Start user authentication 
        let customMessage = "" // Pass in the custom message. e.g: "Authenticate with Face ID"
        auth.startAuthentication(withMessage: customMessage)
    }, completionHandler: { (visaPayload, error) in
        // 3. Success generate payload
        if error == nil {
            
        } else {
            // Handle error
        }    
})
```

{% endtab %}
{% endtabs %}

### Remove a binding (`removeBinding`) <a href="#removebinding-api" id="removebinding-api"></a>

`removeBinding` now requires an additional `correlationID`.

{% tabs %}
{% tab title="Before 3.0.0" %}

```swift
// 1. Start remove binding
visaCTFHelper.removeBinding(vProvisionedTokenId: vProvisionedTokenID,
                            completion: { error in
    // 2. Success remove binding
    if error == nil {
        
    } else {
        // Handle error
    }
})
```

{% endtab %}

{% tab title="3.0.0" %}

```swift
let vProvisionedTokenID: String = ""
let correlationID: String = ""

// 1. Start remove binding
visaCTFHelper.removeBinding(forVProvisionedTokenID: vProvisionedTokenID,
                            correlationID: correlationID) { error in
    // 2. Success remove binding
    if error == nil {
        
    } else {
        // Handle error
    } 
}
```

{% endtab %}
{% endtabs %}

### Sync binding state (`syncBindingState`) <a href="#syncbindingstate-api" id="syncbindingstate-api"></a>

`syncBindingState` now requires an additional `correlationID`.

{% tabs %}
{% tab title="Before 3.0.0" %}

```swift
// 1. Start sync binding state
visaCTFHelper.syncBindingState(vProvisionedTokenId: vProvisionedTokenID,
                               completion: { bindingState, error in
    // 2. Success sync binding state
    if error == nil {
        
    } else {
        // Handle error
    }  
})
```

{% endtab %}

{% tab title="3.0.0" %}

```swift
let vProvisionedTokenID: String = ""
let correlationID: String = ""

// 1. Start sync binding state
visaCTFHelper.syncBindingState(forVProvisionedTokenID: vProvisionedTokenID,
                                correlationID: correlationID) { (state, error) in
    // 2. Success sync binding state
    if error == nil {
        
    } else {
        // Handle error
    }   
}
```

{% endtab %}
{% endtabs %}

### Read the previously selected ID\&V method <a href="#previouslyselectedidvmethod-in-idvsession" id="previouslyselectedidvmethod-in-idvsession"></a>

In addition to the `IDVSession` functions used in the `createBinding` flow, you can read the previously selected ID\&V method. In TMG SDK 3.0.0, `previouslySelectedIDVMethod` changes from async to sync. This simplifies error handling and control flow.

{% tabs %}
{% tab title="Before 3.0.0" %}

```swift
// 1. Get previously selected idv method
pendingBindingSession.previouslySelectedIdvMethod(completion: { idvMethod, error in
    // 2. successfully get previously selected idv method
    if error == nil {
        let prevIDVMethod = idvMethod
    } else {
        // Handle error
    } 
})
```

{% endtab %}

{% tab title="3.0.0" %}

```swift
guard let idvSession = VisaService.shared.idvSession else {
    // no idv session
    return
}
// 1. Get previously selected idv method
do {
    let prevIDVMethod = try idvSession.previouslySelectedIDVMethod
} catch let error {
    // 2. handle error
}
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.payments.thalescloud.io/merchant-tokenization/sdk-integration/ios-api/migrate-from-2.x-to-3.0.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
