> ## Documentation Index
> Fetch the complete documentation index at: https://api.monument.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Shopping api

# Rental Flow API Reference Guide

This document provides a comprehensive guide for integrating with the Monument rental flow API. The API allows third-party companies to build custom rental experiences for their customers.

## Base URL

All endpoints are prefixed with:

```
https://public-api.{env}.monument.io/shopping/:portfolio/v1
```

Where `:portfolio` is the defined database prefix.

## Authentication

All requests require an API key in the header:

```
x-api-key: YOUR_API_KEY
```

## Table of Contents

1. [Get Facilities](#1-get-facilities)
2. [Get Unit Groups](#2-get-unit-groups)
3. [Create a Lead](#3-create-a-lead)
4. [Check if Tenant Exists](#4-check-if-tenant-exists)
5. [Validate Pre-existing Tenant Code](#5-validate-pre-existing-tenant-code)
6. [Get Lead Information](#6-get-lead-information)
7. [Fill in Lead Information](#7-fill-in-lead-information)
8. [Change Facility or Unit Group](#8-change-facility-or-unit-group)
9. [Retrieve Shopping Cart](#9-retrieve-shopping-cart)
10. [Request Coverage List for Facility](#10-request-coverage-list-for-facility)
11. [Assign Coverage or Mark Private Insurance](#11-assign-coverage-or-mark-private-insurance)
12. [Get Additional Services for Unit Group](#12-get-additional-services-for-unit-group)
13. [Assign Additional Services to Lead](#13-assign-additional-services-to-lead)
14. [View Available Access Plans](#14-view-available-access-plans)
15. [Assign Access Plans to Lead](#15-assign-access-plans-to-lead)
16. [Get Payrix Public Keys](#16-get-payrix-public-keys)
17. [Create Payment Profile](#17-create-payment-profile)
18. [Get PandaDoc Iframe Link](#18-get-pandadoc-iframe-link)
19. [Generate Lease](#19-generate-lease)
20. [Sign Lease Redirect](#20-sign-lease-redirect)
21. [Check if Lead Converted to Tenant](#21-check-if-lead-converted-to-tenant)
22. [Minimum Requirements for Lead Conversion](#22-minimum-requirements-for-lead-conversion)
23. [Exit Shopping Experience](#23-exit-shopping-experience)
24. [Get Unit Details](#24-get-unit-details)
25. [Get Gate Access Code](#25-get-gate-access-code)
26. [Get Facility Policies](#26-get-facility-policies)
27. [Find Eligible Auto-Applied Promotions](#27-find-eligible-auto-applied-promotions)
28. [Get Portfolio Organization](#28-get-portfolio-organization)
29. [Get Required Fields for a Facility](#29-get-required-fields-for-a-facility)
30. [Get Lead Completion Status](#30-get-lead-completion-status)

***

## 1. Get Facilities

Retrieves a list of all available facilities in the portfolio.

### Endpoint

```
GET /shopping/:portfolio/v1/facilities
```

### Request Headers

```
x-api-key: YOUR_API_KEY
```

### Response

```json theme={null}
[
  {
    "facilityUuid": "123e4567-e89b-12d3-a456-426614174000",
    "facilityName": "Downtown Storage",
    "address": "123 Main St, Austin, TX 78701",
    "phone": "+1-512-555-0100",
    "email": "info@downtownstorage.com",
    "amenities": ["Climate Controlled", "24/7 Access", "Drive-Up Access"],
    "unitTypes": ["Standard", "Climate Controlled"],
    "uniqueAreas": [25, 50, 100, 200],
    "operatingHours": {
      "Sunday": {
        "isOpen": true,
        "openTime": "06:00:00",
        "closeTime": "22:00:00"
      },
      "Monday": {
        "isOpen": true,
        "openTime": "06:00:00",
        "closeTime": "22:00:00"
      },
      "Tuesday": {
        "isOpen": true,
        "openTime": "06:00:00",
        "closeTime": "22:00:00"
      },
      "Wednesday": {
        "isOpen": true,
        "openTime": "06:00:00",
        "closeTime": "22:00:00"
      },
      "Thursday": {
        "isOpen": true,
        "openTime": "06:00:00",
        "closeTime": "22:00:00"
      },
      "Friday": {
        "isOpen": true,
        "openTime": "06:00:00",
        "closeTime": "22:00:00"
      },
      "Saturday": {
        "isOpen": true,
        "openTime": "06:00:00",
        "closeTime": "22:00:00"
      }
    },
    "minimumCurrentWebRateInPennies": 12000,
    "correspondingCurrentStreetRateInPennies": 15000,
    "rating": 5,
    "latitude": "30.2672",
    "longitude": "-97.7431",
    "publicThumbnailUuid": "123e4567-e89b-12d3-a456-426614174020",
    "publicHeroImageUuid": "123e4567-e89b-12d3-a456-426614174021",
    "facilityGateIntegrationVendorUuid": "123e4567-e89b-12d3-a456-426614174022",
    "bestAutoAppliedPromotion": {
      "promotionUuid": "123e4567-e89b-12d3-a456-426614174023",
      "promotionName": "First Month Free",
      "discountType": "FIXED_AMOUNT",
      "discountAmountInPennies": 12000
    }
  }
]
```

***

## 2. Get Unit Groups

### Understanding Unit Groups

**Unit Groups** are collections of similar storage units that share the same characteristics (size, features, pricing). When a customer selects a unit group, they are not selecting a specific physical unit - instead, they are reserving a unit from that group. The actual unit assignment happens later in the process.

### Get Unit Groups for a Facility

Retrieves all unit groups available at a specific facility.

#### Endpoint

```
GET /shopping/:portfolio/v1/facilities/:facilityUuid/unitGroups
```

#### Request Headers

```
x-api-key: YOUR_API_KEY
```

#### Path Parameters

* `facilityUuid` (string, required): UUID of the facility

#### Response

```json theme={null}
[
  {
    "unitGroupUuid": "123e4567-e89b-12d3-a456-426614174001",
    "description": "5x5 Climate Controlled",
    "unitGroupDepth": 5,
    "unitGroupWidth": 5,
    "unitGroupHeight": 8,
    "amenities": [
      {
        "key": "climateControlled",
        "present": true
      },
      {
        "key": "driveUp",
        "present": false
      }
    ],
    "types": {
      "vehicleRv": false,
      "selfStorage": true
    },
    "availableUnitCount": 3,
    "unitCount": 10,
    "facilityName": "Downtown Storage",
    "facilityAddress": "123 Main St, Austin, TX 78701",
    "currentStreetRate": 15000,
    "currentWebRate": 12000,
    "unitType": "Climate Controlled",
    "unitTypeImage": "https://example.com/images/unit-type.jpg",
    "bestAutoAppliedPromotion": {
      "promotionUuid": "123e4567-e89b-12d3-a456-426614174023",
      "promotionName": "First Month Free",
      "discountType": "FIXED_AMOUNT",
      "discountAmountInPennies": 12000
    }
  }
]
```

### Get Unit Group Details

Retrieves detailed information about a specific unit group, including available additional services.

#### Endpoint

```
GET /shopping/:portfolio/v1/unitGroups/:unitGroupUuid
```

#### Request Headers

```
x-api-key: YOUR_API_KEY
```

#### Path Parameters

* `unitGroupUuid` (string, required): UUID of the unit group

#### Query Parameters

* `isForBusiness` (boolean, optional): Whether this is for a business rental

#### Response

```json theme={null}
{
  "unitGroupUuid": "123e4567-e89b-12d3-a456-426614174001",
  "description": "5x5 Climate Controlled",
  "unitGroupDepth": 5,
  "unitGroupWidth": 5,
  "unitGroupHeight": 8,
  "amenities": [
    {
      "key": "climateControlled",
      "present": true
    }
  ],
  "types": {
    "vehicleRv": false,
    "selfStorage": true
  },
  "availableUnitCount": 3,
  "unitCount": 10,
  "facilityName": "Downtown Storage",
  "facilityAddress": "123 Main St, Austin, TX 78701",
  "currentStreetRate": 15000,
  "currentWebRate": 12000,
  "unitType": "Climate Controlled",
  "unitTypeImage": "https://example.com/images/unit-type.jpg",
  "bestAutoAppliedPromotion": {
    "promotionUuid": "123e4567-e89b-12d3-a456-426614174023",
    "promotionName": "First Month Free",
    "discountType": "FIXED_AMOUNT",
    "discountAmountInPennies": 12000
  },
  "additionalServices": [
    {
      "itemUuid": "123e4567-e89b-12d3-a456-426614174002",
      "itemTypeUuid": "123e4567-e89b-12d3-a456-426614174002",
      "entityAttributeOrganizationUuid": null,
      "title": "Climate Control Service",
      "description": "Maintains temperature and humidity",
      "priceInPennies": 2000,
      "isRecurring": true,
      "isRequiredAtMoveIn": false,
      "feeType": "FIXED_AMOUNT"
    }
  ]
}
```

***

## 3. Create a Lead

Creates a new lead associated with a facility and unit group. Returns a verification token that must be used for all subsequent requests for this lead.

### Endpoint

```
POST /shopping/:portfolio/v1/facilities/lead
```

### Request Headers

```
x-api-key: YOUR_API_KEY
Content-Type: application/json
```

### Request Body

```json theme={null}
{
  "facilityUuid": "123e4567-e89b-12d3-a456-426614174000",
  "unitGroupUuid": "123e4567-e89b-12d3-a456-426614174001",
  "person": {
    "firstName": "John",
    "lastName": "Doe",
    "email": "john.doe@example.com",
    "phone": "+15125550100"
  }
}
```

**Request Body Fields**:

* `facilityUuid` (string, required): UUID of the facility
* `unitGroupUuid` (string, required): UUID of the unit group
* `person` (object, required): Person information
  * `firstName` (string, required): First name
  * `lastName` (string, required): Last name
  * `email` (string, required): Email address
  * `phone` (string, optional): Phone number
  * `phoneType` (string, optional): Phone type (e.g., "MOBILE", "HOME", "WORK")
  * `addressLine1` (string, optional): Street address line 1
  * `addressLine2` (string, optional): Street address line 2
  * `city` (string, optional): City
  * `state` (string, optional): State code
  * `country` (string, optional): Country code
  * `zip` (string, optional): ZIP/postal code
  * `isSmsEnrolled` (boolean, optional): Whether SMS enrollment is enabled
  * `haveMilitary` (boolean, optional): Whether person has military record
  * `military` (object, optional): Military information (required if `haveMilitary` is true)
    * `branch` (string, optional): Military branch
    * `commandingOfficer` (string, required): Commanding officer name
    * `commandingOfficerEmail` (string, required, nullable): Commanding officer email
    * `startDateOfService` (date, required): Start date of military service
    * `dateOfBirth` (date, required): Date of birth
  * `identification` (object, optional): Identification information
    * `identificationType` (string, required): Identification type (e.g., "DRIVERS\_LICENSE", "PASSPORT")
    * `identificationString` (string, required, nullable): Identification number
    * `issueDate` (date, optional): Issue date
    * `expirationDate` (string, optional): Expiration date
    * `country` (string, required): Country where ID was issued
    * `state` (string, required): State where ID was issued
* `dateDesiredMoveIn` (date, optional, nullable): Desired move-in date
* `leadType` (string, optional): Lead type (e.g., "PERSONAL", "BUSINESS")
* `leadStatus` (string, optional): Lead status (e.g., "OPEN", "RESERVED")
* `businessName` (string, optional, nullable): Business name (for business accounts)
* `taxId` (string, optional, nullable): Tax ID (for business accounts)
* `haveVehicle` (boolean, optional): Whether lead has a vehicle
  * `vehicle` (object, optional): Vehicle information (see [section 7](#7-fill-in-lead-information) for full structure)
* `haveAlternateContact` (boolean, optional): Whether lead has an alternate contact
* `alternateContact` (object, optional): Alternate contact information (see [section 7](#7-fill-in-lead-information) for full structure)
* `hasBeneficiary` (boolean, optional): Whether lead has a beneficiary
* `beneficiary` (object, optional): Beneficiary information (see [section 7](#7-fill-in-lead-information) for full structure)

### Response

```json theme={null}
{
  "leadUuid": "123e4567-e89b-12d3-a456-426614174003",
  "verifyToken": "abc123xyz789"
}
```

**Response Fields**:

* `leadUuid` (string, required): UUID of the created lead
* `verifyToken` (string, required, nullable): Verification token for authenticating future requests. May be `null` in some cases.

**Important**: Save both `leadUuid` and `verifyToken` - you'll need them for all subsequent API calls for this lead. The `verifyToken` is used to authenticate requests when updating lead information (see [section 7](#7-fill-in-lead-information)).

***

## 4. Check if Tenant Exists

Checks if a tenant with the provided email already exists in the system. If they do, a verification code will be sent to their email. Allowing further validation (see [section 5](#5-validate-pre-existing-tenant-code)).
We recommend to run this validation whenever inputting a new email for a lead, this ensures data consistency and security.

**Important**: If a lead is created without going through this verification and the email is already associated with an existing tenant, the conversion will fail and the lead will be contacted about the email issue.

### Endpoint

```
POST /shopping/:portfolio/v1/facilities/tenant/check-preexisting
```

### Request Headers

```
x-api-key: YOUR_API_KEY
Content-Type: application/json
```

### Request Body

```json theme={null}
{
  "email": "john.doe@example.com"
}
```

### Response

```json theme={null}
{
  "exists": true,
  "expiration": "2025-11-13T14:50:30.000Z"
}
```

If `exists` is `true`, proceed to [section 5](#5-validate-pre-existing-tenant-code) to validate the verification code.

***

## 5. Validate Pre-existing Tenant Code

After checking if a tenant exists ([section 4](#4-check-if-tenant-exists)) and receiving the verification code sent to their email, validate the code to create a lead associated with their existing account.

### Endpoint

```
POST /shopping/:portfolio/v1/facilities/tenant/validate-preexisting
```

### Request Headers

```
x-api-key: YOUR_API_KEY
Content-Type: application/json
```

### Request Body

**Required Fields:**

* `email` (string, required): Email address of the pre-existing tenant
* `validationCode` (string, required): Verification code sent to the tenant's email
* `unitGroupUuid` (string, required): UUID of the unit group
* `facilityUuid` (string, required): UUID of the facility

**Optional Fields:**

* `leadUuid` (string, optional): UUID of an existing lead (if updating an existing lead)

**Example Request:**

```json theme={null}
{
  "email": "john.doe@example.com",
  "validationCode": "123456",
  "unitGroupUuid": "123e4567-e89b-12d3-a456-426614174001",
  "facilityUuid": "123e4567-e89b-12d3-a456-426614174000",
  "leadUuid": "123e4567-e89b-12d3-a456-426614174003"
}
```

### Response

```json theme={null}
{
  "valid": true,
  "expired": false,
  "personalInfo": {
    "personUuid": "123e4567-e89b-12d3-a456-426614174024",
    "firstName": "John",
    "lastName": "Doe",
    "email": "john.doe@example.com",
    "phone": "+15125550100",
    "addressLine1": "456 Oak Ave",
    "addressLine2": null,
    "city": "Austin",
    "state": "TX",
    "country": "US",
    "zip": "78702",
    "businessName": null,
    "taxId": null,
    "isSmsEnrolled": true,
    "phoneType": "MOBILE",
    "idType": "DRIVERS_LICENSE",
    "idCode": "12345678",
    "idState": "TX",
    "idCountry": "US",
    "accountType": "PERSONAL",
    "haveAlternateContact": false,
    "alternateContactFirstName": null,
    "alternateContactLastName": null,
    "alternateContactPhone": null,
    "alternateContactRelationship": null,
    "haveMilitary": false,
    "militaryBranch": null,
    "dateOfBirth": "1990-01-15T00:00:00Z",
    "startDateOfService": null,
    "commanderOfficer": null,
    "officerEmail": null,
    "dateDesiredMoveIn": "2024-02-01T00:00:00Z",
    "haveVehicle": false,
    "haveLienHolder": false,
    "isPreviousTenant": false,
    "vehicleType": null,
    "vehicleMake": null,
    "vehicleModel": null,
    "vinNumber": null,
    "licensePlate": null,
    "lienHolderName": null,
    "lienHolderAddress": null,
    "facilityUuid": "123e4567-e89b-12d3-a456-426614174000",
    "unitGroupUuid": "123e4567-e89b-12d3-a456-426614174001",
    "leadUuid": "123e4567-e89b-12d3-a456-426614174003",
    "beneficiary": null
  },
  "createdLead": {
    "leadUuid": "123e4567-e89b-12d3-a456-426614174003",
    "verifyToken": "abc123xyz789"
  }
}
```

If validation is successful, use the `createdLead` information to continue with the rental flow.

**Important**: If validation fails (e.g., `valid` is `false` or the code is expired), you cannot create a lead with the same email address from an existing tenant unless you successfully validate the code. This validation is required to connect the new lead to the existing tenant account. If validation fails, you must either retry with the correct verification code or use a different email address.

***

## 6. Get Lead Information

Validates a lead verification token and returns the lead's personal information. Useful for resuming a shopping session or verifying lead identity.

### Endpoint

```
GET /shopping/:portfolio/v1/facilities/lead/:leadUuid
```

### Request Headers

```
x-api-key: YOUR_API_KEY
```

### Path Parameters

* `leadUuid` (string, required): UUID of the lead

### Query Parameters

* `verifyToken` (string, required): The verification token returned when the lead was created

### Response

```json theme={null}
{
  "personUuid": "123e4567-e89b-12d3-a456-426614174000",
  "firstName": "John",
  "lastName": "Doe",
  "email": "john.doe@example.com",
  "phone": "+15125550100",
  "phoneType": "MOBILE",
  "addressLine1": "456 Oak Ave",
  "addressLine2": null,
  "city": "Austin",
  "state": "TX",
  "country": "US",
  "zip": "78702",
  "businessName": null,
  "taxId": null,
  "isSmsEnrolled": true,
  "idType": "DRIVERS_LICENSE",
  "idCode": "12345678",
  "idState": "TX",
  "idCountry": "US",
  "accountType": "PERSONAL",
  "haveAlternateContact": false,
  "alternateContactFirstName": null,
  "alternateContactLastName": null,
  "alternateContactPhone": null,
  "alternateContactRelationship": null,
  "haveMilitary": false,
  "militaryBranch": null,
  "dateOfBirth": null,
  "startDateOfService": null,
  "commanderOfficer": null,
  "officerEmail": null,
  "dateDesiredMoveIn": "2024-02-01T00:00:00Z",
  "haveVehicle": false,
  "haveLienHolder": false,
  "isPreviousTenant": false,
  "vehicleType": null,
  "vehicleMake": null,
  "vehicleModel": null,
  "vinNumber": null,
  "licensePlate": null,
  "lienHolderName": null,
  "lienHolderAddress": null,
  "facilityUuid": "123e4567-e89b-12d3-a456-426614174001",
  "unitGroupUuid": "123e4567-e89b-12d3-a456-426614174002",
  "leadUuid": "123e4567-e89b-12d3-a456-426614174003",
  "beneficiary": null
}
```

**Response Fields**:

* `personUuid` (string, required): UUID of the person
* `firstName` (string, required): First name
* `lastName` (string, required): Last name
* `email` (string, required, nullable): Email address
* `phone` (string, required, nullable): Phone number
* `phoneType` (string, required): Phone type (e.g., "MOBILE", "HOME", "WORK")
* `addressLine1` (string, required, nullable): Street address line 1
* `addressLine2` (string, required, nullable): Street address line 2
* `city` (string, required, nullable): City
* `state` (string, required): State code
* `country` (string, required): Country code
* `zip` (string, required, nullable): ZIP/postal code
* `businessName` (string, required, nullable): Business name (for business accounts)
* `taxId` (string, required, nullable): Tax ID (for business accounts)
* `isSmsEnrolled` (boolean, optional): Whether SMS enrollment is enabled
* `idType` (string, required): Identification type (e.g., "DRIVERS\_LICENSE", "PASSPORT")
* `idCode` (string, required): Identification number
* `idState` (string, optional, nullable): State where ID was issued
* `idCountry` (string, optional, nullable): Country where ID was issued
* `accountType` (string, required): Account type (e.g., "PERSONAL", "BUSINESS")
* `haveAlternateContact` (boolean, optional, nullable): Whether alternate contact exists
* `alternateContactFirstName` (string, optional, nullable): Alternate contact first name
* `alternateContactLastName` (string, optional, nullable): Alternate contact last name
* `alternateContactPhone` (string, optional, nullable): Alternate contact phone
* `alternateContactRelationship` (string, optional, nullable): Relationship to alternate contact
* `haveMilitary` (boolean, optional): Whether person has military record
* `militaryBranch` (string, optional, nullable): Military branch
* `dateOfBirth` (date, optional, nullable): Date of birth
* `startDateOfService` (date, optional, nullable): Start date of military service
* `commanderOfficer` (string, optional, nullable): Commanding officer name
* `officerEmail` (string, optional, nullable): Commanding officer email
* `dateDesiredMoveIn` (date, optional, nullable): Desired move-in date
* `haveVehicle` (boolean, optional): Whether lead has a vehicle
* `haveLienHolder` (boolean, optional): Whether vehicle has a lien holder
* `isPreviousTenant` (boolean, optional): Whether person is a previous tenant
* `vehicleType` (string, optional, nullable): Vehicle type
* `vehicleMake` (string, optional, nullable): Vehicle make
* `vehicleModel` (string, optional, nullable): Vehicle model
* `vinNumber` (string, optional, nullable): Vehicle VIN number
* `licensePlate` (string, optional, nullable): License plate number
* `lienHolderName` (string, optional, nullable): Lien holder name
* `lienHolderAddress` (string, optional, nullable): Lien holder address
* `facilityUuid` (string, optional): UUID of the facility associated with the lead
* `unitGroupUuid` (string, optional): UUID of the unit group associated with the lead
* `leadUuid` (string, optional): UUID of the lead
* `beneficiary` (object, optional, nullable): Beneficiary information
  * `firstName` (string, optional): Beneficiary first name
  * `lastName` (string, optional): Beneficiary last name
  * `email` (string, optional): Beneficiary email
  * `phone` (string, optional): Beneficiary phone
  * `relationship` (string, optional): Relationship to beneficiary

**Note**: This endpoint is useful for resuming a shopping session when a user returns. Store the `verifyToken` securely and use it to validate and retrieve lead information. The response includes all personal information associated with the lead, including optional fields that may be null if not provided.

***

## 7. Fill in Lead Information

Updates a lead with personal information, unit details, and other required fields. Requires the verification token from lead creation.

### Endpoint

```
PUT /shopping/:portfolio/v1/facilities/lead/:leadUuid
```

### Request Headers

```
x-api-key: YOUR_API_KEY
Content-Type: application/json
```

### Path Parameters

* `leadUuid` (string, required): UUID of the lead

### Request Body

**Required Fields:**

* `verifyToken` (string, required): Verification token from lead creation

**Optional Fields:**

* `lead` (object, optional): Lead information object
  * `person` (object, required if `lead` is provided): Person information
    * `firstName` (string, required): First name
    * `lastName` (string, required): Last name
    * `email` (string, required): Email address
    * `phone` (string, optional): Phone number
    * `phoneType` (string, optional): Phone type (e.g., "MOBILE", "HOME", "WORK")
    * `addressLine1` (string, optional): Street address line 1
    * `addressLine2` (string, optional): Street address line 2
    * `city` (string, optional): City
    * `state` (string, optional): State code
    * `country` (string, optional): Country code
    * `zip` (string, optional): ZIP code
    * `isSmsEnrolled` (boolean, optional): Whether SMS enrollment is enabled
    * `identification` (object, optional): Identification information
      * `idType` (string, optional): Type of ID (e.g., "DRIVERS\_LICENSE")
      * `idCode` (string, optional): ID number
      * `idState` (string, optional): State where ID was issued
      * `idCountry` (string, optional): Country where ID was issued
    * `military` (object, optional): Military information
      * `militaryBranch` (string, optional): Branch of military
      * `startDateOfService` (date, optional): Start date of service
      * `commanderOfficer` (string, optional): Commander/officer name
      * `officerEmail` (string, optional): Officer email
    * `haveMilitary` (boolean, optional): Whether person has military affiliation
  * `leadType` (string, optional): Type of lead ("PERSONAL" or "BUSINESS")
  * `leadStatus` (string, optional): Status of the lead
  * `businessName` (string, optional): Business name (required if leadType is "BUSINESS")
  * `taxId` (string, optional): Tax ID number
  * `dateDesiredMoveIn` (date, optional): Desired move-in date
  * `hasBeneficiary` (boolean, optional): Whether lead has a beneficiary
  * `beneficiary` (object, optional): Beneficiary information
    * `firstName` (string, optional): Beneficiary first name
    * `lastName` (string, optional): Beneficiary last name
    * `email` (string, optional): Beneficiary email
    * `phone` (string, optional): Beneficiary phone
    * `relationship` (string, optional): Relationship to lead
  * `haveAlternateContact` (boolean, optional): Whether lead has alternate contact
  * `alternateContact` (object, optional): Alternate contact information
    * `firstName` (string, optional): Alternate contact first name
    * `lastName` (string, optional): Alternate contact last name
    * `phone` (string, optional): Alternate contact phone
    * `relationship` (string, optional): Relationship to lead
  * `haveVehicle` (boolean, optional): Whether lead has a vehicle
  * `vehicle` (object, optional): Vehicle information
    * `type` (string, required if vehicle provided): Vehicle type
    * `make` (string, required if vehicle provided): Vehicle make
    * `model` (string, required if vehicle provided): Vehicle model
    * `vinNumber` (string, required if vehicle provided): VIN number
    * `licensePlateNumber` (string, optional): License plate number
    * `haveVehicleLien` (boolean, required if vehicle provided): Whether vehicle has a lien
    * `vehicleLien` (object, optional): Lien holder information
      * `name` (string, optional): Lien holder name
      * `address` (string, optional): Lien holder address
* `facilityUuid` (string, optional): UUID of the facility
* `unitGroupUuid` (string, optional): UUID of the unit group
* `coverageUuid` (string, optional, nullable): UUID of the coverage option, or null for no coverage
* `accessPlanUuid` (string, optional, nullable): UUID of the access plan, or null for no access plan
* `additionalServices` (array of strings, optional): Array of additional service UUIDs
* `isAutopayEnabled` (boolean, optional): Whether autopay is enabled

**Example Request:**

```json theme={null}
{
  "verifyToken": "abc123xyz789",
  "lead": {
    "person": {
      "firstName": "John",
      "lastName": "Doe",
      "email": "john.doe@example.com",
      "phone": "+15125550100",
      "phoneType": "MOBILE",
      "addressLine1": "456 Oak Ave",
      "city": "Austin",
      "state": "TX",
      "zip": "78702",
      "country": "US",
      "isSmsEnrolled": true,
      "identification": {
        "idType": "DRIVERS_LICENSE",
        "idCode": "12345678",
        "idState": "TX",
        "idCountry": "US"
      }
    },
    "leadType": "PERSONAL",
    "dateDesiredMoveIn": "2024-02-01T00:00:00Z",
    "haveVehicle": false,
    "haveAlternateContact": false,
    "hasBeneficiary": false
  },
  "facilityUuid": "123e4567-e89b-12d3-a456-426614174000",
  "unitGroupUuid": "123e4567-e89b-12d3-a456-426614174001"
}
```

### Response

```
200 OK
```

**Note**: The `verifyToken` must match the token returned when the lead was created, or the request will fail with a 403 Forbidden error.

***

## 8. Change Facility or Unit Group

Updates a lead's facility or unit group selection. This can be done by including the new `facilityUuid` or `unitGroupUuid` in the update lead request.

### Endpoint

```
PUT /shopping/:portfolio/v1/facilities/lead/:leadUuid
```

### Request Headers

```
x-api-key: YOUR_API_KEY
Content-Type: application/json
```

### Request Body

**Required Fields:**

* `verifyToken` (string, required): Verification token from lead creation

**Optional Fields:**

* `facilityUuid` (string, optional): New facility UUID
* `unitGroupUuid` (string, optional): New unit group UUID
* `lead` (object, optional): Lead information (see [section 7](#7-fill-in-lead-information) for full structure)
* `coverageUuid` (string, optional, nullable): Coverage UUID or null
* `accessPlanUuid` (string, optional, nullable): Access plan UUID or null
* `additionalServices` (array of strings, optional): Additional service UUIDs
* `isAutopayEnabled` (boolean, optional): Whether autopay is enabled

**Example Request:**

```json theme={null}
{
  "verifyToken": "abc123xyz789",
  "facilityUuid": "123e4567-e89b-12d3-a456-426614174004",
  "unitGroupUuid": "123e4567-e89b-12d3-a456-426614174005"
}
```

### Response

```
200 OK
```

**Important**: After changing the facility or unit group, you should refresh the shopping cart (see [section 9](#9-retrieve-shopping-cart)) to get updated pricing and available services.

***

## 9. Retrieve Shopping Cart

Retrieves the current shopping cart for a lead, including all items, fees, taxes, and totals.

### Endpoint

```
GET /shopping/:portfolio/v1/shopping-cart/unitGroup/:unitGroupUuid/lead/:leadUuid?verifyToken=:verifyToken
```

### Request Headers

```
x-api-key: YOUR_API_KEY
```

### Path Parameters

* `unitGroupUuid` (string, required): UUID of the unit group
* `leadUuid` (string, required): UUID of the lead

### Query Parameters

* `verifyToken` (string, required): Verification token for the lead

### Response

```json theme={null}
{
  "dateDesiredMoveIn": "2024-02-01T00:00:00Z",
  "items": [
    {
      "leadUuid": "123e4567-e89b-12d3-a456-426614174003",
      "shoppingCartItemUuid": "123e4567-e89b-12d3-a456-426614174014",
      "itemType": {
        "itemTypeUuid": "123e4567-e89b-12d3-a456-426614174015",
        "itemTypeName": "Rent",
        "description": "Monthly rent for unit",
        "isTaxable": true,
        "category": "RENT",
        "isRecurring": true,
        "isRequiredAtMoveIn": true,
        "isRequiredAtTransfer": false,
        "isActive": true,
        "numberOfFacilities": 1,
        "amount": "120.00",
        "amountInPennies": 12000,
        "taxAmountInPennies": 1000,
        "entityAttributeOrganizationUuid": null,
        "entityAttributeOrganizationDescription": null,
        "feeType": "FIXED_AMOUNT",
        "fixedFeeAmount": 12000,
        "feePercentage": null,
        "isProratedAtMoveIn": true,
        "fullNonProratedAmount": 12000,
        "invoiceGenerationType": "FIRST_OF_MONTH",
        "glAccountTypeUuid": "123e4567-e89b-12d3-a456-426614174016",
        "promotion": {
          "promotionUuid": "123e4567-e89b-12d3-a456-426614174023",
          "promotionName": "First Month Free",
          "discountType": "FIXED_AMOUNT",
          "discountAmountInPennies": 12000,
          "internalNote": "Auto-applied promotion"
        }
      },
      "amountInPennies": 12000,
      "preProrationAmountInPennies": 6000
    },
    {
      "leadUuid": "123e4567-e89b-12d3-a456-426614174003",
      "shoppingCartItemUuid": "123e4567-e89b-12d3-a456-426614174016",
      "itemType": {
        "itemTypeUuid": "123e4567-e89b-12d3-a456-426614174008",
        "itemTypeName": "Climate Control Service",
        "description": "Maintains temperature and humidity",
        "isTaxable": true,
        "category": "SERVICES",
        "isRecurring": true,
        "isRequiredAtMoveIn": false,
        "isRequiredAtTransfer": false,
        "isActive": true,
        "numberOfFacilities": 1,
        "amount": "20.00",
        "amountInPennies": 2000,
        "taxAmountInPennies": 200,
        "entityAttributeOrganizationUuid": null,
        "entityAttributeOrganizationDescription": null,
        "feeType": "FIXED_AMOUNT",
        "fixedFeeAmount": 2000,
        "feePercentage": null,
        "isProratedAtMoveIn": true,
        "fullNonProratedAmount": 2000,
        "invoiceGenerationType": "FIRST_OF_MONTH",
        "glAccountTypeUuid": "123e4567-e89b-12d3-a456-426614174017"
      },
      "amountInPennies": 2000,
      "preProrationAmountInPennies": 1000
    },
    {
      "leadUuid": "123e4567-e89b-12d3-a456-426614174003",
      "shoppingCartItemUuid": "123e4567-e89b-12d3-a456-426614174017",
      "itemType": {
        "itemTypeUuid": "123e4567-e89b-12d3-a456-426614174006",
        "itemTypeName": "Standard Coverage",
        "description": "Basic protection up to $2,000",
        "isTaxable": false,
        "category": "COVERAGE",
        "isRecurring": true,
        "isRequiredAtMoveIn": true,
        "isRequiredAtTransfer": false,
        "isActive": true,
        "numberOfFacilities": 1,
        "amount": "10.00",
        "amountInPennies": 1000,
        "taxAmountInPennies": 0,
        "entityAttributeOrganizationUuid": null,
        "entityAttributeOrganizationDescription": null,
        "feeType": "FIXED_AMOUNT",
        "fixedFeeAmount": 1000,
        "feePercentage": null,
        "isProratedAtMoveIn": true,
        "fullNonProratedAmount": 1000,
        "invoiceGenerationType": "FIRST_OF_MONTH",
        "glAccountTypeUuid": "123e4567-e89b-12d3-a456-426614174018"
      },
      "amountInPennies": 1000,
      "preProrationAmountInPennies": 500
    }
  ]
}
```

### When to Refresh Shopping Cart Data

You should refresh the shopping cart data after:

* Changing the facility or unit group ([section 8](#8-change-facility-or-unit-group))
* Changing coverage selection ([section 11](#11-assign-coverage-or-mark-private-insurance))
* Adding or removing additional services ([section 13](#13-assign-additional-services-to-lead))
* Changing access plans ([section 15](#15-assign-access-plans-to-lead))
* Updating the move-in date
* Any other change that might affect pricing

***

## 10. Request Coverage List for Facility

Retrieves all available coverage options (insurance) for a specific facility.

### Endpoint

```
GET /shopping/:portfolio/v1/coverages/:facilityUuid
```

### Request Headers

```
x-api-key: YOUR_API_KEY
```

### Path Parameters

* `facilityUuid` (string, required): UUID of the facility

### Response

```json theme={null}
[
  {
    "coverageUuid": "123e4567-e89b-12d3-a456-426614174006",
    "itemTypeUuid": "123e4567-e89b-12d3-a456-426614174007",
    "premiumInPennies": 1000,
    "coverageAmountInPennies": 200000,
    "description": "Basic protection up to $2,000",
    "isDefault": true
  },
  {
    "coverageUuid": "123e4567-e89b-12d3-a456-426614174008",
    "itemTypeUuid": "123e4567-e89b-12d3-a456-426614174009",
    "premiumInPennies": 2000,
    "coverageAmountInPennies": 500000,
    "description": "Enhanced protection up to $5,000",
    "isDefault": false
  }
]
```

### Get Private Coverage Information

If the lead wants to use their own insurance (private coverage):

#### Endpoint

```
GET /shopping/:portfolio/v1/coverages/private
```

#### Response

```json theme={null}
{
  "provider": "PRIVATE",
  "providerWebsiteUrl": "https://example.com",
  "description": "Use your own insurance provider"
}
```

***

## 11. Assign Coverage or Mark Private Insurance

Assigns a coverage option to a lead or marks them as using private insurance. To mark as private insurance, use the private coverage UUID (`11111111-1111-1111-1111-111111111111`), to set coverage none use `coverageUuid` as `null`.

### Endpoint

```
PUT /shopping/:portfolio/v1/facilities/lead/:leadUuid/
```

### Request Headers

```
x-api-key: YOUR_API_KEY
Content-Type: application/json
```

### Request Body

**Required Fields:**

* `verifyToken` (string, required): Verification token from lead creation

**Optional Fields:**

* `coverageUuid` (string, optional, nullable): UUID of the coverage option. Use `"11111111-1111-1111-1111-111111111111"` for private insurance, `null` for no coverage, or a coverage UUID from [section 10](#10-request-coverage-list-for-facility).
* `facilityUuid` (string, optional): Facility UUID
* `unitGroupUuid` (string, optional): Unit group UUID
* `lead` (object, optional): Lead information (see [section 7](#7-fill-in-lead-information) for full structure)
* `accessPlanUuid` (string, optional, nullable): Access plan UUID or null
* `additionalServices` (array of strings, optional): Additional service UUIDs
* `isAutopayEnabled` (boolean, optional): Whether autopay is enabled

**Example Request (with coverage):**

```json theme={null}
{
  "verifyToken": "abc123xyz789",
  "coverageUuid": "123e4567-e89b-12d3-a456-426614174006",
  "facilityUuid": "123e4567-e89b-12d3-a456-426614174000",
  "unitGroupUuid": "123e4567-e89b-12d3-a456-426614174001"
}
```

**Example Request (private insurance):**

```json theme={null}
{
  "verifyToken": "abc123xyz789",
  "coverageUuid": "11111111-1111-1111-1111-111111111111",
  "facilityUuid": "123e4567-e89b-12d3-a456-426614174000",
  "unitGroupUuid": "123e4567-e89b-12d3-a456-426614174001"
}
```

**Example Request (no coverage):**

```json theme={null}
{
  "verifyToken": "abc123xyz789",
  "coverageUuid": null,
  "facilityUuid": "123e4567-e89b-12d3-a456-426614174000",
  "unitGroupUuid": "123e4567-e89b-12d3-a456-426614174001"
}
```

### Response

```
200 OK
```

**Important**: After changing coverage, refresh the shopping cart (see [section 9](#9-retrieve-shopping-cart)) to get updated pricing.

***

## 12. Get Additional Services for Unit Group

Retrieves detailed information about a specific unit group, including all available additional services that can be assigned to a lead.

### Endpoint

```
GET /shopping/:portfolio/v1/unitGroups/:unitGroupUuid
```

### Request Headers

```
x-api-key: YOUR_API_KEY
```

### Path Parameters

* `unitGroupUuid` (string, required): UUID of the unit group

### Query Parameters

* `isForBusiness` (boolean, optional): Whether this is for a business rental

### Response

```json theme={null}
{
  "unitGroupUuid": "123e4567-e89b-12d3-a456-426614174001",
  "description": "5x5 Climate Controlled",
  "unitGroupDepth": 5,
  "unitGroupWidth": 5,
  "unitGroupHeight": 8,
  "amenities": [
    {
      "key": "climateControlled",
      "present": true
    }
  ],
  "types": {
    "vehicleRv": false,
    "selfStorage": true
  },
  "availableUnitCount": 3,
  "unitCount": 10,
  "facilityName": "Downtown Storage",
  "facilityAddress": "123 Main St, Austin, TX 78701",
  "currentStreetRate": 15000,
  "currentWebRate": 12000,
  "unitType": "Climate Controlled",
  "unitTypeImage": "https://example.com/images/unit-type.jpg",
  "bestAutoAppliedPromotion": {
    "promotionUuid": "123e4567-e89b-12d3-a456-426614174023",
    "promotionName": "First Month Free",
    "discountType": "FIXED_AMOUNT",
    "discountAmountInPennies": 12000
  },
  "additionalServices": [
    {
      "itemUuid": "123e4567-e89b-12d3-a456-426614174002",
      "itemTypeUuid": "123e4567-e89b-12d3-a456-426614174002",
      "entityAttributeOrganizationUuid": null,
      "title": "Climate Control Service",
      "description": "Maintains temperature and humidity",
      "priceInPennies": 2000,
      "isRecurring": true,
      "isRequiredAtMoveIn": false,
      "feeType": "FIXED_AMOUNT"
    }
  ]
}
```

**Response Fields**:

* `unitGroupUuid` (string, required): UUID of the unit group
* `description` (string, required): Description of the unit group
* `unitGroupDepth` (number, required): Depth of units in this group
* `unitGroupWidth` (number, required): Width of units in this group
* `unitGroupHeight` (number, required): Height of units in this group
* `amenities` (array, required): Array of amenities available in this unit group
* `types` (object, required): Unit type information
* `availableUnitCount` (number, required): Number of available units
* `unitCount` (number, required): Total number of units in this group
* `facilityName` (string, required): Name of the facility
* `facilityAddress` (string, required): Address of the facility
* `currentStreetRate` (number, optional): Current street rate in pennies
* `currentWebRate` (number, optional): Current web rate in pennies
* `unitType` (string, optional): Type of unit
* `unitTypeImage` (string, optional, nullable): URL to unit type image
* `bestAutoAppliedPromotion` (object, optional, nullable): Best auto-applied promotion for this unit group
* `additionalServices` (array, required): Array of additional services available for this unit group
  * `itemUuid` (string, required): UUID of the service item (use this when assigning services)
  * `itemTypeUuid` (string, required): UUID of the item type
  * `entityAttributeOrganizationUuid` (string, optional, nullable): Entity attribute organization UUID
  * `title` (string, required): Service title
  * `description` (string, optional, nullable): Service description
  * `priceInPennies` (number, required): Price of the service in pennies
  * `isRecurring` (boolean, required): Whether the service is recurring
  * `isRequiredAtMoveIn` (boolean, required): Whether the service is required at move-in
  * `feeType` (string, optional, nullable): Fee type (e.g., "FIXED\_AMOUNT")

**Note**: The `additionalServices` array contains all services that can be assigned to a lead for this unit group. Use the `itemUuid` from each service when assigning services to a lead (see [section 13](#13-assign-additional-services-to-lead)).

***

## 13. Assign Additional Services to Lead

Assigns additional services to a lead by including the service UUIDs in the `additionalServices` array when updating the lead.

**Important**: Monument automatically calculates taxes for all amount values in the rental flow. You do not need to calculate or include tax amounts when assigning services - Monument handles all tax calculations based on facility location, service type, and applicable tax rules.

### Endpoint

```
PUT /shopping/:portfolio/v1/facilities/lead/:leadUuid
```

### Request Headers

```
x-api-key: YOUR_API_KEY
Content-Type: application/json
```

### Request Body

**Required Fields:**

* `verifyToken` (string, required): Verification token from lead creation

**Optional Fields:**

* `additionalServices` (array of strings, optional): Array of additional service UUIDs. To remove services, send an empty array `[]` or omit the field.
* `facilityUuid` (string, optional): Facility UUID
* `unitGroupUuid` (string, optional): Unit group UUID
* `lead` (object, optional): Lead information (see [section 7](#7-fill-in-lead-information) for full structure)
* `coverageUuid` (string, optional, nullable): Coverage UUID or null
* `accessPlanUuid` (string, optional, nullable): Access plan UUID or null
* `isAutopayEnabled` (boolean, optional): Whether autopay is enabled

**Example Request:**

```json theme={null}
{
  "verifyToken": "abc123xyz789",
  "additionalServices": [
    "123e4567-e89b-12d3-a456-426614174008",
    "123e4567-e89b-12d3-a456-426614174009"
  ],
  "facilityUuid": "123e4567-e89b-12d3-a456-426614174000",
  "unitGroupUuid": "123e4567-e89b-12d3-a456-426614174001"
}
```

**Note**: Additional services are available through the unit group details endpoint (see [section 11](#11-get-additional-services-for-unit-group)). The `additionalServices` array in the unit group response contains all available services for that unit group. Use the `itemUuid` from each service when assigning services.

### Response

```
200 OK
```

**Note**: To remove services, simply omit them from the `additionalServices` array or send an empty array `[]`.

***

## 14. View Available Access Plans

Retrieves all available access plans for a facility. Access plans define when and how tenants can access the facility.

### Endpoint

```
GET /shopping/:portfolio/v1/shopping-cart/access-plans/:facilityUuid
```

### Request Headers

```
x-api-key: YOUR_API_KEY
```

### Path Parameters

* `facilityUuid` (string, required): UUID of the facility

### Response

```json theme={null}
[
  {
    "accessPlanUuid": "123e4567-e89b-12d3-a456-426614174010",
    "name": "24/7 Access",
    "isDefault": false,
    "isLegacy": false,
    "planNameDescription": "24/7 Access - $10.00/month",
    "itemType": {
      "itemTypeUuid": "123e4567-e89b-12d3-a456-426614174011",
      "itemTypeName": "24/7 Access Plan",
      "description": "Access anytime, day or night",
      "category": "ACCESS_HOURS_SERVICE",
      "isRecurring": true,
      "isRequiredAtMoveIn": false,
      "isRequiredAtTransfer": false,
      "isReadOnly": false,
      "isTaxable": true,
      "taxCode": null,
      "isActive": true,
      "isProratedAtMoveIn": true,
      "feeType": "FIXED_AMOUNT",
      "fixedFeeAmount": 1000,
      "feePercentage": null
    },
    "accessPlanDayRules": [
      {
        "isOpen": true,
        "accessPlanDayRuleUuid": "123e4567-e89b-12d3-a456-426614174014",
        "accessPlanUuid": "123e4567-e89b-12d3-a456-426614174010",
        "dayOfWeek": "Monday",
        "accessStartTime": "00:00:00",
        "accessEndTime": "23:59:59"
      }
    ]
  },
  {
    "accessPlanUuid": "123e4567-e89b-12d3-a456-426614174012",
    "name": "Business Hours Only",
    "isDefault": true,
    "isLegacy": false,
    "planNameDescription": "Business Hours Only - Free",
    "itemType": {
      "itemTypeUuid": "123e4567-e89b-12d3-a456-426614174013",
      "itemTypeName": "Business Hours Access Plan",
      "description": "Access during business hours",
      "category": "ACCESS_HOURS_SERVICE",
      "isRecurring": true,
      "isRequiredAtMoveIn": false,
      "isRequiredAtTransfer": false,
      "isReadOnly": false,
      "isTaxable": false,
      "taxCode": null,
      "isActive": true,
      "isProratedAtMoveIn": false,
      "feeType": "FIXED_AMOUNT",
      "fixedFeeAmount": 0,
      "feePercentage": null
    },
    "accessPlanDayRules": [
      {
        "isOpen": true,
        "accessPlanDayRuleUuid": "123e4567-e89b-12d3-a456-426614174015",
        "accessPlanUuid": "123e4567-e89b-12d3-a456-426614174012",
        "dayOfWeek": "Monday",
        "accessStartTime": "06:00:00",
        "accessEndTime": "22:00:00"
      }
    ]
  }
]
```

***

## 15. Assign Access Plans to Lead

Assigns an access plan to a lead by including the `accessPlanUuid` when updating the lead.

### Endpoint

```
PUT /shopping/:portfolio/v1/facilities/lead/:leadUuid
```

### Request Headers

```
x-api-key: YOUR_API_KEY
Content-Type: application/json
```

### Request Body

**Required Fields:**

* `verifyToken` (string, required): Verification token from lead creation

**Optional Fields:**

* `accessPlanUuid` (string, optional, nullable): UUID of the access plan, or null to remove access plan
* `facilityUuid` (string, optional): Facility UUID
* `unitGroupUuid` (string, optional): Unit group UUID
* `lead` (object, optional): Lead information (see [section 7](#7-fill-in-lead-information) for full structure)
* `coverageUuid` (string, optional, nullable): Coverage UUID or null
* `additionalServices` (array of strings, optional): Additional service UUIDs
* `isAutopayEnabled` (boolean, optional): Whether autopay is enabled

**Example Request:**

```json theme={null}
{
  "verifyToken": "abc123xyz789",
  "accessPlanUuid": "123e4567-e89b-12d3-a456-426614174010",
  "facilityUuid": "123e4567-e89b-12d3-a456-426614174000",
  "unitGroupUuid": "123e4567-e89b-12d3-a456-426614174001"
}
```

### Response

```
200 OK
```

**Note**: To remove an access plan, set `accessPlanUuid` to `null`.

***

## 16. Get Payrix Public Keys

### What is Payrix?

Payrix is a payment processing platform that Monument uses to securely handle credit card and ACH payments. Payrix provides **PayFields**, which are PCI-compliant payment form fields that can be embedded directly into your application. This allows you to collect payment information without handling sensitive card data yourself, as all payment data is tokenized by Payrix.

### What are these keys for?

The public keys returned by this endpoint are used to:

1. Initialize PayFields in your frontend application
2. Securely tokenize payment information (credit cards or bank accounts)
3. Create payment profiles that can be used for future transactions

**Important**: These keys are temporary and expire after 1 hour. You must fetch a new key before it expires.

**Key Rotation and Overlap Period**: Monument rotates Payrix keys at 45 minutes (15 minutes before expiration) to provide a grace period. This means:

* Keys are valid for 60 minutes from Payrix
* New keys are generated at 45 minutes
* There is a 15-minute overlap period (45-60 minutes) where both the old and new keys are valid
* This overlap helps mitigate checkout issues if a user is in the middle of payment processing when the key rotates

### Endpoint

```
GET /shopping/:portfolio/v1/payment/payrix/public-key
```

### Request Headers

```
x-api-key: YOUR_API_KEY
```

### Response

```json theme={null}
{
  "apiKey": "pk_live_abc123xyz789",
  "payfieldsUrl": "https://payrix.com/payfields/v1"
}
```

**Response Fields**:

* `apiKey` (string, required): Payrix public API key used to initialize PayFields
* `payfieldsUrl` (string, required): URL for loading PayFields JavaScript library

### Integration Steps

1. **Fetch the public key**: Call this endpoint to get the `apiKey` and `payfieldsUrl`
2. **Load PayFields library**: Include the PayFields script in your HTML using the `payfieldsUrl`
3. **Initialize PayFields**: Use the `apiKey` to configure PayFields in your payment form
4. **Collect payment information**: Users enter their payment details in the PayFields form
5. **Tokenize payment**: PayFields handles tokenization and returns a secure token
6. **Create payment profile**: Use the token to create a payment profile via [section 17](#17-create-payment-profile)

### Resources

* **Payrix Documentation**: [Integrated Payment Pages](https://resource.payrix.com/docs/integrated-payment-pages) - Complete guide on how to embed PayFields in your application
* **Payrix Status Page**: [Worldpay for Platforms Status](https://worldpayforplatforms.statuspage.io/) - Check Payrix service status and uptime

**Note**: PayFields must be loaded from the `payfieldsUrl` provided in the response. The `apiKey` is used to configure PayFields and must be refreshed every hour. Due to the 15-minute overlap period during key rotation, keys fetched near the expiration time will remain valid for the full checkout process.

***

## 17. Create Payment Profile

### What is a Payment Profile?

A payment profile is a secure, tokenized representation of a customer's payment method (credit card or bank account) that is stored in Monument's system. Payment profiles allow you to:

* Store payment information securely without handling sensitive card data
* Enable automatic recurring payments (autopay)
* Process future transactions without requiring the customer to re-enter payment details
* Meet PCI compliance requirements

**Important**: A payment profile must be created before generating a lease ([section 19](#19-generate-lease)). The payment profile is required for the initial payment and can be used for future automatic payments.

### Step-by-Step Integration Guide

#### Step 1: Get Payrix Public Keys

First, retrieve the Payrix public keys using [section 16](#16-get-payrix-public-keys). You'll need:

* `apiKey`: Used to configure PayFields
* `payfieldsUrl`: URL to load the PayFields JavaScript library

**Note**: Keys are rotated at 45 minutes with a 15-minute overlap period. If you fetch a key during checkout, it will remain valid for the full payment process even if rotation occurs during that time.

#### Step 2: Load PayFields Library

Include the PayFields script in your HTML:

```html theme={null}
<script src="https://payrix.com/payfields/v1/payfields.js"></script>
```

Use the `payfieldsUrl` from step 1 to ensure you're loading from the correct endpoint.

#### Step 3: Initialize PayFields

Configure PayFields with the `apiKey` and merchant ID. The merchant ID should be provided by Monument support or may be available through your integration setup.

```javascript theme={null}
PayFields.config = {
  apiKey: "pk_live_abc123xyz789", // From section 16
  merchant: "merchant_account_12345", // Provided by Monument
  mode: "txnToken",
  txnType: "auth", // Use 'auth' for credit cards, 'ecsale' for ACH
  amount: "0", // Set to '0' for tokenization only
  billingAddress: {
    email: "customer@example.com",
    phone: "+15125550100",
  },
};
```

#### Step 4: Render Payment Form

Add PayFields form elements to your HTML:

```html theme={null}
<div id="payfields-form">
  <div id="payfields-name"></div>
  <div id="payfields-number"></div>
  <div id="payfields-expiration"></div>
  <div id="payfields-cvv"></div>
  <div id="payfields-address"></div>
  <div id="payfields-city"></div>
  <div id="payfields-state"></div>
  <div id="payfields-zip"></div>
</div>
```

Then initialize the fields:

```javascript theme={null}
PayFields.addFields();
```

#### Step 5: Handle PayFields Success Callback

When the user submits the form, PayFields will tokenize the payment information and call your success callback:

```javascript theme={null}
PayFields.onSuccess(function (response) {
  // Extract token information from response
  const transaction = response.data[0];
  const token = transaction.token;

  // Prepare payment profile data
  const paymentProfileData = {
    leadUuid: "your-lead-uuid",
    facilityUuid: "your-facility-uuid",
    processorToken: token.token, // The tokenized payment method
    processorTokenId: token.id,
    processorAuthTransactionId: transaction.id,
    paymentType: "CREDIT/DEBIT", // or 'ACH' for bank accounts
    lastFour: token.payment.number, // Last 4 digits of card/account
    billingFirstName: token.customer.first,
    billingLastName: token.customer.last,
    billingAddressLine1: token.customer.address1,
    billingAddressLine2: token.customer.address2,
    billingCity: token.customer.city,
    billingState: token.customer.state,
    billingZip: token.customer.zip,
    autopayEnabled: true, // or false
  };

  // Proceed to Step 6
});
```

#### Step 6: Create Payment Profile via Monument API

Call this endpoint with the tokenized payment information:

### Endpoint

```
POST /shopping/:portfolio/v1/payment/profile
```

### Request Headers

```
x-api-key: YOUR_API_KEY
Content-Type: application/json
```

### Request Body

**Required Fields:**

* `facilityUuid` (string, required): UUID of the facility
* `billingFirstName` (string, required): Billing first name
* `billingLastName` (string, required): Billing last name
* `leadUuid` (string, required): UUID of the lead
* `processorToken` (string, required): Payment processor token from Payrix (obtained in Step 5)
* `processorTokenId` (string, required): Payment processor token ID (obtained in Step 5)
* `processorAuthTransactionId` (string, required): Payment processor authorization transaction ID (obtained in Step 5)
* `paymentType` (string, required): Payment type (e.g., "CREDIT/DEBIT", "ACH")
* `lastFour` (string, required): Last four digits of payment method
* `billingAddressLine1` (string, required): Billing address line 1
* `billingCity` (string, required): Billing city
* `billingState` (string, required): Billing state
* `billingZip` (string, required): Billing ZIP code
* `autopayEnabled` (boolean, required): Whether autopay is enabled

**Optional Fields:**

* `billingAddressLine2` (string, optional): Billing address line 2

**Example Request:**

```json theme={null}
{
  "leadUuid": "123e4567-e89b-12d3-a456-426614174003",
  "facilityUuid": "123e4567-e89b-12d3-a456-426614174000",
  "processorToken": "payrix_token_abc123xyz789",
  "processorTokenId": "token_id_123",
  "processorAuthTransactionId": "auth_txn_456",
  "paymentType": "CREDIT/DEBIT",
  "lastFour": "1234",
  "billingFirstName": "John",
  "billingLastName": "Doe",
  "billingAddressLine1": "456 Oak Ave",
  "billingCity": "Austin",
  "billingState": "TX",
  "billingZip": "78702",
  "autopayEnabled": true
}
```

### Response

```json theme={null}
{
  "leadUuid": "123e4567-e89b-12d3-a456-426614174003",
  "leaseSessionUrl": ""
}
```

**Response Fields**:

* `leadUuid` (string, required): UUID of the lead
* `leaseSessionUrl` (string, required): Lease session URL (typically empty for payment profile creation)

### Error Handling

If PayFields validation fails, handle the error callback:

```javascript theme={null}
PayFields.onValidationFailure(function (error) {
  // Handle validation errors
  console.error("PayFields validation failed:", error);
});

PayFields.onFailure(function (error) {
  // Handle general errors
  console.error("PayFields error:", error);
});
```

### Next Steps

After successfully creating a payment profile:

1. The lead now has a stored payment method
2. You can proceed to generate a lease ([section 19](#19-generate-lease))
3. If `autopayEnabled` is `true`, future payments will be processed automatically

**Note**: The `processorToken`, `processorTokenId`, and `processorAuthTransactionId` are all obtained from PayFields in Step 5. Never store or log these tokens - they should only be passed directly to this API endpoint.

***

## 18. Get PandaDoc Iframe Link

The lease session URL returned from the generate lease endpoint ([section 19](#19-generate-lease)) is the PandaDoc iframe link. This URL can be embedded in an iframe to display the lease document for signing.

### Usage

The `leaseSessionUrl` from the generate lease response is the PandaDoc iframe link:

```html theme={null}
<iframe
  src="https://app.pandadoc.com/s/abc123xyz789"
  width="100%"
  height="600px"
  frameborder="0"
>
</iframe>
```

### PandaDoc Events

You can listen for PandaDoc events to track the signing process:

```javascript theme={null}
window.addEventListener("message", (event) => {
  if (event.origin !== "https://app.pandadoc.com") return;

  const type = event.data?.type;

  switch (type) {
    case "session_view.document.completed":
      // Document has been signed
      break;
    case "session_view.document.loaded":
      // Document has loaded
      break;
    case "session_view.document.exception":
      // An error occurred
      break;
  }
});
```

**Note**: The lease session URL is valid for 10 days. After signing, the lead will be automatically converted to a tenant (see [section 21](#21-check-if-lead-converted-to-tenant)).

***

## 19. Generate Lease

Generates a lease document for a lead. This endpoint will:

1. Verify that a payment profile exists
2. Find an available unit in the selected unit group
3. Reserve that unit for the lead
4. Create a signable lease document
5. Return a lease session URL for signing

### Endpoint

```
POST /shopping/:portfolio/v1/facilities/lead/generate-lease
```

### Request Headers

```
x-api-key: YOUR_API_KEY
Content-Type: application/json
```

### Request Body

```json theme={null}
{
  "facilityUuid": "123e4567-e89b-12d3-a456-426614174000",
  "unitGroupUuid": "123e4567-e89b-12d3-a456-426614174001",
  "leadUuid": "123e4567-e89b-12d3-a456-426614174003",
  "email": "john.doe@example.com"
}
```

### Response

```json theme={null}
{
  "leaseSessionUrl": "https://app.pandadoc.com/s/abc123xyz789"
}
```

**Important**:

* A payment profile must exist before generating a lease (see [section 17](#17-create-payment-profile))
* This endpoint reserves a unit, so only call it when the lead is ready to sign
* If lease generation fails, the unit reservation will be automatically cancelled

***

## 20. Sign Lease Redirect

Redirects users to the signable lease document. This is a redirect endpoint that sends users directly to PandaDoc for signing.

### Endpoint

```
GET /shopping/:portfolio/v1/sign_lease/:leaseUuid
```

### Request Headers

```
x-api-key: YOUR_API_KEY
```

### Path Parameters

* `leaseUuid` (string, required): UUID of the lease document

### Response

This endpoint performs an HTTP redirect (302) to the PandaDoc signing session URL. The response body may contain error messages if the lease is not available:

* If the lease is not found: "This lease is no longer available. Please check your email for a new link"
* If the lease link is disabled: "Your lease is not ready to be signed. please check again soon."

**Note**: This endpoint is typically used for email links or direct navigation. For iframe embedding, use the `leaseSessionUrl` from the generate lease endpoint ([section 19](#19-generate-lease)) instead. This endpoint is not commonly used by API clients building custom rental flows, as you would typically use the iframe approach.

***

## 21. Check if Lead Converted to Tenant

Checks whether a lead that has signed their lease has been converted to a tenant.

### Endpoint

```
GET /shopping/:portfolio/v1/facilities/leads/check-lead-status/:leadUuid
```

### Request Headers

```
x-api-key: YOUR_API_KEY
```

### Path Parameters

* `leadUuid` (string, required): UUID of the lead

### Response

```json theme={null}
{
  "converted": true
}
```

### Get Converted Lead Details

If the lead has been converted, you can retrieve their tenant information:

#### Endpoint

```
GET /shopping/:portfolio/v1/facilities/tenant/:leadUuid
```

#### Response

```json theme={null}
{
  "unitName": "A-101",
  "unitType": "5x5 Climate Controlled",
  "floor": "1",
  "gateAccessNumber": "12345",
  "rentalStartDate": "2024-02-01T00:00:00Z",
  "facilityName": "Downtown Storage",
  "facilityAddress": "123 Main St, Austin, TX 78701",
  "facilityOperatingHours": {
    "Sunday": {
      "isOpen": true,
      "openTime": "06:00:00",
      "closeTime": "22:00:00"
    },
    "Monday": {
      "isOpen": true,
      "openTime": "06:00:00",
      "closeTime": "22:00:00"
    },
    "Tuesday": {
      "isOpen": true,
      "openTime": "06:00:00",
      "closeTime": "22:00:00"
    },
    "Wednesday": {
      "isOpen": true,
      "openTime": "06:00:00",
      "closeTime": "22:00:00"
    },
    "Thursday": {
      "isOpen": true,
      "openTime": "06:00:00",
      "closeTime": "22:00:00"
    },
    "Friday": {
      "isOpen": true,
      "openTime": "06:00:00",
      "closeTime": "22:00:00"
    },
    "Saturday": {
      "isOpen": true,
      "openTime": "06:00:00",
      "closeTime": "22:00:00"
    }
  },
  "facilityPhone": "+1-512-555-0100"
}
```

**Note**:

* Conversion typically happens automatically after the lease is signed
* You may need to poll this endpoint periodically after the lease is signed
* Once converted, the lead status changes to `CONVERTED` and they become a tenant

***

## 22. Minimum Requirements for Lead Conversion

Before a lead can be successfully converted to a tenant (see [section 19](#19-generate-lease) and [section 21](#21-check-if-lead-converted-to-tenant)), certain minimum information must be provided. **Without these required fields, the conversion will fail with validation errors.**

**Important**: This section describes the minimum requirements for lead conversion. These requirements are enforced by the validation system and conversion will fail if any required field is missing or invalid.

### Overview

The lead conversion process validates multiple entities to ensure all required information is present. This section outlines the minimum requirements based on the validation flow that occurs during conversion.
The conversion process is triggered by a webhook managed by [Pandadoc](https://www.pandadoc.com/) once the [generate lease](#18-generate-lease) is signed by the tenant and processed by Pandadoc.

### Required Lead Information

The following fields must be present on the lead:

* `primaryPerson` (object, required): Primary person information (see Primary Person requirements below)
* `primaryPersonUuid` (string, required): UUID of the primary person
* `leadType` (string, required): Lead type ("PERSONAL" or "BUSINESS")
* `facility` (object, required): Facility object
* `facilityUuid` (string, required): UUID of the facility
* `unitGroup` (object, required): Unit group object
* `unitGroupUuid` (string, required): UUID of the unit group
* `unitUuid` (string, required): UUID of the assigned unit
* `unit` (object, required): Unit object
* `signableLease` (object, required): Signable lease object (see Signable Lease requirements below)
* `leadStatus` (string, required): Must be "PENDING" for conversion to succeed

**Additional Lead Requirements:**

* If `leadData.autoPayEnabled` is `true`, then `leadData.paymentType` must also be defined

### Required Primary Person Information

The primary person must have the following fields:

* `firstName` (string, required): First name
* `lastName` (string, required): Last name
* `email` (string, required): Email address
* `phone` (string, required): Phone number
* `personType` (string, required): Person type
* `addressLine1` (string, required): Street address line 1
* `country` (string, required): Country code
* `city` (string, required): City
* `state` (string, required): State code
* `zip` (string, required): ZIP/postal code

### Required Identification Information

The primary person must have a valid identification document. One of the following is required:

#### Option 1: Driver's License

* `primaryPersonIdentification` (object, required): Identification object
  * `identificationType` (string, required): Must be "Driver's License"
  * `identificationString` (string, optional): Identification number
  * `idState` (string, optional): State where ID was issued
  * `idCountry` (string, optional): Country where ID was issued

#### Option 2: Passport

* `primaryPersonIdentification` (object, required): Identification object
  * `identificationType` (string, required): Must be "PASSPORT"
  * `identificationString` (string, required): Passport number
  * `country` (string, required): Country where passport was issued

### Required Signable Lease Information

The signable lease must have:

* `startDate` (date, required): Lease start date

### Validation Failure

If any of the above required fields are missing or invalid, the conversion will fail with validation errors. The error response will indicate which fields are missing or invalid.

**Important Notes:**

1. **Lead Status**: The lead status must be "PENDING" before conversion. If the lead status is not "PENDING", conversion will fail.

2. **Unit Assignment**: A unit must be assigned to the lead (`unitUuid` and `unit` must be present). Units are typically assigned when a lease is generated (see [section 19](#19-generate-lease)).

3. **Signable Lease**: A signable lease must exist for the lead. This is typically created when generating a lease (see [section 19](#19-generate-lease)).

4. **Payment Profile**: While not explicitly validated in the conversion flow, a payment profile is typically required before generating a lease (see [section 17](#17-create-payment-profile)).

5. **Business Accounts**: If `leadType` is "BUSINESS", additional fields may be required:
   * `businessName` (string, required for business accounts)
   * `taxId` (string, optional for business accounts)

### Best Practices

* Ensure all required fields are collected before attempting to generate a lease
* Validate required fields in your frontend before calling the generate lease endpoint
* Handle validation errors gracefully and provide clear feedback to users about missing required information
* Use the [Fill in Lead Information](#7-fill-in-lead-information) endpoint to update lead information before conversion

***

## 23. Exit Shopping Experience

Marks a lead as no longer hidden in the Facility Management System (FMS). Call this endpoint when a lead exits the shopping experience, making them immediately visible to facility managers.

### Endpoint

```
POST /shopping/:portfolio/v1/facilities/lead/:leadUuid/exit-shopping
```

### Request Headers

```
x-api-key: YOUR_API_KEY
Content-Type: application/json
```

### Path Parameters

* `leadUuid` (string, required): UUID of the lead

### Response

```json theme={null}
{
  "success": true
}
```

**Note**: This endpoint makes the lead visible in the FMS. Use this when a user abandons the shopping flow or completes their session without generating a lease, if not called, the lead will be visible after 10 minutes from it's creation.

***

## 24. Get Unit Details

Retrieves detailed information about a unit for a lead that has been converted to a tenant. Requires verification code for authentication.

### Endpoint

```
GET /shopping/:portfolio/v1/units/:leadUuid/:verifyCode
```

### Request Headers

```
x-api-key: YOUR_API_KEY
```

### Path Parameters

* `leadUuid` (string, required): UUID of the lead (now tenant)
* `verifyCode` (string, required): The verification token returned when the lead was created

### Response

Returns a `GetUnitDetailDto` object with comprehensive unit information including:

```json theme={null}
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "unitType": "Standard",
  "entityAttributeOrganizationUuid": "123e4567-e89b-12d3-a456-426614174001",
  "occupancyStatus": "OCCUPIED",
  "facilityUuid": "123e4567-e89b-12d3-a456-426614174002",
  "lastModified": "2024-01-15T10:30:00Z",
  "amenities": [
    {
      "amenityUuid": "123e4567-e89b-12d3-a456-426614174003",
      "name": "Climate Controlled",
      "description": "Temperature controlled unit"
    }
  ],
  "unitGroupUuid": "123e4567-e89b-12d3-a456-426614174004",
  "unitGroupName": "5x5 Standard",
  "unitGroupUnitType": "Standard",
  "unitGroupDimensions": "5x5",
  "unitCurrentRate": 15000,
  "delinquencyStage": null,
  "tenantEmail": "john.doe@example.com",
  "tenantPhone": "+15125550100",
  "tenantBusinessName": null,
  "tenantActiveMilitaryStatus": false,
  "billingInfo": {
    "outstandingBalance": {
      "taxes": "0.00",
      "total": "0.00"
    },
    "nextPaymentDue": {
      "taxes": "2.50",
      "total": "152.50"
    }
  },
  "gateCode": "1234",
  "lockCode": "5678",
  "paymentStatus": "CURRENT",
  "paymentProfile": {
    "paymentProfileUuid": "123e4567-e89b-12d3-a456-426614174005",
    "lastFour": "1234",
    "paymentType": "CREDIT/DEBIT"
  },
  "timeUnitOccupied": "2 months",
  "leaseEffectiveDate": "2024-01-01",
  "organizationUuid": "123e4567-e89b-12d3-a456-426614174006",
  "unitRentalRecordUuid": "123e4567-e89b-12d3-a456-426614174007",
  "coverage": {
    "coverageUuid": "123e4567-e89b-12d3-a456-426614174008",
    "name": "Basic Coverage",
    "description": "Standard coverage plan"
  },
  "location": "Building A",
  "unitNumber": "A101",
  "streetRate": 15000,
  "pricingRule": "Standard Rate",
  "unitGroupDescription": "5x5 climate controlled unit",
  "doorType": "Roll-Up",
  "doorWidth": 5,
  "doorHeight": 5,
  "unitDetailedDimensions": {
    "length": 5,
    "width": 5,
    "height": 8,
    "measurementUnit": "feet"
  },
  "facilitySegmentUuid": "123e4567-e89b-12d3-a456-426614174009"
}
```

**Note**: This endpoint can only be used after a lead has been converted to a tenant and has a unit assigned. The lead must have a unit associated with it. Use this to display unit details, access codes, and billing information to converted tenants.

***

## 25. Get Gate Access Code

Retrieves the gate access code for a lead that has been converted to a tenant. The gate access code may be pending generation or not configured for the facility.

### Endpoint

```
POST /shopping/:portfolio/v1/units/:leadUuid/:verifyCode/gate-access-code
```

### Request Headers

```
x-api-key: YOUR_API_KEY
Content-Type: application/json
```

### Path Parameters

* `leadUuid` (string, required): UUID of the lead (now tenant)
* `verifyCode` (string, required): The verification token returned when the lead was created

### Request Body

```json theme={null}
{
  "unitUuid": "123e4567-e89b-12d3-a456-426614174000",
  "facilityUuid": "123e4567-e89b-12d3-a456-426614174001"
}
```

**Request Body Fields**:

* `unitUuid` (string, required): UUID of the unit
* `facilityUuid` (string, required): UUID of the facility

### Response

The response includes a status indicating whether the gate access code is available:

**Status: GENERATED**

```json theme={null}
{
  "gateAccessCode": "1234",
  "status": "GENERATED"
}
```

**Status: PENDING**

```json theme={null}
{
  "status": "PENDING"
}
```

**Status: NOT\_CONFIGURED**

```json theme={null}
{
  "status": "NOT_CONFIGURED"
}
```

**Status Values**:

* `GENERATED`: Gate access code is available and returned in `gateAccessCode`
* `PENDING`: Gate access code is being generated, check again later
* `NOT_CONFIGURED`: Facility is not configured to generate gate access codes

**Note**: This endpoint can only be used after a lead has been converted to a tenant. If the status is `PENDING`, you may need to poll this endpoint periodically until the code is generated. If the status is `NOT_CONFIGURED`, the facility does not use gate access codes.

***

## 26. Get Facility Policies

Retrieves facility-specific policies that affect the rental flow behavior.

### Endpoint

```
GET /shopping/:portfolio/v1/policies/facilities/:facilityUuid
```

### Request Headers

```
x-api-key: YOUR_API_KEY
```

### Path Parameters

* `facilityUuid` (string, required): UUID of the facility

### Response

```json theme={null}
{
  "moveOutPhotoRequired": true,
  "manualAccessApproval": false,
  "allowReservations": true,
  "noPrivateCoverageInRentalFlow": false,
  "allowWaitlist": true,
  "messagingTimeRange": {
    "startTime": "09:00:00",
    "endTime": "17:00:00"
  }
}
```

**Response Fields**:

* `moveOutPhotoRequired` (boolean, required): Whether move-out photos are required
* `manualAccessApproval` (boolean, required): Whether manual access approval is required
* `allowReservations` (boolean, required): Whether reservations are allowed
* `noPrivateCoverageInRentalFlow` (boolean, required): Whether private coverage is disabled in the rental flow
* `allowWaitlist` (boolean, required): Whether waitlist functionality is enabled
* `messagingTimeRange` (object, optional, nullable): Time range for messaging (if configured)
  * `startTime` (string): Start time in HH:mm:ss format
  * `endTime` (string): End time in HH:mm:ss format

**Note**: If no policy exists for the facility, all boolean fields will default to `false` and `messagingTimeRange` will be `null`. Use these policies to configure your rental flow UI and behavior.

***

## 27. Find Eligible Auto-Applied Promotions

Finds eligible automatically applied promotions with the highest discount for each unit group. Useful for displaying promotional pricing to users.

**Important**: In the rental flow API, promotions are **only auto-applied** - you cannot manually assign or select promotions. Promotions are automatically applied when a lead is created or updated based on eligibility criteria (facility, unit group, business status, autopay status, etc.). This endpoint allows you to preview which promotions would be auto-applied, but you do not need to explicitly assign them.

### Endpoint

```
POST /shopping/:portfolio/v1/promotions/eligible-auto-applied-promotions-with-highest-discount
```

### Request Headers

```
x-api-key: YOUR_API_KEY
Content-Type: application/json
```

### Request Body

```json theme={null}
{
  "facilityUuids": [
    "123e4567-e89b-12d3-a456-426614174000",
    "123e4567-e89b-12d3-a456-426614174001"
  ],
  "unitGroupUuids": ["123e4567-e89b-12d3-a456-426614174002"],
  "isForBusiness": false,
  "isAutopayEnabled": true
}
```

**Request Body Fields**:

* `facilityUuids` (array of strings, required): Array of facility UUIDs to check promotions for
* `unitGroupUuids` (array of strings, optional): Optional array of unit group UUIDs to filter by
* `isForBusiness` (boolean, optional): Whether the lead is a business account
* `isAutopayEnabled` (boolean, optional): Whether autopay is enabled (affects promotion eligibility)

### Response

```json theme={null}
[
  {
    "facilityUuid": "123e4567-e89b-12d3-a456-426614174000",
    "unitGroupUuid": "123e4567-e89b-12d3-a456-426614174002",
    "promotionUuid": "123e4567-e89b-12d3-a456-426614174003",
    "promotionName": "First Month Free",
    "highestDiscountAmount": 15000
  }
]
```

**Response Fields**:

* `facilityUuid` (string, required): UUID of the facility
* `unitGroupUuid` (string, required): UUID of the unit group
* `promotionUuid` (string, required): UUID of the promotion
* `promotionName` (string, required): Name of the promotion
* `highestDiscountAmount` (number, required): Discount amount in pennies

**Note**: This endpoint returns the best eligible promotion for each unit group. The discount amount is in pennies (e.g., 15000 = \$150.00). Promotions are automatically applied when a lead is created or updated based on eligibility, but you can use this endpoint to display promotional pricing to users before they commit.

***

## 28. Get Portfolio Organization

Retrieves the portfolio organization communications name. Useful for branding and displaying the organization name in your custom rental flow.

### Endpoint

```
GET /shopping/:portfolio/v1/organization/portfolio
```

### Request Headers

```
x-api-key: YOUR_API_KEY
```

### Response

```json theme={null}
{
  "portfolioName": "Monument Storage"
}
```

**Response Fields**:

* `portfolioName` (string, optional, nullable): The portfolio organization communications name, or `null` if not set

**Note**: Use this endpoint to retrieve the organization name for branding purposes in your custom rental flow UI.

***

## 29. Get Required Fields for a Facility

Returns the required fields derived from the facility's rental flow configuration (org-specific, or the system default when the org has none). Each field carries its `isSystemRequired` flag: `true` means it blocks lease generation, `false` means it is org-required only.

### Endpoint

```
GET /shopping/:portfolio/v1/facilities/:facilityUuid/required-fields
```

### Request Headers

```
x-api-key: YOUR_API_KEY
```

### Path Parameters

* `facilityUuid` (string, required): UUID of the facility

### Response

```json theme={null}
[
  {
    "fieldId": "person-date-of-birth",
    "title": "Date of Birth",
    "apiKey": "person.dateOfBirth",
    "group": "Contact Information",
    "isSystemRequired": false,
    "isRequired": true
  }
]
```

**Response Fields**:

* `fieldId` (string, required): Unique identifier of the field in the rental flow configuration
* `title` (string, required): Human-readable title of the field
* `apiKey` (string, required): API key (dot-notation path) the field maps to
* `group` (string, required): Title of the group the field belongs to
* `isSystemRequired` (boolean, required): `true` when the field is system-required (blocks lease generation); `false` when the field is org-required only
* `isRequired` (boolean, required): `true` when the field is required by the org configuration

***

## 30. Get Lead Completion Status

Read-only pre-flight check reporting whether a lead has the information required to generate a lease. `canGenerateLease` mirrors exactly the generate-lease validation (system-required tier); `isComplete` also accounts for org-required fields. The missing-field lists are disjoint. See also [Minimum Requirements for Lead Conversion](#22-minimum-requirements-for-lead-conversion).

### Endpoint

```
GET /shopping/:portfolio/v1/facilities/:facilityUuid/lead/:leadUuid/completion-status
```

### Request Headers

```
x-api-key: YOUR_API_KEY
```

### Path Parameters

* `facilityUuid` (string, required): UUID of the facility
* `leadUuid` (string, required): UUID of the lead

### Response

```json theme={null}
{
  "canGenerateLease": true,
  "isComplete": false,
  "missingSystemRequiredFields": [],
  "missingRequiredFields": ["Date of Birth"],
  "errors": []
}
```

**Response Fields**:

* `canGenerateLease` (boolean, required): `true` when no system-required field is missing and there are no errors. Mirrors exactly what the generate-lease validation enforces
* `isComplete` (boolean, required): `true` when no required field of either tier (system-required or org-required) is missing and there are no errors
* `missingSystemRequiredFields` (array of string, required): Human-readable titles of missing fields that are system-required (block lease generation)
* `missingRequiredFields` (array of string, required): Human-readable titles of missing fields that are org-required only (do not block lease generation). Disjoint from `missingSystemRequiredFields`
* `errors` (array of string, required): Validation errors encountered while evaluating the lead

**Note**: Responds `404` when the lead is not found or does not belong to the facility.

***

## Error Handling

### Common HTTP Status Codes

* `200 OK`: Request successful
* `201 Created`: Resource created successfully
* `400 Bad Request`: Invalid request data
* `403 Forbidden`: Invalid verification token or unauthorized
* `404 Not Found`: Resource not found
* `500 Internal Server Error`: Server error

### Error Response Format

```json theme={null}
{
  "statusCode": 400,
  "message": "Invalid verification token",
  "error": "Bad Request"
}
```

### Verification Token Errors

If you receive a 403 Forbidden error when updating a lead, verify:

1. The `verifyToken` matches the one returned when the lead was created
2. The token hasn't expired (tokens don't expire, but ensure you're using the correct one)
3. The `leadUuid` is correct

***

## Best Practices

1. **Always store the verification token**: Save both `leadUuid` and `verifyToken` immediately after lead creation
2. **Refresh shopping cart after changes**: Always refresh the shopping cart after any change that might affect pricing
3. **Handle pre-existing tenants**: Always check if a tenant exists before creating a new lead
4. **Poll for conversion**: After lease signing, poll the check-lead-status endpoint to detect conversion
5. **Refresh Payrix keys**: Payrix public keys expire after 1 hour - refresh them before expiration. Keys are rotated at 45 minutes with a 15-minute overlap period to mitigate checkout issues.
6. **Validate before generating lease**: Ensure all required information is filled before generating a lease
7. **Handle errors gracefully**: Implement proper error handling for all API calls

***

## Questions?

If you have questions about any endpoint or need clarification on the API behavior, please contact the Monument Integrations Support Team.
Email: [integrationsupport@monument.io](mailto:integrationsupport@monument.io)
