# API Specifications

## Post Request

This section covers how user information is sent via requests to Engine by MoneyLion's API.

### Post Request Endpoint

`POST` to `https://api.engine.tech/leads/rateTables`\
\
\&#xNAN;*Partners building a Native API integration posting user information to this endpoint will need to make a separate request to retrieve offers.*

### Post Request Authorization

Engine will provide testing and production API access tokens. All requests to the Engine API must be authenticated using a bearer token specified in the Authorization header.

The header value is prefixed with the string “Bearer “, so a properly-authenticated request will look similar to the one here:

```
Authorization: Bearer 0a930e7f-4a96-4388-8c12-c901a161084e_409cc5f2-4008-11aa-84a4-0b68f163f437
```

### Post Request Body - Object Structure

The **required format** of the body (JSON) in the request to Engine by MoneyLion's API is as follows:

```json
{
  "productTypes": ["loan"],
  "personalInformation": {
    "firstName": "John",
    "lastName": "Doe",
    "email": "john@example.com",
    "city": "New York",
    "state": "NY",
    "primaryPhone": "2125556789",
    "address1": "175 5th Ave",
    "address2": "Apartment 5",
    "zipcode": "10010",
    "dateOfBirth": "1993-10-09",
    "ssn": "111-22-3333"
  },
  "loanInformation": {
    "purpose": "debt_consolidation",
    "loanAmount": 10000
  },
  "mortgageInformation": {
    "propertyStatus": "own_with_mortgage"
  },
  "creditInformation": {
    "providedCreditRating": "good"
  },
  "financialInformation": {
    "employmentStatus": "employed",
    "employmentPayFrequency": "biweekly",
    "annualIncome": 80000
  },
  "legalInformation": {
    "consentsToFcra": true,
    "consentsToTcpa": true,
    "fcraLanguage": "By checking this box/clicking 'agree' I hereby consent to the 'E-Sign Agreement', the 'Credit Authorization Agreement', the Terms of Service and Privacy Policy, and I am providing written consent under the Fair Credit Reporting Act (FCRA) for [Engine by MoneyLion and/or Insert Company Name], its partners and financial institutions to obtain consumer report information from my credit profile. I request that my information be provided to their partners, lenders, and financial services partners to provide me with financial recommendations, which may also include debt relief, credit repair, credit monitoring or other related services",
    "tcpaLanguage": "I agree to be contacted by [Engine by MoneyLion and/or Insert Company Name] its partners and their affiliated companies and financial institutions via email, postal mail service and/or at the telephone number(s) I have provided above to explore various financial products and services I inquired about, including contact through automatic dialing systems, artificial or pre-recorded voice messaging, or text message. Consent is not required as a condition to utilize the service, and you may choose to be contacted by an individual customer care representative(s) by calling XXXXX or emailing XXXX"
  },
  "sessionInformation": {
    "ipAddress": "x.x.x.x",
    "userAgent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Mobile Safari/537.36"
  }
}
```

**Product Types**

<table><thead><tr><th>Field</th><th width="94.5736083984375">Type</th><th>Required?</th><th>Sample Value</th><th>Enum/Comment</th></tr></thead><tbody><tr><td>productTypes*</td><td>Array of strings</td><td>Y</td><td>"loan", "other"</td><td><p>Enum: </p><ul><li>"loan"</li><li>"loan", "other"</li><li>"other"</li></ul></td></tr></tbody></table>

\*In the `productTypes` array, you may pass `["loan"]` for the lead to receive First Look / Personal Loan offers only), `["other"]` for the lead to receive Second Look Marketplace offers only, or `["loan", "other"]` for the lead to receive 1st Look offers when eligible, or *else* Second Look offers (if not eligible for any 1st Look offers).&#x20;

\*See [2nd Look Marketplace (Channel Partners)](https://engine.tech/developer-center/loans-integrations/api/products/2nd-look-marketplace/channel-partners) for more information on how to directly access our 2nd Look Marketplace.&#x20;

**Personal Information**

| Field          | Type   | Required? (Yes/No/Conditional) | Sample Value        | Enum/Comment                                                                                                                                                                                                 |
| -------------- | ------ | ------------------------------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `firstName`    | String | Y                              | John                |                                                                                                                                                                                                              |
| `lastName`     | String | Y                              | Doe                 |                                                                                                                                                                                                              |
| `email`        | String | Y                              | <john@example.com>  | uses [Apache domain name validator](https://github.com/apache/commons-validator/blob/768d48d95dd6ef202acc8f0900d0f2582c6204c4/src/main/java/org/apache/commons/validator/routines/DomainValidator.java#L182) |
| `city`         | String | Y                              | New York            |                                                                                                                                                                                                              |
| `state`        | String | Y                              | NY                  | <p>2-letter State abbreviation</p><p><br>50 U.S. states + DC / PR / VI</p>                                                                                                                                   |
| `primaryPhone` | String | Y                              | 2125556789          | See below Regex Validations for more information                                                                                                                                                             |
| `address1`     | String | Y                              | 45 West 21st Street |                                                                                                                                                                                                              |
| `address2`     | String | N                              | 5th Floor           | Optional                                                                                                                                                                                                     |
| `zipcode`      | String | Y                              | 10010               | See below Regex Validations for more information                                                                                                                                                             |
| `dateOfBirth`  | String | Y                              | 1993-10-09          | yyyy-mm-dd                                                                                                                                                                                                   |
| `ssn`          | String | Y                              | 111-22-3333         | <p>Social Security Number.<br>See below Regex Validations for more information</p>                                                                                                                           |

**Loan Information**

| Field        | Type    | Required? (Yes/No) | Sample Value        | Comment                                                                                          |
| ------------ | ------- | ------------------ | ------------------- | ------------------------------------------------------------------------------------------------ |
| `purpose`    | String  | Y                  | debt\_consolidation | See enum at  API reference - [purpose](https://engine.tech/docs/api-reference/#tocS_LoanPurpose) |
| `loanAmount` | Integer | Y                  | 1000                | Unit in USD                                                                                      |

**Mortgage Information**

| Field            | Type   | Required? (Yes/No) | Sample Value        | Comment                                                                                                   |
| ---------------- | ------ | ------------------ | ------------------- | --------------------------------------------------------------------------------------------------------- |
| `propertyStatus` | String | Y                  | own\_with\_mortgage | See enum at API reference - [propertyStatus](https://engine.tech/docs/api-reference/#tocS_PropertyStatus) |

**Credit Information**

| Field                        | Type    | Required? (Yes/No/Conditional) | Sample Value | Comment                                                                                                               |
| ---------------------------- | ------- | ------------------------------ | ------------ | --------------------------------------------------------------------------------------------------------------------- |
| `providedCreditRating`       | String  | Conditional                    | good         | See enum at API reference - [providedCreditRating](https://engine.tech/docs/api-reference/#tocS_ProvidedCreditRating) |
| `providedNumericCreditScore` | Integer | Conditional                    | 750          | Either `providedCreditRating` or `providedNumericCreditScore` must be present                                         |

**Financial Information**

| Field                    | Type    | Required? (Yes/No/Conditional) | Sample Value | Enum/Comment                                                                                                              |
| ------------------------ | ------- | ------------------------------ | ------------ | ------------------------------------------------------------------------------------------------------------------------- |
| `employmentStatus`       | String  | Yes                            | employed     | See enum at API reference - [employmentStatus](https://engine.tech/docs/api-reference/#tocS_EmploymentStatus)             |
| `employmentPayFrequency` | String  | Yes                            | weekly       | See enum at API reference - [employmentPayFrequency](https://engine.tech/docs/api-reference/#tocS_EmploymentPayFrequency) |
| `annualIncome`           | Integer | Yes                            | 100000       | Unit in USD                                                                                                               |

**Education Information**&#x20;

| Field            | Type   | Required? (Yes/No/Conditional) | Sample Value | Enum/Comment                                                                                                   |
| ---------------- | ------ | ------------------------------ | ------------ | -------------------------------------------------------------------------------------------------------------- |
| `educationLevel` | String | N                              | masters      | See enum at API reference - [educationLevel](https://engine.tech/docs/api-reference/#tocS_ConversionEventData) |

**Legal Information**

<table><thead><tr><th>Field</th><th>Type</th><th width="115.79296875">Required? (Yes/No/Conditional)</th><th>Sample Value</th><th>Enum/Comment</th></tr></thead><tbody><tr><td><code>consentsToFcra</code></td><td>Boolean</td><td>Yes</td><td>true</td><td>Must be set to <code>true</code>.  </td></tr><tr><td><code>fcraLanguage</code></td><td>String</td><td>Yes</td><td>"By checking this box/clicking 'agree' I hereby consent to ..."</td><td>Must include the exact FCRA language shown to users.</td></tr><tr><td><code>consentsToSms</code></td><td>Boolean</td><td>No</td><td>true</td><td>Highly recommended</td></tr><tr><td><code>consentsToTcpa</code></td><td>Boolean</td><td>No</td><td>true</td><td>Highly recommended*</td></tr><tr><td><code>tcpaLanguage</code></td><td>String</td><td>Conditional</td><td>"By checking this box/clicking 'agree' I hereby consent to ..."</td><td>Required if <code>consentsToTcpa</code> is <code>true</code>. Must include the exact TCPA language shown to users.</td></tr></tbody></table>

{% hint style="info" %}
\*Although the FCC has [postponed](https://www.fcc.gov/document/fcc-postpones-effective-date-one-one-consent-rule) the effective date of the TCPA One-to-One Consent Rule—meaning the `consentsToTcpa` field is no longer strictly required (i.e. does not need to be `true`—Engine still strongly encourages our channel partners to obtain user consent to maintain the highest standards of compliance and performance.
{% endhint %}

**Session Information**

| Field       | Type   | Required? (Yes/No) | Sample Value                     | Enum/Comment                                                          |
| ----------- | ------ | ------------------ | -------------------------------- | --------------------------------------------------------------------- |
| `ipAddress` | String | Yes                | 8.8.8.8                          | Used for fraud detection by Engine and Financial Institution partners |
| `userAgent` | String | Yes                | MyApp/2.1 (iOS 16.3; iPhone13,2) | Used for fraud detection/prevention by Financial Institution partners |

{% hint style="info" %}
`sessionInformation.userAgent` should reflect the userAgent of the *client* (i.e. **consumer**'s device), which is different from the `User-Agent` required in request headers (which should reflect the channel partner's server).
{% endhint %}

**Regex Validations**

The following fields have the regex checks and will return errors if your lead submission does not adhere to this logic:

**personalInformation.primaryPhone**

The primary must be a string of 10 digits, with or without a leading 1, and with or without special characters e.g. `()-.`&#x20;

The area code cannot be the same 3 digits repeated, e.g. `222` or `333`.

**personalInformation.zipcode**

The zip code must be a string of either:

1. 5 digits
2. 5 digits, a hyphen `-`, and 4 more digits

**personalInformation.ssn**

1. The SSN cannot have all digits in each group be identical (e.g., `111-11-1111` or `222-22-2222`).
2. The following specific SSNs are not allowed because they are commonly used in examples or considered invalid:

* `123-45-6789`
* `219-09-9999`
* `078-05-1120`

3. The first group of three digits cannot be:

* `666`
* `000`
* Any number starting with `9` (e.g., `900`–`999`).

4. The middle group of two digits cannot be:

* `00`

5. The last group of four digits cannot be:

* `0000` &#x20;

## Response

This section covers how partners building a Native API integration retrieve offers from Engine by MoneyLion's API.

Partners building a Native API integration will receive a response from Engine’s API almost instantaneously. This response **does not contain complete offer information** and contains two key fields to retrieve offer information:

* **“uuid”:** Engine’s Rate Table UUID which will be used to retrieve offer information
* **“leadUuid”:** Engine’s Lead UUID which partners building a Native API integration should store for internal records

Here is an example of the API response. Note that `pendingResponses` contains information about the Financial Services partners to whom Engine is sending user information.

<figure><img src="https://3849802388-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MeMvVDbjd8vJWZ9Hwf0%2Fuploads%2Fgit-blob-a7886c46442e23e5656ade2c4cb2ff8a4159a508%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

Partners building a Native API integration must make a secondary request to Even’s API to retrieve offer information. Below are instructions for this secondary request:

* Capture the `uuid` returned in the initial API response
* Execute a GET request to Engine’s Offers Endpoint:&#x20;
  * `GET https://api.engine.tech/originator/rateTables/:uuid`
* Poll the `GET rateTables` endpoint *once every second* until “pendingResponses” is empty (either up to 15s or 30s, depending on whether 2nd Look Marketplace offers are also enabled. (Please see [Response Timing](https://engine.tech/developer-center/loans-savings-second-look-marketplace/api/products/loans/personal/api-specifications?q=blocking#response-timing) section below for more info.)

Below is a mock of the API response for Even’s Offers endpoint. Note that `pendingResponses` is empty as Even has already received offers back for the user from all Financial Services partners.

<figure><img src="https://3849802388-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MeMvVDbjd8vJWZ9Hwf0%2Fuploads%2Fgit-blob-1f346370f4a2a6be591934c097a74e6160a685af%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

### Response Timing

Below are p25, 50, 75, and 95 response times across our network of Financial Institution API Partners (current as of 2/28/25). You can use this to estimate the average time it will take for Engine's rate table response to *fully* resolve (i.e. no more `pendingResponses`) - please see notes below the table.

#### Response Times by Marketplace - Table

**1st Look Response Time**

| Percentile | Response Time (seconds) |
| ---------- | ----------------------- |
| p25        | 1                       |
| p50        | 2                       |
| p75        | 4                       |
| p95        | 8                       |

**2nd Look Marketplace Response Time**

| Percentile | Response Time (seconds) |
| ---------- | ----------------------- |
| p25        | <1                      |
| p50        | 1                       |
| p75        | 4                       |
| p95        | 11                      |

{% hint style="info" %}
Engine will respond immediately (average response times are <1 second), but you will need to keep `GET`ting the resulting rate table until the `pendingResponses` array is empty. The table above shows the time it will take until you no longer need to poll `/rateTables/:uuid`.
{% endhint %}

#### 1st Look, 2nd Look, or 1st Look + 2nd Look Waterfall

If you are set up for only 1st Look or 2nd Look through your integration (i.e. if you are only including one value in the `productTypes` array, either \["loan"] or \["other"], you can use the times above as an indication of the time for a rate table to fully resolve.&#x20;

If you are set up with the 1st Look / 2nd Look waterfall (i.e. `productTypes = ["loan", "other"]`, where Engine waits for all 1st Look Partners to respond before submitting to 2nd Look partners, you should add the 1st Look response times to the 2nd Look response times to interpret the time it takes for the rate table to fully resolve with offers.

#### Caveat - Full API Gateway May Take Longer

This only displays the time it takes for Financial Institutions to respond to Engine's API requests. The full end-to-end experience may take longer than the times in the table above, considering the full flow of info from one end to the other:

* What is typically negligible: the additional time from the time your request hits Engine *before* we initiate those requests, and the time for Engine to respond to you *after* our Financial Institution partners respond to us.
* What *may not* be negligible: the additional time it takes for the user/client to make the request to the Engine API via your own API, and the additional time it takes for the user/client to process the response they receive by your API.

### Response Parsing

#### loanOffers array

Offers will be returned in the `loanOffers`array, and only that array should be used to display loan offers (aka 1st Look offers).

Rate tables with loanOffers present may also contain offers in the specialOffers array, for example:

```
{
    "uuid": "4e016504-f728-450c-9c3a-fd012057e3dc",
    "leadUuid": "09a589c8-b6be-427f-ab09-450408742dbb",
    "creditCardOffers": [],
    "lifeInsuranceOffers": [],
    "lineOfCreditOffers": [],
    "loanOffers": [
        {
            "uuid": "0c66af13-ddaf-4493-bacf-c6c9c0a5bbc9",
            "originator": {
                "key": "engine-demo-loans-demand-sub-account-1",
                "name": "Engine Demo Loans Demand Sub Account 1",
                "description": "Demo Sub Account 1 - Description: This is a description of the FI, usually marketing material. <b> This section may include html.</b>",
                "images": [
                    {
                        "sizeKey": "120x40",
                        "url": "https://s3.amazonaws.com/images.evenfinancial.com/logos/dev/engine_demo_loans_demand_sub_account_1-202-wqm88e4a.png"
                    }
                ],
                "disclaimer": "<p>Demo Sub Account 1 - Disclaimer: This is a disclaimer on the FI/offer, usually includes: \n<ul>\n<li>Legal Terms</li>\n<li>Stipulations</li>\n<li>Limitations</li>\n</ul>\n</p>\n<br/>\n<p>On occasion there may be a separate <a href=\"www.google.com\" target=\"_blank\">hyperlink to another site</a>, or <sup>1</sup>other tag types.</p>\n<br/>\n<sup>1</sup>These are common disclaimer conventions solved by the inclusion of basic HTML",
                "companyUuid": "d50195db-34f8-4dda-8702-e87165cce17d",
                "financialInstitutionUuid": "fa8ed168-9a3e-4612-aa2a-47781dede8f1"
            },
            "originatorId": null,
            "termLength": 36,
            "termUnit": "month",
            "maxAmount": 10000,
            "minAmount": 10000,
            "maxApr": 13.99,
            "minApr": 13.99,
            "meanApr": 13.99,
            "feeRate": null,
            "maxFeeRate": null,
            "minFeeRate": null,
            "feeFixed": null,
            "maxFeeFixed": null,
            "minFeeFixed": null,
            "allowPrepayment": true,
            "prepaymentFee": null,
            "monthlyPayment": 341.73,
            "maxMonthlyPayment": 341.73,
            "minMonthlyPayment": 341.73,
            "meanMonthlyPayment": 341.73,
            "maxTotalPayment": 12303,
            "minTotalPayment": 12303,
            "meanTotalPayment": 12303,
            "terms": null,
            "url": "https://offers.moneylion.com/ref/6a946016-702f-4e8c-8b3b-1d194d6743fb",
            "preQualified": true,
            "preApproved": false,
            "secured": false,
            "sponsored": false,
            "recommendationScore": null,
            "productType": "loan",
            "productSubType": "personal_loan",
            "payout": null,
            "aprType": "fixed",
            "coApplicant": false,
            "aprDescription": null,
            "displayTermUnit": null,
            "productSubTypeDisclaimer": null,
            "monthlyPaymentDescription": null,
            "termDescription": null,
            "amountPrefix": null
        },
        {...other loan offers}
    ],
    "mortgageOffers": [],
    "savingsOffers": [],
    "specialOffers": [
        {
            "uuid": "8ddc320c-2a52-4c87-ba35-bfce3a8a7b3a",
            "name": "Mock Credit Builder Offer",
            "desc": "Description of the credit builder offer",
            "url": "https://offers.moneylion.com/ref/37089591-5d47-4219-a532-a65f7bd8c535",
            "partnerName": "Engine Demo Loans Demand Sub Account 1",
            "partnerImageUrl": "https://s3.amazonaws.com/images.evenfinancial.com/logos/dev/engine_demo_loans_demand_sub_account_1-202-wqm88e4a.png",
            "productSubType": "credit_builder",
            "disclaimer": "test special offer disclaimer 1",
            "financialInstitutionUuid": "fa8ed168-9a3e-4612-aa2a-47781dede8f1"
        }
    ],
    "pendingOriginators": [],
    "pendingResponses": []
}
```

`specialOffers` returned in rate tables that also contain `loanOffers` are static 2nd Look (i.e. non-loan) offers that are unlikely to be a match for the applicant requesting a loan, and should be ignored.

You should write your display logic such that:&#x20;

* If `loanOffers` is present and non-empty, display all loan offers.&#x20;
* If `loanOffers` is empty, display `specialOffers.`&#x20;

Leads posted with `productTypes: ["loan", "other"]` will always get either `loanOffers` or `specialOffers` in the resulting rate table.

#### Response field mapping

Below is the mapping of the required fields for the offer display page to the fields present in the “`loanOffers`” section of the API response:

| **Key**                                                                                                                           | **Value**                                                        |
| --------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| Financial Services Partner Logo                                                                                                   | originator.images.url                                            |
| Offer Amount                                                                                                                      | maxAmount                                                        |
| Offer Term Length                                                                                                                 | termLength                                                       |
| Offer Term Unit                                                                                                                   | termUnit                                                         |
| Offer Term Description                                                                                                            | termDescription                                                  |
| Offer APR Amount (%)                                                                                                              | maxApr                                                           |
| Offer APR Description                                                                                                             | aprDescription                                                   |
| Offer Monthly Payment Amount                                                                                                      | maxMonthlyPayment                                                |
| Offer Monthly Payment Description                                                                                                 | monthlyPaymentDescription                                        |
| <p>• If “preApproved” is “true”</p><p>• If “preQualified” is “true”</p><p>• If both “preApproved” & “preQualified” are “true”</p> | <p>• Pre-Approved</p><p>• Pre-Qualified</p><p>• Pre-Approved</p> |
| Offer Disclaimer                                                                                                                  | originator.disclaimer                                            |

For the additional fields required for Secured Loans or Line of Credit products:

| **Key**                 | **Value**                |
| ----------------------- | ------------------------ |
| Product Type Label      | productSubType           |
| Product Type Disclaimer | productSubTypeDisclaimer |

#### **Error codes**

Response types are mapped to HTTP status codes. In particular:

* **200 OK:** when data is successfully returned for a GET request
* **201 Created:** when new data is submitted via a POST
* **400 Bad Request:** the submitted data is malformed
* **401 Unauthorized:** when the Authorization header is missing, if the value is invalid, or if the corresponding access token lacks the required scopes to complete the request
* **404 Not Found:** the URL is invalid, or the resource ID reference in the URL does not exist
* **422 Unprocessable Entity:** the submitted data is properly formatted, but invalid according to business logic (some legacy endpoints use 409 Conflict in this case)
* **5xx:** server error

Minor version changes to the API are guaranteed to be backwards compatible. Major version changes may break the API, but legacy versions are supported indefinitely.


---

# Agent Instructions: 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:

```
GET https://even-financial.gitbook.io/developer-center/native-api-integrations/personal/api-specifications.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
