Authentication & website scoping
One bearer token per website, how Resi decides which website a request is for, and why everything else is a 404.
The token
Every request needs a bearer token:
Authorization: Bearer <token>
Accept: application/jsonA token is scoped to exactly one website. It carries one of two abilities:
| Ability | Reads |
|---|---|
website:{id}:deliver | Published content. This is the token a production deployment holds in RESI_DELIVERY_TOKEN. |
website:{id}:preview | Everything deliver reads, plus draft and in-review content entries. Archived entries stay hidden. For preview deployments only. |
The production token is issued when Resi provisions the site and is written straight into the hosting project's environment. A site Resi does not host on Vercel is issued one by Resi staff instead (php artisan websites:delivery-token {website}, shown once; --revoke to withdraw it). A preview token is issued, rotated or revoked by Resi staff (php artisan websites:preview-token {website}, --revoke to withdraw it).
GET /site reports which one you hold in data.website.environment (production or preview).
Which website a request is for
The website never appears in the URL. Resi resolves it, in order, from:
- the
X-Resi-Websiteheader, holding the website id — use this from CI and build machines, whereHostmeans nothing; - the
Hostheader, matched against the website's domains.
The resolved website and the token's website must agree.
| Situation | Status |
|---|---|
| No token, or a revoked one | 401 |
| A valid token for a different website, or from another account | 403 |
An account API token (the wildcard * ability) | 403 — only a token issued for the website is accepted |
| A host or website id Resi does not know | 404 |
Send X-Resi-Website on every request. It costs nothing and removes any dependence on how your host forwards Host.
Scoping: slugs, and a uniform 404
Properties, floor plans and units are addressed by slug, and looked up only among the website's own enabled properties. UUIDs are not accepted in paths.
Anything outside that set answers exactly as a record that does not exist:
{ "message": "Not found." }That covers a property on another website, a disabled property, a hidden or disabled unit, a grouped floor plan's non-primary sibling, a form attached to none of the website's properties, and a malformed id. The body is identical in every case, so a response never confirms that a record exists somewhere else.
What is never served, anywhere in the API:
- properties that are disabled or not attached to the website;
- units that are disabled or marked hidden;
- connections that render nothing on a page (PMS, CRM, listing feeds, hosting) — see Lead sources & integrations.
Last updated on