Skip to content
Dashboard

Organization and lookups

These read-only operations give you values that other operations need: your organization’s temperature unit, the payment accounts a paid upsell can charge against, the tag IDs that filters and scopes take, and the icon names and stock photos a cover can use. None of them changes anything. Every field is listed on the operation’s page in the API Reference.

OperationRequestPermission
getOrganizationGET /organizationview_organization
listPaymentAccountsGET /payment-accountsview_payments
listTagsGET /tagsview_properties
listPropertyTagsGET /properties/{propertyId}/tagsview_properties
searchCoverIconsGET /cover-iconsNone
searchStockPhotosGET /stock-photosNone

Paths are relative to your region’s base URL, for example https://api-us.suiteop.com/api/v1. See Authentication for permissions. All six are also tools on the MCP server, under the same names.

GET /organization returns the organization your credential acts in. It takes no ID and no parameters, and it can’t reach another organization.

Terminal window
curl https://api-us.suiteop.com/api/v1/organization \
-H "Authorization: Bearer sk_live_your_key_here"
{
"data": {
"id": "9e4b1c27-3f8a-4d6e-b2c5-7a0f1e9d3b84",
"name": "Riva Stays",
"slug": "riva-stays",
"timezone": "Europe/Paris",
"region": "eu",
"temperatureUnit": "celsius",
"createdAt": "2024-02-11T08:15:42.000Z"
},
"meta": { "requestId": "3f1c9a52-…" }
}
  • temperatureUnit is celsius or fahrenheit, and defaults to fahrenheit. setDeviceTemperature reads every number you send in this unit, and no other operation returns it.
  • timezone is an IANA name such as Europe/Paris, or null when the organization has none set. It isn’t the timezone a unit runs on: timezones and check-in hours are set per property, so read them with getProperty.
  • region is the data-residency region: us, eu or apac. It is fixed when the organization is created and matches the base URL you call.

Billing, branding, check-in and door-code settings aren’t returned, and nothing on the organization can be changed through the API.

GET /payment-accounts lists the processor accounts your organization can charge guests against. It takes no parameters and is not paginated or sorted. Inactive accounts are included.

Terminal window
curl https://api-us.suiteop.com/api/v1/payment-accounts \
-H "Authorization: Bearer sk_live_your_key_here"
{
"data": [
{
"id": "3f2b7a10-5c4d-4e8f-9a1b-6c2d3e4f5a60",
"nickname": "Riva EUR",
"provider": "stripe",
"currencyCode": "eur",
"isActive": true
},
{
"id": "7a1c9e42-0b3d-4f6a-8e2c-5d9b1f7a3c08",
"nickname": "Old USD account",
"provider": "guesty_pay",
"currencyCode": "usd",
"isActive": false
}
],
"meta": { "requestId": "3f1c9a52-…" }
}
  • provider is currently stripe, guesty_pay or juspay.
  • currencyCode is the currency the account settles in, as a lowercase code such as usd or eur. Match it to the price you set.
  • isActive tells you whether the account can still take money. Only pin an active one.
  • Which account is the organization’s default isn’t returned. To use the default, leave paymentAccountId out of the upsell.

Accounts are connected by an operator in the SuiteOp app, never through the API. Use an account’s id as paymentAccountId on upsells, and for the waiver, deposit and fee fields of a pre-check-in step, where an unknown, inactive or other-organization ID returns 404.

A tag is a free-form label an operator puts on properties, such as “Beachfront”. Tags belong to the organization, not to one property. Tag IDs are what listProperties and listPrecheckSteps filter on with tagIds, and what the entity-scope operations take to reach every property carrying a tag. listTags is the only way to list every tag; listPropertyTags gives the tags on one property.

Tags can’t be created, renamed, deleted or attached to a property through the API. To scope an upsell, manual, step or portal to a tag, see Entity scopes.

GET /tags is paginated, but with its own defaults: limit is 1 to 500 and defaults to 100, and offset defaults to 0. Rows are ordered by title, with the ID breaking ties so paging is stable. Deleted tags are left out, and so is their count in total.

Terminal window
curl "https://api-us.suiteop.com/api/v1/tags?nameContains=beach&limit=50" \
-H "Authorization: Bearer sk_live_your_key_here"
{
"data": [
{
"id": "c8e2f1a4-6b3d-4e9a-8f2c-1d7b5a9e3c60",
"title": "Beachfront",
"createdAt": "2025-05-02T13:20:08.000Z",
"updatedAt": "2025-05-02T13:20:08.000Z"
}
],
"meta": {
"requestId": "3f1c9a52-…",
"pagination": { "total": 1, "limit": 50, "offset": 0 }
}
}
  • nameContains is a case-insensitive substring of the title. % and _ are matched literally, not as wildcards.
  • writableOnly=true keeps only tags whose every property the caller can access, which are the tags the caller can scope an entity to. It changes nothing for an API key.
  • Titles aren’t unique, so two tags can share one. Tell them apart by id.

To read every tag, page until you have total rows:

const base = 'https://api-us.suiteop.com/api/v1'
const headers = { Authorization: 'Bearer sk_live_your_key_here' }
const tags: { id: string; title: string }[] = []
let offset = 0
for (;;) {
const res = await fetch(`${base}/tags?limit=500&offset=${offset}`, { headers })
if (!res.ok) throw new Error(`listTags failed: ${res.status}`)
const { data, meta } = await res.json()
tags.push(...data)
offset += data.length
if (data.length === 0 || offset >= meta.pagination.total) break
}
const beachfront = tags.filter((t) => t.title === 'Beachfront').map((t) => t.id)

GET /properties/{propertyId}/tags returns the tags on one property as id and title, ordered by title. It is a plain array with no paging and no filters. A property with no tags returns [].

Terminal window
curl https://api-us.suiteop.com/api/v1/properties/5d1e8b3a-2c7f-4a9e-b6d0-8f3c1a7e2b94/tags \
-H "Authorization: Bearer sk_live_your_key_here"
{
"data": [
{ "id": "c8e2f1a4-6b3d-4e9a-8f2c-1d7b5a9e3c60", "title": "Beachfront" },
{ "id": "1b7d3e9f-4a2c-4f8e-9d6b-0c5a8e2f7d13", "title": "Pet friendly" }
],
"meta": { "requestId": "3f1c9a52-…" }
}

propertyId must be a UUID, or the request returns 400. A property that doesn’t exist, belongs to another organization or is outside an OAuth user’s access also returns 200 with [], not 404. Check the ID with getProperty if an empty list is surprising.

House manuals and upsells take a cover: an icon name or a photo URL. These two searches supply them. Neither needs a permission, so any valid key can call them, including one that only holds modify_guides.

  • GET /cover-icons searches the icon names iconName accepts. query (up to 64 characters) is trimmed and matched case-insensitively anywhere in the name; omit it to get the start of the catalogue. limit is 1 to 100 (default 25), and total counts every match before the limit. The catalogue is the same for every organization.
  • GET /stock-photos searches Unsplash. query is required (1 to 200 characters), perPage is 1 to 30 (default 20) and page 1 to 100 (default 1). Each item carries imageUrl, thumbnailUrl, description (can be null), photographerName and photographerUrl, with total and totalPages alongside. Save imageUrl as the cover: thumbnailUrl is for previews, and its use isn’t reported to Unsplash. Where stock search isn’t configured, it returns 503.

Both return their results as data.items with data.total (and data.totalPages for photos), not meta.pagination.

How covers are set, with full request and response examples, is in House Manuals and Upsells.

API keys reach every property. An OAuth token acts with its user’s access, so when that user is limited to some properties:

  • getOrganization, listPaymentAccounts, searchCoverIcons and searchStockPhotos behave as they do for an API key.
  • listTags still returns every tag in the organization unless you pass writableOnly=true.
  • listPropertyTags returns [] for a property the user can’t access.