Skip to content
Dashboard

Properties

A property is one rental unit. Its record holds the unit’s details, door-code and guest-portal settings, and four operational status tracks: readiness, cleaning, inspection and maintenance. This guide covers the property operations most integrations need. Every field and filter is listed on the operation’s page in the API Reference.

OperationRequestPermission
listPropertiesGET /propertiesview_properties
getPropertyGET /properties/{id}view_properties
updatePropertyPATCH /properties/{id}modify_properties
updatePropertyStatusPOST /properties/{id}/statusmodify_properties
assignPortalToPropertyPOST /properties/{propertyId}/assign-portalmodify_properties
listPropertyTagsGET /properties/{propertyId}/tagsview_properties
listUpsellsByPropertyGET /properties/{propertyId}/upsellsview_properties
listPortalManualsByPropertyGET /properties/{propertyId}/portal-manualsview_guides
setPropertyDefaultPaymentAccountPOST /properties/{id}/default-payment-accountmodify_properties and manage_payments

Paths are relative to your region’s base URL, for example https://api-us.suiteop.com/api/v1. See Authentication for permissions. Properties can’t be created or deleted through the API.

GET /properties is paginated (default limit 50, maximum 500). Rows are ordered by the unit’s nickname, or its name where it has no nickname.

Terminal window
curl "https://api-us.suiteop.com/api/v1/properties?cleaningStatuses=dirty&readinessStatuses=not_ready&limit=100" \
-H "Authorization: Bearer sk_live_your_key_here"

Filters combine with AND. Each status filter matches any of the values you give; repeat the key for several values.

FilterNotes
readinessStatusesready, not_ready, occupied, unknown. Derived from the other three tracks plus whether a guest is checked in
cleaningStatusesclean, dirty, unknown. occupied is deprecated and only matches legacy rows
inspectionStatusesinspected, not_inspected, failed_inspection, inspection_waived
maintenanceStatusesnormal, attention_needed, blocked. Derived from open maintenance tasks
nameContainsCase- and accent-insensitive match on name, nickname, city or state. Matched literally: % and _ are not wildcards
propertyGroupIdOnly properties in this group. ungroupedOnly=true keeps only ungrouped ones, and is ignored when propertyGroupId is set
excludePropertyGroupIdDrops properties already in this group, keeping ungrouped ones
propertyIds, tagIdsRestrict to these IDs, or to properties carrying at least one of these tags (listTags)
includeDisabledDisabled properties are hidden by default
archivedOnlyReturns only archived properties, those deleted in the dashboard. No single call returns archived and live properties together

Each row carries fields such as id, name, nickname, unitNumber, city, state, countryCode, bedroomCount, bathroomCount, maxGuests, propertyGroupId, ownerId, portalSettingsId, isDisabled and the four status fields.

GET /properties/{id} returns the record, including the address, timezone, default check-in and check-out hours, wifiName, codeDisplay, the guest-portal flags and internalAccessNotes. A property outside the caller’s reach returns 404.

Secrets are write-only. wifiPassword, codeEntryKey, codeValidationKey, groupCodeEntryKey and groupCodeValidationKey can be set with updateProperty but no operation returns them.

GET /properties/{id} also does not return these writable fields: description, houseRules, checkInDescription, customAddress, addressOverride, isUnitCodeDisabled, isWifiHidden, defaultCheckInMinute and defaultCheckOutMinute. Keep your own copy if you need to read them back.

PATCH /properties/{id} takes the fields to change inside a data object. Fields you leave out keep their current value; most nullable fields take null to clear them.

Terminal window
curl -X PATCH https://api-us.suiteop.com/api/v1/properties/9a3d7e40-… \
-H "Authorization: Bearer sk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"data": {"wifiName": "Loft-Guest", "wifiPassword": "sunny-2026", "maxGuests": 4}}'

The response is the updated property, without the secrets.

Field notes:

  • Guest texts: description, houseRules and checkInDescription take plain English text. It overwrites the English copy, and the organization’s other languages then follow from it. Only checkInDescription has a length limit, 150 characters. The response returns descriptionId, houseRulesId and checkInDescriptionId, translation IDs rather than text. Resending the stored text or an empty string changes nothing; to clear one, set its …Id field to null.

  • Shared guest texts: several properties can point at the same text record, for example units set up as copies of one another. Writing houseRules, checkInDescription or description edits that record in place, so it changes the text for every property sharing it. getProperty returns houseRulesSharedWithCount, checkInDescriptionSharedWithCount and descriptionSharedWithCount: how many other properties share each record (0 when it’s this unit’s own or unset). To give this unit its own copy, first send the …Id field as null in one call, then send the text in a second call.

  • holdAccessUntilPmsPaid: true holds the guest’s check-in instructions, door codes and device controls until the PMS reports the reservation fully paid. Only an explicit unpaid report from the PMS holds a stay, and the hold applies to verified guests too. It never holds a stay the PMS has once reported fully paid, even if a balance appears later, nor one whose guest has arrived: checked in by staff or the PMS, or a successful door unlock attributed to that stay alone. A check-in set through the guest portal or a workflow does not count. The flag has an effect only once SuiteOp staff turn on the organization’s PMS-paid hold feature, which is off by default; until then it is saved but ignored.

  • propertyGroupId moves the unit to another group, or ungroups it with null. If the unit has no default payment account of its own, it collects payments through its group’s, so a move that changes which account collects them also needs manage_payments. Without it the request returns 403 and nothing moves. Someone with manage_payments can first set the unit’s own default payment account so the move doesn’t change it.

  • ownerId links the unit to one of the organization’s owner records, and null unassigns it. Owners are managed in the app; the API can’t list or create them.

  • isUnitCodeDisabled: true revokes the unit door code, not just hides it. Managed codes on the unit’s lock are retired and a delete is requested, including for guests mid-stay, though some codes can survive. The building code is unaffected. Set it back to false to resume.

  • Clearing the address: streetAddress, city, state, postalCode, countryCode and formattedAddress each take null to clear them. Guest surfaces fall back to formattedAddress when the structured fields are incomplete, so to wipe an address completely, send null for formattedAddress and every structured field (and latitude and longitude to drop the map pin, which leaves the timezone as it is). An empty string for formattedAddress is stored as entered, not treated as a clear.

    {
    "data": {
    "streetAddress": null,
    "city": null,
    "state": null,
    "postalCode": null,
    "countryCode": null,
    "formattedAddress": null,
    "latitude": null,
    "longitude": null
    }
    }
  • groupCheckInDescriptionOverrideId links the unit’s own building check-in summary, shown to guests instead of its group’s while isCodeOverrideFixed is true. Like the other …Id fields it’s the ID of an existing translation record, not text; read the text with getTranslationEntries (see Translations). If that record is empty, guests see the group’s summary. null unlinks it. getProperty and the update response return it.

  • customAddress is the address shown to guests on the portal and in automated email instead of the real one. addressOverride is not an address: it’s an https URL that replaces the map link behind the address.

  • timezone is re-resolved from the coordinates when you send both latitude and longitude without a timezone.

  • coverImageUrl: replacing or clearing it deletes the previously stored file.

  • reviewRequestOverrides replaces the whole per-channel map with what you send.

  • orderTasksByElements: true orders the unit’s task checklists by its element order (each area, then its items) instead of the task template’s section order. A change re-orders the unit’s tasks that haven’t started and hold no recorded work.

  • Operational status and the assigned portal can’t be changed here. Use updatePropertyStatus and assignPortalToProperty.

POST /properties/{id}/status sets one of the two declarable tracks. field, value and trigger are required:

Terminal window
curl -X POST https://api-us.suiteop.com/api/v1/properties/9a3d7e40-…/status \
-H "Authorization: Bearer sk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"field": "cleaningStatus", "value": "clean", "trigger": "cleaning_declared"}'
  • field is cleaningStatus (values clean, dirty, unknown) or inspectionStatus (values inspected, not_inspected, failed_inspection, inspection_waived). A value from the other field’s set is rejected.
  • Either write recomputes readiness. Sending the current value writes nothing.
  • trigger records why the status changed; it doesn’t perform the named action. Use cleaning_declared or inspection_declared for an outcome a person declared. With checkout or reservation_cancelled, the write is skipped while another guest is still checked in. Pass reservationId to exclude that stay from the check.
  • Maintenance and readiness can’t be set: a field of maintenanceStatus or readinessStatus is rejected with 400 validation_error rather than saved. Maintenance follows open maintenance tasks, and readiness follows reservations and these writes.

The response is the full property, not the status change.

POST /properties/{propertyId}/assign-portal puts an existing guest portal on one property:

Terminal window
curl -X POST https://api-us.suiteop.com/api/v1/properties/9a3d7e40-…/assign-portal \
-H "Authorization: Bearer sk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"portalSettingsId": "c41e…"}'

portalSettingsId is the id returned by listPortals. Pass null to leave the property without a portal. The portal must belong to your organization. An OAuth token limited to some properties can only assign a portal it can already see, the organization’s default portal, or a portal serving no property; anything else returns 403.

Three reads resolve what is attached to one property. None is paginated.

  • GET /properties/{propertyId}/tags returns the property’s tags as id and title. Use listTags for every tag in the organization.
  • GET /properties/{propertyId}/upsells returns the upsells that reach the property directly, through its group, through its guest portal or through a tag, deduplicated. assignmentLevel says which route applied. Archived upsells are left out. Titles aren’t included; call getUpsell for those.
  • GET /properties/{propertyId}/portal-manuals needs view_guides. It returns the house manuals assigned directly, through the group or through a tag, including inactive ones and without applying visibility rules, so it’s a superset of what a guest sees.

For a property outside your reach, the upsell and manual lists come back empty rather than as a 404.

A guest charge that doesn’t name its own payment account, such as an upsell or a pre-check-in fee, waiver or deposit with no account pinned, is charged through the first of these that is set:

  1. the property’s default payment account,
  2. its property group’s default,
  3. the organization’s active default account.

POST /properties/{id}/default-payment-account sets the property’s default. It needs both modify_properties and manage_payments:

Terminal window
curl -X POST https://api-us.suiteop.com/api/v1/properties/9a3d7e40-5b6c-4d7e-8f90-1a2b3c4d5e6f/default-payment-account \
-H "Authorization: Bearer sk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"paymentAccountId": "3f2b7a10-5c4d-4e8f-9a1b-6c2d3e4f5a60"}'
{
"data": {
"id": "9a3d7e40-5b6c-4d7e-8f90-1a2b3c4d5e6f",
"defaultPaymentAccountId": "3f2b7a10-5c4d-4e8f-9a1b-6c2d3e4f5a60"
},
"meta": { "requestId": "…" }
}
  • paymentAccountId is required. Use an id from listPaymentAccounts. An inactive account, or one from another organization, returns 404 not_found_error. So does a property outside your reach.
  • null clears the default, and the property inherits its group’s or the organization’s again. A clear succeeds even when nothing is left to inherit. It is refused with 400 validation_error only when it would leave an active Screen & Protect check that charges a damage waiver with no account to charge.
  • getProperty returns defaultPaymentAccountId: the property’s own setting, not the account that applies. null means it inherits.
  • A default whose account stops taking money doesn’t fall through. If the account is switched off in the SuiteOp app, every property and group default pointing at it is cleared, so they inherit again. If it goes inactive any other way, for example when the provider disconnects it, charges that resolve to it are blocked until you set another default.