Skip to content
Join our Slack

Domains

A form’s share link normally lives on the fomr host. With a custom domain, it can live on your own domain or on a fomr subdomain, under a path you choose. Domains are added and verified in the app, as described in Custom domains. The Platform API lists them and binds them to forms.

OperationWhat it doesPermission
GET /v1/domainsLists the domains of the organization.domains:read
PUT /v1/forms/{form_public_id}/domainSets the custom domain and slug of the share link.forms:write and domains:write
DELETE /v1/forms/{form_public_id}/domainRemoves the custom domain from the share link.forms:write and domains:write
Terminal window
curl -s -H "Authorization: Bearer $FOMR_TOKEN" \
https://platform.fomr.io/v1/domains
GET /v1/domains
{
"data": [
{
"host": "acme.fomr.io",
"status": "verified",
"is_active": true,
"is_fomr_subdomain": true,
"created_at": "2026-09-14T08:30:00.000Z"
},
{
"host": "forms.acme.com",
"status": "verified",
"is_active": true,
"is_fomr_subdomain": false,
"created_at": "2026-09-20T12:00:00.000Z"
},
{
"host": "events.acme.com",
"status": "pending",
"is_active": true,
"is_fomr_subdomain": false,
"created_at": "2026-10-20T16:45:00.000Z"
}
]
}

Every field of a domain is listed in the response of List domains.

Only a domain whose status is verified and whose is_active is true can be bound to a form. A domain turns inactive when the organization’s plan no longer includes custom domains.

Terminal window
curl -s -X PUT "https://platform.fomr.io/v1/forms/Ev3ntReg01/domain" \
-H "Authorization: Bearer $FOMR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"domain":"forms.acme.com","slug":"/register"}'

The response is the form resource. Its domain block shows the binding, and urls.share uses it once a version is published.

  • domain is the host from GET /v1/domains, matched without regard to case.
  • slug is the path after the host. Trailing slashes are removed and a leading slash is added, the same normalization the Share link tab applies, so register/ is stored as /register. Send / to serve the form at the root of the domain. Left out, the slug is /{form_public_id}.
  • A slug is unique per domain. A slug another form already uses on the same domain is 400 INVALID_INPUT at slug.
  • Sending the current binding changes nothing and answers 200, so the call is safe to retry.
  • Setting a domain replaces the previous one. A form has at most one custom domain.
RefusalAnswer
The organization’s plan has no custom domains402 PRO_FEATURE_REQUIRED with feature: "domains"
The host is unknown, not verified, or inactive400 INVALID_INPUT at domain
The slug holds characters other than letters, digits, -, _, and /400 INVALID_INPUT at slug
The resource is a Private Template, which has no share link400 INVALID_INPUT at domain
The form is archived409 FORM_ARCHIVED
The member lacks domains:write403 FORBIDDEN

The binding is stored the way the app stores it, so the editor shows it at once and publishing checks it like any other custom domain.

DELETE /v1/forms/{form_public_id}/domain removes the binding and answers the form resource, which uses the fomr link again. A form without a custom domain answers 200 and writes nothing. Removing a domain needs no plan feature.

Your next form could be the best-looking thing on your site.

Free forever. Unlimited responses. No signup to start.