Skip to main content
A self-hosted app runs inside a server you operate. Reintersect sends every delivery to one HTTPS endpoint you declare, and the SDK verifies, routes and answers it. Self-host when the app needs your own database or network, a fixed outbound address, or a runtime the hosted platform doesn’t offer.

Declare the endpoint

src/reintersect/app.ts
Reintersect sends POST requests to endpoint for every block render, action, insert, select search, reference resolve and search, command, message action and event. The endpoint’s path ending in /reintersect is the delivery path; the part before it (/api here) is the app’s root, where routes and the MCP server (/mcp) are served. The SDK checks the webhook signature on every delivery and rejects anything unsigned, stale or replayed. Endpoints must be HTTPS on the default port and resolve to public addresses. Reintersect doesn’t follow redirects from them.

Environment

Set these on your server: Also set the variables your app declares in env. The SDK reads them from the environment, or from the env object you pass as the second argument of app.fetch (as Workers does).

Mount the app

app.fetch(request, env?, ctx?) is a standard fetch handler. It only has a function type once the app is complete: if a piece needs a block, environment variable or service the app doesn’t provide, the mount is a type error that names what is missing. Mount it so it receives the delivery path, your routes and /mcp.
A catch-all route under /api, as the Next.js template writes it:
src/app/api/[[...path]]/route.ts
The project’s JSX is Reintersect JSX; start any React page or component with /** @jsxImportSource react */.

Install tokens

A self-hosted app keeps only install ids and never stores Reintersect tokens:
  • Inside a delivery, the body carries a one-hour install token for that install, and the handler’s reintersect client uses it. Action deliveries also carry an interaction token for the one block, valid for 15 minutes.
  • Outside a delivery (routes, cron jobs, your own backend), call reintersect.forInstall(installId) in a route, or createReintersectClient(app, { installId }) anywhere. The SDK mints a one-hour token with your client credentials (POST /v0/apps/installs/:installId/access-tokens), caches it and renews it before it expires.
Record install ids when the install link redirects back, or from the app.installed event, and forget them on app.uninstalled.
Treat the client secret like a password. With it and an install id, anyone can act as your app in that workspace, within the scopes the admin granted. Rotating it in Developer → Apps stops the old secret at once.

Local development

reintersect dev builds your app with esbuild, runs it in a local Node server, and relays deliveries for your development install to it. The relay replays the exact signed request production would send, so signature checks run locally too. Your endpoint doesn’t need to be reachable from the internet while you develop. Pick the local port with --port. To run your framework’s own dev server (npm run dev:next in the Next.js template), start it next to reintersect dev; deliveries during development still go to the CLI’s local server.

Deploy

Deploy your server the way you normally do, then sync the manifest so Reintersect knows about new blocks, actions and scopes:
For a self-hosted app this uploads no code. It records a new version with the manifest and endpoint, and the same publishing rules apply. Deploy your server first, so the endpoint can handle the new version before installs move to it. The GitHub Action does the sync on every merge.