How scopes work
A scope is a named permission a host grants to your application. Haven declares 45 of them, of which 24 can be requested today. The full list is in the Scope reference; this page is the model behind it.
Naming
Every scope is resource:action. Reads end in :read; everything else writes.
listings:read calendar:write reservations:cancel
guests:read rates:write messaging:send
There are no wildcards. calendar:* is not a scope and never will be, because a wildcard is a permission whose meaning changes when Haven ships a feature, and a host cannot consent to something that does not exist yet.
Four things have to agree
What your token can do on any given request is the intersection of four sets:
The scopes frozen on the access token when it was minted. The scopes on the host's current grant. The ceiling Haven staff approved for your application. And the set of scopes that are currently grantable at all.
The intersection is recomputed on every request. Nothing is cached and nothing is trusted from the token itself. That is what makes revocation immediate: when a host narrows your grant, the next call reflects it.
The practical rule: treat /me as authoritative for what you hold, re-read it after any authorization change, and never infer permissions from a token you were issued an hour ago.
Dependencies are declared, never implied
Some scopes are meaningless alone. guests:read exposes guest identity on reservations, so it needs reservations:read to have anything to attach to.
Haven enforces these at authorization, not at request time. If you ask for guests:read without reservations:read, /authorize refuses and names what is missing. It does not silently add the dependency.
Holding a scope never confers another one. There is no hierarchy, no implication and no inheritance: reservations:write does not include reservations:read, and calendar:write does not include calendar:read. Ask for what you need, explicitly. A permission the host did not read on the consent screen is a permission they did not grant.
Tiers
Every grantable scope carries a tier that governs how much review it needs and how the consent screen presents it.
standard covers ordinary business data the host already sees on their own dashboard, or a reversible change to it. Any approved application may hold it.
sensitive covers third-party personal data and irreversible actions: guest contact details, the contents of guest correspondence, cancelling a stay, taking a listing off the market, sending a message that reaches a real person. These need a named sign-off recorded against your application, and the consent row carries a warning.
restricted covers arrival secrets and money leaving the account: guidebook:secrets:read and reservations:refund. Same sign-off, plus the consent row is never pre-selected and no bulk-approve affordance covers it. Every write behind a restricted scope also requires an explicit confirmation step.
Declared but not grantable
Two categories of scope appear in the reference that you cannot have.
Planned scopes are real and specified but unbuilt: payouts, reviews, tasks, media upload, listing creation. Requesting one returns invalid_scope naming the release it is planned for, so you can design against a roadmap rather than emailing to ask.
Refused scopes will never be granted to any application, and each carries a written reason. Billing and subscription management, payout destinations, the advertising wallet, team membership, workspace structure and account closure are all in this group. They touch the host's money or their control over their own account, and no integration is going to be the thing that moves either.
Documenting the refusals rather than omitting them is the point. An absent scope is indistinguishable from an oversight; a refused one is an answer.
Scope is necessary, not sufficient
Two things can refuse a write your scope permits.
The host's own role. A grant can never exceed the authority of the person who created it. If a host on a read-only seat authorizes your application, write scopes will not work, and Haven refuses at the consent screen rather than issuing a grant that would fail on first use.
The source-of-truth lock. If a channel manager owns a listing's availability, a calendar:write call against that listing is refused with domain_locked, naming the domain and the owning system. Your scope is real; the listing is not yours to write. Read lockedDomains on the listing before composing the write. See How it fits together.