Skip to content
API referencePlatformProject.settings

Update tenant MagicDNS policy

PUT
/platform/v1/project/dns

Validates + entitlement-gates + persists the project-wide MagicDNS policy, then republishes the project's live device maps (MD-D-07) so the branded suffix / nameservers reach connected devices in place. Admin+ only. Tenant-wide default nameservers + override-local-DNS need a paid project plan; split-DNS routes and static records are top-tier paid (count-metered); the branded mesh suffix is a higher-tier grant (HTTP 402 on a non-entitled tier or over quota). Enabling MagicDNS / override-local with zero resolvers is rejected (never-leak / never-zero, HTTP 400). A custom branded domain must already be a verified project domain.

Authorization

bearer_auth
AuthorizationBearer <token>

In: header

Header Parameters

X-Project-Id*string

UUID of the project that scopes consumer accounts, devices, sessions, and VSpaces for the request.

Formatuuid

Request Body

application/json

Tenant DNS policy patch (PUT semantics: present fields replace, absent fields are unchanged).

TypeScript Definitions

Use the request body type in TypeScript.

The tenant MagicDNS policy PUT body (MD-14). PUT semantics: a present field replaces that knob wholesale; an absent field leaves it unchanged. The two branded-suffix legs are Option<Option<…>>: absent = unchanged, null = clear back to the slug-default, a value = set.

Response Body

application/json

application/json

application/json

application/json

application/json

curl -X PUT "https://example.com/platform/v1/project/dns" \  -H "X-Project-Id: 11111111-1111-1111-1111-111111111111" \  -H "Content-Type: application/json" \  -d '{    "branded_suffix": "acme.mesh.fvpn.net",    "enabled": true,    "extra_records": [      {        "name": "vault.acme.mesh.fvpn.net",        "rtype": "a",        "value": "100.96.0.9"      }    ],    "nameservers": [      {        "addr": "1.1.1.1",        "use_with_exit_node": true      }    ],    "override_local_dns": true,    "routes": [      {        "resolvers": [          {            "addr": "10.0.0.53"          }        ],        "suffix": "corp.example.com"      }    ],    "search_domains": [      "corp.example.com"    ]  }'
{  "branded_suffix": "acme.mesh.fvpn.net",  "custom_domain_id": null,  "enabled": true,  "extra_records": [],  "override_local_dns": true,  "project_id": "11111111-1111-1111-1111-111111111111",  "resolvers": [    {      "addr": "1.1.1.1",      "use_with_exit_node": true    }  ],  "routes": [],  "search_domains": [    "corp.example.com"  ],  "updated_at": "2026-06-17T12:00:00Z"}
{  "detail": "Pool slug must be unique.",  "instance": "urn:forestvpn:trace:a1b2c3d4",  "title": "Validation Error",  "type": "https://fvpn.net/errors/validation"}
{  "detail": "Pool slug must be unique.",  "instance": "urn:forestvpn:trace:a1b2c3d4",  "title": "Validation Error",  "type": "https://fvpn.net/errors/validation"}
{  "detail": "Pool slug must be unique.",  "instance": "urn:forestvpn:trace:a1b2c3d4",  "title": "Validation Error",  "type": "https://fvpn.net/errors/validation"}
{  "detail": "Pool slug must be unique.",  "instance": "urn:forestvpn:trace:a1b2c3d4",  "title": "Validation Error",  "type": "https://fvpn.net/errors/validation"}