NAV Navigation
Documentation
API Reference Data Dictionary Make.com Integration

Introduction

This is a JSON HTTP API. It is not a RESTful API.

In contrast to REST, which is focused on the transfer of state between server and client, this API is oriented around actions that can be performed on system entities. Errors are reported via standard HTTP status codes with a structured JSON body — see Errors.

IDs

Example Entity IDs

cust_FiUtBj8JkF
lease_jOi8joH3Hu
org_Ji9JKfKkhuR
quote_IJf03jNjKuf

Entity IDs in Cubby are generally in the form of <prefix>_<alpha> where the type of the object referred to is defined by the prefix.

Money

We represent money as an integer, representing the number of cents. There are problems both in the use of integers and in the use of floats to represent money. We believe use of integers results in more predictable and obvious behavior for users of our API, and forces anyone that sends us money to confront a possible loss of precision before sending us numbers.

Date and Time

We represent dates and times as ISO-8601 strings. Date-only fields (for example moveInDate, accruesOn, dueDate) use the form yyyy-MM-dd and carry no time component. Date-time fields fall into one of two categories:

Where search endpoints accept date or time range filters, the parameter name signals the bound semantics:

API Response Structure

Successful responses return an HTTP 200. The body is always wrapped in a small envelope:

{
  "status": 200,
  "data": {
    /* Endpoint-specific payload. See each endpoint's documentation. */
  }
}

Example: POST /v1/facilities/search

{
  "status": 200,
  "data": {
    "facilities": [
      /* ... facility objects ... */
    ],
    "organizations": [
      /* ... organization objects ... */
    ]
  }
}

Errors

Failed requests return a standard non-2xx HTTP status code (400, 401, 403, 404, 500, etc.) with the following body:

Error Response

{
  "code": 404,
  "errors": [
    "Facility not found"
  ]
}

Expansions

APIs strive to return comprehensive information in the target entity. Entities in the Cubby system tend to be connected to other entities (for example a lease and a customer), and it may be desirable to retrieve both a subject entity as well as related entities in a single HTTP request.

To accommodate this, some endpoints offer expansions, which are effectively instruction on which related entities should be retrieved in addition to the base entity returned by the endpoint.

Expansions are not expanded in-line, but are provided as auxiliary arrays which can easily be combined by using the embedded entity IDs.

Authentication

API credentials conceptually attach to the Organization concept, and has access to all resources (managers, facilities, customers, leases) visible to the Organization.

Authentication is done via an API key, which is passed in the Authorization header. Example via curl:

curl -X ‘POST’ https://api.cubbystorage.com/v1/organizations/search -H ‘accept: */*’ -H ‘Authorization: Bearer b73c7e4d-81f2-49e3-bbca-9a6fbd321d56’ -H "Content-Type: application/json" -d ‘{"where": {}}’

In order to obtain an API key, please contact support@cubbystorage.com.

Treat your API key like a password - because that’s what it is!

Access to PII

Access to Personally Identifiable Information (PII) is restricted to authorized users only. If your API key does not have access to PII, all PII fields will be skipped in API responses. PII fields include:

Roles

API keys are issued with a specific role that determines which endpoints and operations are accessible. The following roles are available:

Manager

The most comprehensive role, intended for integrations that need full operational control. Grants read and write access to nearly all resources, including managing leases, customers, leads, payments, units, coverage, auctions, notes, tasks, pricing groups, and reports. Also provides read access to access codes, discounts, facilities, facility groups, ledgers, organizations, and payment methods.

Endpoints:

Resource Endpoints
Access Codes search, check
Auctions search, create, start-lien, cancel-lien
Coverage search, enroll, unenroll, add-private-policy, remove-private-policy, download-private-policy
Coverage Levels search
Customers search, update
Discounts search
Facilities search
Facility Groups search
Leads search, create, update
Leases search, create, checkout, cancel-lease, schedule-move-out, preview-charges, get-move-in-charges, get-upsells, make-payment, get-payment-link, enable-auto-pay, disable-auto-pay, update-alternative-contacts, get-rent-change-schedules, change-rents, cancel-rent-changes, get-compliances
Ledgers search
Notes search, create
Organizations search
Payment Methods search, create
Payments search
Pricing Groups search, change-rates, find-unit-for-tier
Reports general-ledger/cash, general-ledger/accrual, aged-receivables, rent-roll, merchant-services-disbursements
Tasks search, create
Units search, set-rentability
Value Pricing Strategies search

A read-only role for integrations that need to query data without making changes. Provides access to search endpoints across most resources.

Endpoints:

Resource Endpoints
Auctions search
Coverage search, download-private-policy
Coverage Levels search
Customers search
Discounts search
Facilities search
Facility Groups search
Leads search
Leases search, preview-charges
Ledgers search
Notes search
Organizations search
Payment Methods search
Payments search
Pricing Groups search, find-unit-for-tier
Tasks search
Units search
Value Pricing Strategies search

Storefront

A narrow role for storefront and website integrations. Provides access to storefront-specific facility and pricing group data, along with organization info.

Endpoints:

Resource Endpoints
Organizations search
Storefront Facilities search
Storefront Pricing Groups search

Report

Intended for reporting and analytics integrations. Provides access to financial reports and facility data.

Endpoints:

Resource Endpoints
Facilities search
Facility Groups search
Organizations search
Reports general-ledger/cash, general-ledger/accrual, aged-receivables, rent-roll, merchant-services-disbursements

Coverages

Designed for insurance and coverage provider integrations. Grants full coverage management along with read access to the related resources needed to look up customers, leases, and units.

Endpoints:

Resource Endpoints
Coverage search, enroll, unenroll, add-private-policy, remove-private-policy, download-private-policy
Coverage Levels search
Customers search
Facilities search
Facility Groups search
Leases search, preview-charges
Ledgers search
Organizations search
Pricing Groups search, find-unit-for-tier
Units search
Value Pricing Strategies search

Access Codes

A minimal role for gate access integrations. Provides the ability to look up and verify access codes.

Endpoints:

Resource Endpoints
Access Codes search, check

Communication

Allows sending SMS and email messages on behalf of the organization.

Endpoints:

Resource Endpoints
Messages sms/send, email/send

Locks

For smart lock integrations. Grants the ability to manage locks — register, attach, disable, return, and transfer.

Endpoints:

Resource Endpoints
Locks search, register, disable, attach, return, transfer

Changelog

August 2026

July 2026

June 2026

May 2026

April 2026

March 2026

February 2026

January 2026

December 2025

November 2025

October 2025

September 2025

December 2024

Operator API

Access Codes

POST /v1/access-codes/search

Request Body — access-codes/search

{
  "where": {
    "facilityId": "fac_<ID>",
    "customerId": "cust_<ID>"
  }
}

Response Body — access-codes/search

{
  "status": 200,
  "data": {
    "accessCodes": [
      {
        "code": "1575",
        "enabled": true,
        "customerId": "cust_K2kybwxRz9L"
      },
      {/* ... */}
    ]
  }
}

Search for access codes by facility or customer

Required Properties

Check Access Code

POST /v1/access-codes/check

Request Body — access-codes/check

{
  "facilityId": "fac_<ID>",
  "code": "1575"
}

Response Body — access-codes/check

{
  "status": 200,
  "data": {
    "accessAllowed": true,
    "message": "Access allowed"
  }
}

Check if an access code is valid for a facility

Required Properties

Response Parameters

Locks

Lock Register

POST /v1/locks/register

Request Body — locks/register

{
  "serial": "M9U2FK",
  "combo": "2934",
  "location": "fac|org_<ID>",
  "actor": "user_<ID>",
}

Response Body — locks/register

{
  "status": 200,
  "data": {
    "id": "lock_<ID>"
  }
}

Adds a new lock to the system. The lock is initially in an "available" state. Available locks can be associated with a location until they are attached to a unit.

Required Properties

Error Conditions

Response Parameters

Parameter Description
id The ID of the newly registered lock

POST /v1/locks/search

Request Body — locks/search

{
  "where": {
    "organizationId": "org_<ID>"
  }
}

Response Body — locks/search

{
  "status": 200,
  "data": {
    "locks": [
      {
        "id": "lock_<ID>",
        "facilityId": "fac_C7bSZyPT6fp",
        "organizationId": "org_4a2da7d271a",
        "serial": "M9U2FK",
        "combo": "2934",
        "status": "AVAILABLE | OPERATOR_USE | TENANT_USE | DISABLED",
        "attachedTo": "unit_<ID>",
        "disabledReason": "DAMAGED | MISSING"
      },
      {/* ... */}
    ]
  }
}

Search for locks by organization

Required Properties

Response Parameters

Parameter Description
id The ID of the lock
facilityId The facility where the lock is physically present
organizationId The organization where the lock is physically present
serial The serial number of the lock
combo The current combination for unlocking the lock
status The current status of the lock.
attachedTo The unit to which the lock is attached (only when status is either OPERATOR_USE or TENANT_USE)
disabledReason The reason the lock is disabled (only when status is DISABLED)

Lock Disable

POST /v1/locks/disable

Request Body — locks/disable

{
  "lockId": "lock_<ID>",
  "reason": "DAMAGED | MISSING",
  "actor": "user_<ID>"
}

Marks the lock as disabled, detaching it from any units it may be attached to.

Required Properties

Optional Properties

Lock Attach

POST /v1/locks/attach

Request Body — locks/attach

{
  "lockId": "lock_<ID>",
  "attachTo": "space_<ID>",
  "lockUse": "TENANT_USE | OPERATOR_USE",
  "actor": "user_<ID>"
}

Attaches a lock to a unit either by renting it to a tenant or by restricting access to the unit.

Required Properties

Optional Properties

Error Conditions

Lock Return

POST /v1/locks/return

Request Body — locks/return

{
  "lockId": "lock_<ID>",
  "actor": "user_<ID>"
}

Puts the lock back into inventory, detaching it from any unit it may be currently attached to and marking it available for re-use.

Required Properties

Optional Properties

Lock Transfer

POST /v1/locks/transfer

Request Body — locks/transfer

{
  "lockId": "lock_<ID>",
  "facilityId": "fac_<ID>"
}

Transfers the lock to a different facility, which must belong to the same organization as the lock's current facility. The lock must not be attached to a unit.

Required Properties

Organizations

POST /v1/organizations/search

Request Body — organizations/search

{
  "where": {
    "organizationId": "org_4a2da7d271a"
  }
}

Response Body — organizations/search

{
  "status": 200,
  "data": {
    "organizations": [
      {
        "organizationId": "org_4a2da7d271a",
        "name": "Anisha Estates"
      },
      {/* ... */}
    ]
  }
}

Returns metadata for co-managed organization(s)

Optional Properties

Managers

POST /v1/managers/search

Request Body — managers/search

{
  "where": {
    "facilityId": "fac_C7bSZyPT6fp",
    "organizationId": "org_4a2da7d271a",
    "phone": "555-555-5555",
    "email": "manager@example.com",
    "name": "Jane",
    "includePermissions": true
  }
}

Response Body — managers/search

{
  "status": 200,
  "data": {
    "managers": [
      {
        "managerId": "user_4a2da7d271a",
        "name": "Jane Smith",
        "email": "manager@example.com",
        "phone": "+15555555555",
        "organizationId": "org_4a2da7d271a",
        "organizationPermissions": {
          "organizationId": "org_4a2da7d271a",
          "name": "Anisha Estates",
          "permissions": {
            "read": ["Task"],
            "manage": ["Task", "Note"]
          }
        },
        "facilitiesPermissions": [
          {
            "facilityId": "fac_C7bSZyPT6fp",
            "name": "315 Anisha Estates",
            "permissions": {
              "read": ["Task"],
              "manage": ["Task", "Note"]
            }
          },
          {/* ... */}
        ]
      },
      {/* ... */}
    ]
  }
}

Search for managers by facility, organization, or contact information

Required Properties

Optional Properties

Facilities

POST /v1/facilities/search

Request Body — facilities/search

{
  "where": {
    "facilityId": "fac_C7bSZyPT6fp", 
    "organizationId": "org_4a2da7d271a",
    "facilityGroupId": "fg_4a2da7d271a"
  },
  "expansions": [
    "organization",
    "schedules",
    "facilityGroups"
  ]
}

Response Body — facilities/search

{
  "status": 200,
  "data": {
    "facilities": [
      {
        "facilityId": "fac_C7bSZyPT6fp",
        "name": "315 Anisha Estates",
        "internalName": "Anisha",
        "contact": {
          "address": "315 Anisha Estates",
          "address2": "",
          "city": "Thompsonview",
          "state": "Alaska",
          "country": "USA",
          "zip": "98748",
          "email": "",
          "phone": ""
        },
        "organizationId": "org_4a2da7d271a",
        "longitude": "-122.419418",
        "latitude": "37.774929",
        "timeZone": "America/New_York",
        "paymentServiceProvider": "STRIPE | PAYABLI",
        "schedules": [
          {
            "name": "Office Hours",
            "schedule": [
              null,
              {"from": "09:00:00", "to": "17:00:00"},
              {"from": "09:00:00", "to": "17:00:00"},
              {"from": "09:00:00", "to": "17:00:00"},
              {"from": "09:00:00", "to": "17:00:00"},
              {"from": "09:00:00", "to": "17:00:00"},
              null
            ],
            "category": "SYSTEM | CUSTOM",
            "systemTypes": ["PHONE_SUPPORT", "OFFICE_HOURS"]
          },
          {/* ... */}
        ],
        "facilityGroupIds": ["fg_4a2da7d271a"]
      },
      {/* ... */}
    ],
    "organizations": [
      {
        "organizationId": "org_4a2da7d271a",
        "name": "Anisha Estates"
      },
      {/* ... */}
    ],
    "facilityGroups": [
      {
        "facilityGroupId": "fg_4a2da7d271a",
        "name": "Main Street Campus",
        "organizationId": "org_4a2da7d271a"
      },
      {/* ... */}
    ]
  }
}

Returns metadata for all co-managed facilities

Each facility object includes a paymentServiceProvider field indicating which payment gateway the facility is configured to use — either STRIPE or PAYABLI. Use this to determine which token-generation flow to follow when collecting payment details (see Generating a Payment Token).

Each facility object always includes a facilityGroupIds array — the ext ids of the facility groups it belongs to (empty when the facility is in no group). This is the lightweight membership signal and requires no expansion.

Required Properties

Exactly one of the following must be provided:

Optional Properties

When the facilityGroups expansion is requested, the response additionally includes a top-level facilityGroups array (sibling to facilities) containing the de-duplicated set of facility groups that the returned facilities belong to. Each entry has facilityGroupId, name, and organizationId. Match them to facilities via each facility's facilityGroupIds. Without the expansion, only the per-facility facilityGroupIds (above) is returned. See Facility Groups for the full facility-group resource.

When the schedules expansion is requested, each facility object includes a schedules array describing the facility's configured schedules (office hours, phone support, etc.). Each schedule has the following fields:

Facility Groups

Facility groups are named, organization-level collections of facilities. A facility can belong to multiple groups at once. They are commonly used to present several nearby facilities as a single location to customers.

POST /v1/facility-groups/search

Request Body

{
  "where": {
    "facilityGroupId": "fg_4a2da7d271a",
    "organizationId": "org_4a2da7d271a"
  },
  "expansions": [
    "facilities"
  ]
}

Response Body

{
  "status": 200,
  "data": {
    "facilityGroups": [
      {
        "facilityGroupId": "fg_4a2da7d271a",
        "name": "Main Street Campus",
        "organizationId": "org_4a2da7d271a",
        "facilityIds": ["fac_C7bSZyPT6fp", "fac_D8cTZyQU7gq"]
      },
      {/* ... */}
    ],
    "facilities": [
      {
        "facilityId": "fac_C7bSZyPT6fp",
        "name": "315 Anisha Estates",
        "organizationId": "org_4a2da7d271a",
        "/* ... same shape as Facilities Search ... */": ""
      },
      {/* ... */}
    ]
  }
}

Each facility group always includes a facilityIds array — the ext ids of its member facilities (empty when the group has none). This requires no expansion.

Required Properties

Exactly one of the following must be provided:

Optional Properties

When the facilities expansion is requested, the response additionally includes a top-level facilities array (sibling to facilityGroups) containing the de-duplicated full facility objects (same shape as Facilities Search) for all member facilities of the returned groups. Match them to groups via each group's facilityIds. Without the expansion, only the per-group facilityIds is returned.

Units

POST /v1/units/search

Request Body — units/search

{
  "where": {
    "unitId": "unit_GfNkzV4itfk",
    "pricingGroupId": "pg_4a2da7d271a",
    "facilityId": "fac_C7bSZyPT6fp"
  },
  "expansions": [ ... ]
}

Response Body — units/search

{
  "status": 200,
  "data": {
    "units": [
      {
        "unitId": "unit_GfNkzV4itfk",
        "name": "M001",
        "width": 20,
        "depth": 30,
        "height": null,
        "area": 600,
        "volume": null,
        "overlocked": false,
        "rentability": {
          "rentable": true,
          "unrentableReason": "ACTIVE_LEASE | REPAIRS_REQUIRED | CLEANING_REQUIRED | UNDER_RENOVATION | USED_BY_FACILITY | OTHER",
          "unrentableReasonNote": "Note why the unit is unavailable"
         },
        "insurable": true,
        "floorName": "1",
        "facilityId": "fac_C7bSZyPT6fp",
        "leaseId": "lease_V4w64pjUwVK",
        "pricingGroupId": "pg_4a2da7d271a",
        "accessInstructions": "Your unit is located on the first floor, down the hall to the left.",
        "walkthroughOrder": 1,
        "legacyId": "19455"
      },
      {/* ... */}
    ]
  }
}

Returns metadata for spaces at co-managed facilities

Required Properties

Optional Properties

Unit Set Rentability

POST /v1/units/set-rentability

Request Body — units/set-rentability

{
  "unitId": "unit_GfNkzV4itfk",
  "rentable": false,
  "unrentableReason": "REPAIRS_REQUIRED | CLEANING_REQUIRED | UNDER_RENOVATION | USED_BY_FACILITY | OTHER",
  "unrentableReasonNote": "Note why the unit is unavailable"
}

Sets the rentability of a unit.

Required Properties

Pricing Groups

POST /v1/pricing-groups/search

Request Body — pricing-groups/search

{
  "where": {
    "facilityId": "fac_4a2da7d271a",
    "pricingGroupId": "pg_4a2da7d271a"
  },
  "expansions": [ ... ]
}

Response Body — pricing-groups/search

{
  "status": 200,
  "data": {
    "pricingGroups": [
      {
        "pricingGroupId": "pg_4a2da7d271a",
        "facilityId": "fac_C7bSZyPT6fp",
        "leaseConfigurationId": "lc_4a2da7d271a",
        "name": "Standard",
        "width": 20,
        "depth": 30,
        "height": null,
        "area": 600,
        "vehicleStorage": false,
        "parking": false,
        "standardRate": 22000,
        "walkInRate": 20000,
        "webRate": 18000,
        "strikethroughRate": 16000,
        "features": [
          "Climate controlled",
          "Ground floor",
          "Drive-up"
        ],
        "discounts": [
          "discount_JgNkzV4itfk",
          "discount_ji43jNjKuf"
        ],
        "availableDiscounts": [
          "discount_JgNkzV4itfk"
        ],
        "availableUnits": 14,
        "valuePricingStrategyId": "vps_4a2da7d271a",
        "valuePricingStatus": "APPROVED",
        "availableTiers": [ "LOWEST", "MEDIUM", "HIGHEST" ]
      },
      {/* ... */}
    ]
  }
}

Search for pricing groups by facilityId or pricingGroupId.

Required Properties

Optional Properties

Response Parameters

Pricing Groups Change Rates

POST /v1/pricing-groups/change-rates

Request Body — pricing-groups/change-rates

{
  "pricingGroups": [
    {
      "pricingGroupId": "pg_4a2da7d271a",
      "standardRate": 23000,
      "webRate": 21000,
      "strikethroughRate": 25000
    }
  ]
}

Changes rates for pricing groups. Only the rates that are to be updated need to be included in the request.

Required Properties

Optional Properties

Pricing Groups Find Unit For Tier

POST /v1/pricing-groups/find-unit-for-tier

Request Body — pricing-groups/find-unit-for-tier

{
  "pricingGroupId": "pg_4a2da7d271a",
  "tier": "LOWEST | MEDIUM | HIGHEST"
}

Response Body — pricing-groups/find-unit-for-tier

{
  "status": 200,
  "data": {
    "unitId": "unit_4a2da7d271a"
  }
}

Resolves a value-pricing tier to the concrete unit a renter would be assigned, using the same ranking the storefront applies: HIGHEST maps to the best-ranked available unit, LOWEST to the lowest-ranked, and MEDIUM to the unit closest to the middle of the ranking. Call Pricing Group Search first and offer only the tiers listed in availableTiers.

Required Properties

Response Parameters

POST /v1/discounts/search

Request Body — discounts/search

{
  "where": {
    "pricingGroupId": "pg_4a2da7d271a",
    "discountId": "discount_JgNkzV4itfk",
    "organizationId": "org_<ID>"
  }
}

Response Body — discounts/search

{
  "status": 200,
  "data": {
    "discounts": [
      {
        "discountId": "discount_JgNkzV4itfk",
        "name": "First Month Free",
        "type": "PERPETUAL | PERIODIC | PAID_UPFRONT | ONE_TIME",
        "status": "PUBLISHED | ARCHIVED",
        "startAfterMonths": 1,
        "discountedMonths": 1
        
        // Upfront discount fields
        "upfrontPaidMonths": 1,
        "upfrontFreeMonths": 1,
        
        // Periodic / perpetual discount fields.
        "applicationMethod": "PERCENT_DEDUCTED | AMOUNT_DEDUCTED | AMOUNT_FIXED",
        "applicationAmount": 1000,        // AMOUNT_DEDUCTED / AMOUNT_FIXED: value in cents. PERCENT_DEDUCTED: percentage x100 (10% -> 1000), DEPRECATED (see Changelog)
        "applicationPercentage": 10,      // PERCENT_DEDUCTED only, a percentage (0-100)
        
        // every pricing group the discount applies to, with its channel visibility
        "pricingGroups": [
          {
            "pricingGroupId": "pg_4a2da7d271a",
            "name": "Standard",
            "visibility": "ALL | CUBBY_ONLY"
          }
        ]
      },
      {/* ... */}
    ]
  }
}

Search for discounts by pricing group or discount id

A discount expresses its value through applicationAmount and/or applicationPercentage, depending on applicationMethod:

Each discount also carries a pricingGroups array listing every pricing group it applies to. Each entry has the pricing group's pricingGroupId and name, plus the visibility (ALL or CUBBY_ONLY) configured for that discount in that pricing group — visibility is per discount-and-pricing-group pairing, so the same pricing group may show a different value on a different discount.

Required Properties

POST /v1/value-pricing-strategies/search

Request Body — value-pricing-strategies/search

{
  "where": {
    "valuePricingStrategyId": "vps_4a2da7d271a"
  }
}

Response Body — value-pricing-strategies/search

{
  "status": 200,
  "data": {
    "valuePricingStrategies": [
      {
        "valuePricingStrategyId": "vps_4a2da7d271a",
        "name": "Unit Type Value Pricing",
        "tiers": [
          {
            "tier": "LOWEST",
            "name": "Standard",
            "benefits": [
              "Furthest from the entrance",
              "Best when you rarely visit your unit"
            ]
          },
          {
            "tier": "MEDIUM",
            "name": "Premium",
            "increaseType": "AMOUNT",
            "increaseAmount": 400,
            "benefits": [
              "Convenient Location",
              "Save money and steps"
            ]
          },
          {
            "tier": "HIGHEST",
            "name": "VIP",
            "increaseType": "PERCENTAGE",
            "increasePercentage": 15.00,
            "benefits": [
              "Best Location",
              "Closest to entrance, elevator, or stairs"
            ]
          }
        ]
      }
    ]
  }
}

Search for value-pricing strategies by strategy id, facility id, or organization id. Exactly one where field must be specified.

A value-pricing strategy defines tier increases (good / better / best) relative to a base rate, but does not itself store one. Per-tier effective rates are computed client-side from each pricing group's webRate and the tier's increaseType plus its type-specific amount:

Each non-LOWEST tier carries exactly one of increaseAmount or increasePercentage, matching its increaseType. The LOWEST tier never carries increaseType, increaseAmount, or increasePercentage — by definition it has no increase.

Required Properties

Customers

POST /v1/customers/search

Request Body — customers/search

{
  "where": {
    "customerId": "cust_BqaN6zApXCH",
    "facilityId": "fac_C7bSZyPT6fp",
    "organizationId": "org_4a2da7d271a",
    "name": "Bebe Flatley",
    "phone": "+15943590263",
    "email": "bebe.flatley@example.com",
    "lease": "ACTIVE | ANY", 
    "lead": "ACTIVE | ANY"
  },
  "expansions": [ 
    "leads" 
  ]
}

Response Body — customers/search

{
  "status": 200,
  "data": {
    "customers": [
      {
        "customerId": "cust_BqaN6zApXCH",
        "createdAt": "2024-03-01T12:00:00.000000Z",
        "updatedAt": "2024-03-01T12:00:00.000000Z",
        "name": "Bebe Flatley",
        "firstName": "Bebe",
        "lastName": "Flatley",
        "companyName": "Cubby",
        "dateOfBirth": "1990-01-01",
        "military": false,
        "contact": {
          "address": "2055 Earnest Mountain",
          "address2": "Apt. 805",
          "city": "Johnston",
          "state": "Minnesota",
          "country": "USA",
          "zip": "15219",
          "email": "",
          "phone": "+15943590263",
        },
        "idType": "DRIVER_LICENSE | PASSPORT | STATE_ID | MILITARY_ID",
        "idNumber": "123456789",
        "leases": [
          "lease_V4w64pjUwVK"
        ],
        "leads": [
          "lead_4a2da7d271a"
        ]
      }
    ],
    "leads": [
      {
        "leadId": "lead_4a2da7d271a",
        "createdAt": "2024-03-01T12:00:00.000000Z",
        "updatedAt": "2024-03-01T12:00:00.000000Z",
        "source": "WALK_IN",
        "status": "NEW",
        "pricingGroupId": "pg_4a2da7d271a",
        "message": "I'm interested in a 10x10 unit",
        "targetMoveInDate": "2024-03-01"
      }    
    ]
  }
}
       

Search for customers

Required Properties

Optional Properties

Customer Update

POST /v1/customers/update

Request Body — customers/update

{
  "customerId": "cust_BqaN6zApXCH",
  "name": "Bebe Flatley",
  "contact": {
    "address": "2055 Earnest Mountain",
    "address2": "Apt. 805",
    "city": "Johnston",
    "zip": "15219"
  },
  "communicationPreferences": {
    "smsMarketing": true,
    "emailMarketing": false
  }
}

Updates customer information. Only the fields that are to be updated need to be included in the request.

Required Properties

Optional Properties

Leads

POST /v1/leads/search

Request Body — leads/search

{
  "where": {
    "facilityId": "fac_C7bSZyPT6fp"
  },
  "expansions": [ ... ]
}

Response Body — leads/search

{
  "status": 200,
  "data": {
    "leads": [
      {
        "leadId": "lead_4a2da7d271a",
        "createdAt": "2024-03-01T12:00:00.000000Z",
        "updatedAt": "2024-03-05T09:30:00.000000Z",
        "source": "WALK_IN",
        "origin": "MANAGER",
        "status": "RESERVATION",
        "facilityId": "fac_C7bSZyPT6fp",
        "pricingGroupId": "pg_4a2da7d271a",
        "unitId": "unit_GfNkzV4itfk",
        "message": "I'm interested in a 10x10 unit",
        "targetMoveInDate": "2024-03-01",
        "customerId": "cust_BqaN6zApXCH",
        "coverageType": "ORGANISATION",
        "coverageLevelId": "covlevel_4a2da7d271a",
        "discounts": [ "discount_4a2da7d271a" ],
        "rateType": "CUSTOM_RATE",
        "customRate": 14900,
        "reservedAt": "2024-03-03T15:42:00.000000Z",
        "convertedAt": null,
        "unqualifiedAt": null,
        "leaseMoveInDate": null
      }
    ]
  }
}

Search for leads by facility

Required Properties

One of the following must be provided:

Optional Properties

Response Parameters

The coverage, discount, and rate assignments above are returned regardless of whether they were set through the API or by staff in the Cubby app.

Leads Create

POST /v1/leads/create

Request Body — leads/create

{
  "organizationId": "org_4a2da7d271a",
  "customerId": "cust_BqaN6zApXCH",
  "source": "WALK_IN"
  "customSource": "Google Ads",
  "pricingGroupId": "pg_4a2da7d271a",
  "unitId": "unit_GfNkzV4itfk",
  "facilityId": "fac_C7bSZyPT6fp",
  "message": "I'm interested in a 10x10 unit",
  "targetMoveInDate": "2024-03-01",
  "reservation": false,
  "coverageLevelId": "covlevel_4a2da7d271a",
  "discounts": [ "discount_4a2da7d271a" ],
  "rateType": "CUSTOM_RATE",
  "customRate": 14900,
  "customer": {
      "name": "Bebe Flatley",
      "dateOfBirth": "1990-01-01",
      "military": false,
      "contact": {
        "address": "2055 Earnest Mountain",
        "address2": "Apt. 805",
        "city": "Johnston",
        "state": "Minnesota",
        "country": "USA",
        "zip": "15219",
        "email": "",
        "phone": "+15943590263"
      },
      "communicationPreferences": {
        "smsMarketing": true,
        "emailMarketing": false
      }
    }
}

Creates a new lead. If customerId is not provided, a new customer will be created.

Required Properties

If source is OTHER, customSource must be provided.

Optional Properties

Leads Update

POST /v1/leads/update

Request Body — leads/update

{
  "leadId": "lead_4a2da7d271a",
  "unitId": "unit_GfNkzV4itfk",
  "pricingGroupId": "pg_4a2da7d271a",
  "status": "IN_PROGRESS_HOT",
  "targetMoveInDate": "2024-03-01",
  "coverageLevelId": "covlevel_4a2da7d271a",
  "discounts": [ "discount_4a2da7d271a" ],
  "rateType": "CUSTOM_RATE",
  "customRate": 14900
}

Updates an existing lead. Only the fields to change need to be included: an omitted field is left unchanged, while an explicit null clears the value (where the field is clearable). The same validation rules as leads/create apply to the resulting lead.

To keep the endpoint predictable it does not perform reservation transitions: a lead that is already a reservation cannot be updated here, and status cannot be set to RESERVATION. status also cannot be set to CONVERTED — a lead becomes converted only when a lease is created for it, so a manual conversion is rejected.

Required Properties

Optional Properties

Leases

POST /v1/leases/search

Request Body — leases/search

{
  "where": {
    "facilityId": "fac_C7bSZyPT6fp",
    "activeOnOrAfter": "2024-03-01",
    "activeOnOrBefore": "2024-03-31"
  },
  "expansions": [ ... ]
}

Response Body — leases/search

{
  "status": 200,
  "data": {
    "leases": [
      {
        "leaseId": "lease_V4w64pjUwVK",
        "createdAt": "2024-03-01T12:00:00.000000Z",
        "updatedAt": "2024-03-01T12:00:00.000000Z",
        "moveInDate": "2024-03-06",
        "moveOutDate": null,
        "monthlyRentalAmount": 20800,
        "paidThroughDate": "2024-03-06",
        "nextChargeAmount": 22672,
        "nextChargeDate": "2024-04-06",
        "delinquencyStartDate": null,
        "overlockNeeded": false,
        "alternativeContacts": [
          {
            "name": "Tyrell Maurice",
            "phone": "+122233344455",
            "email": "tyrel@test.test.test"
          }
        ],
        "coverage": {
          "coverageType": "ORGANISATION",
          "startDate": "2024-05-01",
          "coverageLevelId": "covlevel_4a2da7d271a",
          "premiumAmount": 1500,
          "coverageAmount": 100000
        },
        "coverageChange": {
          "coverageType": "ORGANISATION",
          "startDate": "2024-06-01",
          "coverageLevelId": "covlevel_341f3jNjKuf",
          "premiumAmount": 2000,
          "coverageAmount": 150000
        },
        "privatePolicyNumber": null,
        "privatePolicyExpirationDate": null,
        "coverageAutoenrollable": true,
        "unitContents": "Personal vehicle",
        "storingVehicle": true,
        "vehicle": {
          "type": "SEDAN | SUV | TRUCK | RV | TRAILER | BOAT | PLANE | MOTORCYCLE | OTHER",
          "licenseNumber": "ABC123",
          "state": "MN"
        },
        "customerId": "cust_BqaN6zApXCH",
        "unitId": "unit_GfNkzV4itfk",
        "pricingGroupId": "pg_4a2da7d271a",
        "facilityId": "fac_C7bSZyPT6fp",
        "rentChangeScheduledDate": "2024-06-01",
        "rentChangeNewRentAmount": 22000,
        "scheduledMoveOut": {
          "moveOutDate": "2024-07-01",
          "noticeGivenDate": "2024-06-01",
          "moveOutReason": "OTHER",
          "customReason": "Moving to a new city",
          "moveOutTime": "MORNING"
        }
      }
    ],
    "customers": [
      {
        "customerId": "cust_BqaN6zApXCH",
        "createdAt": "2024-03-01T12:00:00.000000Z",
        "updatedAt": "2024-03-01T12:00:00.000000Z",
        "name": "Bebe Flatley",
        "firstName": "Bebe",
        "lastName": "Flatley",
        "contact": {
          "address": "2055 Earnest Mountain",
          "address2": "Apt. 805",
          "city": "Johnston",
          "state": "Minnesota",
          "country": "USA",
          "zip": "15219",
          "email": "bebe.flatley@example.org",
          "phone": "+15943590263"
        }
      }
    ],
    "units": [],
    "pricingGroups": [],
    "facilities": [],
    "ledgers": [],
    "compliances": []
  }
}

Returns metadata for leases at co-managed facilities

Required Properties

Optional Properties

Response Properties

Leases Get Compliances

POST /v1/leases/get-compliances

Request Body — leases/get-compliances

{
  "leaseIds": [
    "lease_V4w64pjUwVK"
  ]
}

Response Body — leases/get-compliances

{
  "status": 200,
  "data": {
    "compliances": [
      {
        "leaseId": "lease_V4w64pjUwVK",
        "documents": [
          {
            "type": "LEASE_AGREEMENT | COVERAGE | IDENTITY | VEHICLE",
            "status": "NOT_REQUIRED" | "INCOMPLETE" | "PENDING_APPROVAL" | "SIGNATURE_NEEDED" | "REJECTED" | "APPROVED"
          }
        ]
      },
      {/* ... */}
    ]
  }
}

Returns the compliance status for leases

Required Properties

Response Parameters

Leases Get Rent Change Schedules

POST /v1/leases/get-rent-change-schedules

Request Body — leases/get-rent-change-schedules

{
  "leaseIds": [
    "lease_V4w64pjUwVK"
  ]
}

Response Body — leases/get-rent-change-schedules

{
  "status": 200,
  "data": {
    "rentChangeSchedules": [
      {
        "leaseId": "lease_V4w64pjUwVK",
        "rentChangeDate": "2024-06-01",
        "noticeDate": "2024-05-01",
      },
      {/* ... */}
    ]
  }
}

Returns the next possible rent change schedule for leases

Required Properties

Response Parameters

Leases Change Rents

POST /v1/leases/change-rents

Request Body — leases/change-rents

{
  "leases": [
    {
      "leaseId": "lease_V4w64pjUwVK",
      "newRentAmount": 22000,
      "rentChangeDate": "2024-06-01",
      "noticeDate": "2024-05-01",      
    }
  ]
}

Schedules rent changes for leases, which will take effect on the next possible rent change date for each lease

Required Properties

Optional Properties

Leases Cancel Rent Changes

POST /v1/leases/cancel-rent-changes

Request Body — leases/cancel-rent-changes

{
  "leaseIds": [
    "lease_V4w64pjUwVK"
  ]
}

Cancels scheduled rent changes for leases

Lease Update Alternative Contacts

POST /v1/leases/update-alternative-contacts

Request Body — leases/update-alternative-contacts

{
  "leaseId": "lease_V4w64pjUwVK",
  "alternativeContacts": [
    {
      "name": "Tyrell Maurice",
      "phone": "+122233344455",
      "email": "tyrel@test.test.test"
    }
  ]
}

Updates the alternative contacts for a lease

Required Properties

Get Upsells

POST /v1/leases/get-upsells

Request Body — leases/get-upsells

{
  "unitId": "unit_GfNkzV4itfk",
  "rentAmount": 20800
}

Response Body — leases/get-upsells

{
  "status": 200,
  "data": {
    "upsells": [
      {
        "feeId": "fee_3kLmN2pQrSt",
        "name": "Climate Control Upgrade",
        "description": "Keeps your unit between 55°F and 85°F year-round",
        "amount": 1500
      },
      {
        "feeId": "fee_8XyZab9CdEf",
        "name": "Premium Access Hours",
        "description": "24/7 facility access",
        "amount": 500
      }
    ]
  }
}

Returns the optional upsell (upgrade) recurring fees available for a unit. Each upsell can be opted into at move-in by passing its feeId in the upsellFeeIds array of Get Move-In Charges, Create Lease, or Checkout. Only active fees configured as optional upgrades on the unit's pricing group are returned. The amount is the recurring charge per billing cycle; for percentage-based fees it is computed against the supplied rentAmount (or the pricing group's standard rate when rentAmount is omitted), so the preview matches what the same rentAmount will be billed in Get Move-In Charges and Create Lease.

Required Properties

Optional Properties

Preview Charges

POST /v1/leases/preview-charges

Request Body — leases/preview-charges

{
  "leaseId": "lease_jOi8joH3Hu",
  "prepayMonths": 3,
  "paymentMethodId": "pm_V4w64pjUwVK"
}

Response Body — leases/preview-charges

{
  "status": 200,
  "data": {
    "subtotal": 16710,
    "tax": 1545,
    "totalBeforePayments": 18255,
    "totalPaid": 0,
    "prepaidBalance": 0,
    "total": 18255,
    "charges": [
      {
        "type": "RENT",
        "displayName": "Rent",
        "description": "$61.00 (monthly rate) x 3 months",
        "accruesOn": "2026-06-01",
        "accruesThrough": "2026-08-31",
        "amount": 12810,
        "undiscountedAmount": 18300,
        "discounts": [ "Summer Special" ]
      },
      {
        "type": "INSURANCE",
        "displayName": "Coverage",
        "description": "",
        "accruesOn": "2026-06-01",
        "accruesThrough": "2026-08-31",
        "amount": 2400,
        "undiscountedAmount": 2400,
        "discounts": []
      },
      {
        "type": "FEES",
        "displayName": "Admin Fee",
        "description": "",
        "amount": 1500,
        "undiscountedAmount": 1500,
        "discounts": []
      }
    ]
  }
}

Returns a charges breakdown for an existing lease. With no prepayMonths, it returns the lease's current outstanding charges. When prepayMonths is provided, the response also includes the projected charges for prepaying that many billing periods, so total reflects the full cost to bring the lease current and prepay ahead. Any amount already paid toward the outstanding charges (totalPaid) and the lease's prepaid credit balance (prepaidBalance) are deducted from totalBeforePayments to produce total, so total is the amount that would actually be collected. Projected charges account for discounts applied to the specific months they cover (not averaged across the period), coverage premiums, recurring fees, and taxes. All monetary values are in cents.

When paymentMethodId is supplied and resolves to a credit-card method at a facility with credit-card processing fees configured, the fee is added to the breakdown (as a FEES charge) and included in subtotal, tax, totalBeforePayments, and total, so total equals the amount to send to Make Payment with that method to fully settle the charges. Omit paymentMethodId (or supply a non-credit method, or a facility with no fee configured) to get the fee-free charges.

Required Properties

Optional Properties

Response Parameters

Parameter Description
subtotal Subtotal in cents before tax
tax Tax amount in cents
totalBeforePayments Charges in cents before deducting payments and prepaid balance (subtotal + tax)
totalPaid Amount in cents already paid toward the outstanding charges
prepaidBalance The lease's prepaid (credit) balance in cents, applied to offset the charges
total Amount in cents still owed, after deducting totalPaid and prepaidBalance (floored at zero)
charges[].type Charge category. One of RENT, INSURANCE, FEES, DEPOSIT. Taxes are summed into tax and discounts are folded into the parent charge's discounts, so they are not returned as separate charges
charges[].displayName Human-readable name of the charge
charges[].description Charge description (e.g. "$61.00 (monthly rate) x 3 months"), may be empty
charges[].accruesOn Charge period start date (ISO-8601), omitted for point charges
charges[].accruesThrough Charge period end date (ISO-8601), omitted for point charges
charges[].amount Charge amount in cents, after discounts
charges[].undiscountedAmount Charge amount in cents, before discounts
charges[].discounts Names of the discount programs applied to the charge

Error Conditions

Get Move-In Charges

POST /v1/leases/get-move-in-charges

Request Body — leases/get-move-in-charges

{
  "unitId": "unit_GfNkzV4itfk",
  "moveInDate": "2024-03-06",
  "rentAmount": 20800,
  "coverageLevelId": "covlevel_4a2da7d271a",
  "chargeDeposit": true,
  "chargeMoveInFee": true,
  "taxExempt": false,
  "storingVehicle": true,
  "discounts": [ "discount_JgNkzV4itfk" ],
  "upsellFeeIds": [ "fee_3kLmN2pQrSt" ]
}

Response Body — leases/get-move-in-charges

{
  "status": 200,
  "data": {
    "subtotal": 34300,
    "tax": 2898,
    "total": 37198,
    "charges": [
      {
        "accruesOn": "2024-10-21",
        "accruesThrough": "2024-11-20",
        "type": "RENT",
        "displayName": "Rent",
        "description": "",
        "amount": 21000,
        "undiscountedAmount": 21000,
        "discounts": []
      },
      {
        "type": "COVERAGE",
        "displayName": "Coverage",
        "description": "",
        "accruesOn": "2024-10-21",
        "accruesThrough": "2024-11-20",
        "amount": 800,
        "undiscountedAmount": 800,
        "discounts": []
      },
      {
        "type": "FEES",
        "displayName": "Move-in Fee",
        "description": "",
        "amount": 2500,
        "undiscountedAmount": 2500,
        "discounts": []
      },
      {
        "type": "DEPOSIT",
        "displayName": "Security Deposit",
        "description": "",
        "amount": 10000,
        "undiscountedAmount": 10000,
        "discounts": []
      }
    ]
  }
}

Returns the charges for a lease move-in

Required Properties

Optional Properties

Create Lease

POST /v1/leases/create

Creates a new lease without collecting payment. Use this endpoint when payment is handled separately or is not required at move-in time. To create a lease and collect payment in a single step, use the Checkout endpoint instead.

Request Body — leases/create

{
  "unitId": "unit_GfNkzV4itfk",
  "moveInDate": "2024-03-06",
  "rentAmount": 20800,
  "coverageLevelId": "covlevel_4a2da7d271a",
  "chargeDeposit": true,
  "chargeMoveInFee": true,
  "taxExempt": false,
  "storingVehicle": true,
  "discounts": [ "discount_JgNkzV4itfk" ],
  "upsellFeeIds": [ "fee_3kLmN2pQrSt" ],
  "customerId": "cust_BqaN6zApXCH",
  "customer": {
      "name": "Bebe Flatley",
      "contact": {
        "address": "2055 Earnest Mountain",
        "address2": "Apt. 805",
        "city": "Johnston",
        "state": "Minnesota",
        "country": "USA",
        "zip": "15219",
        "email": "bebe.flatley@example.org",
        "phone": "+15943590263"
      },
      "communicationPreferences": {
        "smsMarketing": true,
        "emailMarketing": false
      }
   },
   "source": "WEBSITE",
   "customSource": null
}

Response Body — leases/create

{
  "status": 200,
  "data": {
    "leaseId": "lease_V4w64pjUwVK"
  }
}

Required Properties

Optional Properties

Checkout

POST /v1/leases/checkout

Creates a new lease and collects payment for the move-in charges in a single step. Accepts all the same fields as Create Lease, plus a required payment object.

A lead is created first, then the lease is created and the move-in charges are charged. If the payment is declined, the lease is rolled back but the lead survives. If the payment succeeds, the response includes the leaseId, paymentTransactionId, and paymentSuccess: true. If the payment is declined, leaseId is null, paymentSuccess is false, and paymentFailureInfo contains the reason.

When enableAutoPay is true, a successful payment also saves the card supplied in payment to the customer as a reusable payment method and enrols the new lease in AutoPay using that card. Saving the card and enabling AutoPay happen after the charge and never affect it: if either step fails the payment still stands, and the paymentMethodId and autoPayEnabled response fields report the outcome of each. When enableAutoPay is omitted or false, the card is charged but not saved — paymentMethodId is null and autoPayEnabled is false.

The payment.amount must match the total from Get Move-In Charges exactly, otherwise a 400 error is returned.

Request Body — leases/checkout

{
  "unitId": "unit_GfNkzV4itfk",
  "moveInDate": "2024-03-06",
  "rentAmount": 20800,
  "coverageLevelId": "covlevel_4a2da7d271a",
  "chargeDeposit": true,
  "chargeMoveInFee": true,
  "taxExempt": false,
  "storingVehicle": true,
  "discounts": [ "discount_JgNkzV4itfk" ],
  "upsellFeeIds": [ "fee_3kLmN2pQrSt" ],
  "customerId": "cust_BqaN6zApXCH",
  "customer": {
      "name": "Bebe Flatley",
      "contact": {
        "address": "2055 Earnest Mountain",
        "address2": "Apt. 805",
        "city": "Johnston",
        "state": "Minnesota",
        "country": "USA",
        "zip": "15219",
        "email": "bebe.flatley@example.org",
        "phone": "+15943590263"
      }
   },
   "source": "WEBSITE",
   "customSource": null,
   "enableAutoPay": true,
   "payment": {
      "amount": 37198,
      "address": {
          "address": "2055 Earnest Mountain",
          "address2": "Apt. 805",
          "city": "Johnston",
          "state": "Minnesota",
          "country": "USA",
          "zip": "15219",
          "email": "bebe.flatley@example.com",
          "phone": "+15943590263"
      },
      "methodType": "CREDIT_CARD",
      "token": "tok_1Hh1XYZabc1234567890",
      "cardBrand": "VISA",
      "cardExpiration": "03/24",
      "cardLastFour": "1234",
      "cardHolder": "Bebe Flatley"
   }
}

Response Body (success) — leases/checkout

{
  "status": 200,
  "data": {
    "leaseId": "lease_V4w64pjUwVK",
    "paymentTransactionId": "ptxn_8kLmN2pQrSt",
    "paymentSuccess": true,
    "paymentMethodId": "pm_V4w64pjUwVK",
    "autoPayEnabled": true
  }
}

Response Body (declined) — leases/checkout

{
  "status": 200,
  "data": {
    "leaseId": null,
    "paymentTransactionId": "ptxn_8kLmN2pQrSt",
    "paymentSuccess": false,
    "paymentFailureInfo": {
      "reason": "Insufficient funds"
    },
    "paymentMethodId": null,
    "autoPayEnabled": false
  }
}

Required Properties

All properties from Create Lease, plus:

Optional Properties

All optional properties from Create Lease also apply, plus:

Response Parameters

Cancel Lease

POST /v1/leases/cancel-lease

Request Body — leases/cancel-lease

{
  "leaseId": "lease_V4w64pjUwVK"
}

Cancels a lease which has not yet started (i.e. the move-in date is in the future)

Required Properties

Schedule Move Out

POST /v1/leases/schedule-move-out

Request Body — leases/schedule-move-out

{
  "leaseId": "lease_V4w64pjUwVK",
  "moveOutDate": "2026-04-01",
  "noticeGivenDate": "2026-02-24",
  "moveOutReason": "NO_NEED",
  "customReason": null,
  "moveOutTime": "MORNING",
  "disableAutoPay": true
}

Schedules a move-out for a lease

Required Properties

Optional Properties

POST /v1/leases/get-payment-link

Request Body — leases/get-payment-link

{
  "leaseIds": ["lease_V4w64pjUwVK", "lease_GfNkzV4itfk"]
}

Response Body — leases/get-payment-link

{
  "status": 200,
  "data": {
    "paymentLink": "https://pay.example.com/1?token=abc123"
  }
}

Generates a payment link which can be sent to the tenant to make a payment for one or more leases

Required Properties

POST /v1/leases/get-documents-link

Request Body — leases/get-documents-link

{
  "leaseId": "lease_V4w64pjUwVK"
}

Response Body — leases/get-documents-link

{
  "status": 200,
  "data": {
    "documentsLink": "https://portal.example.com/leases/lease_1/documents?token=abc123"
  }
}

Generates a link which can be sent to the tenant to view, manage, and sign documents for a lease.

Required Properties

Make Payment

POST /v1/leases/make-payment

Request Body — leases/make-payment

{
  "leaseId": "lease_V4w64pjUwVK",
  "paymentMethodId": "pm_V4w64pjUwVK",
  "amount": 1500
}

Makes a payment for a lease using a saved payment method. If the amount paid is more than the amount due, the overpayment will be transferred to the prepaid balance of the lease.

When the payment method is a credit card and the facility has credit-card processing fees configured in its payment settings, the fee is deducted from amount — the card is charged exactly amount, and the remainder is applied to the lease. To fully settle a balance in this case, charge the fee-inclusive total returned by Preview Charges for the same paymentMethodId. Facilities without credit-card fees configured are unaffected.

Required Properties

Enable AutoPay

POST /v1/leases/enable-auto-pay

Request Body — leases/enable-auto-pay

{
  "leaseId": "lease_V4w64pjUwVK",
  "paymentMethodId": "pm_V4w64pjUwVK"
}

Enables AutoPay for a lease using a saved payment method. With AutoPay enabled, the tenant will be automatically charged for the amount due on the next charge date of the lease, and on subsequent charge dates until AutoPay is disabled.

Required Properties

Disable AutoPay

POST /v1/leases/disable-auto-pay

Request Body — leases/disable-auto-pay

{
  "leaseId": "lease_V4w64pjUwVK"
}

Disables AutoPay for a lease.

Payment Methods

POST /v1/payment-methods/search

Request Body — payment-methods/search

{
  "where": {
    "customerId": "cust_BqaN6zApXCH"
  }
}

Response Body — payment-methods/search

{
  "status": 200,
  "data": {
    "paymentMethods": [
      {
        "paymentMethodId": "pm_V4w64pjUwVK",
        "type": "CREDIT_CARD | ACH",
        "cardBrand": "VISA | MASTERCARD | AMERICAN_EXPRESS | DISCOVER | DINERS_CLUB | JCB | MAESTRO | UNIONPAY | MIR | ELO | HIPER | HIPERCARD | FORBRUGSFORENINGEN | VISA_ELECTRON | UNKNOWN",
        "cardLastFour": "1234",
        "cardExpiration": "03/24",
        "achAccountLastFour": "1234",
        "achAccountType": "CHECKING | SAVINGS"
      }
    ]
  }
}

Search for saved payment methods by customer

Required Properties

Generating a Payment Token

Before creating a payment method in Cubby, you must first generate a single-use token through your organization's payment gateway. The token is then passed to the Create Payment Method endpoint below as the token property.

Cubby supports two payment gateways — Stripe and Payabli — configured per facility. A given facility uses exactly one of them. To determine which gateway a facility uses, call the Facilities Search endpoint and read the paymentServiceProvider field (STRIPE or PAYABLI) on the facility. Cubby provides the corresponding publishable key. Follow the flow for that facility's gateway below; the resulting token is sent to the Cubby API in exactly the same way regardless of gateway.

Stripe

Use this flow for facilities whose paymentServiceProvider is STRIPE. Your Stripe publishable key (STRIPE_PK) will be provided by Cubby.

Begin by loading the Stripe.js library on the page where you collect card details.

Step 1a: Load Stripe.js

<script src="https://js.stripe.com/clover/stripe.js"></script>

With the library loaded, create a Stripe instance with your publishable key and an Elements group in setup mode with manual payment-method creation. This renders the card input fields your customer will fill in.

Step 1b: Initialize Stripe Elements

const stripe = Stripe(STRIPE_PK);
const stripeElements = stripe.elements({
    loader: 'auto',
    mode: 'setup',
    currency: 'usd',
    payment_method_types: ['card'],
    paymentMethodCreation: 'manual',
});

Once the customer has entered their card details, submit the Elements form and create a payment method, supplying the cardholder's billing details. The resulting paymentMethod.id is the token you will pass to the Cubby API.

Step 2: Create a Stripe payment method

await stripeElements.submit();
const { paymentMethod, error } = await stripe.createPaymentMethod({
    elements: stripeElements,
    params: {
        billing_details: {
            name: 'Bebe Flatley',
            email: 'bebe.flatley@example.com',
            phone: '+15943590263',
            address: {
                country: 'US',
                postal_code: '15219',
                state: null,
                city: null,
                line1: null,
                line2: null,
            },
        },
    },
});

Payabli

Use this flow for facilities whose paymentServiceProvider is PAYABLI. Payabli card capture is powered by Basis Theory web elements; install the @basis-theory/web-elements package to begin.

First, add a container element to your page. Basis Theory will mount its secure card input into this element.

Step 1a: Add a mount point

<div id="card-element"></div>

Initialize Basis Theory with the publishable key (BT_PK) and environment (test or production) provided by Cubby, then create a card element and mount it into the container you just added.

Step 1b: Initialize Basis Theory

import { basistheory } from '@basis-theory/web-elements';

const bt = await basistheory(BT_PK, { environment: 'test' });
const cardElement = bt.createElement('card', {
    autoComplete: {
        number: 'on',
        expirationDate: 'on',
        csc: 'on',
    },
});
cardElement.mount('#card-element');

Once the customer has entered their card details, create a token intent from the card element. The resulting token.id is the token you will pass to the Cubby API.

Step 2: Create a Basis Theory token

const token = await bt.tokenIntents.create({
    type: 'card',
    data: cardElement,
});

Send the token to Cubby

Use the token produced by your gateway — Stripe's paymentMethod.id or Basis Theory's token.id — as the token value in the Create Payment Method endpoint below.

Create Payment Method

POST /v1/payment-methods/create

Request Body — payment-methods/create

{
    "token": "tok_1Hh1XYZabc1234567890",
    "methodType": "CREDIT_CARD",
    "cardBrand": "VISA",
    "cardExpiration": "03/24",
    "cardLastFour": "1234",
    "cardHolder": "Bebe Flatley",
    "customerId": "cust_BqaN6zApXCH",
    "contact": {
        "address": "2055 Earnest Mountain",
        "address2": "Apt. 805",
        "city": "Johnston",
        "state": "Minnesota",
        "country": "USA",
        "zip": "15219",
        "email": "bebe.flatley@example.com",
        "phone": "+15943590263"
    }
}

Response Body — payment-methods/create

{
  "status": 200,
  "data": {
    "paymentMethodId": "pm_V4w64pjUwVK"
  }
}

Creates a new payment method for a customer using a token generated by the payment gateway.

The caller must ensure the payment method has been successfully validated and authorized by the payment gateway before submission. Unvalidated payment methods may be rejected by the payment gateway when used for a transaction.

Required Properties

Ledgers

POST /v1/ledgers/search

Request Body — ledgers/search

{
  "where": {
    "leaseId": "lease_V4w64pjUwVK",
    "facilityId": "fac_C7bSZyPT6fp"
  }
}

Response Body — ledgers/search

{
  "status": 200,
  "data": {
    "ledgers": [
      {
        "leaseId": "lease_NpZ1BGBoWrS",
        "balances": {
          "totalDue": 1500,
          "deposit": 20000,
          "prepaid": 0
        },
        "bookEntries": [
          {
            "bookEntryId": "be_JfNkzV4itfk",
            "type": "CHARGE",
            "entryTime": "2024-08-26T07:30:50.689691",
            "amount": 2500,
            "amountPaid": 2500,
            "paymentTime": "2024-08-26T07:30:50.826992",
            "details": {
              "category": "FEE",
              "description": "Move-in Fee",
              "waive": false
            }
          },
          {
            "bookEntryId": "be_JfNkzV4itfk",
            "type": "CHARGE",
            "entryTime": "2024-08-26T07:30:50.689691",
            "amount": 20000,
            "amountPaid": 20000,
            "paymentTime": "2024-08-26T07:30:50.826992",
            "details": {
              "category": "DEPOSIT",
              "waive": false
            }
          },
          {
            "bookEntryId": "be_JfNkzV4itfk",
            "type": "CHARGE",
            "entryTime": "2024-08-26T07:30:50.689691",
            "amount": 10000,
            "amountPaid": 10000,
            "paymentTime": "2024-08-26T07:30:50.826992",
            "details": {
              "category": "RENT",
              "accruesOn": "2024-01-01"
              "accruesThrough": "2024-01-31",
              "waive": false
            }
          },
          {
            "bookEntryId": "be_JfNkzV4itfk",
            "type": "CHARGE",
            "entryTime": "2024-08-26T07:30:50.689691",
            "amount": 450,
            "amountPaid": 450,
            "paymentTime": "2024-08-26T07:30:50.826992",
            "details": {
              "category": "TAX_STATE",
              "accruesOn": "2024-01-01",
              "accruesThrough": "2024-01-31",
              "description": "4.5%",
              "waive": false
            }
          },
          {
            "bookEntryId": "be_JfNkzV4itfk",
            "type": "CHARGE",
            "entryTime": "2024-08-26T07:30:50.689691",
            "amount": 50,
            "amountPaid": 50,
            "paymentTime": "2024-08-26T07:30:50.826992",
            "details": {
              "category": "TAX_LOCAL",
              "accruesOn": "2024-01-01",
              "accruesThrough": "2024-01-31",
              "description": "0.5%",
              "waive": false
            }
          },
          {
            "bookEntryId": "be_JfNkzV4itfk",
            "type": "PAYMENT",
            "entryTime": "2024-08-26T07:30:50.826992",
            "amount": -33000,
            "details": {
              "method": "CASH"
            }
          },
          {
            "bookEntryId": "be_JfNkzV4itfk",
            "type": "CHARGE",
            "entryTime": "2024-08-26T07:30:51.983019",
            "amount": 30000,
            "amountPaid": 30000,
            "paymentTime": "2024-08-26T07:30:51.983019",
            "details": {
              "category": "PREPAID",
              "waive": false
            }
          },
          {
            "bookEntryId": "be_JfNkzV4itfk",
            "type": "PAYMENT",
            "entryTime": "2024-08-26T07:30:51.983019",
            "amount": -30000,
            "details": {
              "method": "CASH"
            }
          },
          {
            "bookEntryId": "be_JfNkzV4itfk",
            "type": "CHARGE",
            "entryTime": "2024-08-26T07:30:52.327646",
            "amount": 1500,
            "amountPaid": 0,
            "details": {
              "category": "FEE",
              "description": "Manual Fee",
              "waive": false
            }
          },
          {
            "bookEntryId": "be_JfNkzV4itfk",
            "type": "PAYMENT",
            "entryTime": "2024-08-26T07:30:52.431402",
            "amount": 30000,
            "details": {
              "method": "CASH"
            }
          },
          {
            "bookEntryId": "be_JfNkzV4itfk",
            "type": "PAYMENT",
            "entryTime": "2024-08-26T07:30:52.43866",
            "amount": -30000,
            "details": {
              "method": "PREPAID"
            }
          },
          {
            "bookEntryId": "be_RMhnGWgFSnp",
            "type": "CHARGE",
            "entryTime": "2024-08-26T07:30:53.063417",
            "amount": 5000,
            "amountPaid": 0,
            "details": {
              "category": "FEE",
              "description": "Test fee",
              "waive": false
            }
          },
          {
            "bookEntryId": "be_K7egMpsjeEs",
            "type": "CHARGE",
            "entryTime": "2024-08-26T07:30:54.70939",
            "amount": -5000,
            "amountPaid": 0,
            "details": {
              "category": "FEE",
              "description": "Test fee",
              "waive": true
            }
          }    
        ]
      }
    ]
  }
}

Loads all Account Receivable activity for ledger linked to a lease.

Required Properties

Book entry structure

Coverage

Add private policy info

POST /v1/coverage/add-private-policy

Request Body — coverage/add-private-policy

{
  "leaseId": "lease_<ID>",
  "policyNumber": "123456",
  "expirationDate": "2024-06-19",
}

Adds the private coverage policy number and expiration date for a lease.

Required Properties

Error Conditions

Remove private policy info

POST /v1/coverage/remove-private-policy

Request Body — coverage/remove-private-policy

{
  "leaseId": "lease_<ID>"
}

Removes the private coverage policy number and expiration date for a lease.

Download Private Policy

POST /v1/coverage/download-private-policy

Request Body — coverage/download-private-policy

{
  "leaseId": "lease_<ID>"
}

Response Headers

Content-Type: application/pdf
Content-Disposition: attachment; filename="private_policy.pdf"

Response Body — coverage/download-private-policy

The response body contains the requested private policy file as a binary stream

Required Properties

Error Conditions

Coverage plans

POST /v1/coverage-levels/search

Request Body — coverage-levels/search

{
  "where": {
    "facilityId": "fac_C7bSZyPT6fp", // Deprecated. Use pricingGroupId
    "pricingGroupId": "pg_4a2da7d271a"
  },
  "expansions": [ "coverageProgram" ]
}

Response Body — coverage-levels/search

{
  "status": 200,
  "data": {
    "coverageLevels": [
      {
        "coverageLevelId": "covlevel_<ID>",
        "coverageProgramId": "covprogram_<ID>",
        "provider": "SAFELEASE", // Deprecated. Use provider from the coverageProgram expansion
        "policyNumber": "123456",  // Deprecated. Use policyNumber from the coverageProgram expansion 
        "active": true | false,
        "default": true | false,
        "coverageAmount": 100000,
        "premiumAmount": 1500,
        "pricingGroupIds": ["pg_4a2da7d271a", "pg_9f13ab77c22"]
      },
      { /* ... */ }
    ],
    "coveragePrograms": [
      {
        "coverageProgramId": "covprogram_<ID>",
        "provider": "SAFELEASE",
        "policyNumber": "123456",
        "coverageOptions": {
          "allowTenantOwnInsurance": true,
          "hideTenantOwnInsuranceOnStorefront": false,
          "allowWaiveInsurance": true,
          "hideWaiveInsuranceOnStorefront": false
        }
      }
    ]
  }
}

Search for coverage levels by pricing group. Coverage is configured per pricing group, so each coverage level is returned once with pricingGroupIds listing every pricing group it applies to. Filtering by facilityId is deprecated but still supported; it returns the union of coverage levels across all of the facility's pricing groups.

Each coverage level belongs to a coverage program, identified by coverageProgramId. Request the coverageProgram expansion to also receive the program object(s) — returned as the coveragePrograms array — which carry the program-wide coverageOptions.

Required Properties

Exactly one of the following must be provided:

Response Properties

Optional Properties

Response Parameters

Expansions

POST /v1/coverage/search

Request Body — coverage/search

{
  "where": {
    "facilityId": "fac_C7bSZyPT6fp",
    "leaseId": "lease_V4w64pjUwVK",
    "activeOnOrAfter": "2024-03-01",
    "activeOnOrBefore": "2024-10-31"
  }
}

Response Body — coverage/search

{
  "status": 200,
  "data": {
    "coverages": [
      {
        "leaseId": "lease_V4w64pjUwVK",
        "facilityId": "fac_C7bSZyPT6fp",
        "startDate": "2024-05-01",
        "endDate": "2024-07-01",
        "coverageAmount": 100000,
        "premiumAmount": 1500
      },
      {/* ... */}
    ]
  }
}

Required Properties

Optional Properties

Coverage Enroll

POST /v1/coverage/enroll

Request Body — coverage/enroll

{
  "lease": "lease_<ID>", 
  "coverageLevelId": "covlevel_<ID>",
  "immediate": true | false
}

If immediate is true, immediately enrolls a lease at the specified coverage level. Charges to the next rent date are automatically prorated. Any coverage which is already paid for is cancelled, with the unused portion credited to the account.

If immediate is false, changes will take effect on the next rent date.

Error Conditions

Coverage Policy Unenroll

POST /v1/coverage/unenroll

Request Body — coverage/unenroll

{
  "lease": "lease_<ID>",
  "immediate": true | false
}

If immediate is true, immediately unenrolls a lease from coverage. Any coverage which is already paid for is cancelled, with the unused portion credited to the account.

If immediate is false, changes will take effect on the next rent date.

Error Conditions

Payments

POST /v1/payments/search

Request Body — payments/search

{
  "where": {
    "facilityId": "fac_C7bSZyPT6fp",
    "customerId": "cust_BqaN6zApXCH",
    "paymentDateOnOrAfter": "2024-03-01",
    "paymentDateOnOrBefore": "2024-03-31"
  }
}

Response Body — payments/search

{
  "status": 200,
  "data": {
    "payments": [
      {
        "paymentId": "payment_V4w64pjUwVK",
        "createdAt": "2024-03-01T12:00:00",
        "amount": 1500,
        "customerId": "cust_BqaN6zApXCH",
        "methodType": "CREDIT_CARD" | "ACH" | "ACSS" | "CASH" | "CASH_APP" | "CHECK" | "E_TRANSFER" | "MONEY_ORDER" | "OFFLINE_CARD" | "ONLINE_BANKING" | "PAYPAL" | "VENMO" | "ZELLE"
        "status": "SUCCEEDED" | "DECLINED" | "REJECTED" | "FAILED" | "REFUND_INITIATED" | "REFUNDED" | "DISPUTED" | "DIRECT_DEBIT_RETURN" | "PENDING",
        "reason": "Insufficient funds",
        "explanation": "The account did not have sufficient funds to cover the transaction amount."
      },
      {/* ... */}
    ]
  }
}

Search for payments by facility, customer, or payment date

Required Properties

Optional Properties

Auctions

POST /v1/auctions/search

Request Body — auctions/search

{
  "where": {
    "auctionId": "auction_V4w64pjUwVK",
    "facilityId": "fac_C7bSZyPT6fp"
  },
  "expansions": [ "winningBidders", "leases", "units" ]
}

Response Body — auctions/search

{
  "status": 200,
  "data": {
    "auctions": [
      {
        "auctionId": "auction_V4w64pjUwVK",
        "auctionTime": "2024-03-01T12:00:00",
        "advertisementDeadline": "2024-02-01T12:00:00",
        "leaseConfigurationId": "lc_4a2da7d271a",
        "auctionedLeases": [
          {
            "leaseId": "lease_V4w64pjUwVK",
            "unitId": "unit_GfNkzV4itfk",
            "lienStartDate": "2024-03-01",
            "status": "LISTED" | "NO_BIDS" | "SOLD" | "PAYMENT_RECEIVED" | "COMPLETE" | "CANCELLED",
            "winningBidderId": "cust_BqaN6zApXCH",
            "bidAmount": 10000,
            "depositAmount": 5000
          }
        ]
      },
      {/* ... */}
    ],
    "winningBidders": [
      {
        "customerId": "cust_BqaN6zApXCH",
        "name": "John Smith",
        "firstName": "John",
        "lastName": "Smith",
        "contact": {
          "address": "2055 Earnest Mountain",
          "address2": "Apt. 805",
          "city": "Johnston",
          "state": "Minnesota",
          "country": "USA",
          "zip": "15219",
          "email": "john.smith@example.org",
          "phone": "+15943590263"
        }
      }
    ],
    "leases": [ ... ],
    "units": [ ... ]
  }
}

Search for auctions by facility or auction ID

Required Properties

Supported expansions:

Response Parameters

Auction Create

POST /v1/auctions/create

Request Body — auctions/create

{
  "facilityId": "fac_C7bSZyPT6fp",
  "auctionTime": "2024-03-01T12:00:00",
  "leaseConfigurationId": "lc_4a2da7d271a"
}

Response Body — auctions/create

{
  "status": 200,
  "data": {
    "auctionId": "auction_V4w64pjUwVK"
  }
}

Creates a new auction for a facility

Required Properties

Start lien process

POST /v1/auctions/start-lien

Request Body — auctions/start-lien

{
  "leaseId": "lease_V4w64pjUwVK",
  "auctionId": "auction_V4w64pjUwVK",
  "sendEmailAndSms": true | false,
  "sendToAlternativeContacts": true | false
}

Starts the lien process for a lease, which may include sending lien notices to the tenant and alternative contacts

Required Properties

Optional Properties

Cancel lien process

POST /v1/auctions/cancel-lien

Request Body — auctions/cancel-lien

{
  "leaseId": "lease_V4w64pjUwVK"
}

Cancels the lien process for a lease which is in lien process but has not yet been settled and/or paid for

Notes

POST /v1/notes/search

Request Body — notes/search

{
  "where": {
    "leaseId": "lease_V4w64pjUwVK",
    "customerId": "cust_BqaN6zApXCH",
    "leadId": "lead_4a2da7d271a",
    "unitId": "unit_GfNkzV4itfk",
    "pricingGroupId": "pg_4a2da7d271a",
  }
}

Response Body — notes/search

{
  "status": 200,
  "data": {
    "notes": [
      {
        "text": "Customer requested a larger unit",
        "createdAt": "2024-03-01T12:00:00.000000Z",
        "createdBy": "user_4a2da7d271a"
      }
    ]
  }
}

Search for notes related to leases, customers, leads, units, or pricing groups.

Required Properties

Response Properties

Notes Create

POST /v1/notes/create

Request Body — notes/create

{
  "text": "Customer requested a larger unit",
  "leaseId": "lease_V4w64pjUwVK",
  "customerId": "cust_BqaN6zApXCH",
  "leadId": "lead_4a2da7d271a",
  "unitId": "unit_GfNkzV4itfk",
  "pricingGroupId": "pg_4a2da7d271a"
}

Creates a new note related to a lease, customer, lead, unit, or pricing group.

Required Properties

Tasks

POST /v1/tasks/search

Request Body — tasks/search

{
  "where": {
    "facilityId": "fac_C7bSZyPT6fp",
    "organizationId": "org_4a2da7d271a",
    "unitId": "unit_GfNkzV4itfk",
    "customerId": "cust_BqaN6zApXCH",
    "status": "OPEN",
    "due": true
  },
  "expansions": ["facility", "unit", "tenant"]
}

Response Body — tasks/search

{
  "status": 200,
  "data": {
    "tasks": [
      {
        "id": "task_V4w64pjUwVK",
        "title": "Inspect unit for damage",
        "description": "Check for water damage after recent storm",
        "dueDate": "2026-03-01",
        "status": "OPEN",
        "facilityId": "fac_C7bSZyPT6fp",
        "customerId": "cust_BqaN6zApXCH",
        "unitId": "unit_GfNkzV4itfk"
      },
      {/* ... */}
    ],
    "facilities": [
      {/* ... */}
    ],
    "units": [
      {/* ... */}
    ],
    "customers": [
      {/* ... */}
    ]
  }
}

Search for tasks by facility, organization, unit, customer, status, or due date

Required Properties

At least one of the following:

Optional Properties

Tasks Create

POST /v1/tasks/create

Request Body — tasks/create

{
  "facilityId": "fac_C7bSZyPT6fp",
  "title": "Inspect unit for damage",
  "description": "Check for water damage after recent storm",
  "dueDate": "2026-03-01",
  "customerId": "cust_BqaN6zApXCH",
  "unitId": "unit_GfNkzV4itfk",
  "assignedManagerIds": ["user_4a2da7d271a"]
}

Creates a new task at the specified facility

Required Properties

Optional Properties

Reports

General Ledger Cash Based Report

POST /v1/reports/general-ledger/cash

Request Body — reports/general-ledger/cash

{
  "where": {
    "facilityId": "fac_C7bSZyPT6fp",
    "startDate": "2024-01-01",
    "reportRelativeDuration": "M"
  }
}

Response Body — reports/general-ledger/cash

{
  "status": 200,
  "data": {
    "entries": [
      {
        "id": "je_F7N3jm5F1MU.be_BRGbhSRYecW",
        "journalEntryId": "je_F7N3jm5F1MU",
        "paymentTime": "2025-08-22T04:43:02.56492",
        "entryTime": "2025-08-22T04:45:45.725995",
        "amount": 10000,
        "direction": "CREDIT",
        "account": "PREPAID_RENT",
        "details": {
          "customerId": "cust_FH1Hw36xoLd",
          "customerName": "John Smith",
          "unitName": "A-100",
          "pricingGroupId": "pg_LnKY1qJHmc6"
        }
      },
      {
        "id": "je_F7N3jm5F1MU.be_CmkcJ6Gq16a",
        "journalEntryId": "je_F7N3jm5F1MU",
        "paymentTime": "2025-08-22T04:43:02.56492",
        "entryTime": "2025-08-22T04:45:45.715093",
        "amount": 10000,
        "direction": "DEBIT",
        "account": "DEPOSIT",
        "details": {
          "description": "Security Deposit",
          "customerId": "cust_FH1Hw36xoLd",
          "customerName": "John Smith",
          "unitName": "A-100",
          "pricingGroupId": "pg_LnKY1qJHmc6"
        }
      },
      {
        "id": "je_F7N3jm5F1MU.be_FAK3KdKWWqw",
        "journalEntryId": "je_F7N3jm5F1MU",
        "paymentTime": "2025-08-22T04:43:02.56492",
        "entryTime": "2025-08-22T04:43:02.588516",
        "amount": 25031,
        "direction": "DEBIT",
        "account": "CREDIT_CARD_PAYMENTS",
        "details": {
          "cardType": "visa",
          "cardLastFour": "1111",
          "customerId": "cust_FH1Hw36xoLd",
          "customerName": "John Smith",
          "unitName": "A-100",
          "pricingGroupId": "pg_LnKY1qJHmc6"
        }
      },
      {
        "id": "je_F7N3jm5F1MU.be_LDPdoUPucz8",
        "journalEntryId": "je_F7N3jm5F1MU",
        "paymentTime": "2025-08-22T04:43:02.56492",
        "entryTime": "2025-08-22T04:42:27.975048",
        "amount": 14100,
        "direction": "CREDIT",
        "account": "RENT",
        "details": {
          "customerId": "cust_FH1Hw36xoLd",
          "customerName": "John Smith",
          "unitName": "A-100",
          "pricingGroupId": "pg_LnKY1qJHmc6"
        }
      },
      {
        "id": "je_F7N3jm5F1MU.be_VPKcAEmitNk",
        "journalEntryId": "je_F7N3jm5F1MU",
        "paymentTime": "2025-08-22T04:43:02.56492",
        "entryTime": "2025-08-22T04:42:27.975048",
        "amount": 282,
        "direction": "CREDIT",
        "account": "TAX_STATE",
        "details": {
          "description": "2%",
          "customerId": "cust_FH1Hw36xoLd",
          "customerName": "John Smith",
          "unitName": "A-100",
          "pricingGroupId": "pg_LnKY1qJHmc6"
        }
      },
      {
        "id": "je_F7N3jm5F1MU.be_WLEM365sWGg",
        "journalEntryId": "je_F7N3jm5F1MU",
        "paymentTime": "2025-08-22T04:43:02.56492",
        "entryTime": "2025-08-22T04:42:27.975048",
        "amount": 649,
        "direction": "CREDIT",
        "account": "TAX_LOCAL",
        "details": {
          "description": "4.6%",
          "customerId": "cust_FH1Hw36xoLd",
          "customerName": "John Smith",
          "unitName": "A-100",
          "pricingGroupId": "pg_LnKY1qJHmc6"
        }
      },
      {
        "id": "je_F7N3jm5F1MU.be_NM4tPTmWjcK",
        "journalEntryId": "je_F7N3jm5F1MU",
        "paymentTime": "2025-08-22T04:43:02.56492",
        "entryTime": "2025-08-22T04:42:27.975048",
        "amount": 10000,
        "direction": "CREDIT",
        "account": "DEPOSIT",
        "details": {
          "customerId": "cust_FH1Hw36xoLd",
          "customerName": "John Smith",
          "unitName": "A-100",
          "pricingGroupId": "pg_LnKY1qJHmc6"
        }
      }
    ]
  }
}

Generates a cash basis general ledger report for a facility over a specified time period.

Required Properties

Response Parameters

The response contains an array of journal entries, each of which contains the following fields:

General Ledger Accrual Based Report

POST /v1/reports/general-ledger/accrual

Request Body — reports/general-ledger/accrual

{
  "where": {
    "facilityId": "fac_C7bSZyPT6fp",
    "startDate": "2024-01-01",
    "reportRelativeDuration": "M"
  }
}

Response Body — reports/general-ledger/accrual

{
  "status": 200,
  "data": {
    "entries": [
      {
        "id": "be_NBN5vzcHBv5",
        "journalEntryId": "je_Md6kbRese5r",
        "entryTime": "2024-01-01T00:00:00",
        "facilityId": "fac_JPzPkHHhPcP",
        "facilityName": "Test Facility",
        "customerId": "cust_JZQa2bFkpvW",
        "customerName": "John Smith",
        "unitId": "unit_G77Ba9sR8Cr",
        "unitName": "IPFN723",
        "account": "FEES",
        "mappedGlAccount": "",
        "mappedGlAccountNumber": "",
        "taxExempt": false,
        "taxCategory": "FEE_NON_TAXABLE",
        "explanation": "Move-In Fee $25.0",
        "debit": 0,
        "credit": 2500
      },
      {
        "id": "be_PSwhQQa9UVC",
        "journalEntryId": "je_Md6kbRese5r",
        "entryTime": "2024-01-01T00:00:00",
        "facilityId": "fac_JPzPkHHhPcP",
        "facilityName": "Test Facility",
        "customerId": "cust_JZQa2bFkpvW",
        "customerName": "John Smith",
        "unitId": "unit_G77Ba9sR8Cr",
        "unitName": "IPFN723",
        "account": "ACCOUNT_RECEIVABLE",
        "mappedGlAccount": "",
        "mappedGlAccountNumber": "",
        "taxExempt": false,
        "taxCategory": "FEE_NON_TAXABLE",
        "explanation": "Move-In Fee $25.0",
        "debit": 2500,
        "credit": 0
      },
      {
        "id": "be_Pjn1cAekzuA",
        "journalEntryId": "je_Md6kbRese5r",
        "entryTime": "2024-01-01T00:00:00",
        "facilityId": "fac_JPzPkHHhPcP",
        "facilityName": "Test Facility",
        "customerId": "cust_JZQa2bFkpvW",
        "customerName": "John Smith",
        "unitId": "unit_G77Ba9sR8Cr",
        "unitName": "IPFN723",
        "account": "DEPOSIT",
        "mappedGlAccount": "",
        "mappedGlAccountNumber": "",
        "taxExempt": false,
        "taxCategory": "DEPOSIT",
        "explanation": "Security Deposit",
        "debit": 0,
        "credit": 20000
      },
      {
        "id": "be_Rqop5WxWs4L",
        "journalEntryId": "je_Md6kbRese5r",
        "entryTime": "2024-01-01T00:00:00",
        "facilityId": "fac_JPzPkHHhPcP",
        "facilityName": "Test Facility",
        "customerId": "cust_JZQa2bFkpvW",
        "customerName": "John Smith",
        "unitId": "unit_G77Ba9sR8Cr",
        "unitName": "IPFN723",
        "account": "ACCOUNT_RECEIVABLE",
        "mappedGlAccount": "",
        "mappedGlAccountNumber": "",
        "taxExempt": false,
        "taxCategory": "DEPOSIT",
        "explanation": "Security Deposit",
        "debit": 20000,
        "credit": 0
      },
      {
        "id": "be_FWuEeHyLSz6",
        "journalEntryId": "je_Md6kbRese5r",
        "entryTime": "2024-01-01T00:00:00",
        "facilityId": "fac_JPzPkHHhPcP",
        "facilityName": "Test Facility",
        "customerId": "cust_JZQa2bFkpvW",
        "customerName": "John Smith",
        "unitId": "unit_G77Ba9sR8Cr",
        "unitName": "IPFN723",
        "accruesOn": "2024-01-01",
        "accruesThrough": "2024-01-31",
        "account": "RENT",
        "mappedGlAccount": "",
        "mappedGlAccountNumber": "",
        "taxExempt": false,
        "taxCategory": "RENT_ENCLOSED_STORAGE",
        "explanation": "Rent",
        "debit": 0,
        "credit": 12500
      },
      {
        "id": "be_AkGodRDQcfo",
        "journalEntryId": "je_Md6kbRese5r",
        "entryTime": "2024-01-01T00:00:00",
        "facilityId": "fac_JPzPkHHhPcP",
        "facilityName": "Test Facility",
        "customerId": "cust_JZQa2bFkpvW",
        "customerName": "John Smith",
        "unitId": "unit_G77Ba9sR8Cr",
        "unitName": "IPFN723",
        "accruesOn": "2024-01-01",
        "accruesThrough": "2024-01-31",
        "account": "ACCOUNT_RECEIVABLE",
        "mappedGlAccount": "",
        "mappedGlAccountNumber": "",
        "taxExempt": false,
        "taxCategory": "RENT_ENCLOSED_STORAGE",
        "explanation": "Rent",
        "debit": 12500,
        "credit": 0
      },
      {
        "id": "be_GHQvBnczPcK",
        "journalEntryId": "je_Md6kbRese5r",
        "entryTime": "2024-01-01T00:00:00",
        "facilityId": "fac_JPzPkHHhPcP",
        "facilityName": "Test Facility",
        "customerId": "cust_JZQa2bFkpvW",
        "customerName": "John Smith",
        "unitId": "unit_G77Ba9sR8Cr",
        "unitName": "IPFN723",
        "accruesOn": "2024-01-01",
        "accruesThrough": "2024-01-31",
        "account": "TAX_STATE",
        "mappedGlAccount": "",
        "mappedGlAccountNumber": "",
        "taxExempt": false,
        "taxCategory": "RENT_ENCLOSED_STORAGE",
        "explanation": "4.5%",
        "debit": 0,
        "credit": 563
      },
      {
        "id": "be_NRD5PG38VXi",
        "journalEntryId": "je_Md6kbRese5r",
        "entryTime": "2024-01-01T00:00:00",
        "facilityId": "fac_JPzPkHHhPcP",
        "facilityName": "Test Facility",
        "customerId": "cust_JZQa2bFkpvW",
        "customerName": "John Smith",
        "unitId": "unit_G77Ba9sR8Cr",
        "unitName": "IPFN723",
        "accruesOn": "2024-01-01",
        "accruesThrough": "2024-01-31",
        "account": "ACCOUNT_RECEIVABLE",
        "mappedGlAccount": "",
        "mappedGlAccountNumber": "",
        "taxExempt": false,
        "taxCategory": "RENT_ENCLOSED_STORAGE",
        "explanation": "4.5%",
        "debit": 563,
        "credit": 0
      },
      {
        "id": "be_BZyw4u5k3Qi",
        "journalEntryId": "je_Md6kbRese5r",
        "entryTime": "2024-01-01T00:00:00",
        "facilityId": "fac_JPzPkHHhPcP",
        "facilityName": "Test Facility",
        "customerId": "cust_JZQa2bFkpvW",
        "customerName": "John Smith",
        "unitId": "unit_G77Ba9sR8Cr",
        "unitName": "IPFN723",
        "accruesOn": "2024-01-01",
        "accruesThrough": "2024-01-31",
        "account": "TAX_LOCAL",
        "mappedGlAccount": "",
        "mappedGlAccountNumber": "",
        "taxExempt": false,
        "taxCategory": "RENT_ENCLOSED_STORAGE",
        "explanation": "0.5%",
        "debit": 0,
        "credit": 63
      },
      {
        "id": "be_KF1TCs8NTPz",
        "journalEntryId": "je_Md6kbRese5r",
        "entryTime": "2024-01-01T00:00:00",
        "facilityId": "fac_JPzPkHHhPcP",
        "facilityName": "Test Facility",
        "customerId": "cust_JZQa2bFkpvW",
        "customerName": "John Smith",
        "unitId": "unit_G77Ba9sR8Cr",
        "unitName": "IPFN723",
        "accruesOn": "2024-01-01",
        "accruesThrough": "2024-01-31",
        "account": "ACCOUNT_RECEIVABLE",
        "mappedGlAccount": "",
        "mappedGlAccountNumber": "",
        "taxExempt": false,
        "taxCategory": "RENT_ENCLOSED_STORAGE",
        "explanation": "0.5%",
        "debit": 63,
        "credit": 0
      }
    ]
  }
}

Generates an accrual basis general ledger report for a facility over a specified time period.

Required Properties

Response Parameters

The response contains an array of journal entry line items, each of which contains the following fields:

Aged Receivables Report

POST /v1/reports/aged-receivables

throughDate is optional and defaults to the facility's current date. When provided, aging buckets are computed as of the end of that date.

Request Body — reports/aged-receivables

{
  "where": {
    "facilityIds": [
      "fac_C7bSZyPT6fp"
    ],
    "throughDate": "2024-08-31"
  }
}

Response Body — reports/aged-receivables

{
  "status": 200,
  "data": {
    "entries": [
      {
        "facilityId": "fac_Qi19JvKQBgu",
        "facilityName": "Test Facility",
        "leaseId": "lease_XQ1zDzcYdfs",
        "unitId": "unit_GHrAvzbKK7K",
        "unitName": "SZEF563",
        "pricingGroupId": "pg_HtikzP9RB3Y",
        "pricingGroupName": "5x5 with AC",
        "customerId": "cust_P4Cecw1xuQE",
        "customerName": "John Smith",
        "totalAmount": 48752,
        "ranges": [
          {
            "range": "RANGE_0_30",
            "amount": 13126
          },
          {
            "range": "RANGE_30_60",
            "amount": 35626
          },
          {
            "range": "RANGE_60_90",
            "amount": 0
          },
          {
            "range": "RANGE_90_120",
            "amount": 0
          },
          {
            "range": "RANGE_120_PLUS",
            "amount": 0
          },
          {
            "range": "RANGE_UNKNOWN",
            "amount": 0
          }
        ]
      }
    ]
  }
}

Generates an aged receivables report for one or more facilities.

Required Properties

Response Parameters

The response contains an array of aged receivable entries, one for each lease with an outstanding balance, each of which contains the following fields:

Rent Roll Report

POST /v1/reports/rent-roll

Request Body — reports/rent-roll

{
  "where": {
    "facilityIds": [
      "fac_C7bSZyPT6fp"
    ],
    "throughDate": "2024-08-31"
  }
}

Response Body — reports/rent-roll

{
  "status": 200,
  "data": {
    "entries": [
      {
        "facilityId": "fac_Qi19JvKQBgu",
        "facilityName": "Test Facility",
        "status": "RENTED",
        "unitId": "unit_GHrAvzbKK7K",
        "unitName": "SZEF563",
        "pricingGroupId": "pg_HtikzP9RB3Y",
        "pricingGroupName": "5x5 with AC",
        "width": 5.0,
        "depth": 5.0,
        "height": 8.0,
        "standardRate": 5000,
        "customerId": "cust_P4Cecw1xuQE",
        "customerName": "John Smith",
        "companyName": "Acme Corp",
        "contact": {
          "address": "2055 Earnest Mountain",
          "address2": "Apt. 805",
          "city": "Johnston",
          "state": "Minnesota",
          "country": "USA",
          "zip": "15219",
          "email": "john.smith@example.org"
        },
        "totalDue": 7500,
        "deposit": 5000,
        "prepaid": 2000,
        "credit": 0,
        "monthlyRentalAmount": 6000,
        "effectiveRate": 5500,
        "rentVarianceAmount": -1000,
        "lastRentChangeDate": "2024-03-01",
        "rentChangeScheduledDate": "2024-09-01",
        "rentChangeNewRentAmount": 6500,
        "billingCycle": "MONTHLY",
        "moveInDate": "2024-01-15",
        "paidOnDate": "2024-07-15",
        "paidThroughDate": "2024-08-14",
        "billingDayOfMonth": 15,
        "taxExempt": false,
        "paid": true,
        "autoPayEnabled": true,
        "autoPayPaymentMethodId": "pm_1GqIC8HYgolSBA35XqL5a2M",
        "overlockNeeded": false,
        "overlockApplied": false
      }
    ]
  }
}

Generates a rent roll report for one or more facilities.

Required Properties

Response Parameters

The response contains an array of rent roll entries, one for each unit, each of which contains the following fields:

Not applicable fields might be omitted or set to null.

Merchant Services Disbursements Report

POST /v1/reports/merchant-services-disbursements

Request Body — reports/merchant-services-disbursements

{
  "where": {
    "facilityIds": [
      "fac_C7bSZyPT6fp"
    ],
    "startDate": "2024-08-01",
    "reportRelativeDuration": "M"
  }
}

Response Body — reports/merchant-services-disbursements

{
  "status": 200,
  "data": {
    "batches": [
      {
        "facilityId": "fac_C7bSZyPT6fp",
        "facilityName": "Test Facility",
        "paymentProvider": "STRIPE",
        "merchantId": "acct_1234567890",
        "batchDate": "2024-08-15",
        "batchNumber": "po_1ABC2DEF3GHI",
        "batchStatus": "paid",
        "methodType": "card",
        "amount": 1250
      }
    ],
    "transactions": [
      {
        "facilityId": "fac_C7bSZyPT6fp",
        "facilityName": "Test Facility",
        "paymentProvider": "STRIPE",
        "batchNumber": "po_1ABC2DEF3GHI",
        "batchDate": "2024-08-15",
        "paymentId": "pay_Ab3xK9mR2wq",
        "transactionId": "txn_9876543210",
        "date": "2024-08-14",
        "amount": 1250,
        "status": "APPROVED",
        "type": "SALE",
        "customerId": "con_7dF2kL9pQx",
        "customerName": "John Smith",
        "methodType": "CREDIT_CARD",
        "cardBrand": "VISA",
        "lastFour": "1234"
      }
    ]
  }
}

Generates a merchant services disbursements report for one or more facilities over a specified time period. The report includes batch-level settlement summaries and individual transaction details from configured payment providers (Stripe, Payabli).

Required Properties

Response Parameters

The response contains two arrays: batches and transactions. Fields that are not applicable are omitted from the response.

Batches

Each batch entry represents a settlement batch from a payment provider:

Transactions

Each transaction entry represents an individual payment within a batch:

Storefront

POST /v1/storefront/facilities/search

Request Body — storefront/facilities/search

{
  "where": {
    "facilityId": "fac_C7bSZyPT6fp",
    "organizationId": "org_4a2da7d271a"
  },
  "expansions": ["organization", "schedules"]
}

Response Body — storefront/facilities/search

{
  "status": 200,
  "data": {
    "facilities": [
      {
        "facilityId": "fac_C7bSZyPT6fp",
        "organizationId": "org_4a2da7d271a",
        "name": "315 Anisha Estates",
        "description": "Climate-controlled self storage in downtown.",
        "slug": "anisha-estates",
        "apiKey": "b73c7e4d-81f2-49e3-bbca-9a6fbd321d56",
        "contact": {
          "address": "315 Anisha Estates",
          "address2": "",
          "city": "Thompsonview",
          "state": "Alaska",
          "country": "USA",
          "zip": "98748",
          "email": "",
          "phone": ""
        },
        "latitude": "37.774929",
        "longitude": "-122.419418",
        "schedules": [{/* ... */}]
      },
      {/* ... */}
    ],
    "organizations": [
      {
        "organizationId": "org_4a2da7d271a",
        "name": "Anisha Estates"
      },
      {/* ... */}
    ]
  }
}

Search for storefront-visible facilities by facility or organization

Required Properties

Optional Properties

POST /v1/storefront/pricing-groups/search

Request Body — storefront/pricing-groups/search

{
  "where": {
    "pricingGroupId": "pg_4a2da7d271a",
    "facilityId": "fac_C7bSZyPT6fp"
  },
  "expansions": ["discounts"]
}

Response Body — storefront/pricing-groups/search

{
  "status": 200,
  "data": {
    "pricingGroups": [
      {
        "pricingGroupId": "pg_4a2da7d271a",
        "name": "Standard",
        "description": "10x20 climate-controlled",
        "priceDescription": "$220/mo",
        "width": 10,
        "depth": 20,
        "height": 8,
        "price": 22000,
        "strikethroughPrice": 25000,
        "images": ["https://example.com/unit.jpg"],
        "features": ["Climate controlled", "Ground floor"],
        "discounts": ["discount_JgNkzV4itfk"],
        "parking": false,
        "vehicleStorage": false
      },
      {/* ... */}
    ],
    "discounts": [
      {
        "discountId": "discount_JgNkzV4itfk",
        "name": "First Month Free",
        "type": "PERPETUAL | PERIODIC | PAID_UPFRONT | ONE_TIME",
        "status": "PUBLISHED | ARCHIVED"
      },
      {/* ... */}
    ]
  }
}

Search for storefront-visible pricing groups by facility or pricing group ID

Required Properties

Optional Properties

Response Parameters

Messages

Send SMS

POST /v1/messages/sms/send

Request Body — messages/sms/send

{
  "customerId": "cust_BqaN6zApXCH",
  "facilityId": "fac_C7bSZyPT6fp",
  "body": "Your payment is due tomorrow."
}

Sends an SMS message to a customer

Required Properties

Send Email

POST /v1/messages/email/send

Sends an email message to a customer. Unlike the other endpoints in this API, this one is sent as multipart/form-data so that file attachments can be included alongside the JSON request.

The request must include the following parts:

Part name Content Required
request A JSON object with the fields described under Required Properties below. The part must be sent with Content-Type: application/json. Yes
attachments A file to attach to the email. Repeat the part name for multiple attachments. Maximum of 5 attachments, each up to 5 MB. No

JSON body of the request part

{
  "customerId": "cust_BqaN6zApXCH",
  "facilityId": "fac_C7bSZyPT6fp",
  "subject": "Payment Due Reminder",
  "body": "<p>Your payment is due tomorrow.</p>"
}

Example: send an email with no attachments

curl -X POST 'https://api.cubbystorage.com/v1/messages/email/send' \
  --header 'Authorization: Bearer b73c7e4d-81f2-49e3-bbca-9a6fbd321d56' \
  --form 'request={
      "customerId": "cust_BqaN6zApXCH",
      "facilityId": "fac_C7bSZyPT6fp",
      "subject": "Payment Due Reminder",
      "body": "<p>Your payment is due tomorrow.</p>"
    };type=application/json'

Example: send an email with two attachments

curl -X POST 'https://api.cubbystorage.com/v1/messages/email/send' \
  --header 'Authorization: Bearer b73c7e4d-81f2-49e3-bbca-9a6fbd321d56' \
  --form 'request={
      "customerId": "cust_BqaN6zApXCH",
      "facilityId": "fac_C7bSZyPT6fp",
      "subject": "Payment Due Reminder",
      "body": "<p>Your payment is due tomorrow.</p>"
    };type=application/json' \
  --form 'attachments=@invoice.pdf' \
  --form 'attachments=@receipt.pdf'

Required Properties

The following fields belong inside the JSON request part:

Checkout

Checkout Component

The Cubby Checkout is an embeddable web component that provides a complete checkout flow for your storefront. It can be embedded on any page by including the storefront components script and placing the <cubby-checkout> element in your HTML.

Setup

Include the Script

<script
    type="module"
    src="https://cdn.cubbystorage.com/components/latest"
    data-api-key="your-storefront-api-key">
</script>

Include the storefront components script on your page. The API key is passed via the data-api-key attribute on the script tag. This is the same API key used for the Storefront API endpoints above.

Usage

Basic Checkout

<cubby-checkout
    pricing-groups="pg_4a2da7d271a">
</cubby-checkout>

Pre-populated Customer Data

<cubby-checkout
    pricing-groups="pg_4a2da7d271a"
    customer-name="Jane Smith"
    customer-email="jane@example.com"
    customer-phone="+15551234567">
</cubby-checkout>

Place the <cubby-checkout> element wherever the checkout flow should appear. The pricing-groups attribute is required and accepts a single pricing group ID as returned by the Storefront Pricing Groups Search endpoint. Only one pricing group is supported at this time.

Attributes

Attribute Type Required Description
pricing-groups string Yes The ID of the pricing group to display
customer-name string No Pre-populates the customer name field
customer-email string No Pre-populates the customer email field
customer-phone string No Pre-populates the customer phone field