Domains, DNS & TLS
Preview Three related resources put a custom hostname in front of an environment. Domains attach a hostname to an environment. DNS records are managed at the site level, where managed.dev runs your zone. TLS is issued and renewed automatically — and its status read is live in the API today.
Domains Preview
Section titled “Domains ”A domain points a hostname at one environment. Production gets your apex and www;
preview and staging environments get their own hostnames. See
custom domains for the conceptual walkthrough.
GET · POST · DELETE /v1/sites/{id}/environments/{envID}/domains[/{domainID}]
Section titled “GET · POST · DELETE /v1/sites/{id}/environments/{envID}/domains[/{domainID}]”- List (domains:read) the domains on an environment.
- Add (domains:write) a domain — returns a
202job while verification and certificate issuance run. - Remove (domains:write) a domain.
| Parameter | Type | Required | Description |
|---|---|---|---|
hostname |
string | yes | The custom hostname, e.g. shop.example.com. |
redirect_to_primary |
boolean | no | If true, redirect this hostname to the primary domain. |
curl -X POST https://api.managed.dev/v1/sites/site_01J7.../environments/env_01J8.../domains \ -H "Authorization: Bearer mfk_live_..." \ -H "Idempotency-Key: 6c1a...d8" \ -H "Content-Type: application/json" \ -d '{ "hostname": "shop.example.com" }'job, err := client.Domains.Create(ctx, "site_01J7...", "env_01J8...", &forge.DomainCreateParams{Hostname: forge.String("shop.example.com")}, forge.WithIdempotencyKey("6c1a...d8"))const job = await client.domains.create( "site_01J7...", "env_01J8...", { hostname: "shop.example.com" }, { idempotencyKey: "6c1a...d8" },);{ "data": { "id": "job_01J9...", "type": "domain.attach", "status": "queued", "created_at": "2026-06-24T14:41:09Z", "resource": { "type": "domain", "id": "dom_01J8...", "hostname": "shop.example.com" }, "links": { "self": "/v1/jobs/job_01J9...", "stream": "/v1/jobs/job_01J9.../stream" } }, "request_id": "req_01J9..."}DNS records Preview
Section titled “DNS records ”When managed.dev runs your zone, DNS records are a site-level resource. See DNS.
GET · POST · PATCH · DELETE /v1/sites/{id}/dns/records[/{recordID}]
Section titled “GET · POST · PATCH · DELETE /v1/sites/{id}/dns/records[/{recordID}]”- List (domains:read) records, cursor-paginated.
- Create, update, or delete (domains:write) a record.
| Parameter | Type | Required | Description |
|---|---|---|---|
type |
string | yes | A, AAAA, CNAME, MX, TXT, … |
name |
string | yes | Record name, e.g. @, www, mail. |
value |
string | yes | Record value, e.g. an IP or target hostname. |
ttl |
integer | no | Time-to-live in seconds; a sensible default applies. |
priority |
integer | no | Priority for MX and SRV records. |
curl -X POST https://api.managed.dev/v1/sites/site_01J7.../dns/records \ -H "Authorization: Bearer mfk_live_..." \ -H "Content-Type: application/json" \ -d '{ "type": "TXT", "name": "@", "value": "v=spf1 include:managed.dev ~all", "ttl": 3600 }'{ "data": { "id": "rec_01J8...", "type": "TXT", "name": "@", "value": "v=spf1 include:managed.dev ~all", "ttl": 3600, "created_at": "2026-06-24T14:43:50Z" }, "request_id": "req_01J9..."}Certificates are issued and renewed automatically — per-node wildcard certs via DNS-01. The status read below is live today; a force-renew action remains on the roadmap. See TLS.
GET /v1/sites/{siteID}/tls
Section titled “GET /v1/sites/{siteID}/tls”tls:read Read certificate status for a site — the covered domain, the certificate’s lifecycle state, its CA, and its issue and expiry timestamps. This is a site-level read, matching how certificates are managed.
curl https://api.managed.dev/v1/sites/site_01J7.../tls \ -H "Authorization: Bearer mfk_live_..." \ -H "Forge-Version: 2026-06-23"tls, err := client.Sites.GetTLS(ctx, "site_01J7...")mf sites tls site_01J7...{ "data": { "domain": "shop.example.com", "state": "valid", "ca": "Let's Encrypt", "issued_at": "2026-06-24T00:00:00Z", "expires_at": "2026-09-22T00:00:00Z" }, "request_id": "req_01J9..."}state walks the certificate lifecycle: unconfigured, not_registered,
pending, valid, or expired. A non-empty error explains a stuck pending
state — usually DNS that doesn’t point at managed.dev yet.
Force a renewal Preview
Section titled “Force a renewal ”A POST force-renew action (under the reserved tls:write scope) is designed but
not yet shipped. You rarely need it — renewal is automatic — but it’s planned for
the case where you’ve just changed DNS and want a fresh certificate immediately.