Docs
Sites API

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/json

A token is scoped to exactly one website. It carries one of two abilities:

AbilityReads
website:{id}:deliverPublished content. This is the token a production deployment holds in RESI_DELIVERY_TOKEN.
website:{id}:previewEverything 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:

  1. the X-Resi-Website header, holding the website id — use this from CI and build machines, where Host means nothing;
  2. the Host header, matched against the website's domains.

The resolved website and the token's website must agree.

SituationStatus
No token, or a revoked one401
A valid token for a different website, or from another account403
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 know404

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

On this page