---
title: "POST /v1/installations/{id}/authorize"
method: POST
path: "/v1/installations/{id}/authorize"
---

# POST /v1/installations/{id}/authorize

`POST /v1/installations/{id}/authorize`

## Request

- The document declares no server URL.
- Auth: one of:
  - HTTP bearer
  - API key in cookie `__Secure-better-auth.session_token`

Start connecting a Cloudflare account. Returns the consent URL to send the founder to.

## Path parameters

- `id` string, required

## Request body

- AuthorizationRequest: Begin the Cloudflare authorization that lets us install the relay into the founder's account. ⛔ **It no longer takes a domain, and that inversion is the point.** It did until 2026-08-26, which forced a founder to name a zone before anything was connected — so they typed one from memory and discovered several irreversible-looking steps later that it was not a zone on that account, or not on Cloudflare DNS at all. Authorising first means `listAvailableZones` can ask Cloudflare what is actually there, and the founder chooses from it. ⚠️ **The capability moved with the domain.** This used to mint one here and stash it for the install; a capability names the domains it covers, so one minted before any domain existed would name none. It is issued at install time instead, from the tenant's CURRENT domains — which is also more correct than before, where a domain added between authorising and installing produced a relay whose capability did not cover it. ⚠️ **No refresh token is requested.** The grant is spent within minutes and deliberately cannot outlive the tab: holding a long-lived credential for someone else's Cloudflare account is the single thing this design exists to avoid. Re-authorising for a teardown later is correct.What the founder has already decided about this run, carried across the consent hop. ⛔ **A refusal SPENDS the credential, which is why this is here and not only on the install.** Every path through the installer wipes the founder's Cloudflare token and the run's brief in a `finally` — the custody rule doing its job — so a founder shown `hostname_taken` and offered "replace it and carry on" cannot simply call `startInstall` again: there is no install in progress any more. They have to re-authorise, and their decision has to survive that. ⚠️ **On the server, not in the tab.** Nothing is stashed in the browser across the consent hop, deliberately: a founder who starts on a laptop and finishes on a phone sees the same thing, and a decision about somebody's DNS is not a thing to keep in `sessionStorage`.
  - `accept` AcceptableDanger[]
  - `initiator` 'console' | 'agent': Who asked for a Cloudflare authorisation, and therefore what should happen after it.

## Response `200`

The request has succeeded.

- CloudflareAuthorization
  - `consentUrl` string, uri, required: Where to send the founder: a `dash.cloudflare.com` consent screen naming every permission this install needs. Single-use and short-lived — asking again replaces it, and the previous one stops being accepted.

## Other responses

- `default`: An unexpected error response.

---

[API](https://skmtc.dev/foundermail/apis/org.md) - [All operations](https://skmtc.dev/foundermail/apis/org/llms.txt) - [OpenAPI document](https://skmtc.dev/foundermail/apis/org/revisions/8bbb36e378ab?raw)
