Deploy the relay and serve the zone. Safe to call again after a failure.

post/v1/installations/{id}/install

Request

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

Path parameters

idstring required

Request body

domainstring required

The zone this run installs. Must already be on the installation — addDomain first.

⛔ Named here rather than remembered from the authorization, because since 2026-08-26 the founder chooses it AFTER authorising and an installation may carry several. The session used to hold it, which only worked while exactly one zone could ever have been meant.

acceptAcceptableDanger[]

Pre-flight dangers the founder has been shown and has chosen to accept.

⛔ NOT foreign_mx, and the asymmetry is the whole design. The pre-flights are not equally serious and treating them as one list would be the mistake this field is most likely to invite:

  • foreign_mx — the domain receives mail somewhere else. Proceeding ENDS a business's email. There is no consent screen that makes that recoverable, and it stays an absolute wall. ⛔ Never add it here.
  • apex_spf — a second SPF record breaks sending for every message from the domain. Waivable, because accepting it REPLACES the existing record with the merge rather than telling somebody to go and do it. See the union below.
  • hostname_taken — something already answers at foundermail.<domain>. That hostname is OURS by construction: we define it, and nothing else has a reason to be there. In practice it is a record left by an earlier attempt at this same setup, which is precisely the case a wall strands a founder in — the install cannot proceed and cannot clean up after itself, so every retry meets the same refusal.
  • events_taken — the domain's Email Sending events already feed a subscription of theirs, and Cloudflare allows one per domain. Waivable, because accepting it REPLACES theirs with ours: the installer deletes it and subscribes the account's FounderMail queue.

⚠️ The server enforces this, not the caller. Anything else named here is ignored and the refusal stands — a client cannot widen what may be accepted by asking.

Response

The request has succeeded.

step'awaiting_authorization' | 'authorized' | 'connecting_account' | 'serving_zone' | 'activating_routing' | 'installed' required

awaiting_authorization: waiting for the founder at Cloudflare's consent screen. authorized: they approved it, and a credential is held for minutes — call startInstall now. ⛔ Reported so an AGENT can see it: until 2026-10-06 the approval left this at awaiting_authorization, so an agent had to ask a person "did it work?" while the credential burned down, and on that day it expired exactly so. Still a label and never the credential. connecting_account: deploying the relay and giving it an address — touches no mail. serving_zone: pointing a domain's mail at the relay. ⚠️ The destructive half. activating_routing: the domain is served and Cloudflare is switching its mail on — usually 5–15 minutes; keep polling. Mail sent before it finishes may bounce 550 5.1.1, which is why the install does not say installed until Cloudflare says ready (P58). failed here names what Cloudflare last reported; installing again carries on waiting and redoes nothing. installed: done — Cloudflare accepts the domain's mail.

state'waiting' | 'running' | 'failed' | 'done' required
completedstring[] required

The steps that completed, in order — so a resumed install can show what it skipped.

errorstring

Why it stopped, when it stopped.

Changes

No recorded changes to this operation across all 1 revision of this API.