openapi: 3.0.3
info:
  title: ShowMojo Legacy API
  description: |
    The legacy version of the ShowMojo API provides programmatic access to core platform features. It enables clients to synchronize property listings, manage availability, and perform basic data integration with external systems.

    This version of the API supports listing import, export of structured reports, lead creation, and tour scheduling. It is intended for systems that require direct synchronization with ShowMojo.

    The legacy API is the current, supported API and is the one to build against. Version 4 is under development and not yet available for integration; it will be announced in the changelog when it is ready.

    Changes to the API and to this documentation are listed, with dates, in the [API changelog](https://docs.showmojo.com/changelog). Breaking changes follow the [versioning and deprecation policy](https://docs.showmojo.com/versioning).

    ## Request tracing

    Every response, including errors, carries an `X-Request-Id` header with a unique id for that request. Log it with your requests and quote it when you contact support, so the request can be found in ShowMojo's logs.

    ShowMojo generates a UUID when the request has no `X-Request-Id` header. If you send one, it is echoed back in the response, which lets you correlate calls with your own trace ids. The value may contain letters, digits, `-`, `_` and `@`; other characters are stripped and the id is cut to 255 characters.

    ```http
    HTTP/1.1 200 OK
    X-Request-Id: 2f1c3b6e-5d4a-4f0e-9c3b-7a8d9e0f1a2b
    ```
  version: 3.2.2
servers:
  - url: https://showmojo.com
    description: Production
  - url: https://mock-docs.showmojo.com
    description: Sandbox
  - url: http://localhost:4010
    description: Localhost
tags:
  - name: authentication
    description: OAuth2 authentication and access token retrieval
    x-displayName: Authentication
  - name: leads
    description: Leads creation and management
    x-displayName: Leads (Incoming Inquiries)
  - name: listings
    description: |
      The Listings API provides access to listing data and allows external systems to import or update rental listings in ShowMojo.

      ## Authentication

      The Listings API uses token authentication. HTTP Basic auth with a ShowMojo login and password is deprecated and stops working on 2027-01-19; see the [versioning and deprecation policy](https://docs.showmojo.com/versioning).

      Send the token in the `Authorization` header using this format:

      ```http
      Authorization: Token {token}
      ```

      The token is available in **[Settings > Listing Import](https://showmojo.com/settings/import)**.

      ### Token lifecycle

      - Each account has one active API token, shown in **[Settings > Listing Import](https://showmojo.com/settings/import)**. The same token authenticates every token-authenticated endpoint.
      - Generating a new token **revokes the previous one immediately**. Requests that still send the old token receive `401 Unauthorized`. Update every integration that uses the token before you generate a new one.
      - There is no separate revoke action: to revoke a token, generate a new one.
      - Generating a token does not affect Zapier connections, which authenticate with OAuth 2.0.

      ## Notes

      - **Photos**: When the account has watermarking enabled, each photo returns a single watermarked URL instead of three size variants.
      - **Highlights**: If the listing is associated with a property that has highlights, they are appended to the listing's highlights (separated by a double newline).
      - **Details**: Combines detail values from both the listing and its parent property.
      - **Neighborhoods**: The `neighborhood`, `primary_neighborhood`, and `secondary_neighborhood` fields are mutually exclusive depending on account configuration. Custom neighborhoods take precedence.
      - **External ID/Source**: Derived from the first non-null integration ID field on the listing. Only one external source is returned per listing.
    x-displayName: Listings
  - name: properties
    description: |
      The Properties API provides read-only access to properties associated with the authenticated account.

      ## Authentication

      Use **Token Authentication**: generate a token in [Settings > Listing Import](https://showmojo.com/settings/import) and send it as `Authorization: Token {token}`. Generating a new token revokes the previous one immediately; see the token lifecycle under [Listings](https://docs.showmojo.com/docs/legacy/listings).

      **HTTP Basic Auth** with a ShowMojo login and password is deprecated and stops working on 2027-01-19. Replace the header with the token header; nothing else changes.

      ## External Sources

      Properties may include `external_id` and `external_source` fields when linked to an external integration system. Manually created properties will have `null` for both fields.

      | Source | Description |
      |--------|-------------|
      | `YARDI` | Yardi property management |
      | `RENT_MANAGER` | Rent Manager |
      | `APPFOLIO` | AppFolio |
      | `ENTRATA` | Entrata |
      | `BUILDIUM` | Buildium |
    x-displayName: Properties
  - name: reports
    description: |
      The Report Export API allows you to fetch structured reporting data from ShowMojo in either **JSON** or **CSV** format.
      Reports are available by name and can be exported via authenticated POST requests.

      ---

      ## Named Reports

      Use the following report names when calling endpoints:

      | Report Display Name         | Endpoint Report Name         | Notes                                   |
      |----------------------------|------------------------------|------------------------------------------|
      | Detailed Listing Data      | `detailed_listing_data`      |                                          |
      | Detailed Prospect Data     | `detailed_prospect_data`     | Date range limited to **1 week**         |
      | Digital Access             | `digital_access`             |                                          |
      | High-Level Metrics         | `high_level_metrics`         |                                          |
      | Listing and Showing Metrics| `listing_and_showing_metrics`|                                          |
      | Prospect Showing Data      | `prospect_showing_data`      |                                          |
      | Listing Performance        | `listing_performance`        | Does **not support** date filtering      |
      | Resident Information       | `resident_information`       |                                          |

      For **custom** reports, use the special endpoints listed below.

      ## Response format

      - JSON endpoints return `{ "response": { "status": "success", "data": [ ... ] } }`. `data` holds one object per row, keyed by the column names below. `high_level_metrics` is the exception: each row is a two-element array, `["<metric>", <value>]`.
      - CSV endpoints return the same rows as `text/csv`. The header row holds the column names in sentence case, so `listing_uid` becomes `Listing uid`. Columns whose name already contains spaces are used as they are.
      - Errors return `{ "response": { "status": "error", "errors": "<message>" } }` with a `4xx` status. An invalid or revoked token returns `401` with an empty body.

      ## Columns by report

      Some columns appear only when a feature is enabled on the account; those are listed under *Also*.

      ### detailed_listing_data

      `address`, `unit`, `city`, `state`, `zip`, `rent`, `bedrooms`, `full_bathrooms`, `partial_bathrooms`, `square_feet`, `access_device`, `market_status`, `last_on_market`, `days_on_market`, `short_url`, `imported_from`, `team_members`, `listing_code`, `listing_uid`

      *Also:* `account_name` first, for master accounts; `listing_type` and `property_name`; `appfolio_id`; `renters_warehouse_id`.

      ### detailed_prospect_data

      `created_at`, `name`, `email`, `phone`, `showtime`, `address`, `unit`, `listing_uid`, `showing_was_scheduled`, `showing_method`, `no_show`, `current_status`, `canceled_by`, `lead_source`, `referrer_url`, `source_email_autoreply`, `source_showmojo_phone`, `team_member`, `notes`, `comments`, `showing_uid`, `listing_code`

      *Also:* `account_name` first, for master accounts; `listing_type` and `property_name`; `calendar_name`; `document_request_outcomes` and `documents_submitted`.

      ### digital_access

      `Serial number`, `Access date`, `Access code`, `Listing`, `Pulled by`, `Pulled for`, `Distributed by ShowMojo`

      Accounts on MojoLock digital access get `Serial number`, `Access date`, `Access code`, `Device Name` instead.

      ### high_level_metrics

      One `[metric, value]` row per metric: Total incoming phone calls, Total incoming text inquiries, Total incoming email inquiries, Total inquiries from the web, Total new leads, Total new showings, Total prospect-confirmed showings, Total no-shows avoided with auto-cancel, Total feedback surveys completed, Total prospects notified about new on-market listings, Total prospects notified about rent reductions, Total showings auto-canceled due to off-market listings. The CSV header is `Metrics,Result`.

      ### listing_and_showing_metrics

      `listing_address_and_unit`, `listing_uid`, `timestamp`, `entry_type`, `referrer`, `listing_code`

      *Also:* `account_name` first, for master accounts.

      ### prospect_showing_data

      `name`, `showtime`, `showing_address_and_unit`, `listing_uid`, `phone`, `email`, `status`, `no_show`, `listing_code`

      *Also:* `account_name` first, for master accounts.

      ### listing_performance

      `Listing address`, `Actual showings`, `Scheduled showings`, `Leads`, `Market time`, `Showing agent`, `Feedback count`, `Boost`, `Attendance score`, `Presentability score`, `Rent score`, `Showing score`, `Will apply score`, `Listing code`

      ### resident_information

      `listing`, `first_name`, `last_name`, `cell_phone`, `email`, `lease_start`, `lease_end`, `resident_access`
    x-displayName: Report Export
  - name: tours
    description: Multi-unit availability and scheduling for tours
    x-displayName: Tours
paths:
  /oauth2/token:
    post:
      tags:
        - authentication
      summary: Obtain OAuth2 access token
      operationId: obtainAccessToken
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required:
                - grant_type
                - client_id
                - client_secret
                - scope
              properties:
                grant_type:
                  type: string
                  example: client_credentials
                client_id:
                  type: string
                client_secret:
                  type: string
                scope:
                  type: string
                  example: api_inquiries
      responses:
        '200':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Access token retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccessTokenResponse'
              example:
                access_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
                token_type: Bearer
                expires_in: 3600
                scope: api_inquiries
  /api/v3/listings:
    post:
      tags:
        - listings
      summary: Import
      description: |
        ### Second Endpoint

        ```http
        POST https://showmojo.com/api/v1/listings
        ```

        ### Authentication

        Token authentication only.

        Send the token in the `Authorization` header using this format:

        ```http
        Authorization: Token {token}
        ```

        The token is available in the customer's **Settings > Listing import** section.

        ### Important Notes

        - Max **100** listings per request
        - Match one of provided IDs: `code`, `uid`, or `mls_id`
        - Exact match of address information: `address`, `unit`, `city` and `state`
        - If no match is found, a **new listing** is created
        - When ShowMojo updates a listing, it **replaces all existing listing information** with the newly provided listing information
        - Do not send a new request until the previous one completes. Otherwise, you’ll receive an **HTTP 409 Conflict** response:

        ```json
        { "status": "error", "errors": "Another import is currently in progress. Please wait..." }
        ```

        - The `code` is your internal listing ID and is used for deduplication and updates.

        ---

        You may specify `assign_to_property` with a property name:

          - If the property exists → the listing is assigned.
          - If it doesn’t exist → listing is imported without assignment.
          - If listing is already assigned → no reassignment will occur (must be done manually in ShowMojo Properties page).

        ---

        ## Listing Group Assignment

        You may specify `listing_group_name` to assign the listing to a listing group:

          - The name is matched case-insensitively against the account's existing groups (whitespace is normalized).
          - If no matching group exists → a new group is created automatically.
          - If the listing already belongs to other groups → the assignment is replaced with the specified group.
          - If the field is omitted or blank → the current group assignment stays unchanged.

        ---

        ## Custom Application URL

        To display a custom application link, use:

        ```json
        {
          "custom_application_url": "https://your.custom.link",
          "application_link_policy": "APPLICATION_LINK_POLICY_CUSTOM_LINK"
        }
        ```
        <details>
        <summary>Available Listing Details</summary>
          - 1 parking spot
          - 2 parking spots
          - 3 parking spots
          - 4 parking spots
          - 5 parking spots
          - 6 parking spots
          - 90+ Walkscore
          - Air conditioning
          - Air conditioning included
          - Alarm included
          - Alarm-ready
          - Attached garage
          - Attic
          - Back porch
          - Balcony
          - Basement
          - Basic cable included
          - Basketball court
          - Bay windows
          - Bike room
          - Breakfast bar
          - Business center
          - Cable ready
          - Cable television
          - Cable television included
          - Can be furnished
          - Carpet floors
          - Carport
          - Cats negotiable
          - Cats ok
          - Ceiling fans
          - Central air conditioning
          - Central heat
          - Chefs kitchen
          - Coffee service
          - Concierge
          - Condo quality
          - Covered parking
          - Deck
          - Decorative fireplace
          - Den
          - Detached garage
          - Dining room
          - Dishwasher
          - Dog spa / dog boarding
          - Dogs negotiable
          - Dogs ok
          - Dogs ok up to 25 lbs
          - Dogs ok up to 40 lbs
          - Door attendant
          - Dry cleaner on site
          - Eat-in kitchen
          - Electric furnace
          - Electric included
          - Elevator
          - Family room
          - Fenced yard
          - Fireplace
          - First floor walkup
          - Fitness center
          - Five year lease
          - Flexible duration lease
          - Floor heat in bathroom
          - Floor to ceiling windows
          - Formal dining room
          - Free laundry on-site
          - Full service
          - Furnished
          - Garage parking
          - Garbage disposal
          - Garden
          - Garden apartment
          - Gas and electric included
          - Gas furnace
          - Gas included
          - Gated property
          - Golf course
          - Granite kitchen counters
          - Grill / barbecue
          - Grocery on site
          - Guest suite
          - Hardwood cabinets
          - Hardwood floors
          - Heat and AC included
          - Heat included
          - High ceilings
          - High-rise
          - I-GO / Zip Car
          - In-unit storage
          - Indoor pool
          - Internet access available
          - Internet access included
          - Kitchen recently updated
          - LEED certified
          - Lake
          - Laundry hookups in unit
          - Laundry in unit
          - Laundry on-site
          - Lawn care included
          - Lawn care not included
          - Less than five years old
          - Less than ten years old
          - Library
          - Living room
          - Loft layout
          - Lounge / club room
          - Marble in bathroom
          - Master Bath
          - Media room / clubhouse
          - Microwave
          - Modern bath fixtures
          - Month to month lease
          - New construction
          - No cats
          - No dogs
          - No laundry available
          - No parking available
          - No pets
          - No section 8
          - No smoking
          - No smoking building
          - Not furnished
          - Office
          - On-site engineer
          - On-site manager
          - One cat ok
          - One year lease
          - Open floor plan
          - Outdoor pool
          - Owner occupied building
          - Pantry
          - Park nearby
          - Parking available
          - Parking included
          - Patio
          - Pay laundry on-site
          - Pets negotiable
          - Playground
          - Porch
          - Premium cable included
          - Private deck
          - Private dog run/park
          - Private party room
          - Private patio
          - Private porch
          - Radiator heat
          - Recently rehabbed
          - Recently renovated
          - Recreation room
          - Refrigerator
          - Restaurant on site
          - Rooftop deck
          - Sauna
          - Section 8 possible
          - Section 8 welcome
          - Secure parking
          - Secured entry
          - Separate tub and shower
          - Shed
          - Small building
          - Smoking allowed
          - Snow removal included
          - Snow removal not included
          - Soaking tub
          - Spa
          - Space heater(s)
          - Sprinkler system
          - Stainless steel appliances
          - Steam shower
          - Storage unit
          - Stove / oven
          - Street parking
          - Sun room
          - Swimming pool
          - Tenant pays all electric
          - Tenant pays all utilities
          - Tenant pays gas and electric
          - Tenant pays parking
          - Tenant pays trash removal
          - Tenant pays water
          - Tennis court
          - Three year lease
          - Tile floors
          - Top floor
          - Trash removal included
          - Two year lease
          - Valet
          - Vaulted ceiling
          - Vintage building
          - Voice Intercom
          - Walk-in closet
          - Walking/biking trails
          - Water included
          - Waterfront
          - Wheelchair access
          - Whirlpool tub
          - Window-unit AC
          - Wired internet available
          - Wired internet included
          - Wireless internet available
          - Wireless internet included
          - Yard
        </details>
        ---
      operationId: importListings
      security:
        - tokenAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ListingsImportRequest'
      responses:
        '200':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Listings processed successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListingsImportResponse'
              example:
                response:
                  - status: created
                    uid: xyz123
                    code: APT-001
                    edit_url: https://showmojo.com/edit/xyz123
                    public_url: https://showmojo.com/listing/xyz123
                  - status: updated
                    uid: abc456
                    code: APT-002
                    edit_url: https://showmojo.com/edit/abc456
                    public_url: https://showmojo.com/listing/abc456
                  - status: error
                    code: APT-003
                    errors: Address can't be blank
        '400':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Bad Request - invalid import payload or field values
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListingsImportErrorResponse'
              examples:
                missing_payload:
                  summary: No listing payload provided
                  value:
                    response:
                      status: error
                      errors: Please provide listings data.
                invalid_batch_shape:
                  summary: listings must be an array
                  value:
                    response:
                      status: error
                      errors: The listings value has to be an array of objects.
                invalid_single_shape:
                  summary: listing must be a single object
                  value:
                    response:
                      status: error
                      errors: The listing value has to be a single object.
                batch_too_large:
                  summary: Batch exceeds max size
                  value:
                    response:
                      status: error
                      errors: Max listings batch size is 100.
                malformed_room_payload:
                  summary: rooms_attributes item is malformed
                  value:
                    response:
                      status: error
                      errors: rooms_attributes[0] must be an object
        '409':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Conflict - another import for this account is already in progress
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListingsImportErrorResponse'
              example:
                response:
                  status: error
                  errors: Another import is currently in progress. Please wait for it to complete before starting a new one.
    get:
      tags:
        - listings
      summary: List Listings
      description: |
        Returns the listings of the authenticated account, ordered by creation (oldest first). The order is stable across requests, so pages do not overlap or skip listings while you iterate.

        ### Filtering

        - `updated_since`: return only listings changed at or after this ISO 8601 timestamp. A listing changes when any of its fields, photos, or fees change. To sync incrementally, store the time at which you started a successful pull and send it as `updated_since` on the next one.
        - `status`: return only `STATUS_ACTIVE` or `STATUS_INACTIVE` listings.
        - `fields`: comma-separated list of fields to include. By default, all available fields are returned.

        An invalid `updated_since` or `status` returns `400 Bad Request` with the reason in `response.errors`.

        ### Pagination

        Pagination is opt-in. Without `page` or `per_page` the response is the full array of listings, as it has always been. Send `page` or `per_page` and the response becomes an object with the page in `data` and a `pagination` block, the same shape as [List Properties](https://docs.showmojo.com/docs/legacy/list-properties).

        ```http
        GET /api/v3/listings?updated_since=2026-10-15T00:00:00Z&page=1&per_page=100
        ```

        ### Neighborhood Fields

        The following fields are included when the account has neighborhoods enabled:

        | Field | Type | Description |
        |-------|------|-------------|
        | `neighborhood` | string | Standard neighborhood name |
        | `primary_neighborhood` | string | Custom primary neighborhood (when custom neighborhoods enabled) |
        | `secondary_neighborhood` | string | Custom secondary neighborhood |
      operationId: listListings
      security:
        - tokenAuth: []
        - basicAuth: []
      parameters:
        - in: query
          name: fields
          schema:
            type: string
          description: Comma-separated list of field names to include. Defaults to all available fields.
          example: uid,title,address,rent,bedrooms,status
        - in: query
          name: updated_since
          schema:
            type: string
            format: date-time
          description: Only listings updated at or after this ISO 8601 timestamp.
          example: '2026-10-15T00:00:00Z'
        - in: query
          name: status
          schema:
            type: string
            enum:
              - STATUS_ACTIVE
              - STATUS_INACTIVE
          description: Only listings with this status.
        - in: query
          name: page
          schema:
            type: integer
            minimum: 1
            default: 1
          description: Page number. Sending `page` or `per_page` switches the response to the paginated shape.
        - in: query
          name: per_page
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          description: Results per page (max 100). Sending `page` or `per_page` switches the response to the paginated shape.
      responses:
        '200':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: List of listings. A bare array by default, or a paginated object when `page` or `per_page` is sent.
          content:
            application/json:
              schema:
                oneOf:
                  - type: array
                    title: Full list
                    items:
                      $ref: '#/components/schemas/ListingResponse'
                  - type: object
                    title: Paginated
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/ListingResponse'
                      pagination:
                        $ref: '#/components/schemas/Pagination'
              examples:
                paginated:
                  summary: Paginated response (page or per_page sent)
                  value:
                    data:
                      - uid: abc123def
                        title: Spacious 2BR Apartment
                        address: 401 Dains St.
                        status: STATUS_ACTIVE
                        updated_at: '2026-10-15T14:22:00.000Z'
                    pagination:
                      page: 1
                      per_page: 100
                      total: 1
                      total_pages: 1
                full:
                  summary: Full response with all fields
                  value:
                    - uid: abc123def
                      property_id: prop456
                      title: Spacious 2BR Apartment
                      address: 401 Dains St.
                      unit: 4B
                      city: San Francisco
                      state: CA
                      zip: '94107'
                      code: DAINS401
                      general_type: RENT
                      housing_type: Apartment
                      status: STATUS_ACTIVE
                      rent: 2500
                      max_rent: 3000
                      price: null
                      property_tax: null
                      bedrooms: 2
                      plus_convertible: false
                      full_bathrooms: 1
                      partial_bathrooms: 1
                      offices: null
                      square_feet: 1200
                      year_built: 1995
                      available_type: Immediate
                      available_date: null
                      highlights: Newly renovated kitchen with stainless steel appliances.
                      lat: 37.7749
                      long: -122.4194
                      video_url: null
                      tour_url: null
                      phone: '4155551234'
                      security_deposit_type: SET_AMOUNT
                      security_deposit_value: 2500
                      notify_tenants: false
                      listing_group_name: Downtown Lofts
                      photos:
                        - - https://cdn.example.com/img1_std.jpg
                          - https://cdn.example.com/img1_lg.jpg
                          - https://cdn.example.com/img1_md.jpg
                      details:
                        - Pet Friendly
                        - Washer/Dryer In Unit
                      external_id: YARDI-12345
                      external_source: YARDI
                      fees:
                        - fee_type: PET_RENT
                          category: monthly
                          amount: 25
                          requirement_type: required
                          per_item: true
                          display_name: Pet Rent
                        - fee_type: APPLICATION_FEE
                          category: one_time
                          amount: 50
                          requirement_type: required
                          per_item: false
                          display_name: Application Fee
                      created_at: '2026-01-15T10:30:00.000Z'
                      updated_at: '2026-03-10T14:22:00.000Z'
                filtered:
                  summary: Response with selected fields
                  value:
                    - uid: abc123def
                      title: Spacious 2BR Apartment
                      address: 401 Dains St.
                      rent: 2500
                      bedrooms: 2
                      status: STATUS_ACTIVE
        '400':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Invalid `updated_since` or `status`
          content:
            application/json:
              schema:
                type: object
                properties:
                  response:
                    type: object
                    properties:
                      status:
                        type: string
                        example: error
                      errors:
                        type: string
                        example: updated_since must be an ISO 8601 timestamp, for example 2026-10-15T00:00:00Z
              examples:
                updated_since:
                  summary: Invalid updated_since
                  value:
                    response:
                      status: error
                      errors: updated_since must be an ISO 8601 timestamp, for example 2026-10-15T00:00:00Z
                status:
                  summary: Invalid status
                  value:
                    response:
                      status: error
                      errors: status must be one of STATUS_ACTIVE, STATUS_INACTIVE
  /api/v3/reports/{report_name}:
    post:
      tags:
        - reports
      summary: Named Report Export (JSON)
      description: |
        ## Authentication

        Use **Token Auth**: send the account API token from [Settings > Listing Import](https://showmojo.com/settings/import) as `Authorization: Token {token}`.

        **HTTP Basic Auth** with a ShowMojo login and password is deprecated and stops working on 2027-01-19. Replace the header with the token header; nothing else changes.

        ---

        ## Notes

        - Date parameters are supported by all reports, **except**:
          - Listing Performance report
        - The API does not support pagination

        ---
      operationId: exportReportJson
      security:
        - tokenAuth: []
        - basicAuth: []
      parameters:
        - name: report_name
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/NamedReportRequest'
      responses:
        '200':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Report rows
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportJsonResponse'
        '400':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: The report is not available on this account
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportErrorResponse'
              example:
                response:
                  status: error
                  errors: Report not found.
        '401':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Missing, invalid or revoked credentials. Empty body.
        '404':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: '`report_name` is not one of the named reports.'
        '422':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: '`detailed_prospect_data` only: date range longer than 7 days, or a missing date'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportErrorResponse'
              example:
                response:
                  status: error
                  errors: Max date range is 1 week.
  /api/v3/reports/{report_name}.csv:
    post:
      tags:
        - reports
      summary: Named Report Export (CSV)
      description: |
        ## Authentication

        Use **Token Auth**: send the account API token from [Settings > Listing Import](https://showmojo.com/settings/import) as `Authorization: Token {token}`.

        **HTTP Basic Auth** with a ShowMojo login and password is deprecated and stops working on 2027-01-19. Replace the header with the token header; nothing else changes.

        ---
      operationId: exportReportCsv
      security:
        - tokenAuth: []
        - basicAuth: []
      parameters:
        - name: report_name
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/NamedReportRequest'
      responses:
        '200':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: CSV report; the example is `detailed_listing_data`
          content:
            text/csv:
              schema:
                type: string
              example: |
                Address,Unit,City,State,Zip,Rent,Bedrooms,Full bathrooms,Partial bathrooms,Square feet,Access device,Market status,Last on market,Days on market,Short url,Imported from,Team members,Listing code,Listing UID
                401 Dains St.,4B,San Francisco,CA,94107,2500,2,1,1,1200,,On market,"Sep 30, 2026",16,https://showmojo.com/l/abc123def,Appfolio,"Alex Manager, Sam Agent",DAINS401,abc123def
        '400':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: The report is not available on this account
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportErrorResponse'
              example:
                response:
                  status: error
                  errors: Report not found.
        '401':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Missing, invalid or revoked credentials. Empty body.
        '404':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: '`report_name` is not one of the named reports.'
        '422':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: '`detailed_prospect_data` only: date range longer than 7 days, or a missing date'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportErrorResponse'
              example:
                response:
                  status: error
                  errors: Max date range is 1 week.
  /api/v3/reports/custom:
    post:
      tags:
        - reports
      summary: Custom Report Export (JSON)
      description: |
        ## Authentication

        Use **Token Auth**: send the account API token from [Settings > Listing Import](https://showmojo.com/settings/import) as `Authorization: Token {token}`.

        **HTTP Basic Auth** with a ShowMojo login and password is deprecated and stops working on 2027-01-19. Replace the header with the token header; nothing else changes.

        ---

        - The API does not support pagination
      operationId: exportCustomReportJson
      security:
        - tokenAuth: []
        - basicAuth: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required:
                - report_id
              properties:
                report_id:
                  type: integer
                start_date:
                  type: string
                end_date:
                  type: string
      responses:
        '200':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Custom report rows, keyed by the columns of the report's SQL
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportJsonResponse'
        '400':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: No custom report with this `report_id` on the account
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportErrorResponse'
              example:
                response:
                  status: error
                  errors: Report not found. Please check report_id in your export settings.
        '401':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Missing, invalid or revoked credentials. Empty body.
  /api/v3/reports/custom.csv:
    post:
      tags:
        - reports
      summary: Custom Report Export (CSV)
      description: |
        ## Authentication

        Use **Token Auth**: send the account API token from [Settings > Listing Import](https://showmojo.com/settings/import) as `Authorization: Token {token}`.

        **HTTP Basic Auth** with a ShowMojo login and password is deprecated and stops working on 2027-01-19. Replace the header with the token header; nothing else changes.

        ---
      operationId: exportCustomReportCsv
      security:
        - tokenAuth: []
        - basicAuth: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/CustomReportRequest'
      responses:
        '200':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Custom report as CSV
          content:
            text/csv:
              schema:
                type: string
              example: |
                Listing uid,Address,Rent
                abc123def,401 Dains St. 4B,2500
        '400':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: No custom report with this `report_id` on the account
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportErrorResponse'
              example:
                response:
                  status: error
                  errors: Report not found. Please check report_id in your export settings.
        '401':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Missing, invalid or revoked credentials. Empty body.
  /api/v3/tours/{listing_id}/available_times:
    get:
      tags:
        - tours
      summary: Fetch available times for a listing
      description: |
        Returns available time slots for a listing.

        **Notes:**
        - Returns an empty array if the listing is off-market, the account cannot create showings, or the customer has turned off tour bookings for your integration
        - Times are in the listing's local timezone
        - Each slot includes `showing_type` indicating whether it is an `in_person` or `self_guided` time slot
        - When no `showing_type` filter is provided, defaults to `in_person` if the listing supports both types, or the only supported type if the listing supports just one
      operationId: getAvailableTourTimes
      security:
        - bearerAuth: []
        - tokenAuth: []
        - basicAuth: []
      parameters:
        - in: path
          name: listing_id
          required: true
          schema:
            type: string
          description: The listing ID or UID (alias `clientPropertyId`)
        - in: query
          name: startLocalDateTime
          schema:
            type: string
          description: Filter times after this ISO8601 datetime
        - in: query
          name: endLocalDateTime
          schema:
            type: string
          description: Filter times before this ISO8601 datetime
        - in: query
          name: showing_type
          schema:
            type: string
          description: Filter by showing type. Accepts `in_person`, `self_guided`, or both as comma-separated (e.g. `in_person,self_guided`). Defaults to `in_person` when the listing supports both, or the only supported type otherwise.
      responses:
        '200':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Available showtimes for a listing
          content:
            application/json:
              schema:
                type: object
                properties:
                  availableLocalDateTimes:
                    type: array
                    items:
                      type: object
                      properties:
                        startLocalDateTime:
                          type: string
                        endLocalDateTime:
                          type: string
                        showing_type:
                          type: string
                          enum:
                            - in_person
                            - self_guided
              examples:
                full_range:
                  summary: All showtimes
                  value:
                    availableLocalDateTimes:
                      - startLocalDateTime: '2024-03-01T10:00:00'
                        endLocalDateTime: '2024-03-01T10:30:00'
                        showing_type: in_person
                      - startLocalDateTime: '2024-03-01T14:00:00'
                        endLocalDateTime: '2024-03-01T14:30:00'
                        showing_type: in_person
                      - startLocalDateTime: '2024-03-01T16:00:00'
                        endLocalDateTime: '2024-03-01T16:30:00'
                        showing_type: self_guided
                filtered:
                  summary: Filtered by date range and showing type
                  value:
                    availableLocalDateTimes:
                      - startLocalDateTime: '2024-03-01T14:00:00'
                        endLocalDateTime: '2024-03-01T14:30:00'
                        showing_type: in_person
                invalid_start:
                  summary: Invalid startLocalDateTime format
                  value:
                    errorCode: 400
                    errorMessage: Invalid parameter value - startLocalDateTime. Datetime must be in ISO8601 format
                not_found:
                  summary: Listing not found
                  value:
                    errorCode: 404
                    errorMessage: Not Found
  /api/v3/tours/{listing_id}/screening_questions:
    get:
      tags:
        - tours
      summary: Fetch screening questions for a listing
      description: |
        Returns screening questions configured for a listing. Use this to collect prospect information before scheduling.

        **Notes:**
        - Questions requiring credit card validation or document verification are excluded
        - Returns an empty list if the customer has turned off tour bookings for your integration
        - Pass question answers in the `screening_answers` array when calling the schedule endpoint
        - Answers must match provided options exactly for questions with options
      operationId: getScreeningQuestions
      security:
        - bearerAuth: []
        - tokenAuth: []
        - basicAuth: []
      parameters:
        - in: path
          name: listing_id
          required: true
          schema:
            type: string
          description: The listing ID or UID
      responses:
        '200':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Screening questions for the listing
          content:
            application/json:
              schema:
                type: object
                properties:
                  questions:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          description: Question ID to use in screening_answers
                        type:
                          type: string
                          enum:
                            - CUSTOM
                            - PETS
                            - MOVEDATE
                            - BEDROOMS
                            - DROPDOWN
                            - INCOME
                            - ROOMMATES
                            - CUSTOM_DATE
                            - BROKER_COMPANY_NAME
                            - BROKER_ID
                            - TENANT_ADDRESS
                          description: Question type
                        text:
                          type: string
                          description: Question text to display
                        required:
                          type: boolean
                          description: Whether an answer is required
                        options:
                          type: array
                          items:
                            type: string
                          description: Available options (for multiple choice questions)
                        hint:
                          type: string
                          description: Additional instructions for answering
              example:
                questions:
                  - id: 123
                    type: PETS
                    text: Do you have any pets?
                    required: true
                    options:
                      - No pets
                      - One or more cats
                      - One or more dogs
                      - Both cat(s) and dog(s)
                  - id: 456
                    type: MOVEDATE
                    text: When do you plan to move in?
                    required: true
                  - id: 789
                    type: ROOMMATES
                    text: Will you have any roommates?
                    required: false
                    hint: Provide comma-separated list of names or emails
                  - id: 101
                    type: INCOME
                    text: What is your monthly income?
                    required: true
                    options:
                      - '500'
                      - '1000'
                      - '1500'
                      - '2000'
                      - '2500'
                      - '3000'
  /api/v3/tours/schedule:
    put:
      tags:
        - tours
      summary: Schedule a new tour
      description: |
        Creates a new showing/tour for a listing.

        **Attribution:**
        - A booking made with a partner OAuth token is always recorded as `THIRD_PARTY` and attributed to the partner application that authenticated. The `channel` field is ignored for those requests, so there is no need to send it.
        - The `AI_*` channels describe scheduling done by ShowMojo's own AI assistant. Reporting them for a booking made on a partner site misattributes the lead.

        **Bookings can be turned off by the customer:**
        - A customer can allow or block tour bookings for an individual partner, per account, property and listing.
        - When bookings are off, scheduling fails with `Scheduling is not available for this listing`, available times come back as an empty array, and screening questions come back as an empty list. An already scheduled tour stays readable through `/api/v3/tours/results`.

        **Important Notes on Screening Answers:**
        - For questions with predefined options (PETS, DROPDOWN, BEDROOMS, INCOME), the answer must exactly match one of the provided options
        - Invalid answers are silently skipped; the prospect will be contacted to provide missing information
        - For ROOMMATES questions, provide a comma-separated list of names or emails (e.g., `"John Doe, jane@example.com, Bob Smith"`)

        **Updating an existing lead (`lead_id`):**
        - When the optional `lead_id` is supplied, an existing **unscheduled** lead is updated instead of creating a new showing.
        - The lead is located by its UID, scoped to your account, and must have no scheduled showtime. If it is not found or already has a showtime, the request fails with a `lead_id` error and no new showing is created.
        - On success the lead's contact info and showtime are updated, the lead is associated with the `listing_id` being scheduled (which may differ from the listing it originally inquired about), the response is identical to the create flow, and `tour_id` equals the supplied `lead_id`.
        - Email matching tolerates partner masked-email addresses (e.g. Zillow `@convo.zillow.com`, Apartments.com `textlead+…@apartments.com`): a differing masked email alone does not block scheduling when name and phone match.
      operationId: scheduleTour
      security:
        - bearerAuth: []
        - tokenAuth: []
        - basicAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - listing_id
                - name
                - email
                - phone
                - showtime
                - can_contact_by_email
              properties:
                listing_id:
                  type: string
                  description: The listing ID or UID
                name:
                  type: string
                  description: Prospect's full name
                email:
                  type: string
                  description: Prospect's email address
                phone:
                  type: string
                  description: Prospect's phone number
                showtime:
                  type: string
                  description: Requested tour time in ISO8601 format
                  example: '2024-03-01T10:00:00'
                can_contact_by_email:
                  type: boolean
                  description: Whether the prospect can be contacted by email
                can_contact_by_phone:
                  type: boolean
                  description: Whether the prospect can be contacted by phone/SMS
                showing_type:
                  type: string
                  enum:
                    - in_person
                    - self_guided
                  description: Type of showing. Defaults to `in_person` when the listing supports both, or the only supported type otherwise. Use the `showing_types` field from the Listings API to determine what a listing supports.
                lead_source:
                  type: string
                  description: Source of the lead
                channel:
                  type: string
                  enum:
                    - THIRD_PARTY
                    - AI
                    - AI_WEB
                    - AI_SMS
                    - AI_VOICE
                  description: 'How the tour was scheduled. ShowMojo uses it to attribute the lead in reporting, so it must describe who actually did the scheduling. `THIRD_PARTY` covers bookings made on a partner site or app. The `AI_*` values are reserved for ShowMojo''s own AI assistant (web chat, SMS and voice) and must not be used by partners. Partner integrations authenticating with an OAuth token can omit this field: such a booking is always recorded as `THIRD_PARTY` under the partner application that authenticated, and any value sent is ignored.'
                lead_id:
                  type: string
                  description: UID of an existing unscheduled lead. When provided, that lead is updated with the supplied contact info and showtime instead of creating a new showing. Omit to always create a new showing. See the operation description for details.
                screening_answers:
                  type: array
                  description: Answers to screening questions
                  items:
                    type: object
                    properties:
                      question_id:
                        type: integer
                        description: Screening question ID
                      answer:
                        type: string
                        description: Answer to the screening question
            example:
              listing_id: abc123
              name: John Doe
              email: john@example.com
              phone: '5551234567'
              showtime: '2024-03-01T10:00:00'
              can_contact_by_email: true
              can_contact_by_phone: true
              showing_type: in_person
              screening_answers:
                - question_id: 123
                  answer: No pets
      responses:
        '200':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Tour scheduled successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  tour_id:
                    type: string
                  showing_type:
                    type: string
                    enum:
                      - in_person
                      - self_guided
                  pending_acceptance:
                    type: boolean
                    description: True when the listing requires the owner or agent to accept the tour. The tour is held rather than confirmed, so tell the prospect it awaits approval.
                  showtime:
                    type: object
                    properties:
                      start_time:
                        type: string
                      end_time:
                        type: string
              example:
                success: true
                tour_id: xyz789
                showing_type: in_person
                pending_acceptance: false
                showtime:
                  start_time: '2024-03-01T10:00:00'
                  end_time: '2024-03-01T10:30:00'
        '400':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Bad Request - Missing or invalid parameters
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  error_code:
                    type: integer
                  error_message:
                    type: string
                    description: All error messages joined together (kept for backward compatibility)
                  errors:
                    type: object
                    description: Error messages grouped by the field they relate to
                    properties:
                      base:
                        type: array
                        items:
                          type: string
                        description: Generic errors not specific to a field (e.g., listing off-market, duplicate showing)
                      name:
                        type: array
                        items:
                          type: string
                      email:
                        type: array
                        items:
                          type: string
                      phone:
                        type: array
                        items:
                          type: string
                      showtime:
                        type: array
                        items:
                          type: string
                      showing_type:
                        type: array
                        items:
                          type: string
                      channel:
                        type: array
                        items:
                          type: string
                      can_contact_by_email:
                        type: array
                        items:
                          type: string
                      lead_id:
                        type: array
                        items:
                          type: string
                        description: Errors related to the existing lead lookup (not found or already scheduled)
                      listing_id:
                        type: array
                        items:
                          type: string
                        description: Errors related to the listing, including bookings being turned off for your integration
              examples:
                missing_field:
                  summary: Missing required field
                  value:
                    success: false
                    error_code: 400
                    error_message: 'Missing required parameter: showtime'
                    errors:
                      showtime:
                        - 'Missing required parameter: showtime'
                listing_off_market:
                  summary: Listing is off-market
                  value:
                    success: false
                    error_code: 400
                    error_message: Listing is off-market
                    errors:
                      base:
                        - Listing is off-market
                invalid_showing_type:
                  summary: Invalid showing type for listing
                  value:
                    success: false
                    error_code: 400
                    error_message: 'Invalid showing_type for this listing. Supported types: in_person'
                    errors:
                      showing_type:
                        - 'Invalid showing_type for this listing. Supported types: in_person'
                scheduling_disabled:
                  summary: Customer has turned off bookings for your integration
                  value:
                    success: false
                    error_code: 400
                    error_message: Scheduling is not available for this listing
                    errors:
                      listing_id:
                        - Scheduling is not available for this listing
                lead_not_found:
                  summary: lead_id not found or already scheduled
                  value:
                    success: false
                    error_code: 400
                    error_message: Lead not found or already scheduled
                    errors:
                      lead_id:
                        - Lead not found or already scheduled
  /api/v3/tours/results:
    get:
      tags:
        - tours
      summary: Fetch scheduled tour result
      operationId: getTourResult
      description: |
        Returns the status of a tour previously scheduled through this API.

        **Notes:**
        - OAuth authentication only.
        - Stays available for tours already booked even after the customer turns off bookings for your integration.
      security:
        - bearerAuth: []
      parameters:
        - in: query
          name: appointmentId
          schema:
            type: string
          required: true
      responses:
        '200':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Tour attribution status
          content:
            application/json:
              examples:
                confirmed:
                  summary: Confirmed appointment
                  value:
                    appointmentStatus: confirmed
                past_confirmed:
                  summary: Past confirmed
                  value:
                    appointmentStatus: unit_shown
                no_show:
                  summary: No-show
                  value:
                    appointmentStatus: unit_not_shown
                cancelled:
                  summary: Cancelled
                  value:
                    appointmentStatus: cancel_appointment
        '400':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Missing parameter
          content:
            application/json:
              example:
                errorCode: 400
                errorMessage: Missing parameter value - appointmentId
        '404':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Appointment not found
          content:
            application/json:
              example:
                errorCode: 404
                errorMessage: Not Found
  /api/v3/listings/{uid}:
    get:
      tags:
        - listings
      summary: Get Listing
      description: |
        Returns a single listing by UID with all available fields, photos, details, contact info, and neighborhood data.
      operationId: getListing
      security:
        - tokenAuth: []
        - basicAuth: []
      parameters:
        - in: path
          name: uid
          required: true
          schema:
            type: string
          description: The listing's unique identifier
      responses:
        '200':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Listing details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListingDetail'
              example:
                uid: abc123def
                property_id: prop456
                title: Spacious 2BR Apartment
                address: 401 Dains St.
                unit: 4B
                city: San Francisco
                state: CA
                zip: '94107'
                code: DAINS401
                general_type: RENT
                housing_type: Apartment
                status: STATUS_ACTIVE
                rent: 2500
                max_rent: null
                price: null
                property_tax: null
                bedrooms: 2
                plus_convertible: false
                full_bathrooms: 1
                partial_bathrooms: 1
                offices: null
                square_feet: 1200
                year_built: 1995
                available_type: Immediate
                available_date: null
                highlights: Newly renovated kitchen with stainless steel appliances.
                lat: 37.7749
                long: -122.4194
                video_url: null
                tour_url: null
                phone: '4155551234'
                security_deposit_type: SET_AMOUNT
                security_deposit_value: 2500
                notify_tenants: false
                listing_group_name: Downtown Lofts
                photos:
                  - - https://cdn.example.com/img1_std.jpg
                    - https://cdn.example.com/img1_lg.jpg
                    - https://cdn.example.com/img1_md.jpg
                  - - https://cdn.example.com/img2_std.jpg
                    - https://cdn.example.com/img2_lg.jpg
                    - https://cdn.example.com/img2_md.jpg
                details:
                  - Pet Friendly
                  - Washer/Dryer In Unit
                  - Parking Included
                contact_info:
                  agent_name: John Smith
                  company: Acme Realty
                  phone: (415) 555-1234
                  email: john@acmerealty.com
                showing_types:
                  - in_person
                  - self_guided
                external_id: YARDI-12345
                external_source: YARDI
                fees:
                  - fee_type: PET_RENT
                    category: monthly
                    amount: 25
                    requirement_type: required
                    per_item: true
                    display_name: Pet Rent
                  - fee_type: APPLICATION_FEE
                    category: one_time
                    amount: 50
                    requirement_type: required
                    per_item: false
                    display_name: Application Fee
                  - fee_type: CUSTOM
                    category: monthly
                    amount: 15
                    requirement_type: optional
                    per_item: false
                    display_name: Rooftop Access
                scheduling_block:
                  type: BETWEEN
                  block_until: '2026-04-15T00:00:00.000Z'
                  block_from: '2026-04-01T00:00:00.000Z'
                application_url: https://apply.example.com/listing/abc123
                created_at: '2026-01-15T10:30:00.000Z'
                updated_at: '2026-03-10T14:22:00.000Z'
        '404':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Listing not found
          content:
            application/json:
              example:
                response:
                  status: error
                  errors: Listing not found
  /api/v3/properties:
    get:
      tags:
        - properties
      summary: List Properties
      description: |
        Returns a paginated list of properties for the authenticated account.

        **Notes:**
        - The `name` field returns the property's name or address
        - `external_id` and `external_source` are `null` for manually created properties
        - Details and photos are not included in the index response
      operationId: listProperties
      security:
        - tokenAuth: []
        - basicAuth: []
      parameters:
        - in: query
          name: page
          schema:
            type: integer
            default: 1
          description: Page number
        - in: query
          name: per_page
          schema:
            type: integer
            default: 25
            maximum: 100
          description: Results per page (max 100)
      responses:
        '200':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Paginated list of properties
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/PropertySummary'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
              example:
                data:
                  - uid: abc123
                    name: 123 Main St
                    label: Main Street Apartments
                    highlights: Recently renovated...
                    specials: First month free!
                    default_address:
                      address: 123 Main St
                      city: Portland
                      state: OR
                      zip: '97201'
                      lat: 45.5231
                      long: -122.6765
                    addresses:
                      - address: 123 Main St
                        city: Portland
                        state: OR
                        zip: '97201'
                        lat: 45.5231
                        long: -122.6765
                    external_id: yardi-prop-001
                    external_source: YARDI
                    created_at: '2024-01-15T10:30:00.000Z'
                    updated_at: '2024-06-01T14:22:00.000Z'
                pagination:
                  page: 1
                  per_page: 25
                  total: 42
                  total_pages: 5
  /api/v3/properties/{uid}:
    get:
      tags:
        - properties
      summary: Get Property
      description: |
        Returns a single property with full details including detail values and photos.
      operationId: getProperty
      security:
        - tokenAuth: []
        - basicAuth: []
      parameters:
        - in: path
          name: uid
          required: true
          schema:
            type: string
          description: The property UID
      responses:
        '200':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Property details
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/PropertyDetail'
              example:
                data:
                  uid: abc123
                  name: 123 Main St
                  label: Main Street Apartments
                  highlights: Recently renovated...
                  specials: First month free!
                  default_address:
                    address: 123 Main St
                    city: Portland
                    state: OR
                    zip: '97201'
                    lat: 45.5231
                    long: -122.6765
                  addresses:
                    - address: 123 Main St
                      city: Portland
                      state: OR
                      zip: '97201'
                      lat: 45.5231
                      long: -122.6765
                  external_id: yardi-prop-001
                  external_source: YARDI
                  created_at: '2024-01-15T10:30:00.000Z'
                  updated_at: '2024-06-01T14:22:00.000Z'
                  details:
                    - Air Conditioning
                    - Dishwasher
                    - Parking Available
                  photos:
                    - standard: https://example.com/photos/1/standard.jpg
                      large: https://example.com/photos/1/large.jpg
                      medium: https://example.com/photos/1/medium.jpg
        '404':
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          description: Property not found
          content:
            application/json:
              example:
                error: Property not found
components:
  headers:
    X-Request-Id:
      description: Unique id of this request. Generated by ShowMojo, or echoed from the request's own `X-Request-Id` header. Quote it when contacting support.
      schema:
        type: string
        example: 2f1c3b6e-5d4a-4f0e-9c3b-7a8d9e0f1a2b
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
    basicAuth:
      type: http
      scheme: basic
      description: |
        **Deprecated, sunset 2027-01-19.** ShowMojo login and password sent as HTTP Basic auth. Announced 2026-10-16; requests using it receive `401 Unauthorized` from the sunset date. Switch to the account API token: replace the `Authorization: Basic ...` header with `Authorization: Token {token}`, using the token from [Settings > Listing Import](https://showmojo.com/settings/import). No other change is needed; every endpoint that accepted Basic auth accepts the token. See the [versioning and deprecation policy](https://docs.showmojo.com/versioning).
    tokenAuth:
      type: apiKey
      in: header
      name: Authorization
      description: |
        Account API token, generated self-serve in [Settings > Listing Import](https://showmojo.com/settings/import) and sent as `Authorization: Token {token}`.

        Each account has one active token. Generating a new one revokes the previous one immediately: requests that still send the old token receive `401 Unauthorized`. There is no separate revoke action; to revoke a token, generate a new one.
  schemas:
    AccessTokenResponse:
      type: object
      properties:
        access_token:
          type: string
        token_type:
          type: string
        expires_in:
          type: integer
        scope:
          type: string
    LeadRequest:
      type: object
      required:
        - listing_uid
        - name
        - phone
        - email
      properties:
        listing_uid:
          type: string
          description: Unique identifier of the listing
        name:
          type: string
          description: Prospect's full name
        phone:
          type: string
          description: Prospect's phone number
        email:
          type: string
          description: Prospect's email address
        prospect_question:
          type: string
          description: Question from the prospect
        move_in_date:
          type: string
          format: date
          description: Optional move-in date
    LeadResponse:
      type: object
      properties:
        showing_uid:
          type: string
          description: Unique identifier of the created showing
    LeadErrorResponse:
      type: object
      properties:
        error:
          type: string
          description: |
            Human-readable error message. May be empty (`""`) when a generic
            validation error occurred.
    ListingsImportRequest:
      type: object
      description: Provide either `listings` (an array of listing objects, max 100 per request) or `listing` (a single listing object). Exactly one of the two should be sent.
      properties:
        listings:
          type: array
          maxItems: 100
          description: Batch import. Max 100 listings per request.
          items:
            type: object
            required:
              - code
              - address
              - city
              - state
              - zip
              - status
            properties:
              code:
                type: string
                description: Internal ID used for deduplication and updates
                example: LIST12345
              mls_id:
                type: string
                description: External MLS identifier
                example: MLS56789
              status:
                type: string
                enum:
                  - STATUS_ACTIVE
                  - STATUS_INACTIVE
                  - STATUS_DELETED
                description: Listing availability status
                example: STATUS_ACTIVE
              address:
                type: string
                description: Street address of the listing
                example: 742 Evergreen Terrace
              unit:
                type: string
                description: Apartment or unit number
                example: B2
              city:
                type: string
                description: City where the property is located
                example: Springfield
              state:
                type: string
                description: US state code (2-letter)
                example: IL
              zip:
                type: string
                description: Postal ZIP code
                example: '62704'
              lat:
                type: number
                format: float
                description: Latitude. On update, ignored when the listing's coordinates were manually overridden in ShowMojo.
                example: 39.7817
              long:
                type: number
                format: float
                description: Longitude. On update, ignored when the listing's coordinates were manually overridden in ShowMojo.
                example: -89.6501
              title:
                type: string
                description: Short descriptive title for the listing
                example: Cozy 2BR Home Near Downtown
              housing_type:
                type: string
                nullable: true
                enum:
                  - Apartment
                  - Condo
                  - Townhouse
                  - House
                  - Bedroom
                  - Commercial
                  - Land
                description: Property category. `Apartment` — apartment unit. `Condo` — condominium. `Townhouse` — townhouse. `House` — single-family home. `Bedroom` — individual bedroom rental. `Commercial` — commercial property. `Land` — vacant land.
                example: Apartment
              listing_group_name:
                type: string
                description: Name of the listing group to assign the listing to. Matched case-insensitively against the account's existing groups (whitespace is normalized); if no group matches, a new one is created automatically. The listing's current group assignment is replaced with this group. Omitted or blank leaves the current assignment unchanged.
                example: Downtown Portfolio
              general_type:
                type: string
                enum:
                  - RENT
                  - SALE
                description: Sale or rental. When omitted, the account's listing defaults apply.
                example: RENT
              year_built:
                type: integer
                description: Year the property was constructed
                example: 1995
              rent:
                type: number
                format: float
                description: Monthly rent amount
                example: 1450
              max_rent:
                type: number
                format: float
                description: Maximum acceptable rent for range-based filtering
                example: 1650
              price:
                type: number
                format: float
                description: Listing price (for sale)
                example: 215000
              available_type:
                type: string
                enum:
                  - Don't show
                  - Immediate
                  - Date
                description: Indicates availability mode. `Don't show` — listing is active but doesn't advertise when it is available. `Immediate` — available now. `Date` — available on the date specified in `available_date`.
                example: Date
              available_date:
                type: string
                format: date
                description: Available move-in date (used if `available_type` = Date)
                example: '2023-10-01'
              bedrooms:
                type: integer
                description: Number of bedrooms
                example: 2
              plus_convertible:
                type: boolean
                description: Whether the bedroom count includes an additional convertible room (advertised as e.g. "2 + convertible").
                example: false
              full_bathrooms:
                type: integer
                description: Number of full bathrooms
                example: 1
              partial_bathrooms:
                type: integer
                description: Number of partial bathrooms (e.g. half-bath)
                example: 1
              offices:
                type: integer
                description: Number of office or study rooms
                example: 1
              square_feet:
                type: integer
                description: Total interior square footage
                example: 1100
              property_tax:
                type: integer
                description: Annual property tax amount
                example: 2300
              highlights:
                type: string
                description: Free-text highlights or notes for this property
                example: Pet-friendly, hardwood floors, quiet neighborhood
              video_url:
                type: string
                format: uri
                description: URL to a listing video
                example: https://youtube.com/watch?v=dQw4w9WgXcQ
              tour_url:
                type: string
                format: uri
                description: URL to a virtual tour or Matterport link
                example: https://virtualtour.com/house123
              security_deposit_type:
                type: string
                enum:
                  - DONT_SHOW
                  - SET_AMOUNT
                  - MULTIPLE_RENT
                  - RENT_PLUS_AMOUNT
                  - NO_DEPOSIT
                description: How the security deposit is calculated. `DONT_SHOW` — not disclosed or not applicable. `SET_AMOUNT` — a fixed dollar amount (see `security_deposit_value`). `MULTIPLE_RENT` — a multiple of monthly rent (see `security_deposit_value` for the multiplier). `NO_DEPOSIT` — no deposit required. `RENT_PLUS_AMOUNT` — one month's rent plus an additional amount (see `security_deposit_value` for the additional amount).
                example: SET_AMOUNT
              security_deposit_value:
                type: number
                format: float
                minimum: 0.01
                description: Security deposit value depending on deposit type
                example: 1450
              pets:
                type: array
                description: List of pet policy labels to import. Known values such as `Dogs ok`, `Cats ok`, `Pets ok`, and `No pets` are mapped to ShowMojo pet-policy details. Unrecognized values are preserved as imported other pet categories.
                items:
                  type: string
                example:
                  - Dogs ok
                  - Cats ok
                  - Birds
              images:
                type: array
                description: Array of image URLs
                items:
                  type: string
                  format: uri
                example:
                  - https://imgur.com/image1.jpg
                  - https://imgur.com/image2.jpg
              details:
                type: array
                description: List of property features or amenities
                items:
                  type: string
                example:
                  - Yard
                  - Garage
                  - Central AC
                  - Washer/Dryer
              phone:
                type: string
                description: Contact phone number displayed on the listing.
                example: '4155551234'
              contact_email_from_api:
                type: string
                format: email
                description: Contact email supplied by the importing system; stored as the listing's imported contact email.
                example: leasing@example.com
              notify_tenants:
                type: boolean
                description: Whether current tenants should be notified about showings. On update, applied only when tenant-notification import is enabled for the listing in ShowMojo.
                example: false
              listing_contacts_attributes:
                type: array
                description: Notification contacts to import. On update (when tenant-notification import is enabled for the listing), previously imported contacts not present in the payload have their showing notifications disabled.
                items:
                  type: object
                  required:
                    - name
                    - email_list
                  properties:
                    name:
                      type: string
                      description: Contact name.
                      example: Jane Smith
                    email_list:
                      type: string
                      description: Comma-separated list of email addresses.
                      example: jane@example.com, backup@example.com
                    role:
                      type: string
                      enum:
                        - Current Tenant
                        - Other
                        - Owner
                        - Unknown
                      description: Contact role. Unrecognized or omitted values are treated as `Other`.
                      example: Current Tenant
                    phone:
                      type: string
                      description: Contact phone number.
                      example: '4155559876'
                    showing_notification_enabled:
                      type: boolean
                      description: Whether the contact receives showing notifications.
                      example: true
              assign_to_property:
                type: string
                description: Name of an existing property to assign the listing to. See the endpoint description for assignment rules.
                example: The Evergreen Apartments
              application_link_policy:
                type: string
                enum:
                  - APPLICATION_LINK_POLICY_STANDARD_LINK
                  - APPLICATION_LINK_POLICY_CUSTOM_LINK
                  - APPLICATION_LINK_POLICY_DISABLED
                description: How the application link is displayed. Use `APPLICATION_LINK_POLICY_CUSTOM_LINK` together with `custom_application_url`.
                example: APPLICATION_LINK_POLICY_CUSTOM_LINK
              custom_application_url:
                type: string
                format: uri
                description: Custom application URL used when `application_link_policy` is set to `APPLICATION_LINK_POLICY_CUSTOM_LINK`.
                example: https://apply.example.com/custom/abc123
              rooms_attributes:
                type: array
                description: Bedroom room data to import. When provided on re-import, existing bedroom rooms are replaced with the supplied collection.
                items:
                  type: object
                  properties:
                    bed_size:
                      type: integer
                      nullable: true
                      description: Bedroom size value.
                      example: 4
                    width:
                      type: integer
                      nullable: true
                      description: Room width.
                      example: 14
                    depth:
                      type: integer
                      nullable: true
                      description: Room depth.
                      example: 12
                    closet:
                      type: integer
                      nullable: true
                      description: Closet size/count value.
                      example: 4
                    master_bath:
                      type: boolean
                      nullable: true
                      description: Whether the bedroom has an attached master bath.
                      example: true
                    balcony:
                      type: boolean
                      nullable: true
                      description: Whether the bedroom has access to a balcony.
                      example: false
              listing_fees_attributes:
                type: array
                description: Listing fee data to import. When provided on re-import, matching fees are updated and missing existing fees are removed.
                items:
                  type: object
                  required:
                    - fee_type
                    - category
                    - amount
                  properties:
                    fee_type:
                      type: string
                      description: Fee type identifier. Use `CUSTOM` with `custom_name` for user-defined fees.
                      example: PET_RENT
                    custom_name:
                      type: string
                      nullable: true
                      description: Required when `fee_type` is `CUSTOM`.
                      example: Key fob
                    category:
                      type: string
                      enum:
                        - monthly
                        - one_time
                      description: Billing cadence.
                      example: monthly
                    amount:
                      type: number
                      format: float
                      description: Fee amount in dollars.
                      example: 50
                    requirement_type:
                      type: string
                      nullable: true
                      enum:
                        - required
                        - optional
                      description: Whether the fee is mandatory.
                      example: optional
                    per_item:
                      type: boolean
                      nullable: true
                      description: Whether the fee multiplies per item.
                      example: true
              floor_plan_url:
                type: string
                format: uri
                description: HTTP(S) URL for a floor plan image or document to import asynchronously.
                example: https://cdn.example.com/floorplans/abc123.png
        listing:
          type: object
          description: Single-listing import — one listing object accepting the same fields as the items of `listings`. Must be a single object, not an array.
    ListingsImportResponse:
      type: object
      properties:
        response:
          oneOf:
            - type: array
              items:
                $ref: '#/components/schemas/ListingImportResult'
            - $ref: '#/components/schemas/ListingImportResult'
          description: 'An array of per-listing results when `listings` was sent, or a single result object when `listing` was sent. Per-listing failures are reported inline with `status: error` — the HTTP status is still 200, so check each item''s `status`.'
    ListingImportResult:
      type: object
      description: Result of importing one listing. In addition to the fields below, every identifier field provided in the request (`code`, `mls_id`, etc.) is echoed back to help correlate results with submitted listings.
      properties:
        status:
          type: string
          enum:
            - created
            - updated
            - error
          description: '`created` — a new listing was created. `updated` — an existing listing was matched and updated. `error` — this listing failed to import (see `errors`).'
        uid:
          type: string
          description: ShowMojo listing UID (absent on error).
        edit_url:
          type: string
          format: uri
          description: URL for editing the listing in ShowMojo (absent on error).
        public_url:
          type: string
          format: uri
          description: Public listing page URL (absent on error).
        code:
          type: string
          description: Echo of the submitted `code`.
        errors:
          type: string
          description: Validation error messages (only when `status` is `error`).
        data:
          type: object
          description: Echo of the submitted listing payload (only when `status` is `error`).
    ListingsImportErrorResponse:
      type: object
      properties:
        response:
          type: object
          properties:
            status:
              type: string
              enum:
                - error
              example: error
            errors:
              type: string
              example: Please provide listings data.
    ListingResponse:
      type: object
      description: A listing as returned by List Listings. Get Listing returns `ListingDetail`, which adds a few fields.
      properties:
        uid:
          type: string
          description: Unique listing identifier
          example: abc123def
        property_id:
          type: string
          nullable: true
          description: UID of the parent property (if associated)
          example: prop456
        title:
          type: string
          description: Listing title
          example: Spacious 2BR Apartment
        address:
          type: string
          description: Street address
          example: 401 Dains St.
        unit:
          type: string
          nullable: true
          description: Unit number
          example: 4B
        city:
          type: string
          description: City
          example: San Francisco
        state:
          type: string
          description: State abbreviation
          example: CA
        zip:
          type: string
          description: ZIP code
          example: '94107'
        code:
          type: string
          nullable: true
          description: Listing code
          example: DAINS401
        general_type:
          type: string
          enum:
            - RENT
            - SALE
          description: Sale or rental
          example: RENT
        housing_type:
          type: string
          nullable: true
          enum:
            - Apartment
            - Condo
            - Townhouse
            - House
            - Bedroom
            - Commercial
            - Land
          description: Property category. `Apartment` — apartment unit. `Condo` — condominium. `Townhouse` — townhouse. `House` — single-family home. `Bedroom` — individual bedroom rental. `Commercial` — commercial property. `Land` — vacant land.
          example: Apartment
        status:
          type: string
          enum:
            - STATUS_ACTIVE
            - STATUS_INACTIVE
          description: Listing status
          example: STATUS_ACTIVE
        rent:
          type: integer
          nullable: true
          description: Monthly rent in dollars (for rentals)
          example: 2500
        max_rent:
          type: integer
          nullable: true
          description: Maximum rent (for range pricing)
          example: 3000
        price:
          type: integer
          nullable: true
          description: Sale price (for sales)
          example: 450000
        property_tax:
          type: integer
          nullable: true
          description: Annual property tax
          example: 5200
        bedrooms:
          type: integer
          nullable: true
          description: Number of bedrooms
          example: 2
        plus_convertible:
          type: boolean
          description: Whether bedrooms include a convertible room
          example: false
        full_bathrooms:
          type: integer
          nullable: true
          description: Number of full bathrooms
          example: 1
        partial_bathrooms:
          type: integer
          nullable: true
          description: Number of half bathrooms
          example: 1
        offices:
          type: integer
          nullable: true
          description: Number of offices (commercial)
          example: 3
        square_feet:
          type: integer
          nullable: true
          description: Total square footage
          example: 1200
        year_built:
          type: integer
          nullable: true
          description: Year the property was built
          example: 1995
        available_type:
          type: string
          nullable: true
          enum:
            - Immediate
            - Date
            - Don't show
          description: Indicates availability mode. `Don't show` — listing is active but doesn't advertise when it is available. `Immediate` — available now. `Date` — available on the date specified in `available_date`.
          example: Immediate
        available_date:
          type: string
          format: date
          nullable: true
          description: Move-in date (when available_type is Date)
          example: '2026-04-01'
        highlights:
          type: string
          nullable: true
          description: Description/highlights (includes property highlights if associated)
          example: Newly renovated kitchen...
        lat:
          type: number
          format: float
          nullable: true
          description: Latitude
          example: 37.7749
        long:
          type: number
          format: float
          nullable: true
          description: Longitude
          example: -122.4194
        video_url:
          type: string
          nullable: true
          description: Video tour URL
          example: https://youtube.com/watch?v=...
        tour_url:
          type: string
          nullable: true
          description: Virtual tour URL
          example: https://tour.example.com/...
        phone:
          type: string
          nullable: true
          description: Contact phone number
          example: '4155551234'
        security_deposit_type:
          type: string
          enum:
            - DONT_SHOW
            - SET_AMOUNT
            - MULTIPLE_RENT
            - RENT_PLUS_AMOUNT
            - NO_DEPOSIT
          description: How the security deposit is calculated. `DONT_SHOW` — not disclosed or not applicable. `SET_AMOUNT` — a fixed dollar amount (see `security_deposit_value`). `MULTIPLE_RENT` — a multiple of monthly rent (see `security_deposit_value` for the multiplier). `NO_DEPOSIT` — no deposit required. `RENT_PLUS_AMOUNT` — one month's rent plus an additional amount (see `security_deposit_value` for the additional amount).
          example: SET_AMOUNT
        security_deposit_value:
          type: number
          format: float
          nullable: true
          description: Deposit amount (interpretation depends on security_deposit_type)
          example: 2500
        notify_tenants:
          type: boolean
          description: Whether tenant notifications are enabled
          example: false
        listing_group_name:
          type: string
          nullable: true
          description: Name of the listing group the listing belongs to, alphabetically first when it belongs to several. `null` when the listing is in no group.
          example: Downtown Lofts
        photos:
          type: array
          description: Nested arrays of photo URLs. Each inner array contains URLs in different sizes (standard, large, medium) or a single watermarked URL.
          items:
            type: array
            items:
              type: string
              format: uri
          example:
            - - https://cdn.example.com/img1_std.jpg
              - https://cdn.example.com/img1_lg.jpg
              - https://cdn.example.com/img1_md.jpg
        details:
          type: array
          description: List of detail values (from listing and property)
          items:
            type: string
          example:
            - Pet Friendly
            - Washer/Dryer In Unit
        external_id:
          type: string
          nullable: true
          description: ID in the external integration system
          example: YARDI-12345
        external_source:
          type: string
          nullable: true
          description: External integration source
          enum:
            - YARDI
            - APPFOLIO
            - BUILDIUM
            - ENTRATA
            - PROPERTYWARE
            - HEROPM
            - VFLYER
            - TRULIA
            - ZILLOW
            - RENT_CAFE
            - RENT_MANAGER
            - RENTEC_DIRECT
            - TENANT_CLOUD
            - CUSTOM
            - FREE_RENTAL_SITE
          example: YARDI
        fees:
          type: array
          description: List of recurring and one-time fees configured on the listing.
          items:
            $ref: '#/components/schemas/ListingFee'
        neighborhood:
          type: string
          nullable: true
          description: Standard neighborhood name (when account has neighborhoods enabled)
          example: Mission District
        primary_neighborhood:
          type: string
          nullable: true
          description: Custom primary neighborhood (when custom neighborhoods enabled)
          example: SoMa
        secondary_neighborhood:
          type: string
          nullable: true
          description: Custom secondary neighborhood
          example: South Beach
        created_at:
          type: string
          format: date-time
          description: When the listing was created
          example: '2026-01-15T10:30:00.000Z'
        updated_at:
          type: string
          format: date-time
          description: When the listing was last updated
          example: '2026-03-10T14:22:00.000Z'
    ListingFee:
      type: object
      properties:
        fee_type:
          type: string
          description: |-
            Fee type identifier. Use `CUSTOM` for user-defined fees. Monthly types are paired with `category: monthly`; one-time types with `category: one_time`.
            **Monthly fee types:** `AIR_FILTER_DELIVERY_FEE`, `BIKE_STORAGE_FEE`, `BIRD_RENT`, `CABLE_FEE`, `CARPORT_PARKING_FEE`, `CAT_RENT`, `COVERED_PARKING_FEE`, `DOG_RENT`, `ELECTRICITY_FEE`, `EV_CHARGING_FEE`, `FISH_RENT`, `GARAGE_PARKING_FEE`, `GARBAGE_FEE`, `GAS_FEE`, `GYM_FEE`, `HEATING_FEE`, `HOA_AMENITY_FEE`, `HOA_FEE`, `INTERNET_FEE`, `LAWN_MAINTENANCE_FEE`, `MONTH_TO_MONTH_FEE`, `PACKAGE_DELIVERY_FEE`, `PARKING_FEE`, `PEST_CONTROL_FEE`, `PET_RENT`, `POOL_MAINTENANCE_FEE`, `RENTERS_INSURANCE_FEE`, `REPTILE_RENT`, `SEPTIC_FEE`, `SEWER_FEE`, `SMART_HOME_FEE`, `SMART_LOCK_FEE`, `SOLAR_HOME_FEE`, `STORAGE_LOCKER_FEE`, `STORMWATER_FEE`, `SURFACE_LOT_PARKING_FEE`, `TECHNOLOGY_FEE`, `UTILITIES_MONTHLY_FEE`, `VALET_TRASH_FEE`, `WATER_FEE`, `WATER_SEWER_FEE`, `WATER_SEWER_GARBAGE_FEE`.
            **One-time fee types:** `ADMINISTRATION_FEE`, `APPLICATION_FEE`, `BIRD_DEPOSIT`, `BROKER_FEE`, `CAT_DEPOSIT`, `CLEANING_FEE`, `CREDIT_CHECK_FEE`, `DOG_DEPOSIT`, `EARLY_TERMINATION_FEE`, `FENCE_FEE`, `FISH_DEPOSIT`, `HOA_APPLICATION_FEE`, `HOLDING_DEPOSIT`, `HOLDING_FEE`, `INSUFFICIENT_FUNDS_FEE`, `LAST_MONTHS_RENT`, `LATE_FEE`, `LEASE_PROCESSING_FEE`, `NON_REFUNDABLE_PET_DEPOSIT`, `PET_DEPOSIT`, `PET_FEE`, `PET_SCREENING_FEE`, `REMOTE_DEPOSIT`, `RENTERS_INSURANCE_COMPLIANCE_FEE`, `REPTILE_DEPOSIT`, `RISK_PREMIUM_DEPOSIT`, `SECURITY_DEPOSIT`, `SECURITY_DEPOSIT_ALTERNATIVE`, `SHORT_TERM_FEE`, `TENANT_DEPOSIT`, `UTILITIES_ADMIN_FEE`, `UTILITIES_CLOSE_ACCOUNT_FEE`, `UTILITIES_SETUP_FEE`.
          example: PET_RENT
        category:
          type: string
          enum:
            - monthly
            - one_time
          description: Billing cadence.
          example: monthly
        amount:
          type: number
          format: float
          description: Fee amount in dollars.
          example: 25
        requirement_type:
          type: string
          enum:
            - required
            - optional
          description: Whether the fee is mandatory.
          example: required
        per_item:
          type: boolean
          description: Whether the fee multiplies per item (e.g. per pet, per parking spot).
          example: false
        display_name:
          type: string
          description: Human-readable label.
          example: Pet Rent
    ListingDetail:
      description: A listing as returned by Get Listing. Everything in `ListingResponse` plus the fields below, which List Listings does not return.
      allOf:
        - $ref: '#/components/schemas/ListingResponse'
        - type: object
          properties:
            scheduling_block:
              type: object
              nullable: true
              description: Window during which showings are blocked on this listing. `null` when no scheduling block is configured.
              properties:
                type:
                  type: string
                  enum:
                    - BEFORE
                    - AFTER
                    - BETWEEN
                  description: '`BEFORE` — blocked until a date. `AFTER` — blocked from a date onward. `BETWEEN` — blocked within a date range.'
                  example: BETWEEN
                block_until:
                  type: string
                  format: date-time
                  nullable: true
                  description: UTC ISO8601 datetime. Present when `type` is `BEFORE` or `BETWEEN`; `null` otherwise.
                  example: '2026-04-15T00:00:00.000Z'
                block_from:
                  type: string
                  format: date-time
                  nullable: true
                  description: UTC ISO8601 datetime. Present when `type` is `AFTER` or `BETWEEN`; `null` otherwise.
                  example: '2026-04-01T00:00:00.000Z'
            application_url:
              type: string
              format: uri
              nullable: true
              description: Absolute URL prospects are directed to for rental applications. `null` when no application URL is configured on the listing.
              example: https://apply.example.com/listing/abc123
            showing_types:
              type: array
              description: Types of showings the listing supports
              items:
                type: string
                enum:
                  - in_person
                  - self_guided
              example:
                - in_person
            contact_info:
              type: object
              nullable: true
              description: Contact information from listing branding (if available)
              properties:
                agent_name:
                  type: string
                  description: Marketing agent name
                  example: John Smith
                company:
                  type: string
                  description: Marketing company name
                  example: Acme Realty
                phone:
                  type: string
                  description: Formatted marketing phone
                  example: (415) 555-1234
                email:
                  type: string
                  description: Publicly visible email (if enabled)
                  example: john@acmerealty.com
    PropertyAddress:
      type: object
      properties:
        address:
          type: string
          description: Street address
          example: 123 Main St
        city:
          type: string
          description: City
          example: Portland
        state:
          type: string
          description: State
          example: OR
        zip:
          type: string
          description: ZIP code
          example: '97201'
        lat:
          type: number
          format: float
          description: Latitude
          example: 45.5231
        long:
          type: number
          format: float
          description: Longitude
          example: -122.6765
    PropertySummary:
      type: object
      properties:
        uid:
          type: string
          description: Unique identifier
          example: abc123
        name:
          type: string
          description: Property address or name
          example: Lake view properties
        label:
          type: string
          description: Display label
          example: Main Street Apartments
        highlights:
          type: string
          description: Property highlights text
          example: Recently renovated...
        specials:
          type: string
          description: Current specials/promotions
          example: First month free!
        default_address:
          $ref: '#/components/schemas/PropertyAddress'
        addresses:
          type: array
          description: All associated addresses
          items:
            $ref: '#/components/schemas/PropertyAddress'
        external_id:
          type: string
          nullable: true
          description: ID from external integration system (null if manual)
          example: yardi-prop-001
        external_source:
          type: string
          nullable: true
          description: Integration source name (null if manual)
          enum:
            - YARDI
            - RENT_MANAGER
            - APPFOLIO
            - ENTRATA
            - BUILDIUM
          example: YARDI
        created_at:
          type: string
          format: date-time
          description: Creation timestamp
          example: '2024-01-15T10:30:00.000Z'
        updated_at:
          type: string
          format: date-time
          description: Last update timestamp
          example: '2024-06-01T14:22:00.000Z'
    PropertyDetail:
      allOf:
        - $ref: '#/components/schemas/PropertySummary'
        - type: object
          properties:
            details:
              type: array
              description: List of property detail/amenity strings
              items:
                type: string
              example:
                - Air Conditioning
                - Dishwasher
                - Parking Available
            photos:
              type: array
              description: Property photos in standard, large, and medium sizes
              items:
                type: object
                properties:
                  standard:
                    type: string
                    format: uri
                  large:
                    type: string
                    format: uri
                  medium:
                    type: string
                    format: uri
    Pagination:
      type: object
      properties:
        page:
          type: integer
          description: Current page number
          example: 1
        per_page:
          type: integer
          description: Results per page
          example: 25
        total:
          type: integer
          description: Total number of results
          example: 42
        total_pages:
          type: integer
          description: Total number of pages
          example: 5
    ReportJsonResponse:
      type: object
      description: JSON report envelope. Rows are keyed by the column names listed under Report Export; `high_level_metrics` rows are `[metric, value]` arrays.
      properties:
        response:
          type: object
          properties:
            status:
              type: string
              enum:
                - success
            data:
              type: array
              description: One entry per report row
              items:
                type: object
                additionalProperties: true
      example:
        response:
          status: success
          data:
            - name: Jane Prospect
              showtime: Oct 14, 2026 10:00 AM CDT
              showing_address_and_unit: 401 Dains St. 4B
              listing_uid: abc123def
              phone: (415) 555-1234
              email: jane@example.com
              status: STATUS_CONFIRMED
              no_show: false
              listing_code: DAINS401
    ReportErrorResponse:
      type: object
      properties:
        response:
          type: object
          properties:
            status:
              type: string
              enum:
                - error
            errors:
              type: string
              example: Report not found.
    NamedReportRequest:
      type: object
      properties:
        start_date:
          type: string
          format: date-time
          description: |
            Start of the reporting period.

            Accepts formats:
            - `yyyy-mm-dd` — e.g. `2023-01-01`
            - `yyyy-mm-dd HH:MM:SS` — e.g. `2023-01-01 00:00:00`

            The value is interpreted in the timezone configured in the account.
          example: '2023-08-01'
        end_date:
          type: string
          format: date-time
          description: |
            End of the reporting period.

            Accepts formats:
            - `yyyy-mm-dd` — e.g. `2023-01-31`
            - `yyyy-mm-dd HH:MM:SS` — e.g. `2023-01-31 23:59:59`

            The value is interpreted in the timezone configured in the account.
          example: '2023-08-31'
        acting_as_master_account:
          type: boolean
          description: |
            Optional flag for master account users.

            Set to `true` to request data as the master account.
          example: true
    CustomReportRequest:
      type: object
      properties:
        report_id:
          type: integer
          description: |
            Unique identifier of the saved custom report configuration.
          example: 412
        start_date:
          type: string
          format: date-time
          description: |
            Start of the reporting period.

            Accepts formats:
            - `yyyy-mm-dd` — e.g. `2023-02-01`
            - `yyyy-mm-dd HH:MM:SS` — e.g. `2023-02-01 00:00:00`

            The value is interpreted in the timezone configured in the account.
          example: '2023-02-01'
        end_date:
          type: string
          format: date-time
          description: |
            End of the reporting period.

            Accepts formats:
            - `yyyy-mm-dd` — e.g. `2023-02-28`
            - `yyyy-mm-dd HH:MM:SS` — e.g. `2023-02-28 23:59:59`

            The value is interpreted in the timezone configured in the account.
          example: '2023-02-28'
webhooks:
  leadOrShowingEvent:
    post:
      summary: Leads and Showings
      tags:
        - Webhooks
      description: |
        The ShowMojo Webhook allows you to receive real-time notifications about lead and showing events via HTTP POST.

        ## Overview

        This webhook is triggered whenever a lead or showing is created, updated, or changed. 
        The webhook will POST a JSON payload to the configured endpoint URL in ShowMojo.

        > Configuration can be found in the **[Leads Webhook](https://showmojo.com/settings/export)** section.

        With a webhook and a programmer, you can export data almost anywhere. Even platforms like Zapier or Podio might be enough — no custom code required.

        ---

        ### Security

        Every request is signed. Two headers carry the signature:

        - `X-ShowMojo-Timestamp`: Unix time, in seconds, when ShowMojo sent the request
        - `X-ShowMojo-Signature`: lowercase hex HMAC-SHA256 of `<timestamp>.<raw request body>`, keyed with your webhook's **signing secret**

        Find the signing secret, or generate a new one, in the **[Leads Webhook](https://showmojo.com/settings/export)** section.

        To verify a request:

        1. Read the raw request body before parsing it as JSON.
        2. Compute HMAC-SHA256 of the `X-ShowMojo-Timestamp` value, a `.`, and the raw body, with the signing secret as the key, and hex-encode it.
        3. Compare the result with `X-ShowMojo-Signature` using a constant-time comparison.
        4. Reject requests whose timestamp is more than five minutes old.

        Ruby (Rails):

        ```ruby
        def showmojo_request?(request, secret)
          timestamp = request.headers['X-ShowMojo-Timestamp'].to_s
          expected = OpenSSL::HMAC.hexdigest('SHA256', secret, "#{timestamp}.#{request.raw_post}")

          (Time.now.to_i - timestamp.to_i).abs <= 300 &&
            ActiveSupport::SecurityUtils.secure_compare(expected, request.headers['X-ShowMojo-Signature'].to_s)
        end
        ```

        Node.js:

        ```js
        const crypto = require('crypto');

        function isShowMojoRequest(rawBody, headers, secret) {
          const timestamp = headers['x-showmojo-timestamp'] || '';
          const signature = headers['x-showmojo-signature'] || '';
          const expected = crypto.createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex');

          return Math.abs(Date.now() / 1000 - Number(timestamp)) <= 300 &&
            signature.length === expected.length &&
            crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
        }
        ```

        > **Deprecated:** HTTPS endpoints configured before request signing was introduced still receive `Authorization: Bearer <API token>`. Endpoints configured since then never receive it, and the header will be removed for all endpoints. Verify the signature instead and do not rely on the Bearer token.

        ### Delivery and retries

        - ShowMojo sends each event once and waits up to 15 seconds for your response.
        - Respond with `200 OK`. Any other status, including other `2xx` codes, a timeout or a connection error, counts as a failed attempt.
        - A failed attempt is retried up to 5 times, after 5, 15, 45, 135 and 405 minutes (about 10 hours in total). After the last retry the event is dropped and not sent again.
        - If 5 events exhaust their retries within 24 hours, the webhook is disabled and the account owner receives an email. Fix the endpoint, then re-enable the webhook in the **[Leads Webhook](https://showmojo.com/settings/export)** section. Events that occur while it is disabled are not sent.

        ### Replay and duplicates

        - Every event has a unique, increasing `event.id`. A retry carries the same `event.id`. Its body is rebuilt at send time, so it may reflect a later state of the lead or showing, and the signature headers are computed fresh for each attempt.
        - Keep the `event.id` values you have processed and ignore a request whose id you have already seen.
        - Reject requests whose `X-ShowMojo-Timestamp` is more than five minutes old, so a captured request cannot be replayed later.
        - **Out-of-order delivery** is possible, for example when an earlier event is retried after a later one succeeded. Use `event.id` to order events.

        ### Notes

        - **HTTPS is strongly preferred**
        - Some fields may be `null` (especially timestamps)

        ---

        ## Actions Reference

        <details>
        <summary>All 169 values of `event.action`, with the meaning shown in the ShowMojo showing history</summary>

        | `event.action` | Meaning |
        |---|---|
        | `accept` | Accepted |
        | `acceptance_reminder` | Showtime acceptance reminder sent |
        | `acceptance_reminder_approvers` | Showtime acceptance reminder sent to approvers |
        | `acceptance_reminder_owner_agent` | Showtime acceptance reminder sent to you |
        | `acceptance_request` | Showtime acceptance requested |
        | `accept_for_everyone` | Showtime accepted for everyone |
        | `accept_for_me` | Showtime accepted |
        | `additional_document_received` | Document received |
        | `additional_document_requested` | Document manually requested |
        | `additional_document_request_sent` | Document requested |
        | `ai_web_conversation_ended` | AI web chat conversation |
        | `annual_follow_up_email` | Annual follow up email sent |
        | `answer_resent` | Answer to prospect question resent |
        | `answer_security_questions` | Answer security questions |
        | `answer_security_questions_third_failure` | Third failed attempt to answer security questions within 24 hours |
        | `appfolio_user_assignment_failed` | User assignment failed in AppFolio due to user permissions |
        | `applicant_transitioned_from_resident` | Resident transitioned to applicant |
        | `applicant_transitioned_to_resident` | Applicant transitioned to resident |
        | `assign_unclaimed_showing_to_owner` | Assign unclaimed showing to account owner |
        | `auto_cancel_no_reply` | Auto-canceled due to no reply |
        | `auto_create_by_sms` | Showing auto-created by SMS |
        | `blacklisted_asn_passed_anti_fraud_checks` | Access code not distributed because the showing was flagged for potential fraudulent activity |
        | `blacklisted_asn_passed_only_location_verification` | Access code not distributed because the showing was flagged for potential fraudulent activity |
        | `blacklisted_prospect` | Email and phone blacklisted |
        | `call_redirected` | Redirected |
        | `call_redirect_ended` | Live call |
        | `call_transferred_from_cci` | Live call was transferred from Live Answer to Property Manager |
        | `call_transferred_to_cci` | Live call was transferred to Live Answer |
        | `call_transferred_to_regular_queue` | Live call transferred to regular queue |
        | `call_transferred_to_self_show_escalation_queue` | Live call transferred to self-show escalation queue |
        | `cancel` | Canceled |
        | `cancel_identity_verification_failed` | Canceled because identity verification failed |
        | `cancel_notice` | Cancel notice sent |
        | `cancel_phone_or_email_blacklisted` | Canceled because phone or email is blacklisted |
        | `cancel_warning` | Cancel warning sent |
        | `cci_prospect_asked_question` | Prospect question submitted |
        | `cci_screening_criteria_not_met` | Screening criteria was not met when scheduled via Live Answer |
        | `claimed` | Claimed |
        | `claim_request` | Claim requested |
        | `confirm` | Confirmed |
        | `confirm_automatically` | Automatically confirmed |
        | `confirm_insecured_lockbox` | Property NOT secured reported |
        | `confirm_lockbox_outcome_no_show` | Prospect did not make showing |
        | `confirm_request` | Confirm requested |
        | `confirm_secured_lockbox` | Property secured reported |
        | `confirm_secured_lockbox_request` | Confirm secured property requested |
        | `create` | Showing created |
        | `decline` | Showtime rejected |
        | `decline_proposed_times` | Proposed showtimes rejected |
        | `document_auto_approved_because_not_reviewed_in_time` | Document auto-approved because was not reviewed in time |
        | `document_received` | Document for verification sent |
        | `document_rejected` | Document rejected |
        | `document_request_resent` | Document request resent |
        | `document_verification_request` | Document verification request sent |
        | `document_verified` | Document verified |
        | `dont_follow_up` | Follow up stopped |
        | `do_follow_up` | Follow up started |
        | `email_address_updated` | Email address changed to |
        | `email_application_criteria_link` | Emailed application criteria link |
        | `email_apply_now_link` | Emailed application link |
        | `email_delivery_failed` | Email delivery failed |
        | `email_link` | Emailed a link |
        | `email_on_new_active_listing` | New active listing email sent |
        | `email_on_off_market_listing` | Listing off market nurturing email sent |
        | `email_on_reannounce_new_listing` | New listing reannouncement email sent |
        | `email_on_rent_reduction` | Rent reduction email sent |
        | `emergency_reschedule_request` | Emergency reschedule requested |
        | `flagged_as_fraudulent` | Flagged as fraudulent |
        | `follow_autoreply` | Followed auto-reply |
        | `follow_up_reschedule` | Follow up reschedule request sent |
        | `fraud_or_scam_report_sent` | Sent report about potential fraud activity to agent |
        | `hide` | Hidden |
        | `identity_verification_failed` | Identity verification failed |
        | `identity_verification_failed_auth_attempts_limit_exceeded` | Identity verification failed (exceeded limit of Precise ID Authentication attempted) |
        | `identity_verification_failed_recently_failed` | Identity verification failed (recently failed Precise ID) |
        | `identity_verification_passed` | Identity verification passed |
        | `identity_verification_requested` | Identity verification requested |
        | `identity_verification_skipped_recently_passed` | Identity verification skipped (recently passed Precise ID) |
        | `inquired` | Inquired |
        | `inquired_about_multi_unit` | Inquired about multi unit property |
        | `inquired_about_off_market_listing` | Inquired about off market listing |
        | `instant_schedule_call_attempted` | AI Instant Schedule call attempt |
        | `instant_schedule_handoff` | AI Instant Schedule handed off to an agent |
        | `instant_schedule_initiated` | AI Instant Schedule initiated |
        | `last_reminder` | Reminder sent |
        | `lead_converted_by_cci` | Lead was converted to showing |
        | `lead_created` | Lead created |
        | `lead_created_by_off_market_update_process` | Lead created by adding an applicant in Required Listing Updates |
        | `lead_showing_denied_custom_question` | Showing denied (didn't meet requirements) |
        | `lead_showing_denied_income` | Showing denied (didn't meet income requirement) |
        | `lead_showing_denied_move_in_date` | Showing denied (didn't meet move-in date requirement) |
        | `lead_showing_denied_pets` | Showing denied (didn't meet pet requirements) |
        | `lead_updated` | Lead updated |
        | `left_voicemail` | Voicemail |
        | `location_verification_auto_triggered` | Location verification anti-fraud measure added |
        | `location_verification_based_on_scheduling_anomaly` | Location verification added based on scheduling anomaly |
        | `lockbox_code_distributed` | Access code was sent to the prospect |
        | `lockbox_code_requested` | Access code requested |
        | `lockbox_showing_started` | Self-showing started |
        | `notified_showtimes_available` | Notified that showtimes are available |
        | `outgoing_call_completed` | Outgoing call completed |
        | `outgoing_call_started` | Outgoing call started |
        | `pet_screening_sent` | Pet screening request sent |
        | `phone_for_lockbox_phone_call_verification_assigned` | Phone number for Phone Call Verification assigned |
        | `phone_number_changed` | Phone number changed |
        | `phone_verification_call_access_code_distributed` | Access code via verification call was sent to the prospect |
        | `phone_verification_call_access_code_distributed_after_no_answer` | Access code via verification call distributed after no phone answer |
        | `phone_verification_call_access_denied_during_call` | Access denied during verification call |
        | `phone_verification_call_hung_up_before_answer` | Verification call hung up before answered |
        | `phone_verification_call_not_answered` | Verification call not answered |
        | `pre_screen_completed` | Pre-screen completed |
        | `pre_screen_overridden` | Pre-screen overridden |
        | `pre_screen_reminder_sent` | Pre-screen reminder sent |
        | `pre_screen_request_sent` | Pre-screen request sent |
        | `pre_showing_reminder_sent` | Pre-showing reminder sent |
        | `proposed_times` | Proposed times |
        | `proposed_times_accpt_request_sent` | Proposed times acceptance request sent |
        | `prospect_arrived_too_late` | Prospect arrived at showing too late |
        | `prospect_question_processed_with_answer` | Inquiry reviewed and answered |
        | `prospect_question_processed_with_forwarding` | Inquiry forwarded for an answer |
        | `prospect_question_processed_with_no_answer` | Inquiry had no question |
        | `question_answered` | Prospect question answered |
        | `reply_needed_score_updated` | Reply needed score was updated |
        | `report_shared` | Report shared |
        | `report_unshared` | Stop sharing report |
        | `requested_application_criteria` | Requested application criteria |
        | `requested_availability_notification` | Requested availability notification |
        | `reschedule_request` | Reschedule requested |
        | `reschedule_request_on_answers_not_received` | Reschedule requested because answers not received |
        | `reschedule_request_on_document_not_received` | Reschedule requested because document not received |
        | `reschedule_request_on_document_not_verified` | Reschedule requested because document not verified |
        | `restore` | Restored |
        | `screening_requested` | Applicant screening requested |
        | `screening_request_automatically` | Applicant screening requested automatically |
        | `screening_request_email_sent` | Applicant screening request sent |
        | `screening_request_text_sent` | Applicant screening request sent |
        | `second_year_follow_up_email` | Second year follow up email sent |
        | `send_upcoming_showings` | Send upcoming showings link |
        | `sent_access_code_email_fallback` | Access code emailed (SMS fallback) |
        | `sent_answers_request` | Answers request sent |
        | `sent_autoreply` | Auto-reply sent |
        | `sent_autoreply_followup` | Sent auto-reply follow-up |
        | `sent_document_and_answers_request` | Document and answers request sent |
        | `sent_document_request` | Document request sent |
        | `sent_follow_up` | Follow up sent |
        | `sent_self_showing_follow_up` | Self-showing follow up sent |
        | `set_no_show` | Reported as a no show |
        | `showing_denied_custom_question` | Showing denied and canceled |
        | `showing_denied_custom_question_reason` | Prospect didn't meet requirements |
        | `showing_denied_income` | Showing denied and canceled |
        | `showing_denied_income_reason` | Prospect didn't meet income requirement |
        | `showing_denied_move_in_date` | Showing denied and canceled |
        | `showing_denied_move_in_date_reason` | Prospect didn't meet move-in date requirement |
        | `showing_denied_pets` | Showing denied and canceled |
        | `showing_denied_pets_reason` | Prospect didn't meet pet requirements |
        | `showing_feedback` | Feedback was left |
        | `showing_mismatched_custom_question` | Scheduling restrictor overridden for pre-scheduled showing (didn't meet requirements) |
        | `showing_mismatched_income` | Scheduling restrictor overridden for pre-scheduled showing (didn't meet income requirement) |
        | `showing_mismatched_move_in_date` | Scheduling restrictor overridden for pre-scheduled showing (didn't meet move-in date requirement) |
        | `showing_mismatched_pets` | Scheduling restrictor overridden for pre-scheduled showing (didn't meet pet requirements) |
        | `showing_with_disabled_location_verification_passed_check` | Location verification was not completed because it was disabled on the listing |
        | `text_application_criteria_link` | Texted application criteria link |
        | `text_apply_now_link` | Texted application link |
        | `text_link` | Texted a link |
        | `third_party_applicant_added` | Applicant applied outside of ShowMojo |
        | `uncancel` | Uncanceled |
        | `unconfirm` | Unconfirmed |
        | `undo_no_show` | Undone a no show |
        | `update` | Showing updated |

        </details>

        ---

        ## Supported Time Zones

        <details>
        <summary>Click to expand the full list</summary>

        ```text
        American Samoa
        International Date Line West
        Midway Island
        Hawaii
        Alaska
        Pacific Time (US & Canada)
        Tijuana
        Arizona
        Chihuahua
        Mazatlan
        Mountain Time (US & Canada)
        Central America
        Central Time (US & Canada)
        Guadalajara
        Mexico City
        Monterrey
        Saskatchewan
        Bogota
        Eastern Time (US & Canada)
        Indiana (East)
        Lima
        Quito
        Atlantic Time (Canada)
        Caracas
        Georgetown
        La Paz
        Santiago
        Newfoundland
        Brasilia
        Buenos Aires
        Greenland
        Mid-Atlantic
        Azores
        Cape Verde Is.
        Casablanca
        Dublin
        Edinburgh
        Lisbon
        London
        Monrovia
        UTC
        Amsterdam
        Belgrade
        Berlin
        Bern
        Bratislava
        Brussels
        Budapest
        Copenhagen
        Ljubljana
        Madrid
        Paris
        Prague
        Rome
        Sarajevo
        Skopje
        Stockholm
        Vienna
        Warsaw
        West Central Africa
        Zagreb
        Athens
        Bucharest
        Cairo
        Harare
        Helsinki
        Jerusalem
        Kyiv
        Pretoria
        Riga
        Sofia
        Tallinn
        Vilnius
        Baghdad
        Istanbul
        Kuwait
        Minsk
        Moscow
        Nairobi
        Riyadh
        St. Petersburg
        Volgograd
        Tehran
        Abu Dhabi
        Baku
        Muscat
        Tbilisi
        Yerevan
        Kabul
        Ekaterinburg
        Islamabad
        Karachi
        Tashkent
        Chennai
        Kolkata
        Mumbai
        New Delhi
        Sri Jayawardenepura
        Kathmandu
        Almaty
        Astana
        Dhaka
        Urumqi
        Rangoon
        Bangkok
        Hanoi
        Jakarta
        Krasnoyarsk
        Novosibirsk
        Beijing
        Chongqing
        Hong Kong
        Irkutsk
        Kuala Lumpur
        Perth
        Singapore
        Taipei
        Ulaan Bataar
        Osaka
        Sapporo
        Seoul
        Tokyo
        Yakutsk
        Adelaide
        Darwin
        Brisbane
        Canberra
        Guam
        Hobart
        Melbourne
        Port Moresby
        Sydney
        Vladivostok
        Magadan
        New Caledonia
        Solomon Is.
        Auckland
        Fiji
        Kamchatka
        Marshall Is.
        Wellington
        Nuku'alofa
        Samoa
        Tokelau Is.
        ```
        </details>
      parameters:
        - name: X-ShowMojo-Timestamp
          in: header
          required: true
          description: Unix time, in seconds, when ShowMojo sent the request.
          schema:
            type: string
            example: '1760250000'
        - name: X-ShowMojo-Signature
          in: header
          required: true
          description: Lowercase hex HMAC-SHA256 of `<X-ShowMojo-Timestamp>.<raw request body>`, keyed with the webhook's signing secret.
          schema:
            type: string
        - name: Authorization
          in: header
          required: false
          deprecated: true
          description: '`Bearer <API token>`, sent only to HTTPS endpoints configured before request signing was introduced. Will be removed; verify the signature instead.'
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                event:
                  type: object
                  required:
                    - id
                    - action
                    - actor
                    - created_at
                  properties:
                    id:
                      type: string
                      description: Unique identifier for the event
                      example: abc-123
                    action:
                      type: string
                      description: What happened. One of the values in the Actions Reference above; showings use `create`, `update` and `cancel`, leads use `lead_created` and `lead_updated`. New actions are added over time and are sent as soon as they exist, so treat an unknown value as an event you do not handle rather than as an error.
                      example: create
                    actor:
                      type: string
                      description: Who initiated the event (usually `prospect` or `system`)
                      example: prospect
                    team_member_name:
                      type: string
                      nullable: true
                      example: Alex Manager
                    team_member_uid:
                      type: string
                      nullable: true
                      example: tm-001
                    created_at:
                      type: string
                      format: date-time
                      example: '2025-05-08T12:34:56Z'
                    showing:
                      type: object
                      nullable: true
                      properties:
                        uid:
                          type: string
                          example: shw-789
                        created_at:
                          type: string
                          format: date-time
                          example: '2025-05-08T12:34:56Z'
                        showtime:
                          type: string
                          format: date-time
                          example: '2025-05-09T14:00:00Z'
                        showing_time_zone:
                          type: string
                          example: Central Time (US & Canada)
                        showing_time_zone_utc_offset:
                          type: integer
                          example: -5
                        name:
                          type: string
                          example: John Doe
                        phone:
                          type: string
                          example: '+14004004444'
                        email:
                          type: string
                          format: email
                          example: john.doe@example.com
                        notes:
                          type: string
                          nullable: true
                          example: Interested in a pet-friendly unit
                        listing_uid:
                          type: string
                          example: lst-456
                        listing_full_address:
                          type: string
                          example: 123 Main St, Springfield, IL 62704
                        is_self_show:
                          type: boolean
                          example: true
                        confirmed_at:
                          type: string
                          format: date-time
                          nullable: true
                          example: '2025-05-08T13:00:00Z'
                        canceled_at:
                          type: string
                          format: date-time
                          nullable: true
                          example: null
                        self_show_code_distributed_at:
                          type: string
                          format: date-time
                          nullable: true
                          example: '2025-05-08T13:10:00Z'
            examples:
              sample:
                summary: Example lead_created event
                value:
                  event:
                    id: abc-123
                    action: lead_created
                    actor: prospect
                    team_member_name: Alex Manager
                    team_member_uid: tm-001
                    created_at: '2025-05-08T12:34:56Z'
                    showing:
                      uid: shw-789
                      created_at: '2025-05-08T12:34:56Z'
                      showtime: '2025-05-09T14:00:00Z'
                      showing_time_zone: Central Time (US & Canada)
                      showing_time_zone_utc_offset: -5
                      name: John Doe
                      phone: '+14004004444'
                      email: john.doe@example.com
                      notes: Interested in a pet-friendly unit
                      listing_uid: lst-456
                      listing_full_address: 123 Main St, Springfield, IL 62704
                      is_self_show: true
                      confirmed_at: '2025-05-08T13:00:00Z'
                      canceled_at: null
                      self_show_code_distributed_at: '2025-05-08T13:10:00Z'
      responses:
        '200':
          description: Successfully received
        '400':
          description: Bad request — malformed payload
        '401':
          description: Unauthorized — invalid or missing token
