Authentication
All requests to the SuiteOp API authenticate with a Bearer token in the Authorization header. There are two kinds of token:
- API keys (
sk_live_…) — long-lived machine credentials that act as a member of your organization. This page covers these. - OAuth 2.1 access tokens — tokens an app or AI assistant obtains after a person authorizes it. Use these when an application acts on a specific user’s behalf. See OAuth 2.1 user-delegated access.
Both are presented the same way — as a Bearer token — and both work on the REST API and the MCP server. A token that starts with sk_ is treated as an API key; anything else is treated as an OAuth access token.
Key Format
Section titled “Key Format”Authorization: Bearer sk_live_your_key_hereThe Bearer scheme is case-insensitive.
Key Anatomy
Section titled “Key Anatomy”| Part | Example | Meaning |
|---|---|---|
| Prefix | sk_ | Always present on API keys |
| Environment | live_ | The SuiteOp environment that issued the key |
| Secret | abc123… | 48 random URL-safe base64 characters (A–Z a–z 0–9 - _) |
sk_live_keys are issued by, and the only keys accepted by, the production API. Every key you create in the SuiteOp dashboard is ansk_live_key and reaches your organization’s real data. Keep it out of source control and client-side code.sk_test_keys exist only on SuiteOp’s internal non-production servers. There is no customer sandbox, and the production base URLs reject ansk_test_key with401: This server only accepts sk_live_ API keys — check your organization’s regional base URL and environment.
Scopes
Section titled “Scopes”Each key is issued with a set of permissions, and the permission names are the scopes. They are the same permissions an organization role grants in the dashboard, written in snake_case: reading tasks needs view_tasks, not tasks:read.
- A key must carry at least one permission.
- You can only give a key permissions you hold yourself.
- Permissions are fixed once the key exists. You can rename a key, but to change its permissions you revoke it and create a new one.
- A request for an operation whose permission the key lacks returns
403 authorization_errorwith the codeFORBIDDENand a message naming the missing permission, for exampleMissing permission: view_tasks. - An operation can require more than one permission.
createUpsell, for example, needs bothmodify_guidesandmodify_properties. Some filters also need an extra permission. TheincludeCancelled,includeTriageandincludeDeletedfilters onlistTasksalso requiremodify_tasks. - An API key sees every property in the organization. An OAuth token is limited to the properties the authorizing user can reach.
OAuth clients request these same permission names as OAuth scopes, plus the standard openid, profile, email and offline_access. See OAuth 2.1.
Scope reference
Section titled “Scope reference”All 55 permissions, grouped as the dashboard’s permission editor groups them. The right-hand column lists the public operations (by operation ID, as shown in the API Reference) that each permission unlocks. Permissions marked none gate no public operation today. They are accepted when you create a key but only matter inside the SuiteOp apps.
| Area | Permission | Public operations it unlocks |
|---|---|---|
| Dashboard | view_dashboard | search |
| Tasks | view_tasks | listDepartments, listTasks, getTask, listTaskRequirements, listAnswerLists |
| Tasks | modify_tasks | createDepartment, updateDepartment, createTask, updateTask, updateTaskStatus, applyTemplateToTask, addTaskRequirement, updateTaskRequirement, createTranslation, createAnswerList, updateAnswerList, archiveAnswerList, restoreAnswerList, duplicateAnswerList, addAnswerListChoice, updateAnswerListChoice, removeAnswerListChoice, reorderAnswerListChoices, setAnswerListScoring |
| Tasks | delete_tasks | deleteTask |
| Task templates | view_task_templates | listTemplates, getTemplate |
| Task templates | manage_task_templates | createTemplate, updateTemplate, addTemplateGroup, updateTemplateGroup, addTemplateChecklistItem, updateTemplateChecklistItem |
| Task templates | delete_task_templates | none |
| Task templates | manage_task_rates | none |
| Devices | view_devices | listDevices, getDevice |
| Devices | control_device | lockDevice, unlockDevice, setDeviceTemperature, setDeviceMode, refreshDeviceStatus |
| Devices | modify_devices | assignDeviceToProperty |
| Properties | view_properties | listProperties, getProperty, listPropertyGroups, getPropertyGroup, listElementCategories, listElementCatalog, listPropertyElements, listInstructions, getInstruction, listPortalBrandings, listPrecheckSteps, getPrecheckStep, listPortals, getPortal, listUpsells, getUpsell, listUpsellsByProperty, listUpsellVisibilityRules, listEntityScopes, listTags, listPropertyTags |
| Properties | modify_properties | updateProperty, updatePropertyStatus, createPropertyGroup, updatePropertyGroup, createElementCatalogEntry, updateElementCatalogEntry, createPropertyElement, updatePropertyElement, createInstruction, updateInstruction, deleteInstruction, reorderInstruction, createPortalBranding, updatePortalBranding, createPrecheckStep, updatePrecheckStep, createPortal, updatePortal, assignPortalToProperty, createUpsell, updateUpsell, reorderUpsell, updateEntityScopes, addEntityScopes, removeEntityScopes, deleteElementCatalogEntry, deletePropertyElement |
| Properties | delete_properties | none |
| Reservations | view_reservations | listReservations, getReservation, getReview |
| Reservations | modify_reservations | createReservation, updateReservation, updateCheckInState |
| Guest IDs | view_guest_ids | none |
| Portals | view_guides | listPortalManuals, listPortalManualsByProperty, listPortalManualCategories |
| Portals | modify_guides | createPortalManual, updatePortalManual, createPortalManualCategory, updatePortalManualCategory, reorderPortalManualCategories, deletePortalManualCategory, createUpsell, retranslateGuideText |
| Portals | delete_guide | none |
| Integrations | view_integration | none |
| Integrations | manage_integrations | none |
| Organization | view_organization | getOrganization |
| Organization | manage_organization | listEmailTemplates, getEmailTemplate, create_email_template, modify_email_template, updateEmailTemplate, initializeLanguageTranslations, getLanguageCoverage |
| Organization | manage_billing | none |
| Users | view_users | listTeamMembers, getMember |
| Users | manage_users | inviteMember, updateMember, updateMemberRole, suspendMember, addPropertyScope, removePropertyScope, updateMemberScopes |
| Users | delete_users | none |
| Access codes | private_code | none |
| Access codes | view_lock_code | listCodes, getCode |
| Access codes | manage_lock_code | createCode, updateCode, deleteCode |
| Access codes | view_staff_codes | none |
| Events | view_event | none |
| Events | manage_event | none |
| Analytics | view_analytics | none |
| Analytics | view_logs | none |
| Workflows | view_workflows | listWorkflowZapierSteps |
| Workflows | manage_workflows | create_workflow, modify_workflow, update_workflow, set_workflow_scopes, publish_workflow |
| Workflows | delete_workflows | none |
| Payments | view_payments | listPaymentAccounts |
| Payments | manage_payments | none |
| Payouts | view_payouts | none |
| Payouts | manage_payouts | none |
| Inbox | view_inbox | none |
| Inbox | manage_inbox | none |
| Inbox | manage_inbox_assignees | none |
| Inbox | manage_message_templates | none |
| Booking engine | view_booking_engine | none |
| Booking engine | manage_booking_engine | none |
| Shifts | view_shifts | listShifts, getShift, listTimeEntries, listClockedShifts |
| Shifts | manage_shifts | none |
| Shifts | approve_time_entries | listCostsByPeriod, getCostsForDay |
| Shifts | view_team_locations | none |
| Account | account_admin | none |
| Not in editor | manage_connections | none |
The dashboard’s permission editor does not list manage_connections yet, and no public operation needs it or either payouts permission.
Seven operations need no specific permission. searchCoverIcons and searchStockPhotos are open to any valid key. getTranslationEntries and getTranslationEntriesBatch need the key to hold at least one permission of any kind. The three webhook subscription operations act only on the calling credential’s own subscriptions: listWebhookSubscriptions and deleteWebhookSubscription are open to any valid credential, and createWebhookSubscription needs at least one permission plus the permission of the event you subscribe to. Each translation’s text is then gated by the domain it belongs to: see Translations.
Pick the smallest set that covers the operations your integration calls.
Key Lifecycle
Section titled “Key Lifecycle”| Action | How |
|---|---|
| Create | Settings → Developer → Create API Key |
| View | Shown once at creation; not retrievable afterwards |
| Revoke | Settings → Developer → Revoke |
| Rotate | Revoke old key, create new key, update your integration |
Keys can be created with no expiry or a fixed lifetime (30 days, 90 days, or 1 year); revoke any key that is no longer in use. For the full step-by-step on creating, scoping, monitoring, and revoking keys from the dashboard, see Managing API Keys.
401 vs 403
Section titled “401 vs 403”| Status | Meaning |
|---|---|
401 authentication_error | No Authorization: Bearer header, or the key is unknown, revoked, expired, belongs to a deactivated member, was sent to a different region, or is an sk_test_ key sent to production |
403 authorization_error | The key is valid but lacks a permission this operation requires (Missing permission: …) |
Security Practices
Section titled “Security Practices”- Server-side only. Never embed API keys in browser JavaScript, mobile apps, or any client-side code. Keys are long-lived bearer tokens with full API access within their scopes.
- Environment variables. Load keys from environment variables or a secrets manager at runtime.
- Rotate on suspicion. If a key may have been exposed, revoke it immediately and issue a new one.
- Scope minimally. A key used only for reading reservations needs
view_reservationsand should not havemodify_tasks.