# API Specifications

This section explains how user information is transmitted to Engine by MoneyLion's API via HTTP requests.

There are two steps involved for getting offers from Engine's 2nd Look Marketplace:

### Step 1: Submit Lead

As the first step, partners should post to the **Submit Lead** endpoint with the user's information:&#x20;

`POST` to `https://api.engine.tech/leads/rateTables`

### Post Request Authorization <a href="#post-request-authorization" id="post-request-authorization"></a>

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". Please contact your Engine Partner Manager for an appropriate bearer token for API testing.

```
Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

#### Request Format

The required format of the request (in JSON) is shown below:&#x20;

<pre class="language-json" data-overflow="wrap"><code class="lang-json"><strong>curl -L -X POST 'https://api.engine.tech/leads/rateTables' \
</strong>-H 'Content-Type: application/json' \
-H 'Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-H 'User-Agent: curl/7.68.0' \
--data-raw '{
  "productTypes": ["other"], 
  "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": "230-13-2346" 
  },
  "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,
    "consentsToSms" 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": "MyApp/2.1 (iOS 16.3; iPhone13,2)"
  }
}'
</code></pre>

#### **Required Fields:**&#x20;

**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;

**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 %}

**Client Tags**

<table><thead><tr><th width="143.78143310546875">Field</th><th width="143.0289306640625">Type</th><th>Required (Yes/No)</th><th>Sample Value</th><th>Enum/Comment</th></tr></thead><tbody><tr><td><code>clientId</code></td><td>array</td><td>No</td><td>clientId123</td><td>Client Tags can be added for ease of reporting/attribution (i.e. for the partner's convenience when Engine reports metrics to the partner). Refer to <a href="https://engine.tech/developer-center/loans-savings-second-look-marketplace/api/client-tags">Client Tags for Reporting</a> for details</td></tr></tbody></table>

**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 from the Submit Lead Endpoint

After posting to the `Submit Lead` endpoint, partners will receive a response almost instantaneously. Below is a sample response:&#x20;

```json
{
  "uuid": "b9b212a8-b284-5986-813e-a8d8e87c1863",
  "leadUuid": "144bd0ea-b9c6-52d5-a7ef-dccb223d060d",
  "loanAmount": 1000,
  "loanOffers": [],
  "mortgageOffers": [],
  "savingsOffers": [],
  "specialOffers": [{...one or more 2nd Look offers, if those resolve immediately}],
  "creditCardOffers": [],
  "pendingResponses": [
    {
      "partner": {
        "uuid": "91d08be0-2a8c-4d28-b399-7e1b38e2522e",
        "name": "Beta Inc.",
        "description": "Voluptas quas aspernatur aut nihil rerum. Voluptatibus laboriosam amet porro veniam ut.",
        "disclaimer": "Est delectus et rem consequatur magni. Molestiae asperiores sit debitis et id corporis.",
        "imageUrl": "https://aff-tag.evenfinancial.com/images/beta/Beta_120x80.png"
      },
      "productTypes": [
        "other"
      ]
    }
  ],
  "pendingOriginators": []
}
```

You’ll receive the following information upon a successful request. Note that the initial response **does not** include complete offer information.&#x20;

* `uuid`: Engine’s Rate Table UUID, used to retrieve offer data
* `leadUuid`: Engine’s Lead UUID, which partners should retain for internal records
* `loanOffers` - This is an array that contains 1st Look offers (i.e. prequalified/preapproved loan offers).&#x20;
* `specialOffers` - This is an array that contains 2nd Look Marketplace offers (i.e. alternative products such as debt relief and credit builders)&#x20;
* `pendingOriginators` - Deprecated field. Partners should ignore this field.&#x20;
* `pendingResponses` - This is a list of FI partners from which Engine is awaiting responses.
  * If `pendingResponses` is empty, it means all offers from Engine's Financial Partners for the lead have been returned. The supply partner will not need to make any further API calls (i.e. ignore Step 2 below)
  * If `pendingResponses` is NOT empty, it means Engine is still awaiting responses from FI partners. In this common scenario, the supply partner will need to continue to step 2 and poll the `GET originator/rateTables/:uuid` endpoint until all requests to FI partners are resolved.

{% hint style="info" %}
`leadUuid` is not needed to make the second call to retrieve offers, but you should record it in case you need to reach out to your Partner Manager regarding any questions or issues regarding that lead.
{% endhint %}

### Step 2: Poll the `GET /originator/rateTables` endpoint for a Specific rate table `uuid` until `pendingResponses` is empty

Below are the instructions for the secondary request(s) that channel partners need to follow, in order to retrieve the complete offers for a specific user from Step 1:

1. **Capture `uuid`**: Capture the `uuid` returned in Engine's response (the call made in Step 1)
2. **Execute `GET` request:** Use the captured `uuid` to make a GET request to the endpoint below:

* `GET https://api.engine.tech/originator/rateTables/:uuid`

3. **Polling**: If there are `pendingResponses` (i.e. the array is not empty), continue polling every second.
   * Rate tables will typically resolve within 15 seconds if `productTypes` is set to `"other"` .

Below is a sample response from step 2's `GET originator/rateTables/:uuid` request. The `pendingResponses` field is empty, showing that all responses from Financial Institution partners have been received by the Engine.

```json
{
  "uuid": "b9b212a8-b284-5986-813e-a8d8e87c1863",
  "leadUuid": "144bd0ea-b9c6-52d5-a7ef-dccb223d060d",
  "loanAmount": 10000,
  "loanOffers": [],
  "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"
      }
  ],
  "creditCardOffers": [],
  "pendingResponses": [],
  "pendingOriginators": []
}
```

For your visibility, below are the typical response time it takes for Engine to receive offers from all our  Financial Institutions partners.&#x20;

**2nd Look Marketplace Response Time**

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

For mapping of the fields for display, you may refer to the previous section - [Displaying 2L Marketplace Offers](https://engine.tech/developer-center/loans-savings-second-look-marketplace/api/products/2nd-look-marketplace/channel-partners/displaying-offers).&#x20;

#### **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
