> For the complete documentation index, see [llms.txt](https://even-financial.gitbook.io/developer-center/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://even-financial.gitbook.io/developer-center/embeddable-integrations/mobile-sdks/swift/personal-loans.md).

# Personal Loans

## Overview

The Personal Loans vertical is delivered through Engine's Web Wrapper SDK for iOS. This guide covers installation, prerequisites, the core configuration props (`channel`, `zone`, `productTypes`), a basic usage example, prefilling lead data, client tags, and event handlers.

You'll need the correct `channel` and `zone` values for your integration. Ask your Partner Manager to provide these values for Personal Loans.

{% hint style="info" %}
Before you start, request an API token from your Partner Manager. It authenticates with the Engine API and is required to use the Prefill API. You may want multiple tokens depending on how many entry points your app has into the SDK.
{% endhint %}

## Requirements

* Xcode 15 or higher
* iOS 15.0 or higher deployment target
* Swift 5.9 or higher

## Install

Add the package via Swift Package Manager. In Xcode, select your project → **Package Dependencies → “+”**, enter the repository URL, then choose a version rule (**Up to Next Major Version** is recommended) and add the **`SwiftWrapperSdk`** library to your app target. Use the latest published release — check the repository's **Releases** for the current version:

```
https://github.com/MoneyLion/engine-mobile-native-sdk.git
```

Because the repo is public, no GitHub account or token is required — SwiftPM downloads the binary directly.

Or add it to your `Package.swift`:

```swift
dependencies: [
    .package(
        url: "https://github.com/MoneyLion/engine-mobile-native-sdk.git",
        from: "0.0.2" // use the latest published release
    )
],
targets: [
    .target(
        name: "YourApp",
        dependencies: [
            .product(name: "SwiftWrapperSdk", package: "engine-mobile-native-sdk")
        ]
    )
]
```

## Initialize

Import the SDK in any file where you want to render the Engine flow:

```swift
import SwiftWrapperSdk
```

## Basic Example

Build an `EngineSDKConfig`, provide `EngineSDKCallbacks`, then start `EngineEmbed` and attach the returned view. Use `[.loan]` for `productTypes` to render the Personal Loans flow. Your `channel` and `zone` values are provided by your Partner Manager.

```swift
let config = EngineSDKConfig(
    channel: "your-channel",
    zone: "your-zone",
    productTypes: [.loan]
)

let callbacks = EngineSDKCallbacks(
    onExit: { _ in
        // handle exit / navigation
    }
    // ...optional event handlers, see Event Handlers
)

let embed = EngineEmbed(config: config, callbacks: callbacks)
embed.start { embedView in
    // embedView is a UIView — add it to your view hierarchy
    view.addSubview(embedView)
}
```

{% hint style="warning" %}
Retain the `EngineEmbed` instance (e.g. as a property on your view controller or a SwiftUI coordinator). If it deallocates, the embed stops working.
{% endhint %}

## Properties

<table><thead><tr><th width="220">Prop</th><th width="220">Type</th><th width="130">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>channel</code></td><td><code>String</code></td><td>Yes</td><td>Identifies your integration in Engine. Provided by your Partner Manager (e.g. <code>"direct"</code>).</td></tr><tr><td><code>zone</code></td><td><code>String</code></td><td>Yes</td><td>Identifies the placement or distribution surface for the SDK. Provided by your Partner Manager (e.g. <code>"marketplace"</code>).</td></tr><tr><td><code>productTypes</code></td><td><code>[ProductType]</code></td><td>Yes</td><td>Product flow(s) to render. Use <code>[.loan]</code> for Personal Loans.</td></tr><tr><td><code>bearerToken</code></td><td><code>String?</code></td><td>For prefill</td><td>API token from your Partner Manager. Required to use the Prefill API. Without it, the standard non-prefilled flow renders.</td></tr><tr><td><code>isDev</code></td><td><code>Bool</code></td><td>No</td><td>When <code>true</code>, the SDK targets Engine's dev/staging hosts. Defaults to <code>false</code> (production).</td></tr><tr><td><code>personalInformation</code>, <code>loanInformation</code>, <code>mortgageInformation</code>, <code>creditInformation</code>, <code>financialInformation</code>, <code>employmentInformation</code>, <code>legalInformation</code>, <code>educationInformation</code></td><td><code>Lead*Information?</code></td><td>No</td><td>Prefill data. See <a href="#prefilling-lead-data">Prefilling Lead Data</a>.</td></tr><tr><td><code>clientTags</code></td><td><code>[String: [String]]?</code></td><td>No</td><td>Reporting/attribution tags. See <a href="#client-tags">Client Tags</a>.</td></tr><tr><td><code>onExit</code></td><td><code>EngineSDKCallbacks.OnExit</code></td><td>Yes</td><td>Fired when the user exits the flow. Set on <code>EngineSDKCallbacks</code>.</td></tr><tr><td><code>onInitialize</code>, <code>onCreate</code>, <code>onUpdate</code>, <code>onNavigate</code>, <code>onSubmit</code>, <code>onRateTableRender</code>, <code>onOfferClick</code>, <code>onErrorPageView</code>, <code>onErrorPageRetry</code>, <code>onEmbedError</code>, <code>onEmbedErrorRetry</code></td><td>Callbacks</td><td>No</td><td>Optional tracking hooks set on <code>EngineSDKCallbacks</code>. See <a href="#event-handlers">Event Handlers</a>.</td></tr></tbody></table>

## Prefilling Lead Data

Prefill any user data you already have to reduce what the user has to type in-flow. Prefilled data is grouped into typed information objects, each passed on `EngineSDKConfig` (e.g. `personalInformation`, `loanInformation`, `financialInformation`).

{% hint style="info" %}
Prefilling requires a `bearerToken`. Pass only the fields you have — omitted fields are collected from the user in-flow.
{% endhint %}

### Example

```swift
let config = EngineSDKConfig(
    channel: "your-channel",
    zone: "your-zone",
    bearerToken: "{your_token}",
    productTypes: [.loan],
    personalInformation: LeadPersonalInformation(
        firstName: "Bob",
        lastName: "Dylan",
        email: "bobdylan@gmail.com",
        dateOfBirth: DateComponents(year: 1990, month: 1, day: 1),
        primaryPhone: "2325624852",
        address1: "1600 Pennsylvania Avenue",
        address2: "Apt 2",
        city: "Washington",
        state: .DC,
        zipcode: "20500",
        ssn: "512-54-7862"
    ),
    loanInformation: LeadLoanInformation(
        purpose: .creditCardRefi,
        loanAmount: 7500
    ),
    mortgageInformation: LeadMortgageInformation(
        propertyStatus: .ownWithMortgage
    ),
    creditInformation: LeadCreditInformation(
        providedCreditRating: .good
    ),
    financialInformation: LeadFinancialInformation(
        employmentStatus: .employedFullTime,
        employmentPayFrequency: .biweekly,
        annualIncome: 20000,
        creditCardDebt: 5000,
        bankRoutingNumber: "123456789",
        bankAccountNumber: "55555555555"
    ),
    employmentInformation: LeadEmploymentInformation(
        directDeposit: false
    ),
    legalInformation: LeadLegalInformation(
        consentsToSms: true
    ),
    educationInformation: LeadEducationInformation(
        educationLevel: .associate
    )
)

let callbacks = EngineSDKCallbacks(onExit: { _ in })
let embed = EngineEmbed(config: config, callbacks: callbacks)
```

### Type Definitions

Every prop and field is optional — pass only what you have.

```swift
struct LeadPersonalInformation {
    var firstName: String?
    var lastName: String?
    var email: String?
    var dateOfBirth: DateComponents?
    var primaryPhone: String?   // 10 digits, no "+" or "-" chars
    var address1: String?
    var address2: String?       // optional apartment / suite
    var city: String?
    var state: State?           // 2-letter state enum (e.g. .DC)
    var zipcode: String?
    var ssn: String?            // 9 digits with or without hyphens
}

struct LeadLoanInformation {
    var purpose: LoanPurpose?
    var loanAmount: Int?        // whole numbers only
}

struct LeadMortgageInformation {
    var propertyStatus: PropertyStatus?
}

struct LeadCreditInformation {
    var providedCreditRating: ProvidedCreditRating?
}

struct LeadFinancialInformation {
    var employmentStatus: EmploymentStatus?
    var employmentPayFrequency: EmploymentPayFrequency?
    var annualIncome: Int?          // raw integer value (e.g. 20000)
    var creditCardDebt: Int?        // total credit card debt, raw integer value
    var bankRoutingNumber: String?  // must be exactly 9 digits
    var bankAccountNumber: String?
}

struct LeadEmploymentInformation {
    var directDeposit: Bool?
}

struct LeadLegalInformation {
    var consentsToSms: Bool?    // lead agrees to receive SMS
}

struct LeadEducationInformation {
    var educationLevel: EducationLevel?
}
```

### Enums / Accepted Values

Fields backed by an enum must use a valid value.

```swift
enum LoanPurpose {
    case auto
    case autoPurchase
    case autoRefinance
    case baby
    case boat
    case business
    case carRepair
    case cosmetic
    case creditCardRefi
    case debtConsolidation
    case emergency
    case engagement
    case green
    case homeImprovement
    case homePurchase
    case homeRefi
    case householdExpenses
    case largePurchases
    case lifeEvent
    case medicalDental
    case motorcycle
    case movingRelocation
    case other
    case rv
    case specialOccasion
    case studentLoan
    case studentLoanRefi
    case taxes
    case vacation
    case wedding
}

enum ProvidedCreditRating {
    case excellent
    case good
    case fair
    case poor
    case limited
}

enum PropertyStatus {
    case ownOutright
    case ownWithMortgage
    case rent
}

enum EducationLevel {
    case highSchool
    case associate
    case bachelors
    case masters
    case doctorate
    case otherGradDegree
    case certificate
    case didNotGraduate
    case stillEnrolled
    case other
}

enum EmploymentStatus {
    case employed
    case employedFullTime
    case employedPartTime
    case military
    case notEmployed
    case selfEmployed
    case retired
    case other
}

enum EmploymentPayFrequency {
    case biweekly
    case monthly
    case twiceMonthly
    case weekly
}

// State is a 2-letter US state enum, e.g. .CA, .DC, .NY
```

{% hint style="warning" %}
Do not prefill any fields that are empty or unavailable — omit them so the user is prompted in-flow. Prefilled data must match the type definitions above, and any field backed by an enum must use a valid value. If a value is invalid, that attribute is stripped and the user will have to enter it again manually.
{% endhint %}

## Client Tags

The Engine Web Wrapper SDK supports adding your unique Client Tags to track performance of specific campaigns or users. All Client Tag data is attributed to the lead level.

Client Tags are added via the `clientTags` property on `EngineSDKConfig`, a map of string keys to lists of string values. We strongly recommend including only one element per list for ease of reporting and attribution — if you want two separate tags, include the second tag under a different key. There is no limit to the number of keys.

```swift
let config = EngineSDKConfig(
    channel: "your-channel",
    zone: "your-zone",
    bearerToken: "{your_token}",
    productTypes: [.loan],
    personalInformation: LeadPersonalInformation(/* ...any data you don't want to ask for again */),
    clientTags: [
        "clientId": ["client1"],
        "trafficsource": ["email"],
        "campaignId": ["campaign1"]
    ]
)
```

{% hint style="info" %}
**Note**: Client Tags are only sent as part of a prefill request. You must provide both a `bearerToken` and prefill data (via the information props such as `personalInformation`). If no prefill data is supplied, the SDK makes no prefill call and any `clientTags` you pass are ignored.
{% endhint %}

### Supported Client Tag Keys for Reporting

If you plan for the Engine team to set up reporting (i.e., you do not plan to hit the Analytics API), these are the only keys that are currently fully supported. If a different key is needed, please reach out to your partner manager.

* agentId
* campaignId
* clientId
* deviceid
* medium
* sourceId
* subid
* subid1
* subid2
* subid3
* target
* trafficsource
* userid

## Event Handlers

`EngineSDKCallbacks` exposes optional callbacks that notify your app when key moments occur during the user's journey. Each callback receives an event object containing a `timestamp` (ISO 8601 UTC) and event-specific fields.

All callbacks are optional. Pass any combination when constructing `EngineSDKCallbacks`. If a callback is not provided, the SDK will still log the event to the debug console in development mode.

```swift
let callbacks = EngineSDKCallbacks(
    onInitialize: { event in print("onInitialize \(event.timestamp)") },
    onCreate: { event in print("onCreate \(event.leadUuid)") },
    onSubmit: { event in print("onSubmit \(event.leadUuid)") },
    onOfferClick: { event in print("onOfferClick \(event.offerUuid)") },
    onExit: { event in
        // Navigate the user back or perform cleanup
    }
    // ...other callbacks
)
```

### Available Events

| Callback              | Trigger                          |
| --------------------- | -------------------------------- |
| **onInitialize**      | SDK finished loading the embed   |
| **onCreate**          | New lead created                 |
| **onUpdate**          | Lead data updated                |
| **onNavigate**        | Page navigation within the flow  |
| **onSubmit**          | Lead form submitted              |
| **onRateTableRender** | Rate table displayed with offers |
| **onOfferClick**      | User clicked an offer            |
| **onErrorPageView**   | Error page displayed in the flow |
| **onErrorPageRetry**  | User retried from the error page |
| **onExit**            | User exited the SDK              |
| **onEmbedError**      | Web embed failed to load         |
| **onEmbedErrorRetry** | User retried after embed failure |

For Personal Loans, `onRateTableRender` populates `loanOffers` and `specialOffers`, and `onOfferClick` includes loan-specific fields such as `financialInstitutionName`, `loanAmount`, `apr`, `termLength`, and `monthlyPayment`. Every event includes a `timestamp` (ISO 8601 UTC).


---

# 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://even-financial.gitbook.io/developer-center/embeddable-integrations/mobile-sdks/swift/personal-loans.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.
