Connect with OAuth

OAuth lets an app work with Maison on your behalf without an API key. You sign in to Maison, see what the app is asking for, choose which hotels it may reach, and approve. You can disconnect it at any time. This is how Claude, ChatGPT and other MCP clients connect to Maison, and how a hotel's own integrations sign their users in.

An app can never do more than you can. A connection acts as the person who approved it, limited to the permissions and hotels they chose. It reaches only the public tool API — REST https://maison-labs.com/api/v1, MCP https://maison-labs.com/mcp and A2A https://maison-labs.com/a2a — never the admin console.

Pick your path:

Reference for app builders:

Connect Claude, ChatGPT or another MCP client as yourself

You need a Maison account and an MCP client that supports OAuth sign-in. You do not need an API key, and you do not register anything first: the client introduces itself to Maison when you connect.

1. Copy the Maison MCP server URL

text
https://maison-labs.com/mcp

2. Add it to your client

  • Claude (web or desktop): open the connector settings, add a custom connector, paste the URL and leave any API key or header fields empty.
  • ChatGPT: add a custom connector (MCP server) in the connector settings, paste the URL and choose OAuth as the authentication.
  • Claude Code: add the server, then run /mcp in a session and choose to authenticate.
  • Any other MCP client: add an HTTP (Streamable HTTP) server with the URL and no headers. A client that follows the MCP authorization spec finds Maison's sign-in by itself.
bash
claude mcp add --transport http maison https://maison-labs.com/mcp

Menu names differ between products and plans; look for “connectors” or “MCP servers”.

3. Sign in with Maison

Your client opens a Maison sign-in page in the browser. Sign in with your Maison email and password. If you are already signed in, you go straight to the consent screen.

4. Review what you are approving

The consent screen shows:

  • The app — its name and logo, with a badge: Verified app when Maison has confirmed who it is (Claude and ChatGPT are recognised automatically when they introduce themselves with their published identity), or Unverified app with a warning to connect only if you trust the developer.
  • Running locally on your machine — shown whenever the app receives the sign-in on localhost, for example a command-line tool. Continue only if you started it yourself.
  • Where you will be sent back — the web address the app receives your approval on.
  • What the app is requesting — permissions grouped by area (see Scopes). A permission you do not hold yourself is greyed out with “You do not have this permission” and is not given to the app.
  • Which hotels it may access — tick the hotels, or choose All hotels I can access, including future ones. If you can reach only one hotel, it is chosen for you.

Choose Allow to connect or Deny to cancel. You are sent back to your client and the Maison tools appear.

What the app can do once connected

  • Call Maison tools through MCP (or REST and A2A), and only the tools covered by the permissions you approved. The tool list it sees is already filtered to those.
  • Act on the hotels you chose. A tool aimed at another hotel is refused. Tools that work across your whole account, such as listing hotels, see every hotel you can reach.
  • Never exceed your own access: if an admin removes a permission or a hotel from you, the app loses it too, within about 30 seconds.

Staying connected

The app holds an access token that lasts 15 minutes and renews it with a refresh token, so you normally sign in once. If the client asks you to sign in again, the consent screen is skipped when nothing new is being requested.

Disconnect

Open your profile in the admin console, find the app under Connected apps and choose Revoke. The panel lists each app, what it can access, which hotels, when you connected and when it was last used. Revoking takes effect within 30 seconds and the app has to ask you again to reconnect. Removing the connector inside Claude or ChatGPT only removes it from that client; revoke in Maison to cut its access.

Register an app for your hotel (Developer apps)

A Developer app is an OAuth app that your hotel registers with Maison: an integration you build or buy that lets your team sign in with Maison and work with your hotel's data. Registering it gives you a client id (and, for a server-side app, a client secret). It does not grant access to anything by itself: each person who uses the app signs in and approves it, and the app then acts as that person.

For an unattended server-to-server job with no person signing in, use an API key instead. OAuth tokens always belong to a person.

1. Get Developer apps switched on

Developer apps is a plan feature that is off by default. A Maison admin switches it on for your hotel (Account › Features › Plan features › Developer apps); ask your Maison contact. The section then appears under Connect › Developer apps for people whose role includes a policy granting Developer apps (oauth-apps) with write access. Your hotel admin adds that policy under Access › Policies.

2. Register the app

In your hotel's workspace, open Connect › Developer apps and choose Register app.

FieldWhat to enter
App nameUp to 80 characters. People see it on the consent screen.
Redirect URIsOne per line, up to 10. Each must be https://, or http://localhost / http://127.0.0.1 for a local tool. The URI your app sends must match one exactly.
ScopesThe permissions your app needs (see Scopes). Request only what it uses: people approve each one.
Client typePublic (no secret) for browser, mobile and desktop apps, which cannot keep a secret. Confidential (client secret) for an app with a server. You cannot change the type later.
Logo URL, websiteOptional, https:// only. Shown to people who connect.

3. Store the client id and secret

The App registered dialog shows the client id and, for a confidential app, the client secret, each with a copy button. The secret is shown only once and cannot be recovered; keep it in your server's secret store, never in a browser or mobile app or in source control. If you lose it, delete the app and register it again (people will need to reconnect).

4. Sign people in

Use the authorization code flow with PKCE (S256, required for every app). Send resource to name the API the token is for — https://maison-labs.com/api/v1, https://maison-labs.com/mcp or https://maison-labs.com/a2a; a token only works on the resource it was issued for. Without resource the token is for https://maison-labs.com/api/v1.

text
https://maison-labs.com/as/authorize
  ?response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=https://yourapp.example.com/callback
  &scope=openid clients:read knowledge:read
  &resource=https://maison-labs.com/api/v1
  &state=RANDOM_STATE
  &code_challenge=BASE64URL_SHA256_OF_VERIFIER
  &code_challenge_method=S256

Exchange the code at /as/token. A confidential app sends its secret in the form body (client_secret_post); a public app sends only its client id and the verifier.

bash
curl -X POST https://maison-labs.com/as/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "grant_type=authorization_code" \
  --data-urlencode "code=CODE_FROM_CALLBACK" \
  --data-urlencode "redirect_uri=https://yourapp.example.com/callback" \
  --data-urlencode "code_verifier=YOUR_VERIFIER" \
  --data-urlencode "client_id=YOUR_CLIENT_ID" \
  --data-urlencode "client_secret=YOUR_CLIENT_SECRET"   # confidential apps only

The response carries an access_token (15 minutes) and a refresh_token (7 days; always keep the newest one, see Reading the token). Call the API with Authorization: Bearer ACCESS_TOKEN:

bash
curl https://maison-labs.com/api/v1/tools -H "Authorization: Bearer ACCESS_TOKEN"

# Renew before or after expiry
curl -X POST https://maison-labs.com/as/token \
  --data-urlencode "grant_type=refresh_token" \
  --data-urlencode "refresh_token=REFRESH_TOKEN" \
  --data-urlencode "client_id=YOUR_CLIENT_ID" \
  --data-urlencode "client_secret=YOUR_CLIENT_SECRET"   # confidential apps only

To sign people in with Maison and read their name and email (id_token, /as/userinfo, sign-out, the Continue with Maison button), follow Login with Maison. Server metadata is published at https://maison-labs.com/.well-known/oauth-authorization-server.

Verified badge, edits and deletion

  • New apps are unverified: people see an Unverified app warning, but the flow works. A Maison admin can mark the app verified.
  • Edit changes the name, redirect URIs, scopes, logo and website. Adding a scope does not reach existing connections by itself: see Getting more access.
  • Delete removes the app and revokes every connection people made to it. It cannot be undone.

For admins: approving and revoking

There is no approval queue. Each person approves an app for themselves on the consent screen, and the app gets at most that person's own access, only on the hotels they chose. Admins decide who may register apps, and can verify, suspend or delete apps and revoke connections afterwards.

WhatWhoWhere
Approve an app as yourselfAnyone with a Maison accountThe consent screen, when connecting
See and revoke your own connectionsEveryone, no permission neededProfile › Connected apps
Switch Developer apps on for a hotelMaison adminsThe hotel's Account › Features › Plan features
Register, edit and delete a hotel's appsPeople with Developer apps (oauth-apps) write access on that hotel, once the hotel has the featureThe hotel's Connect › Developer apps
See and revoke another person's connectionsMaison staff with user management accessUsers › the person › Connected apps
Verify, suspend or delete any appMaison adminsThe admin console's OAuth apps page

What an approval grants

One connection: this app, acting as this person, with the permissions they approved, on the hotels they chose (or every hotel they can reach, including future ones). It lasts until it is revoked. Every call is checked again against the person's current permissions and the hotel's plan, so taking a permission away from the person takes it away from the app too.

Revoking access

ActionEffect
Revoke a connection (Connected apps)That person's connection ends; the app's tokens stop working within 30 seconds.
Delete the app (Developer apps or OAuth apps)Every connection to the app ends; the app can no longer sign anyone in.
Suspend the app (Maison admins)No new sign-ins or token renewals. Tokens already issued stop working when they expire, within 15 minutes. Unsuspending restores existing connections.
Remove a person's permission or hotelTheir connections lose it within about 30 seconds.

Scopes reference

A scope is a permission an app asks for. It never adds to what the person can do: a scope only lets the app use, on that person's behalf, permissions the person already holds. :write does not include :read; request both when the app reads and changes the same thing.

ScopeWhat it grantsWho can get itTools that accept it
openidIssues an ID token that says who signed in.Any app. Request it in scope=; it is not on the Developer apps form.None
profileThe person's name (full, given and family) in the ID token.Any app. Request it in scope=; it is not on the Developer apps form.None
emailThe person's email address, and whether it is verified, in the ID token.Any app. Request it in scope=; it is not on the Developer apps form.None
offline_accessAccepted for OpenID Connect compatibility: apps allowed refresh tokens (every Developer app) get one without it.Any app. Request it in scope=; it is not on the Developer apps form.None
clients:readSee the hotel's configuration, channels, integrations, branding, activity and emails.Choose it on the Developer apps form.
50 tools
  • check_integration_config
  • get_chat_runtime
  • get_chat_styles
  • get_client
  • get_client_access
  • get_client_activity
  • get_client_email
  • get_client_email_attachment
  • get_client_hierarchy
  • get_client_metrics
  • get_client_overview
  • get_clients_summary
  • get_dashboard_stats
  • get_gateway_fee_totals
  • get_hotel_config
  • get_live_clients_report
  • get_portfolio_analytics (checks more than one permission)
  • get_portfolio_overview
  • get_property_discovery
  • get_qa_pair
  • get_staff_notification_emails
  • get_theme
  • get_theme_visual
  • get_webhook
  • get_webhook_analytics
  • get_webhook_request
  • get_widget_embed_code
  • list_channel_instructions
  • list_channels
  • list_client_emails
  • list_client_gateway_fees
  • list_client_integrations
  • list_client_notes
  • list_client_settings
  • list_clients
  • list_integration_catalog
  • list_integration_properties
  • list_knowledge_gaps
  • list_media_assets
  • list_note_versions
  • list_plan_gateway_fees
  • list_pms_rate_plans
  • list_qa_pairs
  • list_qa_versions (checks more than one permission)
  • list_report_subscribers
  • list_webhook_requests
  • list_webhooks
  • restore_qa_version (checks more than one permission)
  • send_message
  • translate_text
clients:writeChange the hotel's configuration, channels, integrations, branding and policies.Choose it on the Developer apps form.
68 tools
  • add_channel_instruction
  • add_client_note
  • add_client_policy_statement
  • add_client_role_rule (checks more than one permission)
  • add_client_setting
  • add_integration
  • add_report_subscribers
  • add_role_policy (checks more than one permission)
  • add_webhook_key
  • approve_property_discovery
  • attach_child_property
  • clear_client_gateway_fee
  • clear_plan_gateway_fee
  • connect_chatgpt_channel
  • create_client
  • create_client_policy
  • create_media_upload
  • create_policy
  • create_theme_visual_upload
  • create_webhook
  • decide_property_candidates
  • delete_channel_instruction
  • delete_client_note
  • delete_client_policy
  • delete_policy
  • delete_webhook
  • detach_child_property
  • disable_client
  • disable_integration
  • disconnect_channel
  • enable_client
  • enable_integration
  • generate_theme_icon
  • get_channel_connect_link
  • list_child_candidates
  • remove_client_policy_statement
  • remove_client_role_rule (checks more than one permission)
  • remove_client_setting
  • remove_integration
  • remove_media_asset
  • remove_report_subscribers
  • remove_role_policy (checks more than one permission)
  • remove_theme_visual
  • rename_webhook_key
  • reveal_webhook_key
  • revoke_webhook_key
  • rotate_webhook_key
  • set_chat_styles
  • set_client_gateway_fee
  • set_client_policy_rules
  • set_plan_gateway_fee
  • set_policy_rules
  • set_staff_notification_emails
  • set_theme_color
  • update_channel_instruction
  • update_channel_settings
  • update_chat_runtime
  • update_client
  • update_client_note
  • update_client_policy
  • update_client_setting
  • update_hotel_config
  • update_media_asset
  • update_policy
  • update_property_candidate
  • update_webhook
  • upload_media_asset
  • upload_theme_visual
clients:executeDeploy the hotel's demo site, start property discovery, look for knowledge gaps and send integration connect links.Choose it on the Developer apps form.
4 tools
  • deploy_preview_site
  • detect_knowledge_gaps
  • send_integration_connect_link
  • start_property_discovery
knowledge:readSee the hotel's document sources, questions and answers, tone and translations.Choose it on the Developer apps form.
11 tools
  • download_document
  • get_chatbot_tone
  • get_qa_counts
  • get_source_run_logs
  • get_source_run_report
  • get_translations
  • get_website_scrape
  • list_document_versions
  • list_knowledge_sources
  • list_qa_versions (checks more than one permission)
  • list_source_runs
knowledge:writeAdd and change the hotel's document sources, questions and answers, tone and translations.Choose it on the Developer apps form.
23 tools
  • add_document_source
  • add_document_version
  • add_qa_pairs
  • add_website_source
  • answer_knowledge_gap
  • create_document_upload
  • delete_document_version
  • delete_qa_pairs
  • disable_source
  • dismiss_knowledge_gap
  • publish_qa_pairs
  • reactivate_source
  • remove_source
  • rename_document_source
  • reopen_knowledge_gap
  • restore_document_version
  • restore_qa_version (checks more than one permission)
  • set_chatbot_tone
  • set_main_website_source
  • set_source_sync_schedule (checks more than one permission)
  • unpublish_qa_pairs
  • update_qa_pair
  • update_translations
knowledge:executeSync and scrape the hotel's sources and rediscover its booking links.Choose it on the Developer apps form.
4 tools
  • discover_booking_links
  • rescrape_client_website
  • scrape_website_source
  • sync_source
conversations:readRead the hotel's guest conversations.Choose it on the Developer apps form.
13 tools
  • export_chat_logs
  • get_common_questions
  • get_conversation
  • get_conversation_attention
  • get_conversation_guest (checks more than one permission)
  • get_notice_summary
  • list_conversation_inbox
  • list_conversations
  • list_guest_conversations (checks more than one permission)
  • list_notices
  • list_recent_conversations
  • mark_notices_read
  • search_conversations
conversations:writeTake over and hand back the hotel's guest conversations, stop a reply and mark them read.Choose it on the Developer apps form.
3 tools
  • mark_conversation_read
  • set_conversation_mode
  • stop_conversation_turn
conversations:executeSend replies to the hotel's guests and whisper to the agent.Choose it on the Developer apps form.
2 tools
  • reply_to_conversation
  • whisper_to_agent
guest-identity:readSee who a guest is: their verified identity and contact details, their name on conversation lists, and their other conversations.Choose it on the Developer apps form.
2 tools
  • get_conversation_guest (checks more than one permission)
  • list_guest_conversations (checks more than one permission)
analytics:readSee conversation analytics and AI visibility analytics.Choose it on the Developer apps form.
7 tools
  • get_ai_visibility_report
  • get_chatlog_report
  • get_conversation_analytics
  • get_portfolio_analytics (checks more than one permission)
  • list_ai_visibility_reports
  • list_chatlog_reports
  • list_report_runs
analytics:writeChange the settings behind conversation and AI visibility analytics.Choose it on the Developer apps form.None
analytics:executeRun analytics reports.Choose it on the Developer apps form.
4 tools
  • rerun_ai_visibility_report
  • rerun_chatlog_report
  • run_ai_visibility_report
  • run_chatlog_report
agents:readSee the hotel's agents and their ledger.Choose it on the Developer apps form.
8 tools
  • get_agent
  • get_agent_execution_history
  • get_guest_agent_settings
  • list_agent_execution_history
  • list_agent_sessions
  • list_agent_templates
  • list_agent_tools
  • list_agents
agents:writeCreate and change the hotel's agents.Choose it on the Developer apps form.
6 tools
  • create_agent
  • delete_agent
  • disable_agent
  • enable_agent
  • update_agent
  • update_guest_agent_settings
agents:executeTest the hotel's agents against a conversation.Choose it on the Developer apps form.
1 tool
  • test_agent
quality:readSee conversation feedback scores and test session results.Choose it on the Developer apps form.
7 tools
  • get_knowledge_quality_run
  • get_test_report
  • list_chat_feedback
  • list_chat_tests
  • list_golden_questions
  • list_knowledge_quality_runs
  • list_test_runs
quality:executeRun feedback scoring, consistency checks, duplicate clean-up and test sessions.Choose it on the Developer apps form.
8 tools
  • check_knowledge_consistency
  • deduplicate_knowledge
  • dismiss_chat_feedback
  • reopen_chat_feedback
  • resolve_chat_feedback
  • run_chat_feedback
  • run_chat_tests
  • run_golden_faq_test
users:readSee people's accounts, the roles they hold and their access.Choose it on the Developer apps form.
10 tools
  • get_client_group (checks more than one permission)
  • get_client_user_access
  • get_user
  • get_user_activity
  • list_client_users
  • list_credential_audit
  • list_user_api_keys
  • list_user_clients
  • list_user_connected_apps
  • list_users
users:writeInvite people, change their access and remove them.Choose it on the Developer apps form.
17 tools
  • add_client_user
  • assign_role
  • assign_role_to_group
  • disable_user
  • disable_user_api_key
  • enable_user
  • force_password_reset
  • invite_user
  • link_client_group_role (checks more than one permission)
  • remove_client_user
  • revoke_client_invite
  • revoke_user_connected_app
  • set_client_user_groups
  • set_client_user_roles
  • unassign_role
  • update_group_roles (checks more than one permission)
  • update_user
users:executeResend invitations.Choose it on the Developer apps form.
2 tools
  • reinvite_user
  • resend_client_invite
groups:readSee groups and who belongs to them.Choose it on the Developer apps form.
4 tools
  • get_client_group (checks more than one permission)
  • get_group
  • list_client_groups
  • list_groups
groups:writeCreate, change and delete groups, and add or remove their members and roles.Choose it on the Developer apps form.
11 tools
  • create_client_group
  • create_group
  • delete_client_group
  • delete_group
  • link_client_group_role (checks more than one permission)
  • unlink_client_group
  • update_client_group
  • update_client_group_members
  • update_group
  • update_group_members
  • update_group_roles (checks more than one permission)
roles:readSee roles and what each one allows.Choose it on the Developer apps form.
7 tools
  • get_client_role
  • get_role
  • list_client_roles
  • list_features
  • list_role_groups
  • list_role_users
  • list_roles
roles:writeCreate, change and delete roles, and give them to people and groups.Choose it on the Developer apps form.
19 tools
  • add_client_role_rule (checks more than one permission)
  • add_role_policy (checks more than one permission)
  • attach_client_role_policy
  • attach_role_policy
  • create_client_role
  • create_feature
  • create_role
  • deprecate_feature
  • detach_client_role_policy
  • detach_role_policy
  • disable_client_role
  • disable_role
  • remove_client_role_rule (checks more than one permission)
  • remove_role_policy (checks more than one permission)
  • restore_role
  • set_role_policy_applies_to
  • update_client_role
  • update_feature
  • update_role
policies:readSee policies and the rules in them.Choose it on the Developer apps form.
5 tools
  • get_client_policy
  • get_policy
  • list_client_features_catalogue
  • list_client_policies
  • list_policies
policies:writeCreate, change and delete policies and their rules.Choose it on the Developer apps form.
14 tools
  • add_client_policy_statement
  • add_client_role_rule (checks more than one permission)
  • add_role_policy (checks more than one permission)
  • create_client_policy
  • create_policy
  • delete_client_policy
  • delete_policy
  • remove_client_policy_statement
  • remove_client_role_rule (checks more than one permission)
  • remove_role_policy (checks more than one permission)
  • set_client_policy_rules
  • set_policy_rules
  • update_client_policy
  • update_policy
apps:readSee the hotel's developer apps, their usage, request log and audit trail.Choose it on the Developer apps form.
5 tools
  • get_client_app
  • get_client_app_analytics
  • list_client_app_audit
  • list_client_app_requests
  • list_client_apps
apps:writeRegister, change, revoke and reinstate the hotel's developer apps.Choose it on the Developer apps form.
11 tools
  • create_client_app
  • list_oauth_apps
  • reinstate_client_app
  • reinstate_oauth_app
  • revoke_client_app
  • revoke_oauth_app
  • suspend_oauth_app
  • unsuspend_oauth_app
  • unverify_oauth_app
  • update_client_app
  • verify_oauth_app
usage:readSee AI usage and cost summaries.Choose it on the Developer apps form.
2 tools
  • get_llm_usage_summary
  • list_llm_usage
hubspot:readSee HubSpot company and deal data.On the Developer apps form, but it works only for Maison staff who hold the matching permission.
2 tools
  • get_hubspot_link
  • search_hubspot_companies
hubspot:writeChange HubSpot company and deal data.On the Developer apps form, but it works only for Maison staff who hold the matching permission.
2 tools
  • link_hubspot_company
  • unlink_hubspot_company
hubspot:executePush conversation volume to HubSpot.On the Developer apps form, but it works only for Maison staff who hold the matching permission.
1 tool
  • push_hubspot_chat_volume
features:readSee which features each hotel has, and the plan templates.On the Developer apps form, but it works only for Maison staff who hold the matching permission.
8 tools
  • get_client_plan
  • get_plan_template
  • list_children_feature_counts
  • list_client_features
  • list_client_plan_history
  • list_plan_template_clients
  • list_plan_template_history
  • list_plan_templates
features:writeTurn features on and off for hotels, and create and change plan templates.On the Developer apps form, but it works only for Maison staff who hold the matching permission.
12 tools
  • apply_plan_template
  • assign_plan_template
  • clear_client_feature_override
  • create_plan_template
  • delete_plan_template
  • grant_client_feature
  • grant_feature_to_children
  • revoke_client_feature
  • set_client_feature_override
  • set_client_features
  • set_client_plan
  • update_plan_template
jobs:executeSee and stop a hotel's running background jobs, such as a website scrape.On the Developer apps form, but it works only for Maison staff who hold the matching permission.
2 tools
  • list_client_jobs
  • stop_client_job
schedules:writeChange how often a hotel's website sources sync on their own.On the Developer apps form, but it works only for Maison staff who hold the matching permission.
1 tool
  • set_source_sync_schedule (checks more than one permission)
adminRun the whole platform (roles, policies, users, developer apps, features, clients, jobs and schedules) from Maison's own apps only.Maison's own apps only. Never grantable to a Developer app or an MCP client.
170 tools
  • add_client_policy_statement
  • add_client_role_rule (checks more than one permission)
  • add_client_setting
  • add_client_user
  • add_role_policy (checks more than one permission)
  • apply_plan_template
  • approve_property_discovery
  • assign_plan_template
  • assign_role
  • assign_role_to_group
  • attach_child_property
  • attach_client_role_policy
  • attach_role_policy
  • clear_client_feature_override
  • clear_client_gateway_fee
  • clear_plan_gateway_fee
  • create_client
  • create_client_app
  • create_client_group
  • create_client_policy
  • create_client_role
  • create_feature
  • create_group
  • create_plan_template
  • create_policy
  • create_role
  • decide_property_candidates
  • delete_client_group
  • delete_client_policy
  • delete_group
  • delete_plan_template
  • delete_policy
  • deploy_preview_site
  • deprecate_feature
  • detach_child_property
  • detach_client_role_policy
  • detach_role_policy
  • detect_knowledge_gaps
  • disable_client
  • disable_client_role
  • disable_role
  • disable_user
  • disable_user_api_key
  • enable_client
  • enable_user
  • force_password_reset
  • get_client
  • get_client_access
  • get_client_app
  • get_client_app_analytics
  • get_client_group (checks more than one permission)
  • get_client_hierarchy
  • get_client_metrics
  • get_client_overview
  • get_client_plan
  • get_client_policy
  • get_client_role
  • get_client_user_access
  • get_clients_summary
  • get_conversation_guest (checks more than one permission)
  • get_gateway_fee_totals
  • get_group
  • get_live_clients_report
  • get_plan_template
  • get_policy
  • get_portfolio_analytics (checks more than one permission)
  • get_portfolio_overview
  • get_property_discovery
  • get_qa_pair
  • get_role
  • get_user
  • get_user_activity
  • get_widget_embed_code
  • grant_client_feature
  • grant_feature_to_children
  • invite_user
  • link_client_group_role (checks more than one permission)
  • list_child_candidates
  • list_children_feature_counts
  • list_client_app_audit
  • list_client_app_requests
  • list_client_apps
  • list_client_features
  • list_client_features_catalogue
  • list_client_groups
  • list_client_jobs
  • list_client_plan_history
  • list_client_policies
  • list_client_roles
  • list_client_settings
  • list_client_users
  • list_clients
  • list_credential_audit
  • list_features
  • list_groups
  • list_guest_conversations (checks more than one permission)
  • list_integration_catalog
  • list_knowledge_gaps
  • list_oauth_apps
  • list_plan_gateway_fees
  • list_plan_template_clients
  • list_plan_template_history
  • list_plan_templates
  • list_policies
  • list_qa_pairs
  • list_qa_versions (checks more than one permission)
  • list_report_subscribers
  • list_role_groups
  • list_role_users
  • list_roles
  • list_user_api_keys
  • list_user_clients
  • list_user_connected_apps
  • list_users
  • mark_conversation_read
  • reinstate_client_app
  • reinstate_oauth_app
  • reinvite_user
  • remove_client_policy_statement
  • remove_client_role_rule (checks more than one permission)
  • remove_client_setting
  • remove_client_user
  • remove_role_policy (checks more than one permission)
  • reply_to_conversation
  • resend_client_invite
  • restore_qa_version (checks more than one permission)
  • restore_role
  • revoke_client_app
  • revoke_client_feature
  • revoke_client_invite
  • revoke_oauth_app
  • revoke_user_connected_app
  • set_client_feature_override
  • set_client_features
  • set_client_gateway_fee
  • set_client_plan
  • set_client_policy_rules
  • set_client_user_groups
  • set_client_user_roles
  • set_conversation_mode
  • set_plan_gateway_fee
  • set_policy_rules
  • set_role_policy_applies_to
  • set_source_sync_schedule (checks more than one permission)
  • start_property_discovery
  • stop_client_job
  • stop_conversation_turn
  • suspend_oauth_app
  • translate_text
  • unassign_role
  • unlink_client_group
  • unsuspend_oauth_app
  • unverify_oauth_app
  • update_client_app
  • update_client_group
  • update_client_group_members
  • update_client_policy
  • update_client_role
  • update_client_setting
  • update_feature
  • update_group
  • update_group_members
  • update_group_roles (checks more than one permission)
  • update_plan_template
  • update_policy
  • update_property_candidate
  • update_role
  • update_user
  • verify_oauth_app
  • whisper_to_agent

The tool lists come from the API's tool registry. A tool marked checks more than one permission declares several grants, and the token needs a scope covering each of them. The security entry of each operation in the API reference is authoritative.

These tools need no scope and work with any connection: chat_site_diagnostic, check_website, disable_my_api_key, get_documentation, get_platform_status, get_site_diagnostic, list_my_api_keys, list_my_connected_apps, revoke_my_connected_app, start_site_diagnostic, whoami.

Where scopes are used

A scope is checked at every step from sign-in to each call. What the app can finally do is the overlap of four things: the scopes on its token, the person's own permissions, the hotels the person chose, and each hotel's plan.

StepWhat happens
Authorize requestThe app lists the scopes in scope=, separated by spaces. A Developer app gets only the scopes registered on it; any other API scope it asks for is dropped. admin is refused with invalid_scope. The identity scopes (openid, profile, email) and offline_access work for any app.
Consent screenThe person sees the scopes grouped by area. A scope they do not hold themselves is greyed out and not given. Consent is skipped when an existing connection already covers every scope requested.
The tokenThe access token's scope claim lists the API scopes granted for the one API the token is for. Identity scopes are not in it; they shape the id_token.
Tool listsGET https://maison-labs.com/api/v1/tools and the MCP tool list show only the tools the token's scopes cover and the person may use.
Every callOn https://maison-labs.com/api/v1, https://maison-labs.com/mcp and https://maison-labs.com/a2a the scope check runs first, then the chosen hotels, the person's permission and the hotel's plan.

When a scope is missing

The call fails with 403 and code insufficient_scope. details.scopes lists the scopes that would cover what the token is missing.

json
{
  "error": "Token scopes insufficient for this operation",
  "code": "insufficient_scope",
  "details": { "scopes": ["clients:read", "admin"] }
}
  • REST (https://maison-labs.com/api/v1): the body above with status 403.
  • MCP: a tool result with isError: true, the same body in structuredContent, and a WWW-Authenticate challenge naming the scopes in _meta["mcp/www_authenticate"].
  • A2A: a JSON-RPC error whose data carries the same error, code and details, plus status: 403.

A 403 with code forbidden is different: the token has the scope, but the person lacks the permission or did not choose that hotel. A new scope does not fix it.

Reading the token

What the token response holds

FieldWhat it is
access_tokenA signed JWT (RS256) for one API, valid for 15 minutes. Send it as Authorization: Bearer.
token_typeBearer
expires_inSeconds until the access token expires.
scopeThe API scopes granted on this token.
refresh_tokenGets a new access token for up to 7 days. Every Developer app receives one, with or without offline_access.
id_tokenOnly when you asked for openid: who signed in, as a signed JWT for your client id.

Claims in the access token

ClaimMeaning
issThe issuer, https://maison-labs.com.
subThe person's Maison user id. Stable: use it as your user key, together with iss.
audThe API the token is for: https://maison-labs.com/api/v1, https://maison-labs.com/mcp or https://maison-labs.com/a2a.
scopeThe API scopes granted, separated by spaces.
client_idYour app's client id.
gidThe id of this connection (the person's approval of your app).
iat, exp, jtiIssued at, expiry and the token's own id.

Verify the signature against https://maison-labs.com/as/jwks before you trust any claim. The token does not carry the hotels the person chose or the person's own permissions: Maison checks both on every call. Maison does not offer a token introspection endpoint.

javascript
import * as jose from "jose";

const JWKS = jose.createRemoteJWKSet(new URL("https://maison-labs.com/as/jwks"));

const { payload } = await jose.jwtVerify(accessToken, JWKS, {
  issuer: "https://maison-labs.com",
  audience: "https://maison-labs.com/api/v1", // the resource you asked for
});
const scopes = String(payload.scope ?? "").split(" ").filter(Boolean);
const canReadHotels = scopes.includes("clients:read");

Learn what the token can do

Ask the API. GET /tools lists every tool this token can call: its scopes and the person's permissions, both applied. GET /me (the whoami tool, no scope needed) returns the person's name, email, permissions and the hotel ids they can act on; it describes the person, not the hotels they chose for your app.

bash
curl https://maison-labs.com/api/v1/tools -H "Authorization: Bearer ACCESS_TOKEN"
curl https://maison-labs.com/api/v1/me -H "Authorization: Bearer ACCESS_TOKEN"

Who signed in

Read identity from the id_token. Ask for openid to get one; add profile for name, given_name, family_name and updated_at, and email for email and email_verified. Because every Maison access token is issued for one of the three APIs, the id_token carries the claims of every identity scope you were granted, and /as/userinfo does not accept these access tokens. Verification steps: Login with Maison.

Refreshing

Exchange the refresh token at /as/token before or after the access token expires (curl in step 4 of Register an app). A public app receives a new refresh token on every refresh; a confidential app receives one once 70% of the current token's 7 days have passed. Always store the refresh token from the latest response. A refresh can narrow the scopes (send a smaller scope=) but never add one.

Getting more access

A Developer app keeps its client id, secret and connections when you change its scopes. Adding a scope takes three steps; every person who uses the app approves it again.

1. Add the scope to the app

In the hotel's workspace, open Connect › Developer apps, choose Edit on the app and tick the scope. Only people with Developer apps (oauth-apps) write access on that hotel can do this; Maison admins cannot change a hotel app's scopes from the OAuth apps page.

2. Ask for it in the authorize request

Add the scope to scope=. Registering it on the app is not enough: a token only carries what the app asked for and the person approved.

text
https://maison-labs.com/as/authorize
  ?response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=https://yourapp.example.com/callback
  &scope=openid clients:read knowledge:read knowledge:write
  &resource=https://maison-labs.com/api/v1
  &state=RANDOM_STATE
  &code_challenge=BASE64URL_SHA256_OF_VERIFIER
  &code_challenge_method=S256

3. Send each person through sign-in again

The existing connection does not cover the new scope, so Maison shows the consent screen once more. After Allow, the new tokens carry the scope. Until then the app's current tokens and refresh token keep the old scopes, and a call that needs the new one fails with insufficient_scope: a good moment to start the sign-in. The person must hold the permission themselves, or the scope stays greyed out.

Removing a scope

Untick it in Edit. Tokens already issued keep it until they expire (15 minutes at most); the next refreshed token no longer has it, and a connection that held it shows the consent screen at the next sign-in.

Edit the app or register a new one?

  • Edit when it is the same product asking for more or less: new scopes, another redirect URI, a new name or logo.
  • Register a new app when you need the other client type (public and confidential cannot be switched), when the secret is lost, or for a separate product people should approve and revoke on its own. Each app has its own consent and its own line in Connected apps.

What you cannot get

  • admin belongs to Maison's own apps. It is not on the Developer apps form, and any other app that asks for it is refused.
  • Staff-only scopes (hubspot:read, hubspot:write, hubspot:execute, features:read, features:write, jobs:execute, schedules:write) can be registered, but only Maison staff hold the permissions behind them, so for anyone else the consent screen greys them out.
  • A scope never exceeds the person: to reach more, an admin gives the person the permission first (Access › Policies).

MCP clients such as Claude and ChatGPT are not registered in Developer apps. To change what one may do, disconnect it and connect again; the consent screen shows what it asks for. To have Developer apps switched on for a hotel, or for anything the form does not offer, ask your Maison contact.

Common mistakes

  • Write without Read. knowledge:write does not let the app read knowledge. Tick and request both when the app reads what it changes.
  • Commas between scopes. Separate scopes with spaces (%20 or + once URL-encoded). clients:read,knowledge:read is one unknown scope, so the app gets neither.
  • Asking for a scope the app is not registered for. It is dropped without an error, and the token arrives without it. Add it in Edit first.
  • Requesting offline_access to get a refresh token. Every Developer app already receives one. Leave it out unless you need it.
  • Expecting a refresh to add a scope. Refreshing never adds scopes; send the person through sign-in again.
  • A token for the wrong API. A token for https://maison-labs.com/api/v1 gets 401 on https://maison-labs.com/mcp. Send the matching resource=.
  • Calling /as/userinfo with the access token. Read the person's identity from the id_token.
  • Reusing an old refresh token. Store the newest one from every refresh response.

Endpoints

URLPurpose
https://maison-labs.com/.well-known/oauth-authorization-serverAuthorization server metadata
https://maison-labs.com/.well-known/openid-configurationThe same, OpenID Connect name
https://maison-labs.com/.well-known/oauth-protected-resource/mcpWhere MCP clients discover Maison's sign-in (also /a2a, and the bare path for the REST API)
https://maison-labs.com/as/authorizeStart sign-in (PKCE S256 required)
https://maison-labs.com/as/tokenExchange a code or refresh token
https://maison-labs.com/as/revokeRevoke a refresh token (ends that connection)
https://maison-labs.com/as/registerDynamic client registration for MCP clients (public apps only)
https://maison-labs.com/as/jwksPublic signing keys (RS256)
https://maison-labs.com/as/userinfoOpenID Connect userinfo. It does not accept Maison's access tokens, which are always issued for an API; read the id_token instead

Errors

ErrorWhat it meansWhat to do
access_deniedThe person chose Deny on the consent screen.Show a message and offer to try again.
invalid_clientUnknown or deleted app, a suspended app, or a wrong client secret. Developer apps send the secret in the form body (client_secret_post), not HTTP Basic.Check the client id and secret; ask your Maison contact if the app was suspended.
invalid_redirect_uriThe redirect URI is not registered exactly.Register the exact URI in Developer apps.
invalid_requestA missing or malformed parameter, often PKCE (S256 is required).Send code_challenge with code_challenge_method=S256.
invalid_targetThe resource parameter is not one of Maison's three resources.Use https://maison-labs.com/mcp, https://maison-labs.com/a2a or https://maison-labs.com/api/v1.
invalid_grantThe code expired (10 minutes) or was used twice, the verifier is wrong, or the refresh token expired or was revoked.Start the sign-in again.
429 too_many_requestsMore than 60 token requests a minute for one app, or too many registrations from one address.Wait for the Retry-After seconds, then retry.
401 UnauthorizedThe access token expired, was minted for a different resource, or the connection was revoked.Refresh the token or reconnect. MCP clients do this for you.
403 insufficient_scopeThe connection is missing a permission this tool needs; details.scopes lists the ones that would work.Request the scope and have the person sign in again; see Getting more access.
403 forbiddenYou lack the permission on that hotel, or the hotel was not chosen when you connected (details.missing is empty).Ask an admin for the permission, or reconnect and choose the hotel.
403 not_entitledThe hotel's plan does not include the feature. On Developer apps: the feature is off or you lack the permission.Ask your Maison contact.

Related