---
title: "Scopes and permissions"
sidebar: apaleo_docs_sidebar
permalink: /guides/api/scopes.html
description:
---

Every app that calls the Apaleo APIs has to be granted access. How that access is defined depends on the **client access** type you choose when you register your app. You choose once: the client access type can't be changed after the app is created.

## Two ways to get access

| | **Scope client** | **Fine-grained client (recommended)** |
| --- | --- | --- |
| How access is defined | Broad API scopes bundled into the OAuth token | The exact permissions your app needs, per API |
| Property access | The whole account | All properties, or only selected properties |
| Who picks the properties | n/a | The hotel, when it connects your app. In your own developer account, you pick test properties |
| `scope` in the authorize request | The API scopes you need, plus OpenID Connect scopes | OpenID Connect scopes only (`offline_access`, `openid`, `profile`). API scopes you send anyway are ignored |
| `scope` in the token response | The granted scopes | The marker scope `identity:permissions`. Apps where a user signs in also get `openid`, `profile` and `offline_access` |
| Changing access later | Edit the scopes. Users have to re-authorize | Edit the permissions. Users have to re-authorize |

Existing scope clients keep working exactly as before.

To register an app and choose its client access type, see [Register an OAuth connect client (Apaleo store) app](/guides/oauth-connection/register-connect-client-app.html) or [Register an OAuth simple client (custom) app](/guides/oauth-connection/register-simple-client-app.html).

## Find out what an operation requires

The Swagger UI of each API shows the scopes and permissions each operation requires. <!-- TO CONFIRM: wait for the Swagger update to be live -->

1. Open the Swagger UI of the API you want to call (see the table below).
2. Expand the operation.
3. Check its security requirements.

| API | Swagger UI |
| --- | --- |
| Core API | [api.apaleo.com/swagger](https://api.apaleo.com/swagger/index.html) |
| Payment API | [payment.apaleo.com/swagger](https://payment.apaleo.com/swagger/index.html) |
| Identity / OAuth | [identity.apaleo.com/swagger](https://identity.apaleo.com/swagger/index.html) |
| Integration / Apaleo One | [integration.apaleo.com/swagger](https://integration.apaleo.com/swagger/index.html) |
| Webhooks | [webhook.apaleo.com/swagger](https://webhook.apaleo.com/swagger/index.html) |
| Distribution / ARI | [distribution.apaleo.com/swagger](https://distribution.apaleo.com/swagger/index.html) |
| Automation | [scheduler.apaleo.com/swagger](https://scheduler.apaleo.com/swagger/) |
| Identity / Users | [identity.apaleo.com/swagger](https://identity.apaleo.com/swagger/) |
| Rendering / Invoices | [rendering.apaleo.com/swagger](https://rendering.apaleo.com/swagger/) |

For the MCP server, see [MCP](#mcp) below.

## Scopes (scope clients)

The access token of a scope client has scopes. A scope restricts the endpoints to which a client has access, and whether the client has read or write access to an endpoint. For example, if you want to access endpoints that contain reservation data, then your app must have the `reservations.read` access scope.

Scopes are written as `resource.action`, for example `reservations.read` or `folios.manage`. Scopes of other APIs have a prefix, such as `identity:`, `distribution:`, `integration:`, `rendering:`, `fiscalization:` or `mcp:`.

## Permissions (fine-grained clients)

A fine-grained client is granted permissions instead of scopes. You choose them per API when you register the app, and the same permissions apply to every property the app can access. Hotels see the permissions your app requests, with a readable name, on the consent screen. See [Review the consent screen](/guides/oauth-connection/review-consent-screen.html).

Permissions are written as `service.resource.action`, for example `core.reservations.read` or `payment.reports.read`. <!-- TO CONFIRM: naming format -->

Access that scope clients request as API scopes, including `identity:account-users.read`, is granted as permissions for fine-grained clients. Your app doesn't send these in the `scope` parameter.

### How access is decided

A request from a fine-grained client succeeds only if all of these are true:

1. The app has been granted the permission the operation requires.
2. The hotel has granted the app access to the property the request is about.
3. The user who connected the app still has an Apaleo role and property access that cover everything the app was granted. A user can only use the app if their role includes all of the permissions the app requires. This is checked when the user connects the app, every time the app refreshes a token, and on every API call. A user who lacks a required permission is blocked immediately.

If 1 or 2 isn't true, the API responds with `403 Forbidden`. If 3 stops being true, API calls with that user's token are blocked right away, and the next token refresh fails with `400 Bad Request`. See [OAuth 2.0: Refresh token grant flow](/guides/oauth-connection/refresh-token.html#refresh-can-fail-if-the-user-is-no-longer-eligible).

List calls without a property filter return only the data of the properties your app can access, without an error.

Users don't need to be account admins to connect an app, as long as their role and property access cover the access the app requests. Embedded apps are an exception: installing one needs an account admin, who chooses the properties at connect time. <!-- TO CONFIRM: embedded apps, waiting for product -->

Apps that run inside Apaleo (UI integrations) work differently. Their calls use the token of the user who installed the app, not the token of the user who is working in the UI. What the app can do therefore follows the installer's role and property access.

Hotels can change which properties your app can access later, from **Apps > Connected apps** in Apaleo. The change applies right away. For a custom app that you create in your own account, you choose the properties and permissions when you create the app.

## Ask for as little as possible

- Prefer a fine-grained client.
- Request only the scopes or permissions your app needs.
- Every user who connects a fine-grained app needs a role that includes all of its permissions. The more permissions you request, the fewer users can use your app.
- Some operations accept more than one scope. Where they do, choose the narrowest one that covers what your app does, for example a `.read` scope if it only reads.
- Broad scopes like `setup.manage` give access to settings across the whole account and all properties. Request them only if your app really needs that.
- If you change your app's scopes or permissions later, users have to re-authorize your app. Request what you need up front.

## MCP

For scope clients, the Apaleo MCP server adds the `mcp:*` scopes on top of the regular API scopes. They map to the three MCP building blocks:

- `mcp:prompts`: access to MCP prompts
- `mcp:resources`: access to MCP resources
- `mcp:tools`: access to MCP tools

An AI client (Claude, ChatGPT, n8n, …) requests these alongside the API scopes for the data it needs (for example `reservations.read` or `folios.read`). Fine-grained clients have no `mcp:*` permissions. Their MCP access comes from the regular permissions that the underlying MCP tools need.

## Requested vs. granted scopes (scope clients)

The consent screen shows every scope an app *requests*, but requesting a scope is not the same as being *granted* it. A scope is only effectively granted where **both**:

- your Apaleo user’s role covers that access, **and**
- the connected app itself holds that scope.

Because of this layered gating, you can consent to the full list on the consent screen and still get a `403` when calling a tool or endpoint your role doesn’t cover — approving on the consent screen does not guarantee access to everything listed. To change what’s granted, adjust the user’s role in Apaleo, then reconnect (a fresh sign-in). An existing session keeps its previous access until you sign in again.
